@auxilium/datalynk-client 1.3.6 โ†’ 1.3.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/README.md CHANGED
@@ -264,32 +264,73 @@ const user = await api.auth.login('spoke', 'username', 'password', '2faCode');
264
264
  <h3 id="pwa" style="display: inline">Offline / PWA</h3>
265
265
  </summary>
266
266
 
267
- Webpages can be made availible offline using Progressive Web Apps + Service Workers.
267
+ ### Support
268
268
 
269
- You must fetch user information from `api.auth.user` & use the slice engine to fetch data `api.slice(...)`; custom `api.requests({...})` calls wont work.
269
+ #### PWA
270
+ Turns the website into an installable native app
271
+ - The PWA manifest can be configured with: `manifest`
272
+ - The install prompt can be configured with: `pwaSettings`
273
+ ```ts
274
+ const api = new Api(`https://${spoke}.auxiliumgroup.com`, {
275
+ name: "Workplace Occupational Health & Safety Inspection", // REQUIRED: App name
276
+ manifest: { // Set/Override any manifest values
277
+ scope: 'https://lynk-forms.scarborough.auxilium.world/OshawaCL/ohsinspection.html'
278
+ },
279
+ pwaSettings: { // PWA install prompt settings
280
+ timeout: 45, // seconds before prompt shows (default: 30)
281
+ dismissExpiry: 3, // days before prompt shows again (0 = every refresh, default: 7)
282
+ loginLink: true // Show install link in login screen
283
+ },
284
+ });
270
285
 
271
- #### Setup
286
+ // Manually trigger
287
+ api.pwa.prompt();
288
+ ```
272
289
 
273
- 1. Upload the [service worker](https://datalynk-client.scarborough.auxilium.world/dist/service.worker.mjs) `dist/service.worker.mjs` to the *root* directory of the server
290
+ #### Static assets
291
+ Upload the [service worker](https://datalynk-client.scarborough.auxilium.world/dist/service.worker.mjs) `dist/service.worker.mjs` to the *root* directory of the server
292
+ to cache all files for use offline
293
+ ```ts
294
+ const api = new Api(`https://${spoke}.auxiliumgroup.com`, {
295
+ serviceWorker: 'https://.../service.worker.mjs', // Shouldnt be needed but can be overriden
296
+ });
297
+ ```
274
298
 
275
- 2. Configure the API:
299
+ #### Slice Engine
300
+ Slices can be used as normal offline using the slice engine by marking the slice as offline with: `offline`
276
301
  ```ts
277
302
  const api = new Api(`https://${spoke}.auxiliumgroup.com`, {
278
- name: "Workplace Occupational Health & Safety Inspection", // REQUIRED: App name
279
303
  offline: [51306, 51531, 51563], // REQUIRED: Specify slices that must be stored offline
280
- manifest: { scope: 'https://lynk-forms.scarborough.auxilium.world/OshawaCL/ohsinspection.html' }, // Any manifest overrides suck as PWA "scope"
281
- pwaSettings: { // PWA install prompt settings
282
- timeout: 45, // seconds before prompt shows (default: 30)
283
- dismissExpiry: 3, // days before prompt shows again (0 = every refresh, default: 7)
284
- loginLink: true // Show install link in login screen
285
- },
286
- serviceWorker: 'https://.../service.worker.mjs', // Override service worker URL, must be on same domain (Step 1)
287
304
  socket: true // Make sure sockets are enabled
288
305
  });
