@auxilium/datalynk-client 1.3.5 โ†’ 1.3.7

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 CHANGED
@@ -58,9 +58,9 @@ export type ApiOptions = {
58
58
  };
59
59
  /** Progressive Web App settings */
60
60
  pwaSettings?: {
61
- /** How long to wait before showing install prompt (seconds). Default is 30 seconds */
61
+ /** How long to wait before showing the installation prompt (seconds). Default is 30 seconds */
62
62
  timeout?: number;
63
- /** Days until dismissed prompt can show again. If set to 0 it will trigger every refresh. (Default is 7 days) */
63
+ /** Days until the dismissed prompt can show again. If set to `0` it will trigger every refresh. (Default is 7 days) */
64
64
  dismissExpiry?: number;
65
65
  /** Show PWA install link on login screen. Default is False */
66
66
  loginLink?: boolean;
@@ -72,6 +72,8 @@ export type ApiOptions = {
72
72
  export interface ApiRequestOptions {
73
73
  /** Skip bundling & caching */
74
74
  noOptimize?: boolean;
75
+ /** Queue for network connection */
76
+ offline?: boolean;
75
77
  /** Skip the token translating step */
76
78
  raw?: boolean;
77
79
  /** Set request token */
@@ -125,7 +127,7 @@ export declare class Api {
125
127
  /** Options */
126
128
  options: ApiOptions;
127
129
  /** Created slices */
128
- sliceCache: Map<number, Slice<any>>;
130
+ sliceCache: Map<number, Slice>;
129
131
  /** API URL */
130
132
  url: string;
131
133
  /** Client library version */
@@ -135,7 +137,7 @@ export declare class Api {
135
137
  /** Get session info from JWT payload */
136
138
  get jwtPayload(): JwtPayload | null;
137
139
  private onlineOverride;
138
- private _online;
140
+ online$: BehaviorSubject<boolean>;
139
141
  /** Check if we are connected */
140
142
  get online(): boolean | null;
141
143
  get offline(): boolean;
@@ -192,13 +194,16 @@ export declare class Api {
192
194
  [key: string]: any;
193
195
  }): Promise<any>;
194
196
  /**
195
- * Exact same as `request` method, but logs the response in the console automatically
197
+ * Exact same as the `request` method, but logs the response in the console automatically
196
198
  *
197
199
  * @param {object | string} data Datalynk request as object or string
198
200
  * @param {ApiRequestOptions} options
199
201
  * @returns {Promise<any>} Datalynk response
200
202
  */
201
203
  debug<T = any>(data: any, options?: ApiRequestOptions): Promise<T>;
204
+ debug<T = any>(data: any, options: {
205
+ offline: true;
206
+ } & ApiRequestOptions): Promise<T | void>;
202
207
  /**
203
208
  * Send a request to Datalynk
204
209
  *
@@ -212,6 +217,9 @@ export declare class Api {
212
217
  * @returns {Promise<any>} Datalynk response or error
213
218
  */
214
219
  request<T = any>(data: any, options?: ApiRequestOptions): Promise<T>;
220
+ request<T = any>(data: any, options: {
221
+ offline: true;
222
+ } & ApiRequestOptions): Promise<T | void>;
215
223
  /**
216
224
  * Create a slice object using the API
217
225
  *
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 {
@@ -3066,7 +3095,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3066
3095
  return this;
3067
3096
  }
3068
3097
  }
3069
- class Slice {
3098
+ const _Slice = class _Slice {
3070
3099
  /**
3071
3100
  * An object to aid in constructing requests
3072
3101
  *
@@ -3077,17 +3106,20 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3077
3106
  __publicField(this, "table");
3078
3107
  __publicField(this, "info");
3079
3108
  __publicField(this, "loaded", false);
3080
- __publicField(this, "pendingInsert", 0);
3081
- /** Unsubscribe from changes, undefined if not subscribed */
3082
- __publicField(this, "unsubscribe");
3083
3109
  /** Cached slice data as an observable */
3084
3110
  __publicField(this, "cache$", new BehaviorSubject([]));
3111
+ /** Unsubscribe from changes, undefined if not subscribed */
3112
+ __publicField(this, "unsubscribe");
3085
3113
  var _a;
3086
3114
  this.slice = slice;
3087
3115
  this.api = api;
3088
3116
  if (this.offlineEnabled) {
3089
3117
  this.table = (_a = api.database) == null ? void 0 : _a.table(slice.toString());
3090
- this.table.getAll().then((resp) => this.cache = resp).finally(() => this.loaded = true);
3118
+ this.table.getAll().then((resp) => {
3119
+ this.cache = resp;
3120
+ const lowest = resp.reduce((acc, r) => Math.min(acc, r.id), 0);
3121
+ if (lowest < _Slice.nextId) _Slice.nextId = lowest;
3122
+ }).finally(() => this.loaded = true);
3091
3123
  this.cache$.pipe(skip(1)).subscribe(async (cache) => {
3092
3124
  var _a2;
3093
3125
  await ((_a2 = this.table) == null ? void 0 : _a2.clear());
@@ -3095,10 +3127,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3095
3127
  var _a3;
3096
3128
  return (_a3 = this.table) == null ? void 0 : _a3.put(c.id, c);
3097
3129
  }));
3098
- this.fixIncrement();
3099
3130
  });
3100
3131
  this.sync();
3101
- window.addEventListener("online", async () => {
3132
+ this.api.online$.subscribe(async (online) => {
3133
+ if (!online) return;
3102
3134
  if (this.api.expired) await lastValueFrom(this.api.auth.user$.pipe(skip(1), takeWhile((u) => !u || this.api.expired, true)));
3103
3135
  this.pushChanges();
3104
3136
  });
@@ -3119,10 +3151,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3119
3151
  var _a;
3120
3152
  return (_a = this.api.database) == null ? void 0 : _a.includes(this.slice.toString());
3121
3153
  }
3122
- fixIncrement() {
3123
- var _a;
3124
- this.pendingInsert = ((_a = this.cache.toSorted(sortByProp("id")).pop()) == null ? void 0 : _a["id"]) || 0;
3125
- }
3126
3154
  execWrapper(call) {
3127
3155
  const onlineExec = call.exec.bind(call);
3128
3156
  return async () => {
@@ -3168,7 +3196,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3168
3196
  } else if (request["$/slice/xinsert"]) {
3169
3197
  const rows = request["$/slice/xinsert"]["rows"].map((r) => ({
3170
3198
  ...r,
3171
- id: -++this.pendingInsert,
3199
+ id: --_Slice.nextId,
3172
3200
  _sync: "insert"
3173
3201
  }));
3174
3202
  this.cache = [...this.cache, ...rows];
@@ -3334,7 +3362,10 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3334
3362
  call.exec = this.execWrapper(call);
3335
3363
  return call.update(rows);
3336
3364
  }
3337
- }
3365
+ };
3366
+ __publicField(_Slice, "idMap", {});
3367
+ __publicField(_Slice, "nextId", 0);
3368
+ let Slice = _Slice;
3338
3369
  class Socket {
3339
3370
  constructor(api, options = {}) {
3340
3371
  __publicField(this, "listeners", []);
@@ -3469,7 +3500,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3469
3500
  } });
3470
3501
  }
