vaniy 0.1.6 → 0.1.8
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.
- package/dist/vaniy.es.js +303 -1
- package/dist/vaniy.iife.min.js +1 -0
- package/dist/vaniy.min.js +1 -1251
- package/package.json +7 -5
- package/dist/vaniy.es.js.map +0 -1
- package/dist/vaniy.js +0 -1251
- package/dist/vaniy.js.map +0 -1
- package/dist/vaniy.min.js.map +0 -1
- package/dist/vaniy.umd.js +0 -1252
- package/dist/vaniy.umd.js.map +0 -1
package/dist/vaniy.es.js
CHANGED
|
@@ -94,6 +94,7 @@ function parseMinMax(param) {
|
|
|
94
94
|
function isBlank(v2) {
|
|
95
95
|
return v2 == null || String(v2 ?? "").trim() === "";
|
|
96
96
|
}
|
|
97
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
97
98
|
function parseByFormat(value, fmt) {
|
|
98
99
|
const v2 = String(value ?? "").trim();
|
|
99
100
|
if (!v2) return null;
|
|
@@ -1212,6 +1213,306 @@ function parseTTL(str) {
|
|
|
1212
1213
|
};
|
|
1213
1214
|
return num * (map[unit] || 1);
|
|
1214
1215
|
}
|
|
1216
|
+
const createQuery = (options = {}) => {
|
|
1217
|
+
const {
|
|
1218
|
+
persistKey = "query-cache",
|
|
1219
|
+
persistedKeys = null,
|
|
1220
|
+
defaultTtl = 6e4,
|
|
1221
|
+
defaultStaleTime = 5e3,
|
|
1222
|
+
defaultRetries = 3,
|
|
1223
|
+
defaultRetryDelay = 1e3
|
|
1224
|
+
} = options;
|
|
1225
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
1226
|
+
const pollingIntervals = /* @__PURE__ */ new Map();
|
|
1227
|
+
const emit = (event, key, data) => {
|
|
1228
|
+
EVT.pub(`query:${event}`, { key, ...data });
|
|
1229
|
+
EVT.pub(`query:${key}:${event}`, data);
|
|
1230
|
+
};
|
|
1231
|
+
const loadFromStorage = () => {
|
|
1232
|
+
try {
|
|
1233
|
+
const stored = localStorage.getItem(persistKey);
|
|
1234
|
+
if (!stored) return;
|
|
1235
|
+
const entries = JSON.parse(stored);
|
|
1236
|
+
const now2 = Date.now();
|
|
1237
|
+
for (const [key, entry] of Object.entries(entries)) {
|
|
1238
|
+
if (now2 < entry.expiry) {
|
|
1239
|
+
cache2.set(key, { ...entry, promise: null });
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
EVT.pub("query:hydrated", { keys: [...cache2.keys()] });
|
|
1243
|
+
} catch (e) {
|
|
1244
|
+
console.warn("Failed to load query cache: ", e);
|
|
1245
|
+
}
|
|
1246
|
+
};
|
|
1247
|
+
const saveToStorage = () => {
|
|
1248
|
+
try {
|
|
1249
|
+
const toStore = {};
|
|
1250
|
+
for (const [key, entry] of cache2.entries()) {
|
|
1251
|
+
if (entry.data === void 0) continue;
|
|
1252
|
+
if (persistedKeys && !persistedKeys.some((pk) => key.startsWith(pk)))
|
|
1253
|
+
continue;
|
|
1254
|
+
toStore[key] = {
|
|
1255
|
+
data: entry.data,
|
|
1256
|
+
staleAt: entry.staleAt,
|
|
1257
|
+
expiry: entry.expiry
|
|
1258
|
+
};
|
|
1259
|
+
}
|
|
1260
|
+
localStorage.setItem(persistKey, JSON.stringify(toStore));
|
|
1261
|
+
} catch (e) {
|
|
1262
|
+
console.warn("Failed to persist query cache: ", e);
|
|
1263
|
+
}
|
|
1264
|
+
};
|
|
1265
|
+
let persistTimeout = null;
|
|
1266
|
+
const schedulePersist = () => {
|
|
1267
|
+
if (persistTimeout) clearTimeout(persistTimeout);
|
|
1268
|
+
persistTimeout = setTimeout(saveToStorage, 1e3);
|
|
1269
|
+
};
|
|
1270
|
+
const getEntry = (key) => cache2.get(key) ?? null;
|
|
1271
|
+
const fetchWithRetry = async (key, fetcher, retries, retryDelay) => {
|
|
1272
|
+
let lastError;
|
|
1273
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
1274
|
+
try {
|
|
1275
|
+
return await fetcher();
|
|
1276
|
+
} catch (error) {
|
|
1277
|
+
lastError = error;
|
|
1278
|
+
if (attempt < retries) {
|
|
1279
|
+
const delay = retryDelay * Math.pow(2, attempt);
|
|
1280
|
+
emit("retry", key, {
|
|
1281
|
+
attempt: attempt + 1,
|
|
1282
|
+
maxRetries: retries,
|
|
1283
|
+
delay,
|
|
1284
|
+
error
|
|
1285
|
+
});
|
|
1286
|
+
await sleep(delay);
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
throw lastError;
|
|
1291
|
+
};
|
|
1292
|
+
const query = async (key, fetcher, options2 = {}) => {
|
|
1293
|
+
const {
|
|
1294
|
+
ttl = defaultTtl,
|
|
1295
|
+
staleTime = defaultStaleTime,
|
|
1296
|
+
retries = defaultRetries,
|
|
1297
|
+
retryDelay = defaultRetryDelay
|
|
1298
|
+
} = options2;
|
|
1299
|
+
const now2 = Date.now();
|
|
1300
|
+
const entry = getEntry(key);
|
|
1301
|
+
if (entry && now2 < entry.staleAt) {
|
|
1302
|
+
emit("hit", key, { data: entry.data });
|
|
1303
|
+
return entry.data;
|
|
1304
|
+
}
|
|
1305
|
+
if (entry?.promise) {
|
|
1306
|
+
return entry.promise;
|
|
1307
|
+
}
|
|
1308
|
+
const isStale = entry && now2 < entry.expiry;
|
|
1309
|
+
emit("fetch", key, { isStale, hasCache: !!entry });
|
|
1310
|
+
const promise = fetchWithRetry(key, fetcher, retries, retryDelay).then((data) => {
|
|
1311
|
+
cache2.set(key, {
|
|
1312
|
+
data,
|
|
1313
|
+
staleAt: Date.now() + staleTime,
|
|
1314
|
+
expiry: Date.now() + ttl,
|
|
1315
|
+
promise: null,
|
|
1316
|
+
error: null
|
|
1317
|
+
});
|
|
1318
|
+
emit("success", key, { data });
|
|
1319
|
+
schedulePersist();
|
|
1320
|
+
return data;
|
|
1321
|
+
}).catch((error) => {
|
|
1322
|
+
cache2.set(key, {
|
|
1323
|
+
data: entry?.data ?? null,
|
|
1324
|
+
staleAt: entry?.staleAt ?? 0,
|
|
1325
|
+
expiry: entry?.expiry ?? 0,
|
|
1326
|
+
promise: null,
|
|
1327
|
+
error
|
|
1328
|
+
});
|
|
1329
|
+
emit("error", key, { error, staleData: entry?.data ?? null });
|
|
1330
|
+
throw error;
|
|
1331
|
+
});
|
|
1332
|
+
cache2.set(key, { ...entry, promise });
|
|
1333
|
+
if (isStale) return entry.data;
|
|
1334
|
+
return promise;
|
|
1335
|
+
};
|
|
1336
|
+
const mutate = (key, updater) => {
|
|
1337
|
+
const entry = getEntry(key);
|
|
1338
|
+
if (!entry) return null;
|
|
1339
|
+
const previous = entry.data;
|
|
1340
|
+
const next = typeof updater === "function" ? updater(previous) : updater;
|
|
1341
|
+
cache2.set(key, { ...entry, data: next });
|
|
1342
|
+
emit("mutate", key, { data: next, previous });
|
|
1343
|
+
schedulePersist();
|
|
1344
|
+
return previous;
|
|
1345
|
+
};
|
|
1346
|
+
const setQueryData = (key, data, options2 = {}) => {
|
|
1347
|
+
const { ttl = defaultTtl, staleTime = defaultStaleTime } = options2;
|
|
1348
|
+
const now2 = Date.now();
|
|
1349
|
+
cache2.set(key, {
|
|
1350
|
+
data,
|
|
1351
|
+
staleAt: now2 + staleTime,
|
|
1352
|
+
expiry: now2 + ttl,
|
|
1353
|
+
promise: null,
|
|
1354
|
+
error: null
|
|
1355
|
+
});
|
|
1356
|
+
emit("set", key, { data });
|
|
1357
|
+
schedulePersist();
|
|
1358
|
+
};
|
|
1359
|
+
const invalidate = (key, options2 = {}) => {
|
|
1360
|
+
const { refetch: shouldRefetch, fetcher } = options2;
|
|
1361
|
+
cache2.delete(key);
|
|
1362
|
+
emit("invalidate", key, {});
|
|
1363
|
+
schedulePersist();
|
|
1364
|
+
if (shouldRefetch && fetcher) {
|
|
1365
|
+
return query(key, fetcher);
|
|
1366
|
+
}
|
|
1367
|
+
};
|
|
1368
|
+
const invalidateMatching = (predicate) => {
|
|
1369
|
+
const invalidated = [];
|
|
1370
|
+
for (const key of cache2.keys()) {
|
|
1371
|
+
if (predicate(key)) {
|
|
1372
|
+
cache2.delete(key);
|
|
1373
|
+
invalidated.push(key);
|
|
1374
|
+
emit("invalidate", key, {});
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
schedulePersist();
|
|
1378
|
+
return invalidated;
|
|
1379
|
+
};
|
|
1380
|
+
const stopPolling = (key) => {
|
|
1381
|
+
const intervalId = pollingIntervals.get(key);
|
|
1382
|
+
if (intervalId) {
|
|
1383
|
+
clearInterval(intervalId);
|
|
1384
|
+
pollingIntervals.delete(key);
|
|
1385
|
+
emit("polling:stop", key, {});
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
const stopAllPolling = () => {
|
|
1389
|
+
for (const key of pollingIntervals.keys()) {
|
|
1390
|
+
stopPolling(key);
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
const startPolling = (key, fetcher, interval, queryOptions = {}) => {
|
|
1394
|
+
stopPolling(key);
|
|
1395
|
+
query(key, fetcher, queryOptions).catch(() => {
|
|
1396
|
+
});
|
|
1397
|
+
const intervalId = setInterval(() => {
|
|
1398
|
+
const entry = getEntry(key);
|
|
1399
|
+
if (entry) cache2.set(key, { ...entry, staleAt: 0 });
|
|
1400
|
+
query(key, fetcher, queryOptions).catch(() => {
|
|
1401
|
+
});
|
|
1402
|
+
}, interval);
|
|
1403
|
+
pollingIntervals.set(key, intervalId);
|
|
1404
|
+
emit("polling:start", key, { interval });
|
|
1405
|
+
return () => stopPolling(key);
|
|
1406
|
+
};
|
|
1407
|
+
const prefetch = (key, fetcher, options2) => {
|
|
1408
|
+
const entry = getEntry(key);
|
|
1409
|
+
if (entry && Date.now() < entry.staleAt) return;
|
|
1410
|
+
query(key, fetcher, options2).catch(() => {
|
|
1411
|
+
});
|
|
1412
|
+
};
|
|
1413
|
+
const gc = () => {
|
|
1414
|
+
const now2 = Date.now();
|
|
1415
|
+
const collected = [];
|
|
1416
|
+
for (const [key, entry] of cache2.entries()) {
|
|
1417
|
+
if (now2 > entry.expiry && !EVT.has(`query:${key}:success`)) {
|
|
1418
|
+
cache2.delete(key);
|
|
1419
|
+
collected.push(key);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
if (collected.length) {
|
|
1423
|
+
schedulePersist();
|
|
1424
|
+
EVT.pub("query:gc", { collected });
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1427
|
+
const subscribe = (key, callback) => {
|
|
1428
|
+
const handler = (data) => callback({ ...getEntry(key), ...data });
|
|
1429
|
+
EVT.sub(`query:${key}:success`, handler);
|
|
1430
|
+
EVT.sub(`query:${key}:error`, handler);
|
|
1431
|
+
EVT.sub(`query:${key}:mutate`, handler);
|
|
1432
|
+
EVT.sub(`query:${key}:set`, handler);
|
|
1433
|
+
EVT.sub(`query:${key}:invalidate`, () => callback(null));
|
|
1434
|
+
const entry = getEntry(key);
|
|
1435
|
+
if (entry) callback(entry);
|
|
1436
|
+
return () => {
|
|
1437
|
+
EVT.unsub(`query:${key}:success`, handler);
|
|
1438
|
+
EVT.unsub(`query:${key}:error`, handler);
|
|
1439
|
+
EVT.unsub(`query:${key}:mutate`, handler);
|
|
1440
|
+
EVT.unsub(`query:${key}:set`, handler);
|
|
1441
|
+
EVT.unsub(`query:${key}:invalidate`, handler);
|
|
1442
|
+
};
|
|
1443
|
+
};
|
|
1444
|
+
loadFromStorage();
|
|
1445
|
+
setInterval(gc, 6e4);
|
|
1446
|
+
window.addEventListener("storage", (e) => {
|
|
1447
|
+
if (e.key === persistKey) {
|
|
1448
|
+
loadFromStorage();
|
|
1449
|
+
for (const key of cache2.keys()) {
|
|
1450
|
+
emit("sync", key, { data: cache2.get(key)?.data });
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
window.addEventListener("beforeunload", () => {
|
|
1455
|
+
stopAllPolling();
|
|
1456
|
+
saveToStorage();
|
|
1457
|
+
});
|
|
1458
|
+
return {
|
|
1459
|
+
query,
|
|
1460
|
+
mutate,
|
|
1461
|
+
setQueryData,
|
|
1462
|
+
invalidate,
|
|
1463
|
+
invalidateMatching,
|
|
1464
|
+
subscribe,
|
|
1465
|
+
prefetch,
|
|
1466
|
+
startPolling,
|
|
1467
|
+
stopPolling,
|
|
1468
|
+
stopAllPolling,
|
|
1469
|
+
getEntry,
|
|
1470
|
+
gc,
|
|
1471
|
+
clear: () => {
|
|
1472
|
+
cache2.clear();
|
|
1473
|
+
localStorage.removeItem(persistKey);
|
|
1474
|
+
EVT.pub("query:cleared", {});
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
};
|
|
1478
|
+
const queryClient = createQuery({
|
|
1479
|
+
persistKey: "teksoft-cache",
|
|
1480
|
+
persistedKeys: ["user", "settings"]
|
|
1481
|
+
});
|
|
1482
|
+
const bindQuery = (key, fetcher, options = {}) => {
|
|
1483
|
+
const {
|
|
1484
|
+
target,
|
|
1485
|
+
render,
|
|
1486
|
+
onLoading,
|
|
1487
|
+
onError,
|
|
1488
|
+
poll = null,
|
|
1489
|
+
...queryOptions
|
|
1490
|
+
} = options;
|
|
1491
|
+
const el = typeof target === "string" ? document.querySelector(target) : target;
|
|
1492
|
+
const renderData = (data) => {
|
|
1493
|
+
const html2 = render(data);
|
|
1494
|
+
if (typeof html2 === "string") el.innerHTML = html2;
|
|
1495
|
+
};
|
|
1496
|
+
EVT.sub(`query:${key}:success`, ({ data }) => renderData(data));
|
|
1497
|
+
EVT.sub(`query:${key}:set`, ({ data }) => renderData(data));
|
|
1498
|
+
EVT.sub(`query:${key}:mutate`, ({ data }) => renderData(data));
|
|
1499
|
+
if (onError) {
|
|
1500
|
+
EVT.sub(
|
|
1501
|
+
`query:${key}:error`,
|
|
1502
|
+
({ error, staleData }) => onError(error, staleData, el)
|
|
1503
|
+
);
|
|
1504
|
+
}
|
|
1505
|
+
if (onLoading) {
|
|
1506
|
+
EVT.sub(`query:${key}:fetch`, ({ hasCache }) => {
|
|
1507
|
+
if (!hasCache) onLoading(el);
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
queryClient.query(key, fetcher, queryOptions).catch(() => {
|
|
1511
|
+
});
|
|
1512
|
+
if (poll) {
|
|
1513
|
+
return queryClient.startPolling(key, fetcher, poll, queryOptions);
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1215
1516
|
export {
|
|
1216
1517
|
DOM,
|
|
1217
1518
|
EVT,
|
|
@@ -1222,6 +1523,7 @@ export {
|
|
|
1222
1523
|
Q,
|
|
1223
1524
|
V,
|
|
1224
1525
|
all,
|
|
1526
|
+
bindQuery,
|
|
1225
1527
|
cache,
|
|
1226
1528
|
del,
|
|
1227
1529
|
download,
|
|
@@ -1238,6 +1540,7 @@ export {
|
|
|
1238
1540
|
parseHtml,
|
|
1239
1541
|
post,
|
|
1240
1542
|
put,
|
|
1543
|
+
queryClient,
|
|
1241
1544
|
raw,
|
|
1242
1545
|
redirect,
|
|
1243
1546
|
request,
|
|
@@ -1245,4 +1548,3 @@ export {
|
|
|
1245
1548
|
upload,
|
|
1246
1549
|
useFormHandler
|
|
1247
1550
|
};
|
|
1248
|
-
//# sourceMappingURL=vaniy.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var vaniy=function(e){"use strict";const t={listeners:new Map,sub:function(e,t){let r=this.listeners.get(e);r||(r=new Set,this.listeners.set(e,r)),r.add(t)},once:function(e,t){const r=(...n)=>{t(...n),this.unsub(e,r)};this.sub(e,r)},unsub:function(e,t){let r=this.listeners.get(e);r&&r.delete(t)},pub:function(e,...t){let r=this.listeners.get(e);r&&r.forEach(r=>{try{r(...t)}catch(t){console.error(`Error in event "${e}" listener: `,t)}})},has:function(e){return this.listeners.has(e)&&this.listeners.get(e).size>0},clear:function(e){e?this.listeners.delete(e):this.listeners.clear()},ping:()=>console.log("PONG!"),description:"EVT is for Event publishing and emitting"},r={US:{locale:"en-US",currency:"USD"},CA:{locale:"en-CA",currency:"CAD"},FR:{locale:"fr-FR",currency:"EUR"},HT:{locale:"ht-HT",currency:"HTG"},GB:{locale:"en-GB",currency:"GBP"},AU:{locale:"en-AU",currency:"AUD"}},n=(e,{locale:t="en-US",currency:r="USD"}={})=>Intl.NumberFormat(t,{style:"currency",currency:r}).format(e);function s(e){return Array.isArray(e)?e.length:function(e){if("number"==typeof e)return Number.isFinite(e);if("string"!=typeof e)return!1;const t=v.trim();return!!t&&/^-?\d+(\.\d+)?$/.test(t)}(e)?Number(String(e).trim()):String(e??"").length}function o(e){const[t,r]=String(e??"").split(",").map(e=>e.trim()),n=Number(t),s=Number(r);return Number.isFinite(n)&&Number.isFinite(s)?{min:n,max:s}:null}const a=e=>new Promise(t=>setTimeout(t,e));function i(e,t){const r=String(e??"").trim();if(!r)return null;if("YYYY-MM-DD"===t){const e=r.match(/^(\d{4})-(\d{2})-(\d{2})$/);if(!e)return null;const t=Number(e[1]),n=Number(e[2]),s=Number(e[3]);return!t||n<1||n>12||s<1||s>31?null:{year:t,month:n,day:s}}return null}function l(e,t,r="en-US"){const n=new Intl.DateTimeFormat(r,{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}).formatToParts(e),s=Object.fromEntries(n.map(e=>[e.type,e.value]));return{year:Number(s.year),month:Number(s.month),day:Number(s.day),hour:Number(s.hour),minute:Number(s.minute),second:Number(s.second)}}function u({year:e,month:t,day:r},n){const s=new Date(Date.UTC(e,t-1,r));return s.setUTCDate(s.getUTCDate()+n),{year:s.getUTCFullYear(),month:s.getUTCMonth()+1,day:s.getUTCDate()}}function c(e,t,r){const{base:n,offsetDays:s}=function(e){const t=String(e).trim().match(/^(.+?)([+-]\d+)?$/);return t?{base:t[1].trim(),offsetDays:t[2]?Number(t[2]):0}:{base:String(e).trim(),offsetDays:0}}(e);let o=function(e,t){const r=new Date,{year:n,month:s,day:o}=l(r,t);return"today"===e?{year:n,month:s,day:o}:"tomorrow"===e?u({year:n,month:s,day:o},1):"yesterday"===e?u({year:n,month:s,day:o},-1):null}(n,r.timezone);if(!o){const e=t?.[n];o=d(e,r)}return o||(o=i(n,r.dateFormat)),o?(s&&(o=u(o,s)),o):null}function d(e,t){if(null==(r=e)||""===String(r??"").trim())return null;var r;const n=String(e).trim();let s=i(n,t.dateFormat);if(s)return s;if(!/^\d{4}-\d{2}-\d{2}[T\s]\d{2}:\d{2}(:\d{2}(\.\d{1,3})?)?(Z|[+-]\d{2}:\d{2})?$/.test(n))return null;const o=new Date(n);if(isNaN(o.getTime()))return null;const a=l(o,t.timezone);return{year:a.year,month:a.month,day:a.day}}function m(e,t,r,n){let s=null;return s="value"===n?d(e,r):c(e,t,r),s?function({year:e,month:t,day:r},n){let s=Date.UTC(e,t-1,r,0,0,0);for(let o=0;o<2;o++){const o=l(new Date(s),n),a=Date.UTC(o.year,o.month-1,o.day,o.hour,o.minute,o.second)-Date.UTC(e,t-1,r,0,0,0);if(0===a)break;s-=a}return s}(s,r.timezone):null}function f(e,t){return{method:t=>(r,n,s)=>{const o=m(r,n,s,"value"),a=m(t,n,s,"target");return null!=o&&null!=a&&e(o,a)},message:t}}const h={required:{method:e=>""!==String(e??"").trim(),message:"This field is required"},requiredIf:{method:e=>(t,r)=>{const[n,s]=String(e).split("="),o=r?.[n];return!(null!=s?String(o??"")===s:""!==String(o??"").trim())||""!==String(t??"").trim()},message:e=>{const[t,r]=String(e).split("=");return null!=r?`This field is requied when ${t} is ${r}`:`This field is required when ${t} has a value`}},email:{method:e=>/\S+@\S+\.\S+/.test(e),message:"Email is invalid"},min:{method:e=>t=>String(t??"").length>=Number(e),message:e=>`Must be at least ${e} characters`},max:{method:e=>t=>String(t??"").length<=Number(e),message:e=>`Must be at most ${e} characters`},date:{method:e=>{if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;const[t,r,n]=e.split("-").map(Number),s=new Date(t,r-1,n);return s.getFullYear()===t&&s.getMonth()===r-1&&s.getDate()===n},message:"Date is invalid. Use the format YYYY-MM-DD."},currency:{method:e=>/^\$?\d{1,3}((,\d{3})*|\d*)(\.\d{2})?$/.test(e),message:"Currency is invalid. Use the format $123,456.78 or 123456.78."},same:{method:e=>(t,r)=>String(t??"")===String(r?.[e]??""),message:e=>`Must match ${e}`},in:{method:e=>t=>(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim()).filter(Boolean)).includes(String(t??"").trim()),message:e=>`Must be one of the following: ${(Array.isArray(e)?e:String(e??"").split(",").map(e=>e.trim())).filter(Boolean).join(",")}`},before:f((e,t)=>e<t,e=>`Must be before ${e}`),beforeOrEqual:f((e,t)=>e<=t,e=>`Must be before or equal to ${e}`),after:f((e,t)=>e>t,e=>`Must be after ${e}`),afterOrEqual:f((e,t)=>e>=t,e=>`Must be after or equal to ${e}`),between:{method:e=>t=>{const r=o(e);if(!r)return!1;const n=s(t);return r.min<=n&&n<=r.max},message:e=>{const t=o(e);return t?`Must be between ${t.min} and ${t.max}`:"Between rule is invalid. Use between:min,max"}}};function y(e){const t=e.indexOf(":");return-1===t?{name:e,param:void 0}:{name:e.slice(0,t),param:e.slice(t+1)}}const p={run:function(e,t){let r=!0;const n={};for(const s in e){const o=e[s]||[];for(const e of o){const{name:o,param:a}=y(e),i=h[o];if(!i)continue;const l=t?.[s];if(!(void 0!==a?i.method(a)(l,t):i.method(l,t))){r=!1,n[s]||(n[s]=[]);const e="function"==typeof i.message?i.message(a):i.message;n[s].push(e)}}}return{isValid:r,errors:n}},ping:()=>console.log("PONG"),description:"V is for validating forms"},g=e=>({on:(t,r)=>e?.addEventListener(t,r),off:(t,r)=>e?.removeEventListener(t,r)}),b=(e,t)=>{if(!e)return;const r="innerText"in e?"innerText":"textContent";return null!=t&&(e[r]=t),e[r]},S=(e,t)=>{if(e)return null!=t&&(e.innerHTML=t),e.innerHTML},w=e=>document.createElement(e),E=e=>{let t="";const r="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";for(let n=0;n<e;n++)t+=r.charAt(Math.floor(62*Math.random()));return t},T=e=>{const t=document.implementation.createHTMLDocument("");return t.body.innerHTML=e,[...t.body.childNodes]},A=e=>{"loading"!==document.readyState?e():document.addEventListener("DOMContentLoaded",e)},$=e=>{window.onload=e},C=e=>{const t="string"==typeof e?document.querySelector(e):e,r=e=>(...r)=>{if(t)return e(...r)},n={elt:t,value:t?.value,text:e=>null!=e?(b(t,e),n):b(t),html:e=>null!=e?(S(t,e),n):S(t),val:r(e=>{if(null!=e){if(t.opt&&t.multiple){const r=new Set(Array.isArray(e)?e:[e]);Array.from(t.options).forEach(e=>{e.selected=r.has(e.value)})}else t.value=e;return n.value=t.value,n}return t.options&&t.multiple?Array.from(t.options).filter(e=>e.selected).map(e=>e.value):t.value}),addClass:r(e=>(t.classList.add(e),n)),removeClass:r(e=>(t.classList.remove(e),n)),hasClass:r(e=>t.classList.contains(e)),hide:r(()=>(t.style.display="none",n)),show:r(()=>(t.style.display="",n)),prop:r(e=>t[e]),attr:r(e=>t.getAttribute(e)),removeAttr:e=>{t.removeAttribute(e)},toggle:r(()=>("none"==t.style.display?n.show():n.hide(),n)),css:r(e=>(Object.entries(e).forEach(([e,r])=>{t.style[e]=r}),n)),on:g(t).on,off:g(t).off};return n},D=e=>document.querySelectorAll(e),I={Q:C,$:C,all:D,$$:D,scan:(e,t={})=>{const r=t.refAttr||"v-ref",n="string"==typeof e?document.querySelector(e):e||document;if(!n)throw new Error(`Dom.scan: root "${e}" not found`);const s=Object.create(null);return n.querySelectorAll(`[${r}]`).forEach(e=>{const t=e.getAttribute(r);if(!t)return;const n=C(e);s[t]?Array.isArray(s[t])?s[t].push(n):s[t]=[s[t],n]:s[t]=n}),new Proxy({},{get(e,t){if("_"===t)return s;if("get"===t)return e=>s[e];if("all"===t)return e=>s[e]?Array.isArray(s[e])?s[e]:[s[e]]:[];if("string"!=typeof t)return;const r=s[t];return r||(console.warn(`DOM.scan: ref "${t}" not found`),C(null))}})},make:w,makeId:E,parseHtml:T,onPageLoad:A,onWindowLoad:$,ping:()=>console.log("PONG!"),description:"DOM is for dom manipulation"};let N="",q=8e3,R=null,M=null;const L=new Map,O=()=>Date.now();function U(e){const t="undefined"!=typeof window?window[e]:null;return t?{get(e){const r=t.getItem(e);if(!r)return null;try{const n=JSON.parse(r);return n.exp&&n.exp<O()?(t.removeItem(e),null):n.val}catch{return null}},set(e,r,n){const s=n?O()+n:null;t.setItem(e,JSON.stringify({val:r,exp:s}))},del(e){t&&t.removeItem(e)},clear(){t&&t.clear()}}:null}const x={memory:{get(e){const t=L.get(e);return t?t.exp&&t.exp<O()?(L.delete(e),null):t.val:null},set(e,t,r){const n=r?O()+r:null;L.set(e,{val:t,exp:n})},del(e){L.delete(e)},clear(){L.clear()}},local:U("localStorage"),session:U("sessionStorage")};function H(e){return null===e||"object"!=typeof e?String(e):Array.isArray(e)?`[${e.map(H).join(",")}]`:`{${Object.keys(e).sort().map(t=>`${JSON.stringify(t)}:${H(e[t])}`).join(",")}}`}const F=(e,t)=>setTimeout(()=>t.abort(),e);async function k(e,t,r={}){const{params:n,body:s,headers:o={},cache:a}=r;let i=N+t;if(n){const e=new URLSearchParams(n).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,l),c=!!a,d=a?.strategy,m=a?.ttl??0,f=function(e="memory"){return x[e]||x.memory}(a?.storage),h=a?.key||function(e,t,r,n){return`H|${e}|${t}${r?`?${new URLSearchParams(r).toString()}`:""}${n&&"GET"!==e?`#${H(n)}`:""}`}(e,i,n,s);if(c&&!a?.forceRefresh&&"cache-first"===d){const e=f.get(h);if(null!==e)return e}let y={method:e,headers:o,signal:l.signal};void 0!==s&&(s instanceof FormData?y.body=s:(y.headers["Content-Type"]="application/json",y.body=JSON.stringify(s))),R&&(y=R(y)||y);try{let t,r=await fetch(i,y);clearTimeout(u),M&&(r=M(r)||r);try{t=await r.json()}catch{t=await r.text()}if(!r.ok){const n={status:r.status,data:t,url:i,method:e};if(c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw n}return c&&f.set(h,t,m),t}catch(e){if(clearTimeout(u),c&&"network-first"===d){const e=f.get(h);if(null!==e)return e}throw e}}async function P(e,{filename:t,params:r,headers:n={},method:s="GET",body:o,onProgress:a}={}){let i=N+e;if(r){const e=new URLSearchParams(r).toString();i+=(i.includes("?")?"&":"?")+e}const l=new AbortController,u=F(q,l),c={method:s,headers:{...n},signal:l.signal};void 0!==o&&(o instanceof FormData?c.body=o:(c.headers["Content-Type"]=c.headers["Content-Type"]||"application/json",c.body="string"==typeof o?o:JSON.stringify(o)));const d=await fetch(i,c);if(clearTimeout(u),!d.ok){let e="";try{e=await d.text()}catch{}throw new Error(`Download failed ${d.status}: ${e||d.statusText}`)}if(!t){const e=d.headers.get("Content-Disposition")||"",r=/filename\*=UTF-8''([^;]+)|filename="?([^"]+)"?/i.exec(e);t=decodeURIComponent(r?.[1]||r?.[2]||"download")}let m;if(d.body&&"getReader"in d.body){const e=d.body.getReader(),t=Number(d.headers.get("Content-Length"))||null,r=[];let n=0;for(;;){const{done:s,value:o}=await e.read();if(s)break;if(r.push(o),n+=o.length,"function"==typeof a){a(n,t,t?Math.round(n/t*100):null)}}m=new Blob(r)}else m=await d.blob(),"function"==typeof a&&a(1,1,100);const f=URL.createObjectURL(m),h=document.createElement("a");return h.href=f,h.download=t,h.style.display="none",document.body.appendChild(h),h.click(),document.body.removeChild(h),URL.revokeObjectURL(f),{filename:t,size:m.size,type:m.type}}function j(e,{files:t,fieldName:r="file",fields:n={},headers:s={},method:o="POST",onProgress:a,signal:i}={}){return new Promise((l,u)=>{const c=function({files:e,fieldName:t="file",fields:r={}}){const n=new FormData,s=Array.isArray(e)?e:[e];return s.forEach((e,r)=>{const o=s.length>1?`${t}[${r}]`:t;n.append(o,e)}),Object.entries(r).forEach(([e,t])=>{n.append(e,t instanceof Blob||t instanceof File?t:"object"==typeof t?JSON.stringify(t):String(t))}),n}({files:t,fieldName:r,fields:n}),d=`${N}${e}`,m=new XMLHttpRequest;m.open(o,d,!0);let f={method:o,headers:{...s}};if(R&&(f=R(f)||f),Object.entries(f.headers).forEach(([e,t])=>m.setRequestHeader(e,t)),m.timeout=q,i){const e=()=>{try{m.abort()}catch{}};i.aborted&&e(),i.addEventListener("abort",e,{once:!0})}m.upload&&"function"==typeof a&&(m.upload.onprogress=e=>{if(!e.lengthComputable)return void a(e.loaded,null,null);const t=Math.round(e.loaded/e.total*100);a(e.loaded,e.total,t)}),m.onreadystatechange=async()=>{if(4!==m.readyState)return;if(M){const e={status:m.status,ok:m.status>=200&&m.status<300,headers:new Headers,text:async()=>m.responseText,json:async()=>JSON.parse(m.responseText||"null")};M(e)}const e=(m.getResponseHeader("Content-Type")||"").includes("application/json")?function(e){try{return JSON.parse(e||"null")}catch{return e}}(m.responseText):m.responseText;m.status>=200&&m.status<300?l(e):u({status:m.status,data:e,url:d,method:o})},m.onerror=()=>u({status:0,data:"Network error",url:`${N}${e}`,method:o}),m.ontimeout=()=>u({status:0,data:"Timeout",url:`${N}${e}`,method:o}),m.send(c)})}const _=(e,t)=>k("GET",e,t),V=(e,t,r={})=>k("POST",e,{...r,body:t}),B=(e,t,r={})=>k("PUT",e,{...r,body:t}),G=(e,t={})=>k("DELETE",e,t),J=(e,t)=>fetch(N+e,t),Y={base:e=>(N=e,Y),timeout:e=>(q=e,Y),interceptRequest:e=>(R=e,Y),interceptResponse:e=>(M=e,Y),get:_,post:V,put:B,delete:G,raw:J,download:P,upload:j,ping:()=>console.log("PONG"),description:"H is for Http"},z={STATE_CHANGE:"form:state:change",ERRORS_CHANGE:"form:errors:change",SUBMIT_SUCCESS:"form:submit:success",SUBMIT_ERROR:"form:submit:error",RESET:"form:reset",VALIDATED:"form:validated"};class K{constructor(e,t,r,n={}){this.formId=e,this.schema=t,this.onSubmit=r,this.preSubmit=n.preSubmit||null,this.form=null,this.formState={},this.errors={},this.initialValues={},this._boundHandleSubmit=this.#e.bind(this),this._boundHandleInput=this.#t.bind(this),this.#r()}#r(){this.form=document.getElementById(this.formId),this.form?(this.#n(),this.form.addEventListener("submit",this._boundHandleSubmit),this.form.addEventListener("input",this._boundHandleInput),this.#s()):console.error(`Form with id ${this.formId} not found`)}#n(){const e=this.form.elements;for(const t of Array.from(e))t.name&&(this.initialValues[t.name]=t.value,this.formState[t.name]=t.value)}#t(e){const{name:t,value:r}=e.target;t&&(this.formState[t]=r,this.#s(),this.errors[t]&&(delete this.errors[t],this.#o()))}async#e(e){e.preventDefault();const r=new FormData(this.form);let n={};r.forEach((e,t)=>{n[t]=e}),this.formState=n,this.#s();const{isValid:s,errors:o}=p.run(this.schema,n);if(t.pub(z.VALIDATED,{formId:this.formId,isValid:s,errors:o,data:n}),!s)return this.errors=o,this.#o(),void t.pub(z.SUBMIT_ERROR,{formId:this.formId,errors:o});if(this.errors={},this.#o(),this.preSubmit)try{n=await this.preSubmit(n)}catch(e){return void t.pub(z.SUBMIT_ERROR,{formId:this.formId,errors:{_preSubmit:[e.message]}})}t.pub(z.SUBMIT_SUCCESS,{formId:this.formId,data:n}),this.onSubmit(n)}#s(){t.pub(z.STATE_CHANGE,{formId:this.formId,state:{...this.formState}})}#o(){t.pub(z.ERRORS_CHANGE,{formId:this.formId,errors:{...this.errors}})}getFormState(){return{...this.formState}}getErrors(){return{...this.errors}}reset(){this.formState={...this.initialValues},this.errors={},this.form&&this.form.reset(),this.#s(),this.#o(),t.pub(z.RESET,{formId:this.formId})}validateNow(){const e=new FormData(this.form),r={};e.forEach((e,t)=>{r[t]=e});const n=p.run(this.schema,r);return this.errors=n.errors,this.#o(),t.pub(z.VALIDATED,{formId:this.formId,isValid:n.isValid,errors:n.errors,data:r}),n}destroy(){this.form&&(this.form.removeEventListener("submit",this._boundHandleSubmit),this.form.removeEventListener("input",this._boundHandleInput))}}class Q{constructor(e,r={}){this.formId=e,this.options={containerClass:"form-error-container",errorClass:"text-danger",insertAfterField:!0,...r},this.customContainers={},this._boundHandleErrors=this.#a.bind(this),t.sub(z.ERRORS_CHANGE,this._boundHandleErrors)}#a({formId:e,errors:t}){e===this.formId&&(this.clearAll(),this.renderAll(t))}setContainer(e,t){this.customContainers[e]="string"==typeof t?document.querySelector(t):t}renderAll(e){for(const t in e)this.render(t,e[t])}render(e,t){if(!t||0===t.length)return null;const r=document.createElement("span");r.className=`${this.options.containerClass} ${this.options.errorClass}`,r.dataset.field=e;const n=document.createElement("ul");t.forEach(e=>{const t=document.createElement("li"),r=document.createElement("i");r.textContent=e,t.appendChild(r),n.appendChild(t)}),r.appendChild(n);const s=this.customContainers[e];if(s)s.innerHTML="",s.appendChild(r);else if(this.options.insertAfterField){const t=document.getElementById(this.formId),n=t?.querySelector(`[name="${e}"]`);n&&n.insertAdjacentElement("afterend",r)}return r}clearAll(){const e=document.getElementById(this.formId);if(!e)return;e.querySelectorAll(`.${this.options.containerClass}`).forEach(e=>e.remove());for(const e in this.customContainers)this.customContainers[e]&&(this.customContainers[e].innerHTML="")}destroy(){t.unsub(z.ERRORS_CHANGE,this._boundHandleErrors),this.clearAll()}}const W=((e={})=>{const{persistKey:r="query-cache",persistedKeys:n=null,defaultTtl:s=6e4,defaultStaleTime:o=5e3,defaultRetries:i=3,defaultRetryDelay:l=1e3}=e,u=new Map,c=new Map,d=(e,r,n)=>{t.pub(`query:${e}`,{key:r,...n}),t.pub(`query:${r}:${e}`,n)},m=()=>{try{const e=localStorage.getItem(r);if(!e)return;const n=JSON.parse(e),s=Date.now();for(const[e,t]of Object.entries(n))s<t.expiry&&u.set(e,{...t,promise:null});t.pub("query:hydrated",{keys:[...u.keys()]})}catch(e){console.warn("Failed to load query cache: ",e)}},f=()=>{try{const e={};for(const[t,r]of u.entries())void 0!==r.data&&(n&&!n.some(e=>t.startsWith(e))||(e[t]={data:r.data,staleAt:r.staleAt,expiry:r.expiry}));localStorage.setItem(r,JSON.stringify(e))}catch(e){console.warn("Failed to persist query cache: ",e)}};let h=null;const y=()=>{h&&clearTimeout(h),h=setTimeout(f,1e3)},p=e=>u.get(e)??null,g=async(e,t,r={})=>{const{ttl:n=s,staleTime:c=o,retries:m=i,retryDelay:f=l}=r,h=Date.now(),g=p(e);if(g&&h<g.staleAt)return d("hit",e,{data:g.data}),g.data;if(g?.promise)return g.promise;const b=g&&h<g.expiry;d("fetch",e,{isStale:b,hasCache:!!g});const S=(async(e,t,r,n)=>{let s;for(let o=0;o<=r;o++)try{return await t()}catch(t){if(s=t,o<r){const s=n*Math.pow(2,o);d("retry",e,{attempt:o+1,maxRetries:r,delay:s,error:t}),await a(s)}}throw s})(e,t,m,f).then(t=>(u.set(e,{data:t,staleAt:Date.now()+c,expiry:Date.now()+n,promise:null,error:null}),d("success",e,{data:t}),y(),t)).catch(t=>{throw u.set(e,{data:g?.data??null,staleAt:g?.staleAt??0,expiry:g?.expiry??0,promise:null,error:t}),d("error",e,{error:t,staleData:g?.data??null}),t});return u.set(e,{...g,promise:S}),b?g.data:S},b=e=>{const t=c.get(e);t&&(clearInterval(t),c.delete(e),d("polling:stop",e,{}))},S=()=>{for(const e of c.keys())b(e)},w=()=>{const e=Date.now(),r=[];for(const[n,s]of u.entries())e>s.expiry&&!t.has(`query:${n}:success`)&&(u.delete(n),r.push(n));r.length&&(y(),t.pub("query:gc",{collected:r}))};return m(),setInterval(w,6e4),window.addEventListener("storage",e=>{if(e.key===r){m();for(const e of u.keys())d("sync",e,{data:u.get(e)?.data})}}),window.addEventListener("beforeunload",()=>{S(),f()}),{query:g,mutate:(e,t)=>{const r=p(e);if(!r)return null;const n=r.data,s="function"==typeof t?t(n):t;return u.set(e,{...r,data:s}),d("mutate",e,{data:s,previous:n}),y(),n},setQueryData:(e,t,r={})=>{const{ttl:n=s,staleTime:a=o}=r,i=Date.now();u.set(e,{data:t,staleAt:i+a,expiry:i+n,promise:null,error:null}),d("set",e,{data:t}),y()},invalidate:(e,t={})=>{const{refetch:r,fetcher:n}=t;if(u.delete(e),d("invalidate",e,{}),y(),r&&n)return g(e,n)},invalidateMatching:e=>{const t=[];for(const r of u.keys())e(r)&&(u.delete(r),t.push(r),d("invalidate",r,{}));return y(),t},subscribe:(e,r)=>{const n=t=>r({...p(e),...t});t.sub(`query:${e}:success`,n),t.sub(`query:${e}:error`,n),t.sub(`query:${e}:mutate`,n),t.sub(`query:${e}:set`,n),t.sub(`query:${e}:invalidate`,()=>r(null));const s=p(e);return s&&r(s),()=>{t.unsub(`query:${e}:success`,n),t.unsub(`query:${e}:error`,n),t.unsub(`query:${e}:mutate`,n),t.unsub(`query:${e}:set`,n),t.unsub(`query:${e}:invalidate`,n)}},prefetch:(e,t,r)=>{const n=p(e);n&&Date.now()<n.staleAt||g(e,t,r).catch(()=>{})},startPolling:(e,t,r,n={})=>{b(e),g(e,t,n).catch(()=>{});const s=setInterval(()=>{const r=p(e);r&&u.set(e,{...r,staleAt:0}),g(e,t,n).catch(()=>{})},r);return c.set(e,s),d("polling:start",e,{interval:r}),()=>b(e)},stopPolling:b,stopAllPolling:S,getEntry:p,gc:w,clear:()=>{u.clear(),localStorage.removeItem(r),t.pub("query:cleared",{})}}})({persistKey:"teksoft-cache",persistedKeys:["user","settings"]});return e.DOM=I,e.EVT=t,e.FormErrorRenderer=Q,e.FormEvents=z,e.FormHandler=K,e.HTTP=Y,e.Q=C,e.V=p,e.all=D,e.bindQuery=(e,r,n={})=>{const{target:s,render:o,onLoading:a,onError:i,poll:l=null,...u}=n,c="string"==typeof s?document.querySelector(s):s,d=e=>{const t=o(e);"string"==typeof t&&(c.innerHTML=t)};if(t.sub(`query:${e}:success`,({data:e})=>d(e)),t.sub(`query:${e}:set`,({data:e})=>d(e)),t.sub(`query:${e}:mutate`,({data:e})=>d(e)),i&&t.sub(`query:${e}:error`,({error:e,staleData:t})=>i(e,t,c)),a&&t.sub(`query:${e}:fetch`,({hasCache:e})=>{e||a(c)}),W.query(e,r,u).catch(()=>{}),l)return W.startPolling(e,r,l,u)},e.cache=function(e){if(null==e)return{cache:{strategy:"cache-first",storage:"local",ttl:6e4}};if("object"==typeof e)return{cache:e};const t=e.toLowerCase(),r={cfl:{strategy:"cache-first",storage:"local"},cfs:{strategy:"cache-first",storage:"session"},cfm:{strategy:"cache-first",storage:"memory"},nfl:{strategy:"network-first",storage:"local"},nfs:{strategy:"network-first",storage:"session"},nfm:{strategy:"network-first",storage:"memory"}},n=t.match(/cfl|cfs|cfm|nfl|nfs|nfm/),s=n?r[n[0]]:r.cfl,o=t.match(/(\d+)\s*(s|sec|secs|second|seconds|min|m|mins|minute|minutes|h|hr|hours)?/),a=o?function(e){const t=e.replace(/[0-9]/g,"").trim().toLowerCase(),r=parseInt(e,10),n={s:1e3,sec:1e3,secs:1e3,second:1e3,seconds:1e3,m:6e4,min:6e4,mins:6e4,minute:6e4,minutes:6e4,h:36e5,hr:36e5,hrs:36e5,hours:36e5};return r*(n[t]||1)}(o[0]):6e4;return{cache:{strategy:s.strategy,storage:s.storage,ttl:a}}},e.del=G,e.download=P,e.formatByCountry=(e,t)=>n(e,r[t]??r.US),e.get=_,e.isArray=e=>Array.isArray(e),e.isArrayEmpty=e=>!(Array.isArray(e)&&e.length>0),e.isFocus=e=>e==document.activeElement,e.isValidRoutingNumber=e=>{if(!/^\d{9}$/.test(e))return!1;const t=e.split("").map(Number);return(7*(t[0]+t[3]+t[6])+3*(t[1]+t[4]+t[7])+1*(t[2]+t[5]+t[8]))%10==0},e.make=w,e.makeId=E,e.onPageLoad=A,e.onWindowLoad=$,e.parseHtml=T,e.post=V,e.put=B,e.queryClient=W,e.raw=J,e.redirect=e=>window.location.href=e,e.request=k,e.toCurrency=n,e.upload=j,e.useFormHandler=function(e,t,r,n){const s=new K(e,t,r,n),o=new Q(e,n);return{reset:()=>s.reset(),validate:()=>s.validateNow(),destroy:()=>{o.destroy(),s.destroy()},setContainer:(e,t)=>o.setContainer(e,t)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({});
|