306
+ await api.slice(51306).insert({...}).exec();
307
+ const resp = await api.slice(51306).select().where('id', '<=', 100).exec();
308
+ ```
309
+ #### API Requests
310
+ Any API request can be deferred until online, however you dont get responses when offline
311
+ - Only useful for submitting data or when we dont care about the response
312
+ ```ts
313
+ api.request(..., {offline: true}).then((resp: T | void) => {
314
+ if(resp != null) {
315
+ // Online logic (has response payload)
316
+ } else {
317
+ // Offline logic (no response payload)
318
+ }
319
+ });
320
+ ```
321
+ </details>
289
322
 
290
- // Manually trigger prompt
291
- api.pwa.prompt();
323
+ <details>
324
+ <summary>
325
+ <h3 id="pdf" style="display: inline">PDFs</h3>
326
+ </summary>
327
+
328
+ PDFs can be generated using the API. PDFs can be optionally related to a record by passing an association
329
+
330
+ ```ts
331
+ const resp = await api.pdf.fromUrl('https://google.com', {slice: 12345, row: 1, field: 'resume'});
292
332
  ```
333
+
293
334
  </details>
294
335
 
295
336
  <details>
package/dist/api.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type BannerOptions = {
2
+ color?: string;
3
+ position?: 'top' | 'bottom';
4
+ id?: string;
5
+ };
6
+ export declare function createBanner(message: string, options?: BannerOptions): void;
7
+ export declare function removeBanner(id?: string): void;
8
+ //# sourceMappingURL=banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"banner.d.ts","sourceRoot":"","sources":["../src/banner.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;CACZ,CAAA;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,QAyBxE;AAED,wBAAgB,YAAY,CAAC,EAAE,SAAoB,QAGlD"}
package/dist/index.cjs CHANGED
@@ -1783,13 +1783,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
1783
1783
  pwaLink.addEventListener("click", async (e) => {
1784
1784
  var _a;
1785
1785
  e.preventDefault();
1786
- if ((_a = this.api.pwa) == null ? void 0 : _a.deferredPrompt) {
1787
- this.api.pwa.deferredPrompt.prompt();
1788
- const choice = await this.api.pwa.deferredPrompt.userChoice;
1786
+ if ((_a = this.api.pwa) == null ? void 0 : _a.nativeInstallPrompt) {
1787
+ this.api.pwa.nativeInstallPrompt.prompt();
1788
+ const choice = await this.api.pwa.nativeInstallPrompt.userChoice;
1789
1789
  if (choice.outcome === "accepted") {
1790
1790
  console.log("PWA installed via login link");
1791
1791
  }
1792
- this.api.pwa.deferredPrompt = null;
1792
+ this.api.pwa.nativeInstallPrompt = null;
1793
1793
  } else {
1794
1794
  this.api.pwa.prompt();
1795
1795
  }
@@ -2309,12 +2309,42 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
2309
2309
  return this.api.request({ "$/auth/mobile/generate": { user: login, method: mode } });
2310
2310
  }
2311
2311
  }
2312
+ function createBanner(message, options = {}) {
2313
+ options = {
2314
+ color: "#dc3545",
2315
+ position: "top",
2316
+ id: "datalynk-banner",
2317
+ ...options
2318
+ };
2319
+ removeBanner(options.id);
2320
+ const banner = document.createElement("div");
2321
+ banner.className = options.id;
2322
+ Object.assign(banner.style, {
2323
+ position: "fixed",
2324
+ [options.position === "top" ? "top" : "bottom"]: "0",
2325
+ left: "0",
2326
+ right: "0",
2327
+ padding: ".75rem",
2328
+ fontSize: "1rem",
2329
+ fontWeight: "bolder",
2330
+ backgroundColor: options.color,
2331
+ color: "#fff",
2332
+ textAlign: "center",
2333
+ zIndex: "9999"
2334
+ });
2335
+ banner.innerHTML = message;
2336
+ document.body.appendChild(banner);
2337
+ }
2338
+ function removeBanner(id = "datalynk-banner") {
2339
+ const banner = document.querySelector(`.${id}`);
2340
+ if (banner) banner.remove();
2341
+ }
2312
2342
  class PWA {
2313
2343
  constructor(api) {
2314
- __publicField(this, "deferredPrompt", null);
2344
+ /** Capture Install Event */
2345
+ __publicField(this, "nativeInstallPrompt", null);
2315
2346
  this.api = api;
2316
2347
  }
2317
- // Holds the beforeinstallprompt event
2318
2348
  get headless() {
2319
2349
  return typeof window == "undefined";
2320
2350
  }
@@ -2341,34 +2371,36 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
2341
2371
  if (!installBtn) return;
2342
2372
  installBtn.onclick = async () => {
2343
2373
  var _a;
2344
- this.deferredPrompt.prompt();
2345
- const choice = await this.deferredPrompt.userChoice;
2374
+ if (!this.nativeInstallPrompt) return console.warn("PWA is not supported");
2375
+ this.nativeInstallPrompt.prompt();
2376
+ const choice = await this.nativeInstallPrompt.userChoice;
2346
2377
  if (choice.outcome === "accepted") {
2347
2378
  console.log("PWA installed");
2348
- localStorage.removeItem(`${this.api.options.name}:pwa`);
2379
+ localStorage.setItem(`${this.api.options.name}:pwa`, "installed");
2380
+ } else {
2381
+ localStorage.setItem(`${this.api.options.name}:pwa`, Date.now().toString());
2349
2382
  }
2350
- this.deferredPrompt = null;
2351
2383
  (_a = document.querySelector(".pwa-prompt")) == null ? void 0 : _a.remove();
2352
2384
  };
2353
2385
  }
2354
2386
  /** Setup the PWA */
2355
2387
  async setup(manifest = {}) {
2356
- var _a, _b, _c;
2357
2388
  window.addEventListener("beforeinstallprompt", (e) => {
2358
2389
  e.preventDefault();
2359
- this.deferredPrompt = e;
2390
+ this.nativeInstallPrompt = e;
2360
2391
  const actions = document.querySelector(".pwa-prompt-actions");
2361
2392
  if (actions && !actions.querySelector("#installPwaBtn")) {
2362
2393
  actions.innerHTML = `<button id="installPwaBtn">Install App</button>`;
2363
2394
  this.bindInstallButton();
2364
2395
  }
2365
2396
  });
2366
- const settings = {
2367
- timeout: (((_a = this.api.options.pwaSettings) == null ? void 0 : _a.timeout) ?? 30) * 1e3,
2368
- // default 30s
2369
- dismissExpiry: ((_b = this.api.options.pwaSettings) == null ? void 0 : _b.dismissExpiry) ?? 7,
2370
- // default 7 days
2371
- loginLink: ((_c = this.api.options.pwaSettings) == null ? void 0 : _c.loginLink) ?? false
2397
+ this.api.options.pwaSettings = {
2398
+ timeout: 30,
2399
+ // Seconds
2400
+ dismissExpiry: 7,
2401
+ // Days
2402
+ loginLink: false,
2403
+ ...this.api.options.pwaSettings
2372
2404
  };
2373
2405
  const meta = (key, name, value) => {
2374
2406
  const exists = document.querySelector(`meta[${key}="${name}"]`);
@@ -2402,19 +2434,16 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
2402
2434
  document.head.append(link);
2403
2435
  }
2404
2436
  if (!this.headless && !this.iframe && !this.pwa && this.platform != "mac") setTimeout(() => {
2405
- const dismissedDate = localStorage.getItem(`${this.api.options.name}:pwa`);
2406
- if (settings.dismissExpiry > 0 && dismissedDate) {
2407
- const diffDays = (Date.now() - new Date(dismissedDate).getTime()) / (1e3 * 60 * 60 * 24);
2408
- if (diffDays < settings.dismissExpiry) return;
2409
- } else if (settings.dismissExpiry === 0) {
2410
- localStorage.removeItem(`${this.api.options.name}:pwa`);
2411
- }
2437
+ var _a, _b, _c, _d;
2438
+ if (((_b = (_a = this.api.options) == null ? void 0 : _a.pwaSettings) == null ? void 0 : _b.dismissExpiry) === 0) localStorage.removeItem(`${this.api.options.name}:pwa`);
2439
+ let dismissedDate = localStorage.getItem(`${this.api.options.name}:pwa`);
2440
+ if (dismissedDate) dismissedDate = JSON.parse(dismissedDate);
2441
+ if (!!dismissedDate && Date.now() > dismissedDate + ((_d = (_c = this.api.options) == null ? void 0 : _c.pwaSettings) == null ? void 0 : _d.dismissExpiry) * 6e4 * 60 * 24) return;
2412
2442
  this.prompt();
2413
- }, settings.timeout);
2443
+ }, this.api.options.pwaSettings.timeout);
2414
2444
  }
2415
2445
  /** Prompt user to install the app */
2416
2446
  async prompt(platform) {
2417
- var _a;
2418
2447
  if (document.querySelector(".pwa-prompt")) return;
2419
2448
  const android = (platform || this.platform) == "android";
2420
2449
  let style = document.querySelector("style.pwa");
@@ -2509,10 +2538,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
2509
2538
  <button class="pwa-prompt-close">&times;</button>
2510
2539
  </div>
2511
2540
  <div class="pwa-prompt-body">
2512
- ${this.deferredPrompt ? "Click below to install the app directly to your device." : "Add this app to your home screen for a faster, fullscreen experience."}
2541
+ ${this.nativeInstallPrompt ? "Click below to install the app directly to your device." : "Add this app to your home screen for a faster, fullscreen experience."}
2513
2542
  </div>
2514
2543
  <div class="pwa-prompt-actions">
2515
- ${this.deferredPrompt ? `<button id="installPwaBtn">Install App</button>` : `
2544
+ ${this.nativeInstallPrompt ? `<button id="installPwaBtn">Install App</button>` : `
2516
2545
  <table>
2517
2546
  <tr>
2518
2547
  <td style="width:40px;text-align:center">
@@ -2531,13 +2560,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
2531
2560
  </div>
2532
2561
  `;
2533
2562
  const closeBtn = prompt.querySelector(".pwa-prompt-close");
2534
- const dismissExpiry = ((_a = this.api.options.pwaSettings) == null ? void 0 : _a.dismissExpiry) ?? 7;
2535
2563
  closeBtn.onclick = () => {
2536
- dismissExpiry > 0 ? localStorage.setItem(`${this.api.options.name}:pwa`, (/* @__PURE__ */ new Date()).toISOString()) : localStorage.removeItem(`${this.api.options.name}:pwa`);
2564
+ var _a;
2565
+ !!((_a = this.api.options.pwaSettings) == null ? void 0 : _a.dismissExpiry) ? localStorage.setItem(`${this.api.options.name}:pwa`, Date.now().toString()) : localStorage.removeItem(`${this.api.options.name}:pwa`);
2537
2566
  prompt.remove();
2538
2567
  };
2539
2568
  document.body.append(prompt);
2540
- if (this.deferredPrompt) this.bindInstallButton();
2569
+ if (this.nativeInstallPrompt) this.bindInstallButton();
2541
2570
  }