3471
3502
  }
3472
- const version = "1.3.5";
3503
+ const version = "1.3.7";
3473
3504
  class WebRtc {
3474
3505
  constructor(api) {
3475
3506
  __publicField(this, "ice");
@@ -3643,7 +3674,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3643
3674
  /** Client library version */
3644
3675
  __publicField(this, "version", version);
3645
3676
  __publicField(this, "onlineOverride", false);
3646
- __publicField(this, "_online", typeof navigator == "undefined" ? true : navigator.onLine);
3677
+ __publicField(this, "online$", new BehaviorSubject(typeof navigator == "undefined" ? true : navigator.onLine));
3647
3678
  /** API Session token */
3648
3679
  __publicField(this, "token$", new BehaviorSubject(void 0));
3649
3680
  var _a, _b;
@@ -3679,20 +3710,28 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3679
3710
  this.pwa = new PWA(this);
3680
3711
  this.superuser = new Superuser(this);
3681
3712
  this.webrtc = new WebRtc(this);
3713
+ this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3714
+ this.online$.subscribe(async (online) => {
3715
+ var _a2;
3716
+ if (!online) return;
3717
+ const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3718
+ const keys = await (table == null ? void 0 : table.getAllKeys());
3719
+ await Promise.allSettled(keys.map(async (k) => {
3720
+ const r = await (table == null ? void 0 : table.get(k));
3721
+ await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3722
+ }));
3723
+ });
3682
3724
  if (typeof window !== "undefined") {
3683
- const handleOffline = (state) => {
3684
- this._online = state;
3685
- this.offlineBanner();
3725
+ const handleOffline = (state = this.offline) => {
3726
+ if (this.online != state) this.online$.next(state);
3686
3727
  };
3687
3728
  window.addEventListener("online", () => handleOffline(true));
3688
3729
  window.addEventListener("offline", () => handleOffline(false));
3689
- this.startHeartbeat();
3690
- this.offlineBanner();
3730
+ this.online$.subscribe(() => this.offlineBanner());
3691
3731
  }
3692
3732
  if ((_a = this.options.offline) == null ? void 0 : _a.length) {
3693
3733
  this.pwa.setup();
3694
3734
  if (typeof indexedDB == "undefined") throw new Error("Cannot enable offline support, indexedDB is not available in this environment");
3695
- this.database = new Database("datalynk", this.options.offline);
3696
3735
  (_b = this.options.offline) == null ? void 0 : _b.forEach((id) => this.slice(id));
3697
3736
  if (this.options.serviceWorker && typeof navigator["serviceWorker"] != "undefined") {
3698
3737
  (async () => {
@@ -3725,24 +3764,23 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3725
3764
  }
3726
3765
  /** Check if we are connected */
3727
3766
  get online() {
3728
- return this._online;
3767
+ return this.online$.getValue();
3729
3768
  }
3730
3769
  get offline() {
3731
- return !this._online;
3770
+ return !this.online;
3732
3771
  }
3733
3772
  /** Override connection status */
3734
3773
  set online(value) {
3735
3774
  if (value == null) {
3736
3775
  this.onlineOverride = false;
3737
- this._online = typeof navigator == "undefined" ? true : navigator.onLine;
3776
+ this.online$.next(typeof navigator == "undefined" ? true : navigator.onLine);
3738
3777
  } else {
3739
3778
  this.onlineOverride = true;
3740
3779
  if (value == this.online) return;
3741
- this._online = value;
3780
+ this.online$.next(value);
3742
3781
  if (value) this.startHeartbeat();
3743
3782
  else this.stopHeartbeat();
3744
3783
  }
3745
- this.offlineBanner();
3746
3784
  }
3747
3785
  /** Logged in spoke */
3748
3786
  get spoke() {
@@ -3766,6 +3804,13 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3766
3804
  }),
3767
3805
  body: JSON.stringify(_Api.translateTokens(req))
3768
3806
  }).then(async (resp) => {
3807
+ const warning = resp.headers["X-Warning"];
3808
+ if (warning) console.warn(warning);
3809
+ const banner = resp.headers["X-User-Notice"];
3810
+ if (warning) {
3811
+ createBanner(banner);
3812
+ setTimeout(() => removeBanner(), 1e4);
3813
+ }
3769
3814
  this.online = true;
3770
3815
  let data = JSONAttemptParse(await resp.text());
3771
3816
  if (!resp.ok || (data == null ? void 0 : data.error)) throw Object.assign(errorFromCode(resp.status, data.error), data);
@@ -3775,7 +3820,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3775
3820
  }
3776
3821
  async checkConnection() {
3777
3822
  if (typeof navigator != "undefined" && !navigator.onLine) {
3778
- this._online = false;
3823
+ this.online$.next(false);
3779
3824
  return;
3780
3825
  }
3781
3826
  if (this.onlineOverride) return;
@@ -3783,24 +3828,22 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3783
3828
  const timeout = setTimeout(() => controller.abort(), this.heartbeat.timeout);
3784
3829
  try {
3785
3830
  const response = await fetch(this.url + this.heartbeat.target, { signal: controller.signal });
3786
- this._online = response.ok;
3831
+ this.online$.next(response.ok);
3787
3832
  } catch (error) {
3788
- this._online = false;
3833
+ this.online$.next(false);
3789
3834
  } finally {
3790
3835
  clearTimeout(timeout);
3791
3836
  }
3792
3837
  }
3793
3838
  offlineBanner() {
3794
3839
  if (this.options.offlineBanner === false || typeof document == "undefined") return;
3795
- const banner = document.querySelector(".datalynk-offline-banner");
3796
3840
  if (this.online) {
3797
- banner == null ? void 0 : banner.remove();
3798
- } else if (!banner) {
3799
- const b = document.createElement("div");
3800
- b.className = "datalynk-offline-banner";
3801
- 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" });
3802
- b.innerHTML = "โš ๏ธ You are offline, please reconnect to sync changes";
3803
- document.body.appendChild(b);
3841
+ removeBanner("datalynk-offline-banner");
3842
+ } else {
3843
+ createBanner("โš ๏ธ You are offline, please reconnect to sync changes", {
3844
+ id: "datalynk-offline-banner",
3845
+ position: this.options.offlineBanner === "top" ? "top" : "bottom"
3846
+ });
3804
3847
  }
3805
3848
  }
3806
3849
  startHeartbeat() {
@@ -3896,13 +3939,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3896
3939
  { "$_": "*" }
3897
3940
  ] }, {});
3898
3941
  }
3899
- /**
3900
- * Exact same as `request` method, but logs the response in the console automatically
3901
- *
3902
- * @param {object | string} data Datalynk request as object or string
3903
- * @param {ApiRequestOptions} options
3904
- * @returns {Promise<any>} Datalynk response
3905
- */
3906
3942
  debug(data, options = {}) {
3907
3943
  return this.request(data, options).then((data2) => {
3908
3944
  console.log(data2);
@@ -3912,20 +3948,14 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3912
3948
  return err;
3913
3949
  });
3914
3950
  }
3915
- /**
3916
- * Send a request to Datalynk
3917
- *
3918
- * @example
3919
- * ```ts
3920
- * const response = await api.request('$/auth/current');
3921
- * ```
3922
- *
3923
- * @param {object} data Request using Datalynk API syntax. Strings will be converted: '$/auth/current' -> {'$/auth/current': {}}
3924
- * @param {ApiRequestOptions} options
3925
- * @returns {Promise<any>} Datalynk response or error
3926
- */
3927
3951
  request(data, options = {}) {
3952
+ var _a, _b;
3928
3953
  data = typeof data == "string" ? { [data]: {} } : data;
3954
+ let key = JSON.stringify(data);
3955
+ if (this.offline) {
3956
+ (_b = (_a = this.database) == null ? void 0 : _a.table("pending")) == null ? void 0 : _b.add(data, key);
3957
+ return Promise.resolve();
3958
+ }
3929
3959
  if (options.noOptimize) {
3930
3960
  return new Promise((res, rej) => {
3931
3961
  this._request(data, options).then((resp) => {
@@ -3933,7 +3963,6 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
3933
3963
  }).catch((err) => rej(err));
3934
3964
  });
3935
3965
  }
3936
- let key = JSON.stringify(data);
3937
3966
  if (!this.pending[key]) {
3938
3967
  this.pending[key] = new Promise((res, rej) => this.bundle.push({ data, res, rej }));
3939
3968
  this.pending[key].catch().then(() => delete this.pending[key]);
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 {
@@ -3062,7 +3091,7 @@ class ApiCall {
3062
3091
  return this;
3063
3092
  }
3064
3093
  }
3065
- class Slice {
3094
+ const _Slice = class _Slice {
3066
3095
  /**
3067
3096
  * An object to aid in constructing requests
3068
3097
  *
@@ -3073,17 +3102,20 @@ class Slice {
3073
3102
  __publicField(this, "table");
3074
3103
  __publicField(this, "info");
3075
3104
  __publicField(this, "loaded", false);
3076
- __publicField(this, "pendingInsert", 0);
3077
- /** Unsubscribe from changes, undefined if not subscribed */
3078
- __publicField(this, "unsubscribe");
3079
3105
  /** Cached slice data as an observable */
3080
3106
  __publicField(this, "cache$", new BehaviorSubject([]));
3107
+ /** Unsubscribe from changes, undefined if not subscribed */
3108
+ __publicField(this, "unsubscribe");
3081
3109
  var _a;
3082
3110
  this.slice = slice;
3083
3111
  this.api = api;
3084
3112
  if (this.offlineEnabled) {
3085
3113
  this.table = (_a = api.database) == null ? void 0 : _a.table(slice.toString());
3086
- this.table.getAll().then((resp) => this.cache = resp).finally(() => this.loaded = true);
3114
+ this.table.getAll().then((resp) => {
3115
+ this.cache = resp;
3116
+ const lowest = resp.reduce((acc, r) => Math.min(acc, r.id), 0);
3117
+ if (lowest < _Slice.nextId) _Slice.nextId = lowest;
3118
+ }).finally(() => this.loaded = true);
3087
3119
  this.cache$.pipe(skip(1)).subscribe(async (cache) => {
3088
3120
  var _a2;
3089
3121
  await ((_a2 = this.table) == null ? void 0 : _a2.clear());
@@ -3091,10 +3123,10 @@ class Slice {
3091
3123
  var _a3;
3092
3124
  return (_a3 = this.table) == null ? void 0 : _a3.put(c.id, c);
3093
3125
  }));
3094
- this.fixIncrement();
3095
3126
  });
3096
3127
  this.sync();
3097
- window.addEventListener("online", async () => {
3128
+ this.api.online$.subscribe(async (online) => {
3129
+ if (!online) return;
3098
3130
  if (this.api.expired) await lastValueFrom(this.api.auth.user$.pipe(skip(1), takeWhile((u) => !u || this.api.expired, true)));
3099
3131
  this.pushChanges();
3100
3132
  });
@@ -3115,10 +3147,6 @@ class Slice {
3115
3147
  var _a;
3116
3148
  return (_a = this.api.database) == null ? void 0 : _a.includes(this.slice.toString());
3117
3149
  }
3118
- fixIncrement() {
3119
- var _a;
3120
- this.pendingInsert = ((_a = this.cache.toSorted(sortByProp("id")).pop()) == null ? void 0 : _a["id"]) || 0;
3121
- }
3122
3150
  execWrapper(call) {
3123
3151
  const onlineExec = call.exec.bind(call);
3124
3152
  return async () => {
@@ -3164,7 +3192,7 @@ class Slice {
3164
3192
  } else if (request["$/slice/xinsert"]) {
3165
3193
  const rows = request["$/slice/xinsert"]["rows"].map((r) => ({
3166
3194
  ...r,
3167
- id: -++this.pendingInsert,
3195
+ id: --_Slice.nextId,
3168
3196
  _sync: "insert"
3169
3197
  }));
3170
3198
  this.cache = [...this.cache, ...rows];
@@ -3330,7 +3358,10 @@ class Slice {
3330
3358
  call.exec = this.execWrapper(call);
3331
3359
  return call.update(rows);
3332
3360
  }
3333
- }
3361
+ };
3362
+ __publicField(_Slice, "idMap", {});
3363
+ __publicField(_Slice, "nextId", 0);
3364
+ let Slice = _Slice;
3334
3365
  class Socket {
3335
3366
  constructor(api, options = {}) {
3336
3367
  __publicField(this, "listeners", []);
@@ -3465,7 +3496,7 @@ class Superuser {
3465
3496
  } });
3466
3497
  }
3467
3498
  }
3468
- const version = "1.3.5";
3499
+ const version = "1.3.7";
3469
3500
  class WebRtc {
3470
3501
  constructor(api) {
3471
3502
  __publicField(this, "ice");
@@ -3639,7 +3670,7 @@ const _Api = class _Api {
3639
3670
  /** Client library version */
3640
3671
  __publicField(this, "version", version);
3641
3672
  __publicField(this, "onlineOverride", false);
3642
- __publicField(this, "_online", typeof navigator == "undefined" ? true : navigator.onLine);
3673
+ __publicField(this, "online$", new BehaviorSubject(typeof navigator == "undefined" ? true : navigator.onLine));
3643
3674
  /** API Session token */
3644
3675
  __publicField(this, "token$", new BehaviorSubject(void 0));
3645
3676
  var _a, _b;
@@ -3675,20 +3706,28 @@ const _Api = class _Api {
3675
3706
  this.pwa = new PWA(this);
3676
3707
  this.superuser = new Superuser(this);
3677
3708
  this.webrtc = new WebRtc(this);
3709
+ this.database = new Database("datalynk", ["pending", ...this.options.offline || []]);
3710
+ this.online$.subscribe(async (online) => {
3711
+ var _a2;
3712
+ if (!online) return;
3713
+ const table = (_a2 = this.database) == null ? void 0 : _a2.table("pending");
3714
+ const keys = await (table == null ? void 0 : table.getAllKeys());
3715
+ await Promise.allSettled(keys.map(async (k) => {
3716
+ const r = await (table == null ? void 0 : table.get(k));
3717
+ await this.request(r).then(() => table == null ? void 0 : table.delete(k));
3718
+ }));
3719
+ });
3678
3720
  if (typeof window !== "undefined") {
3679
- const handleOffline = (state) => {
3680
- this._online = state;
3681
- this.offlineBanner();
3721
+ const handleOffline = (state = this.offline) => {
3722
+ if (this.online != state) this.online$.next(state);
3682
3723
  };
3683
3724
  window.addEventListener("online", () => handleOffline(true));
3684
3725
  window.addEventListener("offline", () => handleOffline(false));
3685
- this.startHeartbeat();
3686
- this.offlineBanner();
3726
+ this.online$.subscribe(() => this.offlineBanner());
3687
3727
  }
3688
3728
  if ((_a = this.options.offline) == null ? void 0 : _a.length) {
3689
3729
  this.pwa.setup();
3690
3730
  if (typeof indexedDB == "undefined") throw new Error("Cannot enable offline support, indexedDB is not available in this environment");
3691
- this.database = new Database("datalynk", this.options.offline);
3692
3731
  (_b = this.options.offline) == null ? void 0 : _b.forEach((id) => this.slice(id));
3693
3732
  if (this.options.serviceWorker && typeof navigator["serviceWorker"] != "undefined") {
3694
3733
  (async () => {
@@ -3721,24 +3760,23 @@ const _Api = class _Api {
3721
3760
  }
3722
3761
  /** Check if we are connected */
3723
3762
  get online() {
3724
- return this._online;
3763
+ return this.online$.getValue();
3725
3764
  }
3726
3765
  get offline() {
3727
- return !this._online;
3766
+ return !this.online;
3728
3767
  }
3729
3768
  /** Override connection status */
3730
3769
  set online(value) {
3731
3770
  if (value == null) {
3732
3771
  this.onlineOverride = false;
3733
- this._online = typeof navigator == "undefined" ? true : navigator.onLine;
3772
+ this.online$.next(typeof navigator == "undefined" ? true : navigator.onLine);
3734
3773
  } else {
3735
3774
  this.onlineOverride = true;
3736
3775
  if (value == this.online) return;
3737
- this._online = value;
3776
+ this.online$.next(value);
3738
3777
  if (value) this.startHeartbeat();
3739
3778
  else this.stopHeartbeat();
3740
3779
  }
3741
- this.offlineBanner();
3742
3780
  }
3743
3781
  /** Logged in spoke */
3744
3782
  get spoke() {
@@ -3762,6 +3800,13 @@ const _Api = class _Api {
3762
3800
  }),
3763
3801
  body: JSON.stringify(_Api.translateTokens(req))
3764
3802
  }).then(async (resp) => {
3803
+ const warning = resp.headers["X-Warning"];
3804
+ if (warning) console.warn(warning);
3805
+ const banner = resp.headers["X-User-Notice"];
3806
+ if (warning) {
3807
+ createBanner(banner);
3808
+ setTimeout(() => removeBanner(), 1e4);
3809
+ }
3765
3810
  this.online = true;
3766
3811
  let data = JSONAttemptParse(await resp.text());
3767
3812
  if (!resp.ok || (data == null ? void 0 : data.error)) throw Object.assign(errorFromCode(resp.status, data.error), data);
@@ -3771,7 +3816,7 @@ const _Api = class _Api {
3771
3816
  }
3772
3817
  async checkConnection() {
3773
3818
  if (typeof navigator != "undefined" && !navigator.onLine) {
3774
- this._online = false;
3819
+ this.online$.next(false);
3775
3820
  return;
3776
3821
  }
3777
3822
  if (this.onlineOverride) return;
@@ -3779,24 +3824,22 @@ const _Api = class _Api {
3779
3824
  const timeout = setTimeout(() => controller.abort(), this.heartbeat.timeout);
3780
3825
  try {
3781
3826
  const response = await fetch(this.url + this.heartbeat.target, { signal: controller.signal });
3782
- this._online = response.ok;
3827
+ this.online$.next(response.ok);
3783
3828
  } catch (error) {
3784
- this._online = false;
3829
+ this.online$.next(false);
3785
3830
  } finally {
3786
3831
  clearTimeout(timeout);
3787
3832
  }
3788
3833
  }
3789
3834
  offlineBanner() {
3790
3835
  if (this.options.offlineBanner === false || typeof document == "undefined") return;
3791
- const banner = document.querySelector(".datalynk-offline-banner");
3792
3836
  if (this.online) {
3793
- banner == null ? void 0 : banner.remove();
3794
- } else if (!banner) {
3795
- const b = document.createElement("div");
3796
- b.className = "datalynk-offline-banner";
3797
- 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" });
3798
- b.innerHTML = "โš ๏ธ You are offline, please reconnect to sync changes";
3799
- document.body.appendChild(b);
3837
+ removeBanner("datalynk-offline-banner");
3838
+ } else {
3839
+ createBanner("โš ๏ธ You are offline, please reconnect to sync changes", {
3840
+ id: "datalynk-offline-banner",
3841
+ position: this.options.offlineBanner === "top" ? "top" : "bottom"
3842
+ });
3800
3843
  }
3801
3844
  }
3802
3845
  startHeartbeat() {
@@ -3892,13 +3935,6 @@ const _Api = class _Api {
3892
3935
  { "$_": "*" }
3893
3936
  ] }, {});
3894
3937
  }
3895
- /**
3896
- * Exact same as `request` method, but logs the response in the console automatically
3897
- *
3898
- * @param {object | string} data Datalynk request as object or string
3899
- * @param {ApiRequestOptions} options
3900
- * @returns {Promise<any>} Datalynk response
3901
- */
3902
3938
  debug(data, options = {}) {
3903
3939
  return this.request(data, options).then((data2) => {
3904
3940
  console.log(data2);
@@ -3908,20 +3944,14 @@ const _Api = class _Api {
3908
3944
  return err;
3909
3945
  });
3910
3946
  }
3911
- /**
3912
- * Send a request to Datalynk
3913
- *
3914
- * @example
3915
- * ```ts
3916
- * const response = await api.request('$/auth/current');
3917
- * ```
3918
- *
3919
- * @param {object} data Request using Datalynk API syntax. Strings will be converted: '$/auth/current' -> {'$/auth/current': {}}
3920
- * @param {ApiRequestOptions} options
3921
- * @returns {Promise<any>} Datalynk response or error
3922
- */
3923
3947
  request(data, options = {}) {
3948
+ var _a, _b;
3924
3949
  data = typeof data == "string" ? { [data]: {} } : data;
3950
+ let key = JSON.stringify(data);
3951
+ if (this.offline) {
3952
+ (_b = (_a = this.database) == null ? void 0 : _a.table("pending")) == null ? void 0 : _b.add(data, key);
3953
+ return Promise.resolve();
3954
+ }
3925
3955
  if (options.noOptimize) {
3926
3956
  return new Promise((res, rej) => {
3927
3957
  this._request(data, options).then((resp) => {
@@ -3929,7 +3959,6 @@ const _Api = class _Api {
3929
3959
  }).catch((err) => rej(err));
3930
3960
  });
3931
3961
  }
3932
- let key = JSON.stringify(data);
3933
3962
  if (!this.pending[key]) {
3934
3963
  this.pending[key] = new Promise((res, rej) => this.bundle.push({ data, res, rej }));
3935
3964
  this.pending[key].catch().then(() => delete this.pending[key]);
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/dist/slice.d.ts CHANGED
@@ -231,14 +231,17 @@ export declare class ApiCall<T extends Meta = any> {
231
231
  export declare class Slice<T extends Meta = any> {
232
232
  private slice;
233
233
  private api;
234
+ static idMap: {
235
+ [key: number]: number;
236
+ };
237
+ static nextId: number;
234
238
  private table?;
235
239
  private info?;
236
240
  private loaded;
237
- private pendingInsert;
238
- /** Unsubscribe from changes, undefined if not subscribed */
239
- unsubscribe?: Unsubscribe | null;
240
241
  /** Cached slice data as an observable */
241
242
  cache$: BehaviorSubject<T[]>;
243
+ /** Unsubscribe from changes, undefined if not subscribed */
244
+ unsubscribe?: Unsubscribe | null;
242
245
  /** Cached slice data */
243
246
  get cache(): T[];
244
247
  /** Set cached data & alert subscribers */
@@ -252,7 +255,6 @@ export declare class Slice<T extends Meta = any> {
252
255
  * @param {Api} api Api to send the requests through
253
256
  */
254
257
  constructor(slice: number | string, api: Api);
255
- private fixIncrement;
256
258
  private execWrapper;
257
259
  pushChanges(): Promise<void>;
258
260
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../src/slice.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"slice.d.ts","sourceRoot":"","sources":["../src/slice.ts"],"names":[],"mappings":"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"}
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.5",
5
+ "version": "1.3.7",
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"