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 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}({});