2542
2571
  }
2543
2572
  class Files {
@@ -3471,7 +3500,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3471
3500
  } });
3472
3501
  }
3473
3502
  }
3474
- const version = "1.3.6";
3503
+ const version = "1.3.8";
3475
3504
  class WebRtc {
3476
3505
  constructor(api) {
3477
3506
  __publicField(this, "ice");
@@ -3681,17 +3710,19 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3681
3710
  this.pwa = new PWA(this);
3682
3711
  this.superuser = new Superuser(this);
3683
3712
  this.webrtc = new WebRtc(this);
3684
- this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3685
- this.online$.subscribe(async (online) => {
3686
- var _a2;
3687
- if (!online) return;
3688
- const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3689
- const keys = await (table == null ? void 0 : table.getAllKeys());
3690
- await Promise.allSettled(keys.map(async (k) => {
3691
- const r = await (table == null ? void 0 : table.get(k));
3692
- await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3693
- }));
3694
- });
3713
+ if (typeof indexedDB != "undefined") {
3714
+ this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3715
+ this.online$.subscribe(async (online) => {
3716
+ var _a2;
3717
+ if (!online) return;
3718
+ const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3719
+ const keys = await (table == null ? void 0 : table.getAllKeys());
3720
+ await Promise.allSettled(keys.map(async (k) => {
3721
+ const r = await (table == null ? void 0 : table.get(k));
3722
+ await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3723
+ }));
3724
+ });
3725
+ }
3695
3726
  if (typeof window !== "undefined") {
3696
3727
  const handleOffline = (state = this.offline) => {
3697
3728
  if (this.online != state) this.online$.next(state);
@@ -3777,6 +3808,11 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3777
3808
  }).then(async (resp) => {
3778
3809
  const warning = resp.headers["X-Warning"];
3779
3810
  if (warning) console.warn(warning);
3811
+ const banner = resp.headers["X-User-Notice"];
3812
+ if (warning) {
3813
+ createBanner(banner);
3814
+ setTimeout(() => removeBanner(), 1e4);
3815
+ }
3780
3816
  this.online = true;
3781
3817
  let data = JSONAttemptParse(await resp.text());
3782
3818
  if (!resp.ok || (data == null ? void 0 : data.error)) throw Object.assign(errorFromCode(resp.status, data.error), data);
@@ -3803,15 +3839,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3803
3839
  }
3804
3840
  offlineBanner() {
3805
3841
  if (this.options.offlineBanner === false || typeof document == "undefined") return;
3806
- const banner = document.querySelector(".datalynk-offline-banner");
3807
3842
  if (this.online) {
3808
- banner == null ? void 0 : banner.remove();
3809
- } else if (!banner) {
3810
- const b = document.createElement("div");
3811
- b.className = "datalynk-offline-banner";
3812
- Object.assign(b.style, { position: "fixed", [this.options.offlineBanner === "top" ? "top" : "bottom"]: "0", left: "0", right: "0", padding: ".75rem", fontSize: "1rem", fontWeight: "bolder", backgroundColor: "#dc3545", color: "#fff", textAlign: "center", zIndex: "9999" });
3813
- b.innerHTML = "โš ๏ธ You are offline, please reconnect to sync changes";
3814
- document.body.appendChild(b);
3843
+ removeBanner("datalynk-offline-banner");
3844
+ } else {
3845
+ createBanner("โš ๏ธ You are offline, please reconnect to sync changes", {
3846
+ id: "datalynk-offline-banner",
3847
+ position: this.options.offlineBanner === "top" ? "top" : "bottom"
3848
+ });
3815
3849
  }
3816
3850
  }
3817
3851
  startHeartbeat() {
package/dist/index.mjs CHANGED
@@ -1779,13 +1779,13 @@ const _LoginPrompt = class _LoginPrompt {
1779
1779
  pwaLink.addEventListener("click", async (e) => {
1780
1780
  var _a;
1781
1781
  e.preventDefault();
1782
- if ((_a = this.api.pwa) == null ? void 0 : _a.deferredPrompt) {
1783
- this.api.pwa.deferredPrompt.prompt();
1784
- const choice = await this.api.pwa.deferredPrompt.userChoice;
1782
+ if ((_a = this.api.pwa) == null ? void 0 : _a.nativeInstallPrompt) {
1783
+ this.api.pwa.nativeInstallPrompt.prompt();
1784
+ const choice = await this.api.pwa.nativeInstallPrompt.userChoice;
1785
1785
  if (choice.outcome === "accepted") {
1786
1786
  console.log("PWA installed via login link");
1787
1787
  }
1788
- this.api.pwa.deferredPrompt = null;
1788
+ this.api.pwa.nativeInstallPrompt = null;
1789
1789
  } else {
1790
1790
  this.api.pwa.prompt();
1791
1791
  }
@@ -2305,12 +2305,42 @@ class Auth {
2305
2305
  return this.api.request({ "$/auth/mobile/generate": { user: login, method: mode } });
2306
2306
  }
2307
2307
  }
2308
+ function createBanner(message, options = {}) {
2309
+ options = {
2310
+ color: "#dc3545",
2311
+ position: "top",
2312
+ id: "datalynk-banner",
2313
+ ...options
2314
+ };
2315
+ removeBanner(options.id);
2316
+ const banner = document.createElement("div");
2317
+ banner.className = options.id;
2318
+ Object.assign(banner.style, {
2319
+ position: "fixed",
2320
+ [options.position === "top" ? "top" : "bottom"]: "0",
2321
+ left: "0",
2322
+ right: "0",
2323
+ padding: ".75rem",
2324
+ fontSize: "1rem",
2325
+ fontWeight: "bolder",
2326
+ backgroundColor: options.color,
2327
+ color: "#fff",
2328
+ textAlign: "center",
2329
+ zIndex: "9999"
2330
+ });
2331
+ banner.innerHTML = message;
2332
+ document.body.appendChild(banner);
2333
+ }
2334
+ function removeBanner(id = "datalynk-banner") {
2335
+ const banner = document.querySelector(`.${id}`);
2336
+ if (banner) banner.remove();
2337
+ }
2308
2338
  class PWA {
2309
2339
  constructor(api) {
2310
- __publicField(this, "deferredPrompt", null);
2340
+ /** Capture Install Event */
2341
+ __publicField(this, "nativeInstallPrompt", null);
2311
2342
  this.api = api;
2312
2343
  }
2313
- // Holds the beforeinstallprompt event
2314
2344
  get headless() {
2315
2345
  return typeof window == "undefined";
2316
2346
  }
@@ -2337,34 +2367,36 @@ class PWA {
2337
2367
  if (!installBtn) return;
2338
2368
  installBtn.onclick = async () => {
2339
2369
  var _a;
2340
- this.deferredPrompt.prompt();
2341
- const choice = await this.deferredPrompt.userChoice;
2370
+ if (!this.nativeInstallPrompt) return console.warn("PWA is not supported");
2371
+ this.nativeInstallPrompt.prompt();
2372
+ const choice = await this.nativeInstallPrompt.userChoice;
2342
2373
  if (choice.outcome === "accepted") {
2343
2374
  console.log("PWA installed");
2344
- localStorage.removeItem(`${this.api.options.name}:pwa`);
2375
+ localStorage.setItem(`${this.api.options.name}:pwa`, "installed");
2376
+ } else {
2377
+ localStorage.setItem(`${this.api.options.name}:pwa`, Date.now().toString());
2345
2378
  }
2346
- this.deferredPrompt = null;
2347
2379
  (_a = document.querySelector(".pwa-prompt")) == null ? void 0 : _a.remove();
2348
2380
  };
2349
2381
  }
2350
2382
  /** Setup the PWA */
2351
2383
  async setup(manifest = {}) {
2352
- var _a, _b, _c;
2353
2384
  window.addEventListener("beforeinstallprompt", (e) => {
2354
2385
  e.preventDefault();
2355
- this.deferredPrompt = e;
2386
+ this.nativeInstallPrompt = e;
2356
2387
  const actions = document.querySelector(".pwa-prompt-actions");
2357
2388
  if (actions && !actions.querySelector("#installPwaBtn")) {
2358
2389
  actions.innerHTML = `<button id="installPwaBtn">Install App</button>`;
2359
2390
  this.bindInstallButton();
2360
2391
  }
2361
2392
  });
2362
- const settings = {
2363
- timeout: (((_a = this.api.options.pwaSettings) == null ? void 0 : _a.timeout) ?? 30) * 1e3,
2364
- // default 30s
2365
- dismissExpiry: ((_b = this.api.options.pwaSettings) == null ? void 0 : _b.dismissExpiry) ?? 7,
2366
- // default 7 days
2367
- loginLink: ((_c = this.api.options.pwaSettings) == null ? void 0 : _c.loginLink) ?? false
2393
+ this.api.options.pwaSettings = {
2394
+ timeout: 30,
2395
+ // Seconds
2396
+ dismissExpiry: 7,
2397
+ // Days
2398
+ loginLink: false,
2399
+ ...this.api.options.pwaSettings
2368
2400
  };
2369
2401
  const meta = (key, name, value) => {
2370
2402
  const exists = document.querySelector(`meta[${key}="${name}"]`);
@@ -2398,19 +2430,16 @@ class PWA {
2398
2430
  document.head.append(link);
2399
2431
  }
2400
2432
  if (!this.headless && !this.iframe && !this.pwa && this.platform != "mac") setTimeout(() => {
2401
- const dismissedDate = localStorage.getItem(`${this.api.options.name}:pwa`);
2402
- if (settings.dismissExpiry > 0 && dismissedDate) {
2403
- const diffDays = (Date.now() - new Date(dismissedDate).getTime()) / (1e3 * 60 * 60 * 24);
2404
- if (diffDays < settings.dismissExpiry) return;
2405
- } else if (settings.dismissExpiry === 0) {
2406
- localStorage.removeItem(`${this.api.options.name}:pwa`);
2407
- }
2433
+ var _a, _b, _c, _d;
2434
+ if (((_b = (_a = this.api.options) == null ? void 0 : _a.pwaSettings) == null ? void 0 : _b.dismissExpiry) === 0) localStorage.removeItem(`${this.api.options.name}:pwa`);
2435
+ let dismissedDate = localStorage.getItem(`${this.api.options.name}:pwa`);
2436
+ if (dismissedDate) dismissedDate = JSON.parse(dismissedDate);
2437
+ if (!!dismissedDate && Date.now() > dismissedDate + ((_d = (_c = this.api.options) == null ? void 0 : _c.pwaSettings) == null ? void 0 : _d.dismissExpiry) * 6e4 * 60 * 24) return;
2408
2438
  this.prompt();
2409
- }, settings.timeout);
2439
+ }, this.api.options.pwaSettings.timeout);
2410
2440
  }
2411
2441
  /** Prompt user to install the app */
2412
2442
  async prompt(platform) {
2413
- var _a;
2414
2443
  if (document.querySelector(".pwa-prompt")) return;
2415
2444
  const android = (platform || this.platform) == "android";
2416
2445
  let style = document.querySelector("style.pwa");
@@ -2505,10 +2534,10 @@ class PWA {
2505
2534
  <button class="pwa-prompt-close">&times;</button>
2506
2535
  </div>
2507
2536
  <div class="pwa-prompt-body">
2508
- ${this.deferredPrompt ? "Click below to install the app directly to your device." : "Add this app to your home screen for a faster, fullscreen experience."}
2537
+ ${this.nativeInstallPrompt ? "Click below to install the app directly to your device." : "Add this app to your home screen for a faster, fullscreen experience."}
2509
2538
  </div>
2510
2539
  <div class="pwa-prompt-actions">
2511
- ${this.deferredPrompt ? `<button id="installPwaBtn">Install App</button>` : `
2540
+ ${this.nativeInstallPrompt ? `<button id="installPwaBtn">Install App</button>` : `
2512
2541
  <table>
2513
2542
  <tr>
2514
2543
  <td style="width:40px;text-align:center">
@@ -2527,13 +2556,13 @@ class PWA {
2527
2556
  </div>
2528
2557
  `;
2529
2558
  const closeBtn = prompt.querySelector(".pwa-prompt-close");
2530
- const dismissExpiry = ((_a = this.api.options.pwaSettings) == null ? void 0 : _a.dismissExpiry) ?? 7;
2531
2559
  closeBtn.onclick = () => {
2532
- dismissExpiry > 0 ? localStorage.setItem(`${this.api.options.name}:pwa`, (/* @__PURE__ */ new Date()).toISOString()) : localStorage.removeItem(`${this.api.options.name}:pwa`);
2560
+ var _a;
2561
+ !!((_a = this.api.options.pwaSettings) == null ? void 0 : _a.dismissExpiry) ? localStorage.setItem(`${this.api.options.name}:pwa`, Date.now().toString()) : localStorage.removeItem(`${this.api.options.name}:pwa`);
2533
2562
  prompt.remove();
2534
2563
  };
2535
2564
  document.body.append(prompt);
2536
- if (this.deferredPrompt) this.bindInstallButton();
2565
+ if (this.nativeInstallPrompt) this.bindInstallButton();
2537
2566
  }
2538
2567
  }
2539
2568
  class Files {
@@ -3467,7 +3496,7 @@ class Superuser {
3467
3496
  } });
3468
3497
  }
3469
3498
  }
3470
- const version = "1.3.6";
3499
+ const version = "1.3.8";
3471
3500
  class WebRtc {
3472
3501
  constructor(api) {
3473
3502
  __publicField(this, "ice");
@@ -3677,17 +3706,19 @@ const _Api = class _Api {
3677
3706
  this.pwa = new PWA(this);
3678
3707
  this.superuser = new Superuser(this);
3679
3708
  this.webrtc = new WebRtc(this);
3680
- this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3681
- this.online$.subscribe(async (online) => {
3682
- var _a2;
3683
- if (!online) return;
3684
- const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3685
- const keys = await (table == null ? void 0 : table.getAllKeys());
3686
- await Promise.allSettled(keys.map(async (k) => {
3687
- const r = await (table == null ? void 0 : table.get(k));
3688
- await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3689
- }));
3690
- });
3709
+ if (typeof indexedDB != "undefined") {
3710
+ this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3711
+ this.online$.subscribe(async (online) => {
3712
+ var _a2;
3713
+ if (!online) return;
3714
+ const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3715
+ const keys = await (table == null ? void 0 : table.getAllKeys());
3716
+ await Promise.allSettled(keys.map(async (k) => {
3717
+ const r = await (table == null ? void 0 : table.get(k));
3718
+ await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3719
+ }));
3720
+ });
3721
+ }
3691
3722
  if (typeof window !== "undefined") {
3692
3723
  const handleOffline = (state = this.offline) => {
3693
3724
  if (this.online != state) this.online$.next(state);
@@ -3773,6 +3804,11 @@ const _Api = class _Api {
3773
3804
  }).then(async (resp) => {
3774
3805
  const warning = resp.headers["X-Warning"];
3775
3806
  if (warning) console.warn(warning);
3807
+ const banner = resp.headers["X-User-Notice"];
3808
+ if (warning) {
3809
+ createBanner(banner);
3810
+ setTimeout(() => removeBanner(), 1e4);
3811
+ }
3776
3812
  this.online = true;
3777
3813
  let data = JSONAttemptParse(await resp.text());
3778
3814
  if (!resp.ok || (data == null ? void 0 : data.error)) throw Object.assign(errorFromCode(resp.status, data.error), data);
@@ -3799,15 +3835,13 @@ const _Api = class _Api {
3799
3835
  }
3800
3836
  offlineBanner() {
3801
3837
  if (this.options.offlineBanner === false || typeof document == "undefined") return;
3802
- const banner = document.querySelector(".datalynk-offline-banner");
3803
3838
  if (this.online) {
3804
- banner == null ? void 0 : banner.remove();
3805
- } else if (!banner) {
3806
- const b = document.createElement("div");
3807
- b.className = "datalynk-offline-banner";
3808
- Object.assign(b.style, { position: "fixed", [this.options.offlineBanner === "top" ? "top" : "bottom"]: "0", left: "0", right: "0", padding: ".75rem", fontSize: "1rem", fontWeight: "bolder", backgroundColor: "#dc3545", color: "#fff", textAlign: "center", zIndex: "9999" });
3809
- b.innerHTML = "โš ๏ธ You are offline, please reconnect to sync changes";
3810
- document.body.appendChild(b);
3839
+ removeBanner("datalynk-offline-banner");
3840
+ } else {
3841
+ createBanner("โš ๏ธ You are offline, please reconnect to sync changes", {
3842
+ id: "datalynk-offline-banner",
3843
+ position: this.options.offlineBanner === "top" ? "top" : "bottom"
3844
+ });
3811
3845
  }
3812
3846
  }
3813
3847
  startHeartbeat() {
package/dist/pwa.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import { Api } from './api';
2
2
  export declare class PWA {
3
3
  private readonly api;
4
- deferredPrompt: any;
4
+ /** Capture Install Event */
5
+ nativeInstallPrompt: any;
5
6
  get headless(): boolean;
6
7
  get iframe(): boolean;
7
8
  get mobile(): boolean;
package/dist/pwa.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pwa.d.ts","sourceRoot":"","sources":["../src/pwa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,qBAAa,GAAG;IAuBH,OAAO,CAAC,QAAQ,CAAC,GAAG;IAtBzB,cAAc,EAAE,GAAG,CAAQ;IAElC,IAAI,QAAQ,IAAI,OAAO,CAAwC;IAE/D,IAAI,MAAM,IAAI,OAAO,CAAyC;IAE9D,IAAI,MAAM,IAAI,OAAO,CAAuD;IAE5E,IAAI,QAAQ,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAQ1E;IAED,IAAI,GAAG,IAAI,OAAO,CAEjB;gBAE4B,GAAG,EAAE,GAAG;IAErC,OAAO,CAAC,iBAAiB;IAezB,oBAAoB;IACd,KAAK,CAAC,QAAQ,GAAE,GAAQ;IAmE9B,qCAAqC;IAC/B,MAAM,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK;CAgJzC"}
1
+ {"version":3,"file":"pwa.d.ts","sourceRoot":"","sources":["../src/pwa.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,GAAG,EAAC,MAAM,OAAO,CAAC;AAE1B,qBAAa,GAAG;IAwBH,OAAO,CAAC,QAAQ,CAAC,GAAG;IAvBhC,4BAA4B;IACrB,mBAAmB,EAAE,GAAG,CAAQ;IAEvC,IAAI,QAAQ,IAAI,OAAO,CAAyC;IAEhE,IAAI,MAAM,IAAI,OAAO,CAAyC;IAE9D,IAAI,MAAM,IAAI,OAAO,CAAuD;IAE5E,IAAI,QAAQ,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,CAQ1E;IAED,IAAI,GAAG,IAAI,OAAO,CAEjB;gBAE4B,GAAG,EAAE,GAAG;IAErC,OAAO,CAAC,iBAAiB;IAiBzB,oBAAoB;IACd,KAAK,CAAC,QAAQ,GAAE,GAAQ;IAqE9B,qCAAqC;IAC/B,MAAM,CAAC,QAAQ,CAAC,EAAE,SAAS,GAAG,KAAK;CA6IzC"}
@@ -0,0 +1,128 @@
1
+ import {Api} from 'https://datalynk-client.scarborough.auxilium.world/dist/index.mjs';
2
+
3
+ let api = null;
4
+ const CACHE_NAME = 'datalynk';
5
+ let ONLINE = true;
6
+ const netChan = 'BroadcastChannel' in self ? new BroadcastChannel('sw-net') : null;
7
+
8
+ function broadcastStatus(online) {
9
+ if(ONLINE === online) return;
10
+ ONLINE = online;
11
+ netChan?.postMessage({type: 'status', online, ts: Date.now()});
12
+ }
13
+
14
+ async function getSettings() {
15
+ const cache = await caches.open('api-settings');
16
+ const response = await cache.match('/settings');
17
+ if(!response) return {};
18
+ try {
19
+ return (await response.clone().json()) || {};
20
+ } catch {
21
+ const txt = await response.text();
22
+ try { return JSON.parse(txt || '{}') || {}; }
23
+ catch { return null; }
24
+ }
25
+ }
26
+
27
+ async function setSettings(settings) {
28
+ const oldSettings = await getSettings();
29
+ const cache = await caches.open('api-settings');
30
+ const newSettings = {...oldSettings, ...settings};
31
+ await cache.put(new Request('/settings'), new Response(JSON.stringify(newSettings), {headers: {'Content-Type': 'application/json'}}));
32
+ return newSettings;
33
+ }
34
+
35
+ self.addEventListener('install', (event) => {
36
+ event.waitUntil(self.skipWaiting());
37
+ });
38
+
39
+ self.addEventListener('activate', (event) => {
40
+ event.waitUntil((async () => {
41
+ await self.clients.claim();
42
+
43
+ const keys = await caches.keys();
44
+ await Promise.all(
45
+ keys.filter((k) => k.startsWith('app-cache-') && k !== CACHE_NAME)
46
+ .map((k) => caches.delete(k))
47
+ );
48
+
49
+ const settings = await getSettings();
50
+ if(settings?.url) {
51
+ api = new Api(settings.url, { ...(settings.options || {}), serviceWorker: false });
52
+ if(settings.token) api.token = settings.token;
53
+ }
54
+ })());
55
+ });
56
+
57
+ netChan?.addEventListener('message', (e) => {
58
+ if(e.data === 'status?') netChan?.postMessage({ type: 'status', online: ONLINE, ts: Date.now() });
59
+ });
60
+
61
+ self.addEventListener('fetch', (event) => {
62
+ const request = event.request;
63
+
64
+ if(request.method !== 'GET') {
65
+ event.respondWith((async () => {
66
+ try {
67
+ const res = await fetch(request);
68
+ broadcastStatus(true);
69
+ return res;
70
+ } catch(err) {
71
+ broadcastStatus(false);
72
+ throw err;
73
+ }
74
+ })());
75
+ return;
76
+ }
77
+
78
+ event.respondWith((async () => {
79
+ const cache = await caches.open(CACHE_NAME);
80
+ if(!ONLINE) {
81
+ const cachedEarly = await cache.match(request);
82
+ if(cachedEarly) return cachedEarly;
83
+ }
84
+
85
+ try {
86
+ const networkResponse = await fetch(request);
87
+ broadcastStatus(true);
88
+ if(networkResponse.status === 404) { // purge stale
89
+ await cache.delete(request);
90
+ return networkResponse;
91
+ }
92
+ const isCacheable = networkResponse.ok || networkResponse.type === 'opaque';
93
+ if(isCacheable) {
94
+ const isOpaqueNav = networkResponse.type === 'opaque' && request.mode === 'navigate';
95
+ if (!isOpaqueNav) {
96
+ event.waitUntil(cache.put(request, networkResponse.clone()));
97
+ }
98
+ }
99
+ return networkResponse;
100
+ } catch {
101
+ broadcastStatus(false);
102
+ const cached = await cache.match(request);
103
+ if(cached) return cached;
104
+ if(request.mode === 'navigate') {
105
+ const fallback = (await cache.match('/')) || (await cache.match('/index.html'));
106
+ if(fallback) return fallback;
107
+ }
108
+
109
+ return new Response('You are offline', {
110
+ status: 503,
111
+ statusText: 'Service Unavailable',
112
+ headers: {'Content-Type': 'text/plain'}
113
+ });
114
+ }
115
+ })());
116
+ });
117
+
118
+ self.addEventListener('message', async (event) => {
119
+ if(event.data?.options) { // ๐Ÿ”ง Update settings
120
+ api = new Api(event.data.options.url, { ...event.data.options, serviceWorker: false });
121
+ await setSettings(event.data.options);
122
+ } else if(event.data?.token) { // ๐Ÿ”‘ Update token
123
+ if(api) api.token = event.data.token;
124
+ await setSettings({token: event.data.token});
125
+ } else if(event.data?.clearCache) { // ๐Ÿงน Clear cache (debugging)
126
+ await caches.delete(CACHE_NAME);
127
+ }
128
+ });
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@auxilium/datalynk-client",
3
3
  "description": "Datalynk client library",
4
4
  "repository": "https://gitlab.auxiliumgroup.com/auxilium/datalynk/datalynk-client",
5
- "version": "1.3.6",
5
+ "version": "1.3.8",
6
6
  "author": "Zak Timson <zaktimson@gmail.com>",
7
7
  "private": false,
8
8
  "main": "./dist/index.cjs",
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "scripts": {
22
22
  "build": "tsc && npx vite build",
23
+ "postbuild": "node -e \"const fs=require('fs');fs.cpSync('src/service.worker.mjs','dist/service.worker.mjs')\"",
23
24
  "datalynk-models": "node --no-warnings ./bin/datalynk-models.mjs",
24
25
  "docs": "typedoc --cleanOutputDir false --out ./docs --entryPoints src/**/*.ts --readme README.md",
25
26
  "watch": "vite build --watch"