@levo-so/core 0.1.60 → 0.1.61

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 (3) hide show
  1. package/dist/index.d.ts +528 -502
  2. package/dist/index.js +239 -1204
  3. package/package.json +9 -15
package/dist/index.js CHANGED
@@ -1,973 +1,6 @@
1
- import { onUserActivity } from '@analytics/activity-utils';
2
- import { getVisitorSource } from '@analytics/visitor-source';
3
- import { Analytics } from 'analytics';
4
- import getUserLocale from 'get-user-locale';
5
- import { WretchError } from 'wretch/resolver';
6
1
  import wretch from 'wretch';
7
2
  import queryStringAddon from 'wretch/addons/queryString';
8
-
9
- // src/control/audience.ts
10
-
11
- // src/utils/isIncognito.ts
12
- var isIncognito = () => new Promise((resolve, reject) => {
13
- let browserName = "Unknown";
14
- function __callback(isPrivate) {
15
- resolve({
16
- isPrivate,
17
- browserName
18
- });
19
- }
20
- function identifyChromium() {
21
- const ua = navigator.userAgent;
22
- if (ua.match(/Chrome/)) {
23
- if (navigator.brave !== void 0) {
24
- return "Brave";
25
- }
26
- if (ua.match(/Edg/)) {
27
- return "Edge";
28
- }
29
- if (ua.match(/OPR/)) {
30
- return "Opera";
31
- }
32
- return "Chrome";
33
- }
34
- return "Chromium";
35
- }
36
- function assertEvalToString(value) {
37
- return value === eval.toString().length;
38
- }
39
- function isSafari() {
40
- const v = navigator.vendor;
41
- return v !== void 0 && v.indexOf("Apple") === 0 && assertEvalToString(37);
42
- }
43
- function isChrome() {
44
- const v = navigator.vendor;
45
- return v !== void 0 && v.indexOf("Google") === 0 && assertEvalToString(33);
46
- }
47
- function isFirefox() {
48
- return document.documentElement !== void 0 && document.documentElement.style.MozAppearance !== void 0 && assertEvalToString(37);
49
- }
50
- function isMSIE() {
51
- return navigator.msSaveBlob !== void 0 && assertEvalToString(39);
52
- }
53
- function newSafariTest() {
54
- const tmp_name = String(Math.random());
55
- try {
56
- const db = window.indexedDB.open(tmp_name, 1);
57
- db.onupgradeneeded = (i) => {
58
- const res = i.target?.result;
59
- try {
60
- res.createObjectStore("test", {
61
- autoIncrement: true
62
- }).put(new Blob());
63
- __callback(false);
64
- } catch (e) {
65
- let message = e;
66
- if (e instanceof Error) {
67
- message = e.message ?? e;
68
- }
69
- if (typeof message !== "string") {
70
- return __callback(false);
71
- }
72
- const matchesExpectedError = /BlobURLs are not yet supported/.test(
73
- message
74
- );
75
- return __callback(matchesExpectedError);
76
- } finally {
77
- res.close();
78
- window.indexedDB.deleteDatabase(tmp_name);
79
- }
80
- };
81
- } catch (e) {
82
- return __callback(false);
83
- }
84
- }
85
- function oldSafariTest() {
86
- const openDB = window.openDatabase;
87
- const storage = window.localStorage;
88
- try {
89
- openDB(null, null, null, null);
90
- } catch (e) {
91
- return __callback(true);
92
- }
93
- try {
94
- storage.setItem("test", "1");
95
- storage.removeItem("test");
96
- } catch (e) {
97
- return __callback(true);
98
- }
99
- return __callback(false);
100
- }
101
- function safariPrivateTest() {
102
- if (navigator.maxTouchPoints !== void 0) {
103
- newSafariTest();
104
- } else {
105
- oldSafariTest();
106
- }
107
- }
108
- function getQuotaLimit() {
109
- const w = window;
110
- if (w.performance !== void 0 && w.performance.memory !== void 0 && w.performance.memory.jsHeapSizeLimit !== void 0) {
111
- return performance.memory.jsHeapSizeLimit;
112
- }
113
- return 1073741824;
114
- }
115
- function storageQuotaChromePrivateTest() {
116
- navigator.webkitTemporaryStorage.queryUsageAndQuota(
117
- (_, quota) => {
118
- const quotaInMib = Math.round(quota / (1024 * 1024));
119
- const quotaLimitInMib = Math.round(getQuotaLimit() / (1024 * 1024)) * 2;
120
- __callback(quotaInMib < quotaLimitInMib);
121
- },
122
- (e) => {
123
- reject(
124
- new Error(
125
- `detectIncognito somehow failed to query storage quota: ${e.message}`
126
- )
127
- );
128
- }
129
- );
130
- }
131
- function oldChromePrivateTest() {
132
- const fs = window.webkitRequestFileSystem;
133
- const success = () => {
134
- __callback(false);
135
- };
136
- const error = () => {
137
- __callback(true);
138
- };
139
- fs(0, 1, success, error);
140
- }
141
- function chromePrivateTest() {
142
- if (self.Promise !== void 0 && self.Promise.allSettled !== void 0) {
143
- storageQuotaChromePrivateTest();
144
- } else {
145
- oldChromePrivateTest();
146
- }
147
- }
148
- function firefoxPrivateTest() {
149
- __callback(navigator.serviceWorker === void 0);
150
- }
151
- function msiePrivateTest() {
152
- __callback(window.indexedDB === void 0);
153
- }
154
- function main() {
155
- if (isSafari()) {
156
- browserName = "Safari";
157
- safariPrivateTest();
158
- } else if (isChrome()) {
159
- browserName = identifyChromium();
160
- chromePrivateTest();
161
- } else if (isFirefox()) {
162
- browserName = "Firefox";
163
- firefoxPrivateTest();
164
- } else if (isMSIE()) {
165
- browserName = "Internet Explorer";
166
- msiePrivateTest();
167
- } else {
168
- reject(new Error("detectIncognito cannot determine the browser"));
169
- }
170
- }
171
- main();
172
- });
173
- var isIncognito_default = isIncognito;
174
-
175
- // src/utils/getUserProperties.ts
176
- var getGPUInfo = () => {
177
- const canvas = document.createElement("canvas");
178
- const gl = canvas?.getContext("webgl") || canvas?.getContext("experimental-webgl");
179
- if (!gl) {
180
- return null;
181
- }
182
- const debugInfo = gl?.getExtension("WEBGL_debug_renderer_info");
183
- return debugInfo ? gl?.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) : null;
184
- };
185
- var getUserProperties = async () => {
186
- let locale = "";
187
- let timezone = "";
188
- let dark_mode = false;
189
- let private_mode = false;
190
- const properties = {};
191
- if (!window) {
192
- return {
193
- locale,
194
- timezone,
195
- dark_mode,
196
- private_mode,
197
- properties
198
- };
199
- }
200
- try {
201
- ({ isPrivate: private_mode } = await isIncognito_default());
202
- } catch (e) {
203
- console.error(e);
204
- }
205
- try {
206
- dark_mode = window.matchMedia?.("(prefers-color-scheme: dark)").matches;
207
- } catch (e) {
208
- console.error(e);
209
- }
210
- try {
211
- timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
212
- } catch (e) {
213
- console.error(e);
214
- }
215
- try {
216
- locale = getUserLocale();
217
- } catch (e) {
218
- console.error(e);
219
- }
220
- if (navigator && "connection" in navigator) {
221
- const connection = navigator.connection || navigator?.mozConnection || navigator.webkitConnection;
222
- properties.network_type = connection.effectiveType;
223
- }
224
- properties.width = window?.innerWidth;
225
- properties.height = window?.innerHeight;
226
- properties.pixel_ratio = window?.devicePixelRatio;
227
- if (screen) {
228
- properties.screen_width = screen?.width;
229
- properties.screen_height = screen?.height;
230
- properties.color_depth = screen?.colorDepth;
231
- properties.orientation = screen?.orientation?.type;
232
- }
233
- if (navigator && "getBattery" in navigator) {
234
- const battery = await navigator?.getBattery();
235
- if (battery) {
236
- properties.battery_level = Number((battery?.level * 100).toFixed(0));
237
- properties.battery_charging = battery?.charging;
238
- properties.battery_discharging_time = battery?.dischargingTime;
239
- properties.battery_full_charge_capacity = battery?.fullChargeCapacity;
240
- properties.battery_charging_time = battery?.chargingTime;
241
- }
242
- }
243
- if (navigator && "deviceMemory" in navigator) {
244
- properties.device_memory = navigator?.deviceMemory;
245
- }
246
- const supportsTouch = "ontouchstart" in window || typeof navigator?.maxTouchPoints !== "undefined" && navigator?.maxTouchPoints > 0;
247
- properties.touch_supported = supportsTouch;
248
- if ("hardwareConcurrency" in navigator) {
249
- properties.hardware_concurrency = navigator?.hardwareConcurrency;
250
- }
251
- if (navigator && "mediaDevices" in navigator) {
252
- const mediaDevices = navigator?.mediaDevices;
253
- const devices = await mediaDevices?.enumerateDevices();
254
- const hasCamera = devices.some((device) => device?.kind === "videoinput");
255
- properties.camera_supported = hasCamera;
256
- const hasMicrophone = devices.some(
257
- (device) => device?.kind === "audioinput"
258
- );
259
- properties.microphone_supported = hasMicrophone;
260
- }
261
- properties.gpu = getGPUInfo();
262
- return {
263
- locale,
264
- timezone,
265
- dark_mode,
266
- private_mode,
267
- properties
268
- };
269
- };
270
-
271
- // src/utils/LevoError.ts
272
- var LevoError = class extends Error {
273
- code;
274
- title;
275
- status;
276
- type;
277
- errors;
278
- constructor(data) {
279
- super(data.description);
280
- this.name = "Levo Request Error";
281
- this.status = data.status;
282
- this.code = data.code;
283
- this.title = data.title;
284
- this.type = data.type;
285
- this.errors = data.errors;
286
- }
287
- /**
288
- * Get validation errors for form fields
289
- */
290
- get fieldErrors() {
291
- return this.errors || [];
292
- }
293
- /**
294
- * Check if this is a validation error with field-specific errors
295
- */
296
- get hasFieldErrors() {
297
- return Boolean(this.errors?.length);
298
- }
299
- };
300
-
301
- // src/utils/getLevoError.ts
302
- var getLevoError = (error) => {
303
- if (error instanceof LevoError) {
304
- return error;
305
- }
306
- if (error instanceof WretchError && error?.json) {
307
- const errorResponse = error?.json;
308
- return new LevoError({
309
- status: errorResponse?.content?.status || 500,
310
- code: errorResponse?.content?.code || `Unknown`,
311
- title: errorResponse?.content?.title || `HTTP ${error?.status || 500} Error`,
312
- description: errorResponse?.content?.description || `Request failed with status ${error?.status || 500}`,
313
- type: errorResponse?.content?.type,
314
- errors: errorResponse?.content?.errors
315
- });
316
- }
317
- if (error instanceof TypeError) {
318
- if (error?.message.includes("Failed to fetch") || error?.message.includes("Network request failed") || error?.message.includes("fetch")) {
319
- return new LevoError({
320
- status: 0,
321
- code: "NETWORK_ERROR",
322
- title: "Network Error",
323
- description: "Unable to connect to the server. Please check your internet connection."
324
- });
325
- }
326
- if (error?.message.includes("CORS") || error?.message.includes("cross-origin")) {
327
- return new LevoError({
328
- status: 0,
329
- code: "CORS_ERROR",
330
- title: "CORS Error",
331
- description: "Cross-origin request blocked. Please contact support."
332
- });
333
- }
334
- }
335
- if (error?.name === "AbortError" || error instanceof DOMException) {
336
- return new LevoError({
337
- status: 408,
338
- code: "REQUEST_TIMEOUT",
339
- title: "Request Timeout",
340
- description: "The request was cancelled or timed out. Please try again."
341
- });
342
- }
343
- if (error?.request) {
344
- return new LevoError({
345
- status: error?.response?.status || 500,
346
- code: error?.code || "REQUEST_ERROR",
347
- title: "Request Error",
348
- description: error?.message || "An error occurred while making the request"
349
- });
350
- }
351
- return new LevoError({
352
- status: 500,
353
- code: "UNKNOWN_ERROR",
354
- title: "Unexpected Error",
355
- description: error?.message || "Something unexpected happened"
356
- });
357
- };
358
-
359
- // src/control/audience.ts
360
- var BATCH_SIZE = 50;
361
- var BATCH_INTERVAL_MS = 5e3;
362
- var MAX_EVENTS_PER_PAGE = 500;
363
- var BROADCAST_CHANNEL_NAME = "levo_analytics";
364
- var createLevoAudienceModule = (core, httpClient) => {
365
- const _IDLE_THROTTLE = 1 * 1e3;
366
- const _IDLE_TIMEOUT = 60 * 1e3;
367
- let instance = null;
368
- let idle_listener = null;
369
- const storage_keys = {
370
- /** Legacy: Lock key for identify operation (no longer used internally) */
371
- identify: "lock:lv_aud_identify",
372
- /** Key for tracking open tab count */
373
- open_tabs: "lv_insights_ot",
374
- /** Key for current tab ID (sessionStorage) */
375
- current_tab: "lv_insights_ct",
376
- /** Key for all tabs registry */
377
- all_tabs: "lv_insights_at",
378
- /** Device JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
379
- device_token: "lv_aud_device",
380
- /** Session JWT for direct mode (1yr expiry, rotated on /welcome, analytics-only scope) */
381
- session_token: "lv_aud_session",
382
- /** Cached insights mode ('proxy' | 'direct') */
383
- mode: "lv_aud_mode"
384
- };
385
- let _insightsMode = "proxy";
386
- let _insightsBaseUrl = "";
387
- let _localStorageAvailable = true;
388
- const _memoryStorage = /* @__PURE__ */ new Map();
389
- const checkLocalStorageAvailable = () => {
390
- if (typeof window === "undefined" || !("localStorage" in window)) {
391
- return false;
392
- }
393
- try {
394
- const testKey = "__levo_test__";
395
- window.localStorage.setItem(testKey, "test");
396
- window.localStorage.removeItem(testKey);
397
- return true;
398
- } catch {
399
- return false;
400
- }
401
- };
402
- const getFromStorage = (key) => {
403
- if (typeof window === "undefined") {
404
- return _memoryStorage.get(key) || null;
405
- }
406
- if (_localStorageAvailable) {
407
- try {
408
- return window.localStorage.getItem(key);
409
- } catch {
410
- return _memoryStorage.get(key) || null;
411
- }
412
- }
413
- return _memoryStorage.get(key) || null;
414
- };
415
- const setInStorage = (key, value) => {
416
- if (typeof window === "undefined") {
417
- _memoryStorage.set(key, value);
418
- return;
419
- }
420
- if (_localStorageAvailable) {
421
- try {
422
- window.localStorage.setItem(key, value);
423
- return;
424
- } catch {
425
- }
426
- }
427
- _memoryStorage.set(key, value);
428
- };
429
- const removeFromStorage = (key) => {
430
- _memoryStorage.delete(key);
431
- if (typeof window === "undefined" || !_localStorageAvailable) {
432
- return;
433
- }
434
- try {
435
- window.localStorage.removeItem(key);
436
- } catch {
437
- }
438
- };
439
- const getAuthHeaders = () => {
440
- const headers = {};
441
- if (_insightsMode === "direct") {
442
- const deviceToken = getFromStorage(storage_keys.device_token);
443
- const sessionToken = getFromStorage(storage_keys.session_token);
444
- if (deviceToken) headers["Levo-Audience-Device"] = deviceToken;
445
- if (sessionToken) headers["Levo-Audience-Session"] = sessionToken;
446
- }
447
- return headers;
448
- };
449
- const pingEndpoint = async (url, timeout) => {
450
- let timeoutId = null;
451
- try {
452
- const controller = new AbortController();
453
- timeoutId = setTimeout(() => controller.abort(), timeout);
454
- const response = await fetch(url, {
455
- method: "GET",
456
- signal: controller.signal,
457
- credentials: "omit"
458
- });
459
- return response.ok;
460
- } catch {
461
- return false;
462
- } finally {
463
- if (timeoutId) {
464
- clearTimeout(timeoutId);
465
- }
466
- }
467
- };
468
- const detectInsightsMode = async () => {
469
- if (core.insightsMode === "proxy") {
470
- _insightsBaseUrl = core.insightsUrl;
471
- return "proxy";
472
- }
473
- if (core.insightsMode === "direct") {
474
- if (!core.directInsightsUrl) {
475
- console.warn(
476
- "[@levo-so/core] insightsMode='direct' but directInsightsUrl not set. Falling back to proxy."
477
- );
478
- _insightsBaseUrl = core.insightsUrl;
479
- return "proxy";
480
- }
481
- _insightsBaseUrl = core.directInsightsUrl;
482
- setInStorage(storage_keys.mode, "direct");
483
- return "direct";
484
- }
485
- const cachedMode = getFromStorage(storage_keys.mode);
486
- if (cachedMode === "proxy" || cachedMode === "direct") {
487
- if (cachedMode === "direct" && !core.directInsightsUrl) {
488
- removeFromStorage(storage_keys.mode);
489
- _insightsBaseUrl = "";
490
- } else {
491
- const pingUrl = cachedMode === "proxy" ? `${core.insightsUrl}/ping` : `${core.directInsightsUrl}/ping`;
492
- if (await pingEndpoint(pingUrl, core.pingTimeout)) {
493
- _insightsBaseUrl = cachedMode === "proxy" ? core.insightsUrl : core.directInsightsUrl;
494
- return cachedMode;
495
- }
496
- }
497
- }
498
- if (await pingEndpoint(`${core.insightsUrl}/ping`, core.pingTimeout)) {
499
- setInStorage(storage_keys.mode, "proxy");
500
- _insightsBaseUrl = core.insightsUrl;
501
- return "proxy";
502
- }
503
- if (core.directInsightsUrl) {
504
- setInStorage(storage_keys.mode, "direct");
505
- _insightsBaseUrl = core.directInsightsUrl;
506
- return "direct";
507
- }
508
- _insightsBaseUrl = core.insightsUrl;
509
- return "proxy";
510
- };
511
- let _session = "";
512
- let _device = "";
513
- let is_identified = false;
514
- let _eventCount = 0;
515
- let _eventQueue = [];
516
- let _flushTimer = null;
517
- let _channel = null;
518
- let _pendingIdentify = false;
519
- const buildSessionSyncMessage = () => {
520
- const message = {
521
- type: "SESSION_SYNC",
522
- session: _session,
523
- device: _device
524
- };
525
- if (_insightsMode === "direct") {
526
- const storedDeviceToken = getFromStorage(storage_keys.device_token);
527
- const storedSessionToken = getFromStorage(storage_keys.session_token);
528
- if (storedDeviceToken) message.deviceToken = storedDeviceToken;
529
- if (storedSessionToken) message.sessionToken = storedSessionToken;
530
- }
531
- return message;
532
- };
533
- const initBroadcastChannel = () => {
534
- if (typeof BroadcastChannel === "undefined") {
535
- return;
536
- }
537
- try {
538
- _channel = new BroadcastChannel(BROADCAST_CHANNEL_NAME);
539
- _channel.onmessage = (event) => {
540
- const { type, session, device, deviceToken, sessionToken } = event.data;
541
- if (type === "SESSION_SYNC" && !is_identified) {
542
- _session = session;
543
- _device = device;
544
- is_identified = true;
545
- _pendingIdentify = false;
546
- if (_insightsMode === "direct" && deviceToken && sessionToken) {
547
- setInStorage(storage_keys.device_token, deviceToken);
548
- setInStorage(storage_keys.session_token, sessionToken);
549
- }
550
- }
551
- if (type === "SESSION_REQUEST" && is_identified) {
552
- _channel?.postMessage(buildSessionSyncMessage());
553
- }
554
- };
555
- } catch (e) {
556
- }
557
- };
558
- const requestSessionFromOtherTabs = () => {
559
- _channel?.postMessage({ type: "SESSION_REQUEST" });
560
- };
561
- const broadcastSession = () => {
562
- _channel?.postMessage(buildSessionSyncMessage());
563
- };
564
- const flushEventQueue = () => {
565
- const baseUrl = _insightsBaseUrl || core?.insightsUrl;
566
- if (_eventQueue.length === 0 || !baseUrl || !core.workspace) {
567
- return;
568
- }
569
- const batch = _eventQueue.map((event) => ({
570
- ...event,
571
- session_id: event.session_id || _session,
572
- device_id: event.device_id || _device
573
- }));
574
- _eventQueue = [];
575
- const url = `${baseUrl}/v1/insights/event/bulk?workspace=${core.workspace}`;
576
- const headers = {
577
- "Content-Type": "application/json",
578
- ...getAuthHeaders()
579
- };
580
- if (_insightsMode === "proxy" && navigator.sendBeacon) {
581
- const success = navigator.sendBeacon(url, JSON.stringify(batch));
582
- if (success) {
583
- return;
584
- }
585
- }
586
- fetch(url, {
587
- method: "POST",
588
- body: JSON.stringify(batch),
589
- headers,
590
- keepalive: true,
591
- credentials: _insightsMode === "proxy" ? "include" : "omit"
592
- }).catch(() => {
593
- });
594
- };
595
- const startFlushTimer = () => {
596
- if (_flushTimer) {
597
- return;
598
- }
599
- _flushTimer = setInterval(() => {
600
- flushEventQueue();
601
- }, BATCH_INTERVAL_MS);
602
- if (typeof document !== "undefined") {
603
- document.addEventListener("visibilitychange", () => {
604
- if (document.visibilityState === "hidden") {
605
- flushEventQueue();
606
- }
607
- });
608
- window.addEventListener("beforeunload", () => {
609
- flushEventQueue();
610
- });
611
- window.addEventListener("pagehide", () => {
612
- flushEventQueue();
613
- });
614
- }
615
- };
616
- const stopFlushTimer = () => {
617
- if (_flushTimer) {
618
- clearInterval(_flushTimer);
619
- _flushTimer = null;
620
- }
621
- };
622
- const queueEvent = (collectInput) => {
623
- if (_eventCount >= MAX_EVENTS_PER_PAGE) {
624
- console.warn(
625
- `[@levo-so/core] Event limit (${MAX_EVENTS_PER_PAGE}) reached for this page`
626
- );
627
- return;
628
- }
629
- _eventCount++;
630
- _eventQueue.push(collectInput);
631
- if (_eventQueue.length >= BATCH_SIZE) {
632
- flushEventQueue();
633
- }
634
- };
635
- const getReferrer = () => {
636
- if (typeof document === "undefined") {
637
- return {};
638
- }
639
- const {
640
- type,
641
- referrer,
642
- data = {}
643
- } = getVisitorSource({
644
- referrer: document.referrer,
645
- currentUrl: window.location.href,
646
- mapper: null
647
- });
648
- const dataKeys = Object.keys(data);
649
- for (const key of dataKeys) {
650
- if (data[key] && Array.isArray(data[key]) && data[key].length > 0) {
651
- data[key] = data[key]?.[0];
652
- }
653
- }
654
- return { type, referrer, data, raw: document.referrer };
655
- };
656
- const getCurrentTabId = () => {
657
- try {
658
- if (typeof window === "undefined" || !("sessionStorage" in window)) {
659
- return "";
660
- }
661
- const CURRENT_TAB_LOCAL_STORAGE_KEY = storage_keys.current_tab;
662
- return window.sessionStorage.getItem(CURRENT_TAB_LOCAL_STORAGE_KEY) || "";
663
- } catch (_) {
664
- return "";
665
- }
666
- };
667
- const getTabCount = () => {
668
- try {
669
- if (typeof window === "undefined" || !("localStorage" in window)) {
670
- return 0;
671
- }
672
- const OT_LOCAL_STORAGE_KEY = storage_keys.open_tabs;
673
- return Number(window.localStorage.getItem(OT_LOCAL_STORAGE_KEY)) || 0;
674
- } catch (_) {
675
- return 0;
676
- }
677
- };
678
- const getActivityStatus = () => {
679
- const status = idle_listener?.getStatus();
680
- if (!status) {
681
- return null;
682
- }
683
- return {
684
- status: status.isIdle ? "idle" : "active",
685
- seconds: status.isIdle ? status.idle : status.active
686
- };
687
- };
688
- const identify = async (options) => {
689
- if (!instance) {
690
- return;
691
- }
692
- const withLock = options?.withLock ?? true;
693
- const referrer = getReferrer();
694
- const traits = await getUserProperties();
695
- await instance.identify("", {
696
- ...traits,
697
- referrer,
698
- withLock
699
- });
700
- };
701
- const request = async (url, data) => {
702
- const headers = {
703
- Accept: "application/json",
704
- "Content-Type": "application/json",
705
- ...getAuthHeaders()
706
- };
707
- try {
708
- const response = await httpClient.instance.url(_insightsBaseUrl || core?.insightsUrl, true).url(url).options({
709
- keepAlive: true,
710
- credentials: _insightsMode === "proxy" ? "include" : "omit"
711
- }).headers(headers).post(data).json();
712
- return response;
713
- } catch (error) {
714
- console.warn(`Analytics request failed for ${url}:`, error);
715
- return null;
716
- }
717
- };
718
- const initiate = async (properties) => {
719
- if (core.NODE_ENV === "development") {
720
- return;
721
- }
722
- _eventCount = 0;
723
- _localStorageAvailable = checkLocalStorageAvailable();
724
- _insightsMode = await detectInsightsMode();
725
- initBroadcastChannel();
726
- requestSessionFromOtherTabs();
727
- startFlushTimer();
728
- await new Promise((resolve) => setTimeout(resolve, 50));
729
- const plugin = {
730
- name: core.workspace,
731
- /**
732
- * Handle track events (custom events like clicks, scrolls, etc.)
733
- *
734
- * Enriches the event with:
735
- * - Session/device IDs
736
- * - Page metadata (URL, title, etc.)
737
- * - Tab information
738
- * - Timestamp
739
- *
740
- * Then queues for batched sending.
741
- */
742
- track: ({ payload }) => {
743
- if (!core?.insightsUrl || !core.workspace) {
744
- return;
745
- }
746
- const payloadProperties = payload?.properties || {};
747
- const collectInput = {
748
- session_id: _session,
749
- device_id: _device,
750
- event: payload.event,
751
- version: payload.version || 1,
752
- workspace_id: core.workspace,
753
- site_id: core.site || void 0,
754
- properties: {
755
- ...properties,
756
- ...payloadProperties,
757
- // Remove metadata fields from properties (they're top-level)
758
- version: void 0,
759
- resource: void 0,
760
- identifier: void 0,
761
- hostname: void 0,
762
- pathname: void 0,
763
- url: void 0,
764
- page_title: void 0,
765
- created_at: void 0
766
- },
767
- hostname: payload?.hostname || window.location.hostname,
768
- pathname: payload?.pathname || window.location.pathname,
769
- url: payload?.url || window.location.href,
770
- page_title: payload?.page_title || document.title,
771
- resource: payloadProperties?.resource || "page",
772
- identifier: payloadProperties?.identifier || properties?.id,
773
- created_at: payload?.created_at || (/* @__PURE__ */ new Date()).toISOString(),
774
- tab_id: getCurrentTabId(),
775
- tab_count: getTabCount()
776
- };
777
- queueEvent(collectInput);
778
- },
779
- /**
780
- * Handle page view events.
781
- *
782
- * Called when navigating to a new page (in SPAs) or on initial load.
783
- * Resets the rate limit counter and tracks a page.view event.
784
- */
785
- page: ({ payload }) => {
786
- if (!core?.insightsUrl) {
787
- return;
788
- }
789
- _eventCount = 0;
790
- const payloadProperties = payload?.properties || {};
791
- track("page.view", {
792
- ...properties,
793
- ...payloadProperties,
794
- title: document.title,
795
- identifier: properties.id,
796
- resource: "page"
797
- });
798
- },
799
- /**
800
- * Handle identify events (session establishment).
801
- *
802
- * This is called when identify() is invoked. It:
803
- * 1. Checks if already identified (via BroadcastChannel) - if so, skip
804
- * 2. Calls /welcome API to get session/device IDs
805
- * 3. On success, broadcasts session to other tabs
806
- *
807
- * The /welcome API uses HttpOnly cookies to maintain persistent
808
- * device identity across sessions.
809
- */
810
- identify: ({ payload }) => {
811
- if (!core?.insightsUrl || !core.workspace) {
812
- return;
813
- }
814
- if (is_identified) {
815
- return;
816
- }
817
- if (_pendingIdentify) {
818
- return;
819
- }
820
- _pendingIdentify = true;
821
- const welcomeInput = {
822
- private_mode: payload.traits.private_mode,
823
- dark_mode: payload.traits.dark_mode,
824
- timezone: payload.traits.timezone,
825
- locale: payload.traits.locale,
826
- referrer: payload.traits.referrer,
827
- properties: payload.traits.properties,
828
- workspace_id: core.workspace,
829
- site_id: core.site || void 0,
830
- hostname: window.location.hostname,
831
- pathname: window.location.pathname,
832
- page_title: document.title,
833
- url: window.location.href,
834
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
835
- tab_id: getCurrentTabId(),
836
- tab_count: getTabCount()
837
- };
838
- request(`/v1/insights/event/welcome`, welcomeInput).then((data) => {
839
- if (is_identified) {
840
- _pendingIdentify = false;
841
- return;
842
- }
843
- is_identified = true;
844
- _pendingIdentify = false;
845
- if (data?.content?.data?.session) {
846
- _session = data?.content.data.session;
847
- }
848
- if (data?.content?.data?.device) {
849
- _device = data?.content.data.device;
850
- }
851
- if (_insightsMode === "direct" && data?.content?.meta) {
852
- const meta = data.content.meta;
853
- if (meta.device_token) {
854
- setInStorage(storage_keys.device_token, meta.device_token);
855
- }
856
- if (meta.session_token) {
857
- setInStorage(storage_keys.session_token, meta.session_token);
858
- }
859
- }
860
- broadcastSession();
861
- }).catch((e) => {
862
- _pendingIdentify = false;
863
- return getLevoError(e);
864
- });
865
- }
866
- };
867
- instance = Analytics({
868
- app: core.workspace || "",
869
- plugins: [plugin]
870
- });
871
- await identify();
872
- startActivityListener();
873
- return instance.page({
874
- resource: "page",
875
- identifier: properties.id
876
- });
877
- };
878
- const startActivityListener = () => {
879
- if (typeof document !== "undefined" && !idle_listener) {
880
- idle_listener = onUserActivity({
881
- timeout: _IDLE_TIMEOUT,
882
- throttle: _IDLE_THROTTLE,
883
- onIdle: (activeForSeconds) => {
884
- track("user.idle", {
885
- seconds_active: activeForSeconds
886
- });
887
- },
888
- onWakeUp: (idleForSeconds) => {
889
- track("user.active", {
890
- seconds_idle: idleForSeconds
891
- });
892
- }
893
- });
894
- }
895
- return null;
896
- };
897
- const bounce = async (properties) => {
898
- const activity_status = getActivityStatus();
899
- if (activity_status) {
900
- if (activity_status?.status === "idle") {
901
- properties.seconds_idle = activity_status.seconds;
902
- } else {
903
- properties.seconds_active = activity_status.seconds;
904
- }
905
- }
906
- track("page.bounce", properties);
907
- };
908
- const track = async (event, properties) => {
909
- if (!core.workspace) {
910
- return;
911
- }
912
- if (instance) {
913
- return instance.track(event, properties);
914
- }
915
- const collectInput = {
916
- event,
917
- version: properties?.version || 1,
918
- properties: {
919
- ...properties,
920
- version: void 0,
921
- resource: void 0,
922
- identifier: void 0,
923
- hostname: void 0,
924
- pathname: void 0,
925
- url: void 0,
926
- page_title: void 0,
927
- created_at: void 0
928
- },
929
- hostname: window.location.hostname,
930
- pathname: window.location.pathname,
931
- url: window.location.href,
932
- page_title: document.title,
933
- resource: properties?.resource || "page",
934
- identifier: properties?.identifier || properties?.id,
935
- workspace_id: core.workspace,
936
- site_id: core.site || void 0,
937
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
938
- tab_id: getCurrentTabId(),
939
- tab_count: getTabCount()
940
- };
941
- queueEvent(collectInput);
942
- };
943
- const destroy = () => {
944
- flushEventQueue();
945
- stopFlushTimer();
946
- _channel?.close();
947
- };
948
- return {
949
- /** Get the underlying analytics instance (read-only) */
950
- get instance() {
951
- return instance;
952
- },
953
- /** Check if session has been established (read-only) */
954
- get is_identified() {
955
- return is_identified;
956
- },
957
- /** Storage keys used by the module */
958
- storage_keys,
959
- /** Initialize the module for a page */
960
- initiate,
961
- /** Identify/establish session */
962
- identify,
963
- /** Track a custom event */
964
- track,
965
- /** Track a bounce event */
966
- bounce,
967
- /** Cleanup the module */
968
- destroy
969
- };
970
- };
3
+ import { WretchError } from 'wretch/resolver';
971
4
 
972
5
  // src/control/index.ts
973
6
  var workspaceIdRegex = /^W[A-Z0-9]{7}$/;
@@ -975,16 +8,10 @@ var createLevoControl = (options) => {
975
8
  const {
976
9
  appName,
977
10
  workspace = null,
978
- site = null,
979
11
  apiUrl = "https://public-api.levo.so",
980
- insightsUrl = "/.levo/insights/api",
981
- directInsightsUrl,
982
- insightsMode = "auto",
983
- pingTimeout = 3e3,
984
12
  NODE_ENV = "",
985
13
  APP_MODE = "production"
986
14
  } = options;
987
- const sanitizedPingTimeout = Number.isFinite(pingTimeout) && pingTimeout >= 0 ? pingTimeout : 3e3;
988
15
  if (workspace) {
989
16
  if (!workspaceIdRegex.test(workspace)) {
990
17
  throw new Error(
@@ -993,7 +20,6 @@ var createLevoControl = (options) => {
993
20
  }
994
21
  }
995
22
  let _workspace = workspace;
996
- let _site = site;
997
23
  return {
998
24
  get workspace() {
999
25
  return _workspace;
@@ -1008,30 +34,12 @@ var createLevoControl = (options) => {
1008
34
  }
1009
35
  _workspace = value;
1010
36
  },
1011
- get site() {
1012
- return _site;
1013
- },
1014
- set site(value) {
1015
- _site = value;
1016
- },
1017
37
  get appName() {
1018
38
  return appName;
1019
39
  },
1020
40
  get apiUrl() {
1021
41
  return apiUrl;
1022
42
  },
1023
- get insightsUrl() {
1024
- return insightsUrl;
1025
- },
1026
- get directInsightsUrl() {
1027
- return directInsightsUrl || "";
1028
- },
1029
- get insightsMode() {
1030
- return insightsMode;
1031
- },
1032
- get pingTimeout() {
1033
- return sanitizedPingTimeout;
1034
- },
1035
43
  get NODE_ENV() {
1036
44
  return NODE_ENV;
1037
45
  },
@@ -1256,8 +264,96 @@ var createLevoLogger = (core, options = {}) => {
1256
264
  };
1257
265
  };
1258
266
 
267
+ // src/utils/LevoError.ts
268
+ var LevoError = class extends Error {
269
+ code;
270
+ title;
271
+ status;
272
+ type;
273
+ errors;
274
+ constructor(data) {
275
+ super(data.description);
276
+ this.name = "Levo Request Error";
277
+ this.status = data.status;
278
+ this.code = data.code;
279
+ this.title = data.title;
280
+ this.type = data.type;
281
+ this.errors = data.errors;
282
+ }
283
+ /**
284
+ * Get validation errors for form fields
285
+ */
286
+ get fieldErrors() {
287
+ return this.errors || [];
288
+ }
289
+ /**
290
+ * Check if this is a validation error with field-specific errors
291
+ */
292
+ get hasFieldErrors() {
293
+ return Boolean(this.errors?.length);
294
+ }
295
+ };
296
+
297
+ // src/utils/getLevoError.ts
298
+ var getLevoError = (error) => {
299
+ if (error instanceof LevoError) {
300
+ return error;
301
+ }
302
+ if (error instanceof WretchError && error?.json) {
303
+ const errorResponse = error?.json;
304
+ return new LevoError({
305
+ status: errorResponse?.content?.status || 500,
306
+ code: errorResponse?.content?.code || `Unknown`,
307
+ title: errorResponse?.content?.title || `HTTP ${error?.status || 500} Error`,
308
+ description: errorResponse?.content?.description || `Request failed with status ${error?.status || 500}`,
309
+ type: errorResponse?.content?.type,
310
+ errors: errorResponse?.content?.errors
311
+ });
312
+ }
313
+ if (error instanceof TypeError) {
314
+ if (error?.message.includes("Failed to fetch") || error?.message.includes("Network request failed") || error?.message.includes("fetch")) {
315
+ return new LevoError({
316
+ status: 0,
317
+ code: "NETWORK_ERROR",
318
+ title: "Network Error",
319
+ description: "Unable to connect to the server. Please check your internet connection."
320
+ });
321
+ }
322
+ if (error?.message.includes("CORS") || error?.message.includes("cross-origin")) {
323
+ return new LevoError({
324
+ status: 0,
325
+ code: "CORS_ERROR",
326
+ title: "CORS Error",
327
+ description: "Cross-origin request blocked. Please contact support."
328
+ });
329
+ }
330
+ }
331
+ if (error?.name === "AbortError" || error instanceof DOMException) {
332
+ return new LevoError({
333
+ status: 408,
334
+ code: "REQUEST_TIMEOUT",
335
+ title: "Request Timeout",
336
+ description: "The request was cancelled or timed out. Please try again."
337
+ });
338
+ }
339
+ if (error?.request) {
340
+ return new LevoError({
341
+ status: error?.response?.status || 500,
342
+ code: error?.code || "REQUEST_ERROR",
343
+ title: "Request Error",
344
+ description: error?.message || "An error occurred while making the request"
345
+ });
346
+ }
347
+ return new LevoError({
348
+ status: 500,
349
+ code: "UNKNOWN_ERROR",
350
+ title: "Unexpected Error",
351
+ description: error?.message || "Something unexpected happened"
352
+ });
353
+ };
354
+
1259
355
  // src/modules/blog.ts
1260
- var createLevoBlogModule = (core, httpClient, audience = null) => {
356
+ var createLevoBlogModule = (core, httpClient) => {
1261
357
  const getAllBlogs = async (blog_key, data = {}, options) => {
1262
358
  return httpClient.instance.url(`/v1/blog/${blog_key}/post/query`).query({ ...options?.params || {} }).options({
1263
359
  headers: {
@@ -1283,7 +379,7 @@ var createLevoBlogModule = (core, httpClient, audience = null) => {
1283
379
  };
1284
380
 
1285
381
  // src/modules/collection.ts
1286
- var createLevoCollectionModule = (core, httpsClient, audience = null) => {
382
+ var createLevoCollectionModule = (core, httpsClient) => {
1287
383
  const getAllCollections = async (data = {}, options = {}) => {
1288
384
  return httpsClient.instance.url("/v1/bevy/collection/query").options(options).post(data).json().then((response) => response).catch((error) => {
1289
385
  throw getLevoError(error);
@@ -1339,6 +435,11 @@ var createLevoCollectionModule = (core, httpsClient, audience = null) => {
1339
435
  throw getLevoError(error);
1340
436
  });
1341
437
  };
438
+ const getFilters = async (collectionId, options = {}) => {
439
+ return httpsClient.instance.url(`/v1/bevy/collection/${collectionId}/get-filters`).options(options).get().json().then((response) => response).catch((error) => {
440
+ throw getLevoError(error);
441
+ });
442
+ };
1342
443
  const submitDraftEntry = async (collection_key, data) => {
1343
444
  return httpsClient.instance.url(`/v1/bevy/content/${collection_key}/submit-entry`).post(data).json().then((response) => response).catch((error) => {
1344
445
  throw getLevoError(error);
@@ -1353,12 +454,13 @@ var createLevoCollectionModule = (core, httpsClient, audience = null) => {
1353
454
  saveDraftEntry,
1354
455
  editDraftEntry,
1355
456
  getDraftEntry,
1356
- submitDraftEntry
457
+ submitDraftEntry,
458
+ getFilters
1357
459
  };
1358
460
  };
1359
461
 
1360
462
  // src/modules/media.ts
1361
- var createLevoMediaModule = (core, httpsClient, audience = null) => {
463
+ var createLevoMediaModule = (core, httpsClient) => {
1362
464
  const mediaBulkUpload = async (formData, options = {}) => {
1363
465
  return httpsClient.instance.url("/v1/assets/media/bulk").options(options).post(formData).json().then((response) => response).catch((error) => {
1364
466
  throw getLevoError(error);
@@ -1376,14 +478,10 @@ var createLevoMediaModule = (core, httpsClient, audience = null) => {
1376
478
  };
1377
479
 
1378
480
  // src/constants/oauthProvider.ts
1379
- var LevoOAuthProviderList = [
1380
- "google",
1381
- "linkedin",
1382
- "microsoft"
1383
- ];
481
+ var LevoOAuthProviderList = ["google", "linkedin", "microsoft"];
1384
482
 
1385
483
  // src/modules/membership.ts
1386
- var createLevoMembershipModule = (core, httpsClient, audience = null) => {
484
+ var createLevoMembershipModule = (core, httpsClient) => {
1387
485
  const getOAuthURL = async (options = {}) => {
1388
486
  return httpsClient.instance.url("/v1/membership/auth/oauth/get-redirect-url").options(options).get().json().then((response) => {
1389
487
  const result = response?.content?.data;
@@ -1399,10 +497,7 @@ var createLevoMembershipModule = (core, httpsClient, audience = null) => {
1399
497
  url_params.set("workspace_id", core.workspace);
1400
498
  }
1401
499
  if (httpsClient.pageContext) {
1402
- url_params.set(
1403
- "page_context",
1404
- JSON.stringify(httpsClient.pageContext)
1405
- );
500
+ url_params.set("page_context", JSON.stringify(httpsClient.pageContext));
1406
501
  }
1407
502
  result[provider] = url.toString();
1408
503
  }
@@ -1498,11 +593,10 @@ var createLevoClient = (options) => {
1498
593
  let _pageContext = pageContext;
1499
594
  const core = createLevoControl(coreOptions);
1500
595
  const httpsClient = createHttpClient(core, _pageContext);
1501
- const audience = createLevoAudienceModule(core, httpsClient);
1502
- const blog = createLevoBlogModule(core, httpsClient, audience);
1503
- const membership = createLevoMembershipModule(core, httpsClient, audience);
1504
- const collection = createLevoCollectionModule(core, httpsClient, audience);
1505
- const media = createLevoMediaModule(core, httpsClient, audience);
596
+ const blog = createLevoBlogModule(core, httpsClient);
597
+ const membership = createLevoMembershipModule(core, httpsClient);
598
+ const collection = createLevoCollectionModule(core, httpsClient);
599
+ const media = createLevoMediaModule(core, httpsClient);
1506
600
  const logger = createLevoLogger(core, loggerOptions);
1507
601
  const updatePageContext = (newContext) => {
1508
602
  _pageContext = Object.assign({}, _pageContext, newContext);
@@ -1514,15 +608,9 @@ var createLevoClient = (options) => {
1514
608
  get apiUrl() {
1515
609
  return core.apiUrl;
1516
610
  },
1517
- get insightsUrl() {
1518
- return core.insightsUrl;
1519
- },
1520
611
  get workspace() {
1521
612
  return core.workspace;
1522
613
  },
1523
- get audience() {
1524
- return audience;
1525
- },
1526
614
  get blog() {
1527
615
  return blog;
1528
616
  },
@@ -1544,6 +632,9 @@ var createLevoClient = (options) => {
1544
632
  get APP_MODE() {
1545
633
  return core.APP_MODE;
1546
634
  },
635
+ get NODE_ENV() {
636
+ return core.NODE_ENV;
637
+ },
1547
638
  get pageContext() {
1548
639
  return _pageContext;
1549
640
  },
@@ -1552,67 +643,36 @@ var createLevoClient = (options) => {
1552
643
  };
1553
644
  };
1554
645
 
1555
- // src/utils/listToX.ts
1556
- var listToRecord = (columns) => {
1557
- return columns.reduce((prev, current) => {
1558
- prev[current] = current;
1559
- return prev;
1560
- }, {});
1561
- };
1562
-
1563
- // src/types/audience.ts
1564
- var AnalyticsEventsList = [
1565
- // Bevy Events
1566
- "bevy.collection.filled",
1567
- "bevy.collection.submitted",
1568
- "bevy.collection.view",
1569
- // Block Events
1570
- "block.view",
1571
- // Blog Events
1572
- "blog.post.view",
1573
- // Event Events
1574
- "event.booking.confirmed",
1575
- "event.booking.initiated",
1576
- "event.booking.pending",
1577
- "event.coupon.applied",
1578
- "event.event.view",
1579
- // Form Events
1580
- "form.change",
1581
- "form.submit",
1582
- // Membership Events
1583
- "membership.account.signin",
1584
- "membership.account.signout",
1585
- "membership.account.signup",
1586
- // UI Events
1587
- "button.click",
1588
- "page.bounce",
1589
- "page.click",
1590
- "page.copy",
1591
- "page.impression",
1592
- "page.scroll",
1593
- "page.view",
1594
- "page.selection",
1595
- // User Activity Events
1596
- "user.active",
1597
- "user.idle"
1598
- ];
1599
- var AnalyticsEvents = listToRecord(AnalyticsEventsList);
1600
-
1601
- // src/types/forum/post.ts
1602
- var FORUM_POST_KIND = {
1603
- post: "post",
1604
- poll: "poll",
1605
- gallery: "gallery",
1606
- link: "link"
1607
- };
1608
- var ForumPostKindExpandedList = Object.keys(FORUM_POST_KIND);
1609
-
1610
- // src/types/forum/comment.ts
1611
- var COMMENT_STATUS = {
1612
- active: "active",
1613
- edited: "edited",
1614
- deleted: "deleted",
1615
- pending_moderation: "pending_moderation"
646
+ // src/constants/collection/defaultByKind.ts
647
+ var defaultByKinds = {
648
+ "public-id": "",
649
+ string: "",
650
+ number: null,
651
+ boolean: false,
652
+ location: null,
653
+ file: null,
654
+ date: null,
655
+ identifier: null,
656
+ record: null,
657
+ group: [],
658
+ collection: {
659
+ m2o: null,
660
+ o2o: null,
661
+ m2m: []
662
+ },
663
+ richtext: {
664
+ html: "",
665
+ text: "",
666
+ json: []
667
+ },
668
+ json: {},
669
+ "array-string": [],
670
+ "array-number": [],
671
+ "array-file": [],
672
+ "array-json": [],
673
+ "array-date": [],
674
+ "array-boolean": [],
675
+ "array-location": []
1616
676
  };
1617
677
 
1618
678
  // src/constants/collection/fieldInterfaceFormat.ts
@@ -1632,6 +692,7 @@ var formatsByInterface = {
1632
692
  PhoneWidget: ["phone"],
1633
693
  URLWidget: ["url"],
1634
694
  DateWidget: [],
695
+ TimeWidget: [],
1635
696
  SwitchWidget: [],
1636
697
  RichTextWidget: [],
1637
698
  DateTimeWidget: [],
@@ -1647,37 +708,58 @@ var formatsByInterface = {
1647
708
  SlugWidget: []
1648
709
  };
1649
710
 
1650
- // src/constants/collection/defaultByKind.ts
1651
- var defaultByKinds = {
1652
- "public-id": "",
1653
- string: "",
1654
- number: null,
1655
- boolean: false,
1656
- location: null,
1657
- file: null,
1658
- date: null,
1659
- identifier: null,
1660
- record: null,
1661
- group: [],
1662
- collection: {
1663
- m2o: null,
1664
- o2o: null,
1665
- m2m: []
711
+ // src/constants/collection/fieldInterfaces.ts
712
+ var CommonFieldInterfacesList = [
713
+ "TextWidget",
714
+ "CurrencyWidget",
715
+ "TextareaWidget",
716
+ "GeocoderWidget",
717
+ "MultiGeocoderWidget",
718
+ "DropdownWidget",
719
+ "ToggleCheckboxWidget",
720
+ "RadioWidget",
721
+ "NumberWidget",
722
+ "EmailWidget",
723
+ "PhoneWidget",
724
+ "URLWidget",
725
+ "DateWidget",
726
+ "TimeWidget",
727
+ "SwitchWidget",
728
+ "RichTextWidget",
729
+ "DateTimeWidget",
730
+ "CheckboxWidget",
731
+ "ImageUploadWidget",
732
+ "MultiImageUploadWidget",
733
+ "FileUploadWidget",
734
+ "MultiFileUploadWidget",
735
+ "MultiDropdownWidget",
736
+ "MultiTextWidget"
737
+ ];
738
+ var ComplexFieldInterfacesList = [
739
+ "CollectionWidget",
740
+ "ArrayWidget",
741
+ "RecordWidget",
742
+ "JSONWidget",
743
+ "SlugWidget"
744
+ ];
745
+ var FieldInterfacesList = [
746
+ ...CommonFieldInterfacesList,
747
+ ...ComplexFieldInterfacesList
748
+ ];
749
+ var CommonFieldIntefaces = CommonFieldInterfacesList.reduce(
750
+ (acc, curr) => {
751
+ acc[curr] = curr;
752
+ return acc;
1666
753
  },
1667
- richtext: {
1668
- html: "",
1669
- text: "",
1670
- json: []
754
+ {}
755
+ );
756
+ var FieldInterfaces = FieldInterfacesList.reduce(
757
+ (acc, curr) => {
758
+ acc[curr] = curr;
759
+ return acc;
1671
760
  },
1672
- json: {},
1673
- "array-string": [],
1674
- "array-number": [],
1675
- "array-file": [],
1676
- "array-json": [],
1677
- "array-date": [],
1678
- "array-boolean": [],
1679
- "array-location": []
1680
- };
761
+ {}
762
+ );
1681
763
 
1682
764
  // src/constants/collection/fieldKind.ts
1683
765
  var FieldKindList = [
@@ -1737,6 +819,7 @@ var interfaceKinds = {
1737
819
  SlugWidget: FieldKind.string,
1738
820
  RichTextWidget: FieldKind.string,
1739
821
  DateWidget: FieldKind.date,
822
+ TimeWidget: FieldKind.string,
1740
823
  DateTimeWidget: FieldKind.date,
1741
824
  RadioWidget: FieldKind.string,
1742
825
  CheckboxWidget: FieldKind["array-string"],
@@ -1755,57 +838,17 @@ var interfaceKinds = {
1755
838
  JSONWidget: FieldKind.json
1756
839
  };
1757
840
 
1758
- // src/constants/collection/fieldInterfaces.ts
1759
- var CommonFieldInterfacesList = [
1760
- "TextWidget",
1761
- "CurrencyWidget",
1762
- "TextareaWidget",
1763
- "GeocoderWidget",
1764
- "MultiGeocoderWidget",
1765
- "DropdownWidget",
1766
- "ToggleCheckboxWidget",
1767
- "RadioWidget",
1768
- "NumberWidget",
1769
- "EmailWidget",
1770
- "PhoneWidget",
1771
- "URLWidget",
1772
- "DateWidget",
1773
- "SwitchWidget",
1774
- "RichTextWidget",
1775
- "DateTimeWidget",
1776
- "CheckboxWidget",
1777
- "ImageUploadWidget",
1778
- "MultiImageUploadWidget",
1779
- "FileUploadWidget",
1780
- "MultiFileUploadWidget",
1781
- "MultiDropdownWidget",
1782
- "MultiTextWidget"
1783
- ];
1784
- var ComplexFieldInterfacesList = [
1785
- "CollectionWidget",
1786
- "ArrayWidget",
1787
- "RecordWidget",
1788
- "JSONWidget",
1789
- "SlugWidget"
1790
- ];
1791
- var FieldInterfacesList = [
1792
- ...CommonFieldInterfacesList,
1793
- ...ComplexFieldInterfacesList
1794
- ];
1795
- var CommonFieldIntefaces = CommonFieldInterfacesList.reduce(
1796
- (acc, curr) => {
1797
- acc[curr] = curr;
1798
- return acc;
1799
- },
1800
- {}
1801
- );
1802
- var FieldInterfaces = FieldInterfacesList.reduce(
1803
- (acc, curr) => {
1804
- acc[curr] = curr;
1805
- return acc;
1806
- },
1807
- {}
1808
- );
841
+ // src/constants/integration.ts
842
+ var LEVO_INTEGRATIONS = {
843
+ beacon: "so.levo.beacon",
844
+ blog: "so.levo.blog",
845
+ event: "so.levo.event",
846
+ membership: "so.levo.membership",
847
+ payment: "so.levo.payment",
848
+ community: "so.levo.community",
849
+ search_console: "com.google.search_console"
850
+ };
851
+ var LEVO_INTEGRATIONS_LIST = Object.values(LEVO_INTEGRATIONS);
1809
852
 
1810
853
  // src/constants/media.ts
1811
854
  var MediaKindList = ["image", "video", "audio", "document"];
@@ -1817,17 +860,31 @@ var MediaKind = MediaKindList.reduce(
1817
860
  {}
1818
861
  );
1819
862
 
1820
- // src/constants/integration.ts
1821
- var LEVO_INTEGRATIONS = {
1822
- beacon: "so.levo.beacon",
1823
- blog: "so.levo.blog",
1824
- event: "so.levo.event",
1825
- membership: "so.levo.membership",
1826
- payment: "so.levo.payment",
1827
- community: "so.levo.community",
1828
- search_console: "com.google.search_console"
863
+ // src/types/forum/comment.ts
864
+ var COMMENT_STATUS = {
865
+ published: "published",
866
+ unpublished: "unpublished",
867
+ archived: "archived",
868
+ flagged: "flagged",
869
+ pending_moderation: "pending_moderation"
870
+ };
871
+
872
+ // src/types/forum/post.ts
873
+ var FORUM_POST_KIND = {
874
+ post: "post",
875
+ poll: "poll",
876
+ gallery: "gallery",
877
+ link: "link"
878
+ };
879
+ var ForumPostKindExpandedList = Object.keys(FORUM_POST_KIND);
880
+ var FORUM_POST_STATUS = {
881
+ draft: "draft",
882
+ published: "published",
883
+ unpublished: "unpublished",
884
+ archived: "archived",
885
+ flagged: "flagged",
886
+ pending_moderation: "pending_moderation"
1829
887
  };
1830
- var LEVO_INTEGRATIONS_LIST = Object.values(LEVO_INTEGRATIONS);
1831
888
 
1832
889
  // src/utils/formatImagePath.ts
1833
890
  var formatImagePath = (string) => {
@@ -1840,40 +897,18 @@ var formatImagePath = (string) => {
1840
897
  return "";
1841
898
  };
1842
899
 
1843
- // src/utils/lock.ts
1844
- var LocalStorageLock = class {
1845
- key;
1846
- constructor(lockKey) {
1847
- this.key = lockKey;
1848
- }
1849
- acquireLock(expiryMs = 5e3) {
1850
- const now = Date.now();
1851
- const lockValue = localStorage.getItem(this.key);
1852
- if (lockValue) {
1853
- const timestamp = Number(lockValue);
1854
- if (now - timestamp < expiryMs) {
1855
- return false;
1856
- }
1857
- }
1858
- localStorage.setItem(this.key, now.toString());
1859
- setTimeout(() => {
1860
- if (this.isLocked(expiryMs)) {
1861
- this.releaseLock();
1862
- }
1863
- }, expiryMs);
1864
- return true;
1865
- }
1866
- releaseLock() {
1867
- localStorage.removeItem(this.key);
1868
- }
1869
- isLocked(expiryMs = 5e3) {
1870
- const lockValue = localStorage.getItem(this.key);
1871
- if (!lockValue) {
1872
- return false;
1873
- }
1874
- const timestamp = Number(lockValue);
1875
- return Date.now() - timestamp < expiryMs;
1876
- }
900
+ // src/utils/listToX.ts
901
+ var listToColumn = (columns) => {
902
+ return columns.reduce((prev, current) => {
903
+ prev[current] = current;
904
+ return prev;
905
+ }, {});
906
+ };
907
+ var listToRecord = (columns) => {
908
+ return columns.reduce((prev, current) => {
909
+ prev[current] = current;
910
+ return prev;
911
+ }, {});
1877
912
  };
1878
913
 
1879
- export { AnalyticsEvents, AnalyticsEventsList, COMMENT_STATUS, CommonFieldIntefaces, CommonFieldInterfacesList, ComplexFieldInterfacesList, FORUM_POST_KIND, FieldInterfaces, FieldInterfacesList, FieldKind, FieldKindList, ForumPostKindExpandedList, LEVO_INTEGRATIONS, LEVO_INTEGRATIONS_LIST, LevoError, LevoOAuthProviderList, LocalStorageLock, MediaKind, MediaKindList, createLevoClient, defaultByKinds, formatImagePath, formatsByInterface, getLevoError, interfaceKinds };
914
+ export { COMMENT_STATUS, CommonFieldIntefaces, CommonFieldInterfacesList, ComplexFieldInterfacesList, FORUM_POST_KIND, FORUM_POST_STATUS, FieldInterfaces, FieldInterfacesList, FieldKind, FieldKindList, ForumPostKindExpandedList, LEVO_INTEGRATIONS, LEVO_INTEGRATIONS_LIST, LevoError, LevoOAuthProviderList, MediaKind, MediaKindList, createLevoClient, defaultByKinds, formatImagePath, formatsByInterface, getLevoError, interfaceKinds, listToColumn, listToRecord };