@ztimson/momentum 0.53.1 → 0.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +200 -148
  2. package/bin/build-models.mjs +28 -37
  3. package/dist/actions.d.ts +32 -43
  4. package/dist/actions.d.ts.map +1 -1
  5. package/dist/ai.d.ts +38 -17
  6. package/dist/ai.d.ts.map +1 -1
  7. package/dist/analytics.d.ts +169 -36
  8. package/dist/analytics.d.ts.map +1 -1
  9. package/dist/api.d.ts +22 -22
  10. package/dist/api.d.ts.map +1 -1
  11. package/dist/asset-controller.d.ts +92 -0
  12. package/dist/asset-controller.d.ts.map +1 -0
  13. package/dist/audit.d.ts +22 -0
  14. package/dist/audit.d.ts.map +1 -0
  15. package/dist/auth.d.ts +39 -92
  16. package/dist/auth.d.ts.map +1 -1
  17. package/dist/call.d.ts +39 -0
  18. package/dist/call.d.ts.map +1 -0
  19. package/dist/captcha.d.ts +14 -0
  20. package/dist/captcha.d.ts.map +1 -0
  21. package/dist/client.d.ts +44 -33
  22. package/dist/client.d.ts.map +1 -1
  23. package/dist/core.d.ts +50 -21
  24. package/dist/core.d.ts.map +1 -1
  25. package/dist/data.d.ts +59 -77
  26. package/dist/data.d.ts.map +1 -1
  27. package/dist/dialog.d.ts +11 -0
  28. package/dist/dialog.d.ts.map +1 -0
  29. package/dist/discounts.d.ts +8 -12
  30. package/dist/discounts.d.ts.map +1 -1
  31. package/dist/email.d.ts +19 -19
  32. package/dist/email.d.ts.map +1 -1
  33. package/dist/forms.d.ts +6 -13
  34. package/dist/forms.d.ts.map +1 -1
  35. package/dist/groups.d.ts +22 -16
  36. package/dist/groups.d.ts.map +1 -1
  37. package/dist/index.d.ts +13 -3
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +4446 -0
  40. package/dist/index.mjs +3422 -1731
  41. package/dist/logger.d.ts +78 -48
  42. package/dist/logger.d.ts.map +1 -1
  43. package/dist/momentum.d.ts +69 -15
  44. package/dist/momentum.d.ts.map +1 -1
  45. package/dist/momentum.worker.d.mts +2 -0
  46. package/dist/momentum.worker.d.mts.map +1 -0
  47. package/dist/momentum.worker.mjs +103 -0
  48. package/dist/notifications.d.ts +39 -0
  49. package/dist/notifications.d.ts.map +1 -0
  50. package/dist/pdf.d.ts +31 -14
  51. package/dist/pdf.d.ts.map +1 -1
  52. package/dist/products.d.ts +47 -0
  53. package/dist/products.d.ts.map +1 -0
  54. package/dist/routes.d.ts +40 -0
  55. package/dist/routes.d.ts.map +1 -0
  56. package/dist/schemas.d.ts +79 -0
  57. package/dist/schemas.d.ts.map +1 -0
  58. package/dist/settings.d.ts +30 -14
  59. package/dist/settings.d.ts.map +1 -1
  60. package/dist/sms.d.ts +14 -0
  61. package/dist/sms.d.ts.map +1 -0
  62. package/dist/sockets.d.ts +21 -10
  63. package/dist/sockets.d.ts.map +1 -1
  64. package/dist/static.d.ts +4 -2
  65. package/dist/static.d.ts.map +1 -1
  66. package/dist/storage.d.ts +103 -24
  67. package/dist/storage.d.ts.map +1 -1
  68. package/dist/templates.d.ts +23 -0
  69. package/dist/templates.d.ts.map +1 -0
  70. package/dist/tokens.d.ts +50 -0
  71. package/dist/tokens.d.ts.map +1 -0
  72. package/dist/totp.d.ts +45 -0
  73. package/dist/totp.d.ts.map +1 -0
  74. package/dist/transactions.d.ts +153 -0
  75. package/dist/transactions.d.ts.map +1 -0
  76. package/dist/users.d.ts +63 -25
  77. package/dist/users.d.ts.map +1 -1
  78. package/dist/webRtc.d.ts +39 -0
  79. package/dist/webRtc.d.ts.map +1 -0
  80. package/package.json +53 -43
  81. package/dist/index.cjs +0 -2755
  82. package/dist/momentum.worker.js +0 -16
  83. package/dist/payments.d.ts +0 -184
  84. package/dist/payments.d.ts.map +0 -1
  85. package/dist/phone.d.ts +0 -19
  86. package/dist/phone.d.ts.map +0 -1
package/dist/index.cjs DELETED
@@ -1,2755 +0,0 @@
1
- (function(global, factory) {
2
- typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.utils = {}));
3
- })(this, function(exports2) {
4
- "use strict";var __defProp = Object.defineProperty;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
-
8
- var __defProp2 = Object.defineProperty;
9
- var __defNormalProp2 = (obj, key, value2) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value: value2 }) : obj[key] = value2;
10
- var __publicField2 = (obj, key, value2) => __defNormalProp2(obj, typeof key !== "symbol" ? key + "" : key, value2);
11
- function clean(obj, undefinedOnly = false) {
12
- if (obj == null) throw new Error("Cannot clean a NULL value");
13
- if (Array.isArray(obj)) {
14
- obj = obj.filter((o) => o != null);
15
- } else {
16
- Object.entries(obj).forEach(([key, value2]) => {
17
- if (undefinedOnly && value2 === void 0 || !undefinedOnly && value2 == null) delete obj[key];
18
- });
19
- }
20
- return obj;
21
- }
22
- function deepCopy(value2) {
23
- try {
24
- return structuredClone(value2);
25
- } catch {
26
- return JSON.parse(JSONSanitize(value2));
27
- }
28
- }
29
- function isEqual(a2, b2) {
30
- const ta = typeof a2, tb = typeof b2;
31
- if (ta != "object" || a2 == null || (tb != "object" || b2 == null))
32
- return ta == "function" && tb == "function" ? a2.toString() == b2.toString() : a2 === b2;
33
- const keys = Object.keys(a2);
34
- if (keys.length != Object.keys(b2).length) return false;
35
- return Object.keys(a2).every((key) => isEqual(a2[key], b2[key]));
36
- }
37
- function JSONAttemptParse(json) {
38
- try {
39
- return JSON.parse(json);
40
- } catch {
41
- return json;
42
- }
43
- }
44
- function JSONSanitize(obj, space) {
45
- return JSON.stringify(obj, (key, value2) => {
46
- return value2;
47
- }, space);
48
- }
49
- function makeArray(value2) {
50
- return Array.isArray(value2) ? value2 : [value2];
51
- }
52
- class ASet extends Array {
53
- /** Number of elements in set */
54
- get size() {
55
- return this.length;
56
- }
57
- /**
58
- * Array to create set from, duplicate values will be removed
59
- * @param {T[]} elements Elements which will be added to set
60
- */
61
- constructor(elements = []) {
62
- super();
63
- if (!!(elements == null ? void 0 : elements["forEach"]))
64
- elements.forEach((el) => this.add(el));
65
- }
66
- /**
67
- * Add elements to set if unique
68
- * @param items
69
- */
70
- add(...items) {
71
- items.filter((el) => !this.has(el)).forEach((el) => this.push(el));
72
- return this;
73
- }
74
- /**
75
- * Delete elements from set
76
- * @param items Elements that will be deleted
77
- */
78
- delete(...items) {
79
- items.forEach((el) => {
80
- const index = this.indexOf(el);
81
- if (index != -1) this.splice(index, 1);
82
- });
83
- return this;
84
- }
85
- /**
86
- * Create list of elements this set has which the comparison set does not
87
- * @param {ASet<T>} set Set to compare against
88
- * @return {ASet<T>} Different elements
89
- */
90
- difference(set) {
91
- return new ASet(this.filter((el) => !set.has(el)));
92
- }
93
- /**
94
- * Check if set includes element
95
- * @param {T} el Element to look for
96
- * @return {boolean} True if element was found, false otherwise
97
- */
98
- has(el) {
99
- return this.indexOf(el) != -1;
100
- }
101
- /**
102
- * Find index number of element, or -1 if it doesn't exist. Matches by equality not reference
103
- *
104
- * @param {T} search Element to find
105
- * @param {number} fromIndex Starting index position
106
- * @return {number} Element index number or -1 if missing
107
- */
108
- indexOf(search2, fromIndex) {
109
- return super.findIndex((el) => isEqual(el, search2), fromIndex);
110
- }
111
- /**
112
- * Create list of elements this set has in common with the comparison set
113
- * @param {ASet<T>} set Set to compare against
114
- * @return {boolean} Set of common elements
115
- */
116
- intersection(set) {
117
- return new ASet(this.filter((el) => set.has(el)));
118
- }
119
- /**
120
- * Check if this set has no elements in common with the comparison set
121
- * @param {ASet<T>} set Set to compare against
122
- * @return {boolean} True if nothing in common, false otherwise
123
- */
124
- isDisjointFrom(set) {
125
- return this.intersection(set).size == 0;
126
- }
127
- /**
128
- * Check if all elements in this set are included in the comparison set
129
- * @param {ASet<T>} set Set to compare against
130
- * @return {boolean} True if all elements are included, false otherwise
131
- */
132
- isSubsetOf(set) {
133
- return this.findIndex((el) => !set.has(el)) == -1;
134
- }
135
- /**
136
- * Check if all elements from comparison set are included in this set
137
- * @param {ASet<T>} set Set to compare against
138
- * @return {boolean} True if all elements are included, false otherwise
139
- */
140
- isSuperset(set) {
141
- return set.findIndex((el) => !this.has(el)) == -1;
142
- }
143
- /**
144
- * Create list of elements that are only in one set but not both (XOR)
145
- * @param {ASet<T>} set Set to compare against
146
- * @return {ASet<T>} New set of unique elements
147
- */
148
- symmetricDifference(set) {
149
- return new ASet([...this.difference(set), ...set.difference(this)]);
150
- }
151
- /**
152
- * Create joined list of elements included in this & the comparison set
153
- * @param {ASet<T>} set Set join
154
- * @return {ASet<T>} New set of both previous sets combined
155
- */
156
- union(set) {
157
- return new ASet([...this, ...set]);
158
- }
159
- }
160
- class Cache {
161
- /**
162
- * Create new cache
163
- *
164
- * @param {keyof T} key Default property to use as primary key
165
- * @param options
166
- */
167
- constructor(key, options = {}) {
168
- __publicField2(this, "store", {});
169
- __publicField2(this, "complete", false);
170
- __publicField2(this, "values", this.all());
171
- this.key = key;
172
- this.options = options;
173
- if (options.storageKey && !options.storage && typeof Storage !== "undefined")
174
- options.storage = localStorage;
175
- if (options.storageKey && options.storage) {
176
- const stored = options.storage.getItem(options.storageKey);
177
- if (stored) {
178
- try {
179
- Object.assign(this.store, JSON.parse(stored));
180
- } catch {
181
- }
182
- }
183
- }
184
- return new Proxy(this, {
185
- get: (target, prop2) => {
186
- if (prop2 in target) return target[prop2];
187
- return deepCopy(target.store[prop2]);
188
- },
189
- set: (target, prop2, value2) => {
190
- if (prop2 in target) target[prop2] = value2;
191
- else this.set(prop2, value2);
192
- return true;
193
- }
194
- });
195
- }
196
- getKey(value2) {
197
- if (!this.key) throw new Error("No key defined");
198
- return value2[this.key];
199
- }
200
- /**
201
- * Get all cached items
202
- *
203
- * @return {T[]} Array of items
204
- */
205
- all() {
206
- return deepCopy(Object.values(this.store));
207
- }
208
- /**
209
- * Add a new item to the cache. Like set, but finds key automatically
210
- *
211
- * @param {T} value Item to add to cache
212
- * @param {number | undefined} ttl Override default expiry
213
- * @return {this}
214
- */
215
- add(value2, ttl = this.ttl) {
216
- const key = this.getKey(value2);
217
- this.set(key, value2, ttl);
218
- return this;
219
- }
220
- /**
221
- * Add several rows to the cache
222
- *
223
- * @param {T[]} rows Several items that will be cached using the default key
224
- * @param complete Mark cache as complete & reliable, defaults to true
225
- * @return {this}
226
- */
227
- addAll(rows2, complete = true) {
228
- rows2.forEach((r2) => this.add(r2));
229
- this.complete = complete;
230
- return this;
231
- }
232
- /**
233
- * Remove all keys from cache
234
- */
235
- clear() {
236
- this.store = {};
237
- }
238
- /**
239
- * Delete an item from the cache
240
- *
241
- * @param {K} key Item's primary key
242
- */
243
- delete(key) {
244
- delete this.store[key];
245
- if (this.options.storageKey && this.options.storage)
246
- this.options.storage.setItem(this.options.storageKey, JSON.stringify(this.store));
247
- }
248
- /**
249
- * Return cache as an array of key-value pairs
250
- * @return {[K, T][]} Key-value pairs array
251
- */
252
- entries() {
253
- return Object.entries(this.store);
254
- }
255
- /**
256
- * Get item from the cache
257
- * @param {K} key Key to lookup
258
- * @return {T} Cached item
259
- */
260
- get(key) {
261
- return deepCopy(this.store[key]);
262
- }
263
- /**
264
- * Get a list of cached keys
265
- *
266
- * @return {K[]} Array of keys
267
- */
268
- keys() {
269
- return Object.keys(this.store);
270
- }
271
- /**
272
- * Get map of cached items
273
- *
274
- * @return {Record<K, T>}
275
- */
276
- map() {
277
- return deepCopy(this.store);
278
- }
279
- /**
280
- * Add an item to the cache manually specifying the key
281
- *
282
- * @param {K} key Key item will be cached under
283
- * @param {T} value Item to cache
284
- * @param {number | undefined} ttl Override default expiry in seconds
285
- * @return {this}
286
- */
287
- set(key, value2, ttl = this.options.ttl) {
288
- this.store[key] = value2;
289
- if (this.options.storageKey && this.options.storage)
290
- this.options.storage.setItem(this.options.storageKey, JSON.stringify(this.store));
291
- if (ttl) setTimeout(() => {
292
- this.complete = false;
293
- this.delete(key);
294
- }, ttl * 1e3);
295
- return this;
296
- }
297
- }
298
- function blackOrWhite(background) {
299
- const exploded = background == null ? void 0 : background.match(background.length >= 6 ? /\w\w/g : /\w/g);
300
- if (!exploded) return "black";
301
- const [r2, g, b2] = exploded.map((hex) => parseInt(hex, 16));
302
- const luminance = (0.299 * r2 + 0.587 * g + 0.114 * b2) / 255;
303
- return luminance > 0.5 ? "black" : "white";
304
- }
305
- class PromiseProgress extends Promise {
306
- constructor(executor) {
307
- super((resolve, reject) => executor(
308
- (value2) => resolve(value2),
309
- (reason) => reject(reason),
310
- (progress) => this.progress = progress
311
- ));
312
- __publicField2(this, "listeners", []);
313
- __publicField2(this, "_progress", 0);
314
- }
315
- get progress() {
316
- return this._progress;
317
- }
318
- set progress(p2) {
319
- if (p2 == this._progress) return;
320
- this._progress = p2;
321
- this.listeners.forEach((l) => l(p2));
322
- }
323
- static from(promise) {
324
- if (promise instanceof PromiseProgress) return promise;
325
- return new PromiseProgress((res, rej) => promise.then((...args) => res(...args)).catch((...args) => rej(...args)));
326
- }
327
- from(promise) {
328
- const newPromise = PromiseProgress.from(promise);
329
- this.onProgress((p2) => newPromise.progress = p2);
330
- return newPromise;
331
- }
332
- onProgress(callback) {
333
- this.listeners.push(callback);
334
- return this;
335
- }
336
- then(res, rej) {
337
- const resp = super.then(res, rej);
338
- return this.from(resp);
339
- }
340
- catch(rej) {
341
- return this.from(super.catch(rej));
342
- }
343
- finally(res) {
344
- return this.from(super.finally(res));
345
- }
346
- }
347
- function formatDate(format = "YYYY-MM-DD H:mm", date = /* @__PURE__ */ new Date(), tz) {
348
- const timezones = [
349
- ["IDLW", -12],
350
- ["SST", -11],
351
- ["HST", -10],
352
- ["AKST", -9],
353
- ["PST", -8],
354
- ["MST", -7],
355
- ["CST", -6],
356
- ["EST", -5],
357
- ["AST", -4],
358
- ["BRT", -3],
359
- ["MAT", -2],
360
- ["AZOT", -1],
361
- ["UTC", 0],
362
- ["CET", 1],
363
- ["EET", 2],
364
- ["MSK", 3],
365
- ["AST", 4],
366
- ["PKT", 5],
367
- ["IST", 5.5],
368
- ["BST", 6],
369
- ["ICT", 7],
370
- ["CST", 8],
371
- ["JST", 9],
372
- ["AEST", 10],
373
- ["SBT", 11],
374
- ["FJT", 12],
375
- ["TOT", 13],
376
- ["LINT", 14]
377
- ];
378
- function adjustTz(date2, gmt) {
379
- const currentOffset = date2.getTimezoneOffset();
380
- const adjustedOffset = gmt * 60;
381
- return new Date(date2.getTime() + (adjustedOffset + currentOffset) * 6e4);
382
- }
383
- function day(num) {
384
- return ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][num] || "Unknown";
385
- }
386
- function doy(date2) {
387
- const start = /* @__PURE__ */ new Date(`${date2.getFullYear()}-01-01 0:00:00`);
388
- return Math.ceil((date2.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24));
389
- }
390
- function month(num) {
391
- return ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"][num] || "Unknown";
392
- }
393
- function suffix(num) {
394
- if (num % 100 >= 11 && num % 100 <= 13) return `${num}th`;
395
- switch (num % 10) {
396
- case 1:
397
- return `${num}st`;
398
- case 2:
399
- return `${num}nd`;
400
- case 3:
401
- return `${num}rd`;
402
- default:
403
- return `${num}th`;
404
- }
405
- }
406
- function tzOffset(offset) {
407
- const hours = ~~(offset / 60);
408
- const minutes = offset % 60;
409
- return (offset > 0 ? "-" : "") + `${hours}:${minutes.toString().padStart(2, "0")}`;
410
- }
411
- if (typeof date == "number" || typeof date == "string") date = new Date(date);
412
- let t;
413
- if (tz == null) tz = -(date.getTimezoneOffset() / 60);
414
- t = timezones.find((t2) => isNaN(tz) ? t2[0] == tz : t2[1] == tz);
415
- if (!t) throw new Error(`Unknown timezone: ${tz}`);
416
- date = adjustTz(date, t[1]);
417
- const tokens = {
418
- "YYYY": date.getFullYear().toString(),
419
- "YY": date.getFullYear().toString().slice(2),
420
- "MMMM": month(date.getMonth()),
421
- "MMM": month(date.getMonth()).slice(0, 3),
422
- "MM": (date.getMonth() + 1).toString().padStart(2, "0"),
423
- "M": (date.getMonth() + 1).toString(),
424
- "DDD": doy(date).toString(),
425
- "DD": date.getDate().toString().padStart(2, "0"),
426
- "Do": suffix(date.getDate()),
427
- "D": date.getDate().toString(),
428
- "dddd": day(date.getDay()),
429
- "ddd": day(date.getDay()).slice(0, 3),
430
- "HH": date.getHours().toString().padStart(2, "0"),
431
- "H": date.getHours().toString(),
432
- "hh": (date.getHours() % 12 || 12).toString().padStart(2, "0"),
433
- "h": (date.getHours() % 12 || 12).toString(),
434
- "mm": date.getMinutes().toString().padStart(2, "0"),
435
- "m": date.getMinutes().toString(),
436
- "ss": date.getSeconds().toString().padStart(2, "0"),
437
- "s": date.getSeconds().toString(),
438
- "SSS": date.getMilliseconds().toString().padStart(3, "0"),
439
- "A": date.getHours() >= 12 ? "PM" : "AM",
440
- "a": date.getHours() >= 12 ? "pm" : "am",
441
- "ZZ": tzOffset(t[1] * 60).replace(":", ""),
442
- "Z": tzOffset(t[1] * 60),
443
- "z": typeof tz == "string" ? tz : t[0]
444
- };
445
- return format.replace(/YYYY|YY|MMMM|MMM|MM|M|DDD|DD|Do|D|dddd|ddd|HH|H|hh|h|mm|m|ss|s|SSS|A|a|ZZ|Z|z/g, (token) => tokens[token]);
446
- }
447
- function downloadFile(blob, name) {
448
- if (!(blob instanceof Blob)) blob = new Blob(makeArray(blob));
449
- const url = URL.createObjectURL(blob);
450
- downloadUrl(url, name);
451
- URL.revokeObjectURL(url);
452
- }
453
- function downloadUrl(href, name) {
454
- const a2 = document.createElement("a");
455
- a2.href = href;
456
- a2.download = name || href.split("/").pop();
457
- document.body.appendChild(a2);
458
- a2.click();
459
- document.body.removeChild(a2);
460
- }
461
- function fileBrowser(options = {}) {
462
- return new Promise((res) => {
463
- const input = document.createElement("input");
464
- input.type = "file";
465
- input.accept = options.accept || "*";
466
- input.style.display = "none";
467
- input.multiple = !!options.multiple;
468
- input.onblur = input.onchange = async () => {
469
- res(Array.from(input.files));
470
- input.remove();
471
- };
472
- document.body.appendChild(input);
473
- input.click();
474
- });
475
- }
476
- function timestampFilename(name, date = /* @__PURE__ */ new Date()) {
477
- if (typeof date == "number" || typeof date == "string") date = new Date(date);
478
- const timestamp = formatDate("YYYY-MM-DD_HH:mm:ss", date);
479
- return timestamp;
480
- }
481
- function uploadWithProgress(options) {
482
- return new PromiseProgress((res, rej, prog) => {
483
- const xhr = new XMLHttpRequest();
484
- const formData2 = new FormData();
485
- options.files.forEach((f) => formData2.append("file", f));
486
- xhr.withCredentials = !!options.withCredentials;
487
- xhr.upload.addEventListener("progress", (event) => event.lengthComputable ? prog(event.loaded / event.total) : null);
488
- xhr.addEventListener("loadend", () => res(JSONAttemptParse(xhr.responseText)));
489
- xhr.addEventListener("error", () => rej(JSONAttemptParse(xhr.responseText)));
490
- xhr.addEventListener("timeout", () => rej({ error: "Request timed out" }));
491
- xhr.open("POST", options.url);
492
- Object.entries(options.headers || {}).forEach(([key, value2]) => xhr.setRequestHeader(key, value2));
493
- xhr.send(formData2);
494
- });
495
- }
496
- class TypedEmitter {
497
- constructor() {
498
- __publicField2(this, "listeners", {});
499
- }
500
- static emit(event, ...args) {
501
- (this.listeners["*"] || []).forEach((l) => l(event, ...args));
502
- (this.listeners[event.toString()] || []).forEach((l) => l(...args));
503
- }
504
- static off(event, listener) {
505
- const e = event.toString();
506
- this.listeners[e] = (this.listeners[e] || []).filter((l) => l === listener);
507
- }
508
- static on(event, listener) {
509
- var _a;
510
- const e = event.toString();
511
- if (!this.listeners[e]) this.listeners[e] = [];
512
- (_a = this.listeners[e]) == null ? void 0 : _a.push(listener);
513
- return () => this.off(event, listener);
514
- }
515
- static once(event, listener) {
516
- return new Promise((res) => {
517
- const unsubscribe = this.on(event, (...args) => {
518
- res(args.length == 1 ? args[0] : args);
519
- if (listener) listener(...args);
520
- unsubscribe();
521
- });
522
- });
523
- }
524
- emit(event, ...args) {
525
- (this.listeners["*"] || []).forEach((l) => l(event, ...args));
526
- (this.listeners[event] || []).forEach((l) => l(...args));
527
- }
528
- off(event, listener) {
529
- this.listeners[event] = (this.listeners[event] || []).filter((l) => l === listener);
530
- }
531
- on(event, listener) {
532
- var _a;
533
- if (!this.listeners[event]) this.listeners[event] = [];
534
- (_a = this.listeners[event]) == null ? void 0 : _a.push(listener);
535
- return () => this.off(event, listener);
536
- }
537
- once(event, listener) {
538
- return new Promise((res) => {
539
- const unsubscribe = this.on(event, (...args) => {
540
- res(args.length == 1 ? args[0] : args);
541
- if (listener) listener(...args);
542
- unsubscribe();
543
- });
544
- });
545
- }
546
- }
547
- __publicField2(TypedEmitter, "listeners", {});
548
- class CustomError extends Error {
549
- constructor(message, code) {
550
- super(message);
551
- __publicField2(this, "_code");
552
- if (code != null) this._code = code;
553
- }
554
- get code() {
555
- return this._code || this.constructor.code;
556
- }
557
- set code(c) {
558
- this._code = c;
559
- }
560
- static from(err) {
561
- const code = Number(err.statusCode) ?? Number(err.code);
562
- const newErr = new this(err.message || err.toString());
563
- return Object.assign(newErr, {
564
- stack: err.stack,
565
- ...err,
566
- code: code ?? void 0
567
- });
568
- }
569
- static instanceof(err) {
570
- return err.constructor.code != void 0;
571
- }
572
- toString() {
573
- return this.message || super.toString();
574
- }
575
- }
576
- __publicField2(CustomError, "code", 500);
577
- class BadRequestError extends CustomError {
578
- constructor(message = "Bad Request") {
579
- super(message);
580
- }
581
- static instanceof(err) {
582
- return err.constructor.code == this.code;
583
- }
584
- }
585
- __publicField2(BadRequestError, "code", 400);
586
- class UnauthorizedError extends CustomError {
587
- constructor(message = "Unauthorized") {
588
- super(message);
589
- }
590
- static instanceof(err) {
591
- return err.constructor.code == this.code;
592
- }
593
- }
594
- __publicField2(UnauthorizedError, "code", 401);
595
- class PaymentRequiredError extends CustomError {
596
- constructor(message = "Payment Required") {
597
- super(message);
598
- }
599
- static instanceof(err) {
600
- return err.constructor.code == this.code;
601
- }
602
- }
603
- __publicField2(PaymentRequiredError, "code", 402);
604
- class ForbiddenError extends CustomError {
605
- constructor(message = "Forbidden") {
606
- super(message);
607
- }
608
- static instanceof(err) {
609
- return err.constructor.code == this.code;
610
- }
611
- }
612
- __publicField2(ForbiddenError, "code", 403);
613
- class NotFoundError extends CustomError {
614
- constructor(message = "Not Found") {
615
- super(message);
616
- }
617
- static instanceof(err) {
618
- return err.constructor.code == this.code;
619
- }
620
- }
621
- __publicField2(NotFoundError, "code", 404);
622
- class MethodNotAllowedError extends CustomError {
623
- constructor(message = "Method Not Allowed") {
624
- super(message);
625
- }
626
- static instanceof(err) {
627
- return err.constructor.code == this.code;
628
- }
629
- }
630
- __publicField2(MethodNotAllowedError, "code", 405);
631
- class NotAcceptableError extends CustomError {
632
- constructor(message = "Not Acceptable") {
633
- super(message);
634
- }
635
- static instanceof(err) {
636
- return err.constructor.code == this.code;
637
- }
638
- }
639
- __publicField2(NotAcceptableError, "code", 406);
640
- class InternalServerError extends CustomError {
641
- constructor(message = "Internal Server Error") {
642
- super(message);
643
- }
644
- static instanceof(err) {
645
- return err.constructor.code == this.code;
646
- }
647
- }
648
- __publicField2(InternalServerError, "code", 500);
649
- class NotImplementedError extends CustomError {
650
- constructor(message = "Not Implemented") {
651
- super(message);
652
- }
653
- static instanceof(err) {
654
- return err.constructor.code == this.code;
655
- }
656
- }
657
- __publicField2(NotImplementedError, "code", 501);
658
- class BadGatewayError extends CustomError {
659
- constructor(message = "Bad Gateway") {
660
- super(message);
661
- }
662
- static instanceof(err) {
663
- return err.constructor.code == this.code;
664
- }
665
- }
666
- __publicField2(BadGatewayError, "code", 502);
667
- class ServiceUnavailableError extends CustomError {
668
- constructor(message = "Service Unavailable") {
669
- super(message);
670
- }
671
- static instanceof(err) {
672
- return err.constructor.code == this.code;
673
- }
674
- }
675
- __publicField2(ServiceUnavailableError, "code", 503);
676
- class GatewayTimeoutError extends CustomError {
677
- constructor(message = "Gateway Timeout") {
678
- super(message);
679
- }
680
- static instanceof(err) {
681
- return err.constructor.code == this.code;
682
- }
683
- }
684
- __publicField2(GatewayTimeoutError, "code", 504);
685
- class HttpResponse extends Response {
686
- constructor(resp, stream) {
687
- super(stream, { headers: resp.headers, status: resp.status, statusText: resp.statusText });
688
- __publicField2(this, "data");
689
- __publicField2(this, "ok");
690
- __publicField2(this, "redirected");
691
- __publicField2(this, "type");
692
- __publicField2(this, "url");
693
- this.ok = resp.ok;
694
- this.redirected = resp.redirected;
695
- this.type = resp.type;
696
- this.url = resp.url;
697
- }
698
- }
699
- const _Http = class _Http2 {
700
- constructor(defaults = {}) {
701
- __publicField2(this, "interceptors", {});
702
- __publicField2(this, "headers", {});
703
- __publicField2(this, "url");
704
- this.url = defaults.url ?? null;
705
- this.headers = defaults.headers || {};
706
- if (defaults.interceptors) {
707
- defaults.interceptors.forEach((i) => _Http2.addInterceptor(i));
708
- }
709
- }
710
- static addInterceptor(fn) {
711
- const key = Object.keys(_Http2.interceptors).length.toString();
712
- _Http2.interceptors[key] = fn;
713
- return () => {
714
- _Http2.interceptors[key] = null;
715
- };
716
- }
717
- addInterceptor(fn) {
718
- const key = Object.keys(this.interceptors).length.toString();
719
- this.interceptors[key] = fn;
720
- return () => {
721
- this.interceptors[key] = null;
722
- };
723
- }
724
- request(opts = {}) {
725
- var _a;
726
- if (!this.url && !opts.url) throw new Error("URL needs to be set");
727
- let url = (((_a = opts.url) == null ? void 0 : _a.startsWith("http")) ? opts.url : (this.url || "") + (opts.url || "")).replace(/([^:]\/)\/+/g, "$1");
728
- if (opts.fragment) url.includes("#") ? url.replace(/#.*(\?|\n)/g, (match, arg1) => `#${opts.fragment}${arg1}`) : url += "#" + opts.fragment;
729
- if (opts.query) {
730
- const q = Array.isArray(opts.query) ? opts.query : Object.keys(opts.query).map((k) => ({ key: k, value: opts.query[k] }));
731
- url += (url.includes("?") ? "&" : "?") + q.map((q2) => `${q2.key}=${q2.value}`).join("&");
732
- }
733
- const headers = clean({
734
- "Content-Type": !opts.body ? void 0 : opts.body instanceof FormData ? "multipart/form-data" : "application/json",
735
- ..._Http2.headers,
736
- ...this.headers,
737
- ...opts.headers
738
- });
739
- if (typeof opts.body == "object" && opts.body != null && headers["Content-Type"] == "application/json")
740
- opts.body = JSON.stringify(opts.body);
741
- return new PromiseProgress((res, rej, prog) => {
742
- try {
743
- fetch(url, {
744
- headers,
745
- method: opts.method || (opts.body ? "POST" : "GET"),
746
- body: opts.body
747
- }).then(async (resp) => {
748
- var _a2, _b;
749
- for (let fn of [...Object.values(_Http2.interceptors), ...Object.values(this.interceptors)]) {
750
- await new Promise((res2) => fn(resp, () => res2()));
751
- }
752
- const contentLength = resp.headers.get("Content-Length");
753
- const total = contentLength ? parseInt(contentLength, 10) : 0;
754
- let loaded = 0;
755
- const reader = (_a2 = resp.body) == null ? void 0 : _a2.getReader();
756
- const stream = new ReadableStream({
757
- start(controller) {
758
- function push() {
759
- reader == null ? void 0 : reader.read().then((event) => {
760
- if (event.done) return controller.close();
761
- loaded += event.value.byteLength;
762
- prog(loaded / total);
763
- controller.enqueue(event.value);
764
- push();
765
- }).catch((error) => controller.error(error));
766
- }
767
- push();
768
- }
769
- });
770
- resp = new HttpResponse(resp, stream);
771
- if (opts.decode !== false) {
772
- const content = (_b = resp.headers.get("Content-Type")) == null ? void 0 : _b.toLowerCase();
773
- if (content == null ? void 0 : content.includes("form")) resp.data = await resp.formData();
774
- else if (content == null ? void 0 : content.includes("json")) resp.data = await resp.json();
775
- else if (content == null ? void 0 : content.includes("text")) resp.data = await resp.text();
776
- else if (content == null ? void 0 : content.includes("application")) resp.data = await resp.blob();
777
- }
778
- if (resp.ok) res(resp);
779
- else rej(resp);
780
- }).catch((err) => rej(err));
781
- } catch (err) {
782
- rej(err);
783
- }
784
- });
785
- }
786
- };
787
- __publicField2(_Http, "interceptors", {});
788
- __publicField2(_Http, "headers", {});
789
- let Http = _Http;
790
- const CliEffects = {
791
- CLEAR: "\x1B[0m"
792
- };
793
- const CliForeground = {
794
- RED: "\x1B[31m",
795
- YELLOW: "\x1B[33m",
796
- BLUE: "\x1B[34m",
797
- LIGHT_GREY: "\x1B[37m"
798
- };
799
- var LOG_LEVEL = /* @__PURE__ */ ((LOG_LEVEL2) => {
800
- LOG_LEVEL2[LOG_LEVEL2["ERROR"] = 0] = "ERROR";
801
- LOG_LEVEL2[LOG_LEVEL2["WARN"] = 1] = "WARN";
802
- LOG_LEVEL2[LOG_LEVEL2["INFO"] = 2] = "INFO";
803
- LOG_LEVEL2[LOG_LEVEL2["LOG"] = 3] = "LOG";
804
- LOG_LEVEL2[LOG_LEVEL2["DEBUG"] = 4] = "DEBUG";
805
- return LOG_LEVEL2;
806
- })(LOG_LEVEL || {});
807
- const _Logger = class _Logger2 extends TypedEmitter {
808
- constructor(namespace) {
809
- super();
810
- this.namespace = namespace;
811
- }
812
- format(...text) {
813
- const now = /* @__PURE__ */ new Date();
814
- const timestamp = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()} ${now.getHours().toString().padStart(2, "0")}:${now.getMinutes().toString().padStart(2, "0")}:${now.getSeconds().toString().padStart(2, "0")}.${now.getMilliseconds().toString().padEnd(3, "0")}`;
815
- return `${timestamp}${this.namespace ? ` [${this.namespace}]` : ""} ${text.map((t) => typeof t == "string" ? t : JSONSanitize(t, 2)).join(" ")}`;
816
- }
817
- debug(...args) {
818
- if (_Logger2.LOG_LEVEL < 4) return;
819
- const str = this.format(...args);
820
- _Logger2.emit(4, str);
821
- console.debug(CliForeground.LIGHT_GREY + str + CliEffects.CLEAR);
822
- }
823
- log(...args) {
824
- if (_Logger2.LOG_LEVEL < 3) return;
825
- const str = this.format(...args);
826
- _Logger2.emit(3, str);
827
- console.log(CliEffects.CLEAR + str);
828
- }
829
- info(...args) {
830
- if (_Logger2.LOG_LEVEL < 2) return;
831
- const str = this.format(...args);
832
- _Logger2.emit(2, str);
833
- console.info(CliForeground.BLUE + str + CliEffects.CLEAR);
834
- }
835
- warn(...args) {
836
- if (_Logger2.LOG_LEVEL < 1) return;
837
- const str = this.format(...args);
838
- _Logger2.emit(1, str);
839
- console.warn(CliForeground.YELLOW + str + CliEffects.CLEAR);
840
- }
841
- error(...args) {
842
- if (_Logger2.LOG_LEVEL < 0) return;
843
- const str = this.format(...args);
844
- _Logger2.emit(0, str);
845
- console.error(CliForeground.RED + str + CliEffects.CLEAR);
846
- }
847
- };
848
- __publicField2(_Logger, "LOG_LEVEL", 4);
849
- function PE(str, ...args) {
850
- const combined = [];
851
- for (let i = 0; i < str.length || i < args.length; i++) {
852
- if (str[i]) combined.push(str[i]);
853
- if (args[i]) combined.push(args[i]);
854
- }
855
- return new PathEvent(combined.join(""));
856
- }
857
- function PES(str, ...args) {
858
- let combined = [];
859
- for (let i = 0; i < str.length || i < args.length; i++) {
860
- if (str[i]) combined.push(str[i]);
861
- if (args[i]) combined.push(args[i]);
862
- }
863
- const [paths, methods] = combined.join("").split(":");
864
- return PathEvent.toString(paths, methods == null ? void 0 : methods.split(""));
865
- }
866
- class PathError extends Error {
867
- }
868
- class PathEvent {
869
- constructor(Event) {
870
- __publicField2(this, "module");
871
- __publicField2(this, "fullPath");
872
- __publicField2(this, "path");
873
- __publicField2(this, "name");
874
- __publicField2(this, "methods");
875
- var _a;
876
- if (typeof Event == "object") return Object.assign(this, Event);
877
- let [p2, scope, method] = Event.replaceAll(/\/{2,}/g, "/").split(":");
878
- if (!method) method = scope || "*";
879
- if (p2 == "*" || !p2 && method == "*") {
880
- p2 = "";
881
- method = "*";
882
- }
883
- let temp = p2.split("/").filter((p22) => !!p22);
884
- this.module = ((_a = temp.splice(0, 1)[0]) == null ? void 0 : _a.toLowerCase()) || "";
885
- this.fullPath = p2;
886
- this.path = temp.join("/");
887
- this.name = temp.pop() || "";
888
- this.methods = new ASet(method.split(""));
889
- }
890
- /** All/Wildcard specified */
891
- get all() {
892
- return this.methods.has("*");
893
- }
894
- set all(v2) {
895
- v2 ? new ASet(["*"]) : this.methods.delete("*");
896
- }
897
- /** None specified */
898
- get none() {
899
- return this.methods.has("n");
900
- }
901
- set none(v2) {
902
- v2 ? this.methods = new ASet(["n"]) : this.methods.delete("n");
903
- }
904
- /** Create method specified */
905
- get create() {
906
- return !this.methods.has("n") && (this.methods.has("*") || this.methods.has("c"));
907
- }
908
- set create(v2) {
909
- v2 ? this.methods.delete("n").add("c") : this.methods.delete("c");
910
- }
911
- /** Read method specified */
912
- get read() {
913
- return !this.methods.has("n") && (this.methods.has("*") || this.methods.has("r"));
914
- }
915
- set read(v2) {
916
- v2 ? this.methods.delete("n").add("r") : this.methods.delete("r");
917
- }
918
- /** Update method specified */
919
- get update() {
920
- return !this.methods.has("n") && (this.methods.has("*") || this.methods.has("u"));
921
- }
922
- set update(v2) {
923
- v2 ? this.methods.delete("n").add("u") : this.methods.delete("u");
924
- }
925
- /** Delete method specified */
926
- get delete() {
927
- return !this.methods.has("n") && (this.methods.has("*") || this.methods.has("d"));
928
- }
929
- set delete(v2) {
930
- v2 ? this.methods.delete("n").add("d") : this.methods.delete("d");
931
- }
932
- /**
933
- * Combine multiple events into one parsed object. Longest path takes precedent, but all subsequent methods are
934
- * combined until a "none" is reached
935
- *
936
- * @param {string | PathEvent} paths Events as strings or pre-parsed
937
- * @return {PathEvent} Final combined permission
938
- */
939
- static combine(...paths) {
940
- let hitNone = false;
941
- const combined = paths.map((p2) => new PathEvent(p2)).toSorted((p1, p2) => {
942
- const l1 = p1.fullPath.length, l2 = p2.fullPath.length;
943
- return l1 < l2 ? 1 : l1 > l2 ? -1 : 0;
944
- }).reduce((acc, p2) => {
945
- if (p2.none) hitNone = true;
946
- if (!acc) return p2;
947
- if (hitNone) return acc;
948
- acc.methods = [...acc.methods, ...p2.methods];
949
- return acc;
950
- }, null);
951
- combined.methods = new ASet(combined.methods);
952
- return combined;
953
- }
954
- /**
955
- * Filter a set of paths based on the target
956
- *
957
- * @param {string | PathEvent | (string | PathEvent)[]} target Array of events that will filtered
958
- * @param filter {...PathEvent} Must container one of
959
- * @return {boolean} Whether there is any overlap
960
- */
961
- static filter(target, ...filter) {
962
- const parsedTarget = makeArray(target).map((pe) => new PathEvent(pe));
963
- const parsedFind = makeArray(filter).map((pe) => new PathEvent(pe));
964
- return parsedTarget.filter((t) => {
965
- if (!t.fullPath && t.all) return true;
966
- return !!parsedFind.find((f) => (t.fullPath.startsWith(f.fullPath) || f.fullPath.startsWith(t.fullPath)) && (f.all || t.all || t.methods.intersection(f.methods).length));
967
- });
968
- }
969
- /**
970
- * Squash 2 sets of paths & return true if any overlap is found
971
- *
972
- * @param {string | PathEvent | (string | PathEvent)[]} target Array of Events as strings or pre-parsed
973
- * @param has Target must have at least one of these path
974
- * @return {boolean} Whether there is any overlap
975
- */
976
- static has(target, ...has) {
977
- const parsedRequired = makeArray(has).map((pe) => new PathEvent(pe));
978
- const parsedTarget = makeArray(target).map((pe) => new PathEvent(pe));
979
- return !!parsedRequired.find((r2) => {
980
- if (!r2.fullPath && r2.all) return true;
981
- const filtered = parsedTarget.filter((p2) => r2.fullPath.startsWith(p2.fullPath));
982
- if (!filtered.length) return false;
983
- const combined = PathEvent.combine(...filtered);
984
- return !combined.none && (combined.all || r2.all) || combined.methods.intersection(r2.methods).length;
985
- });
986
- }
987
- /**
988
- * Squash 2 sets of paths & return true if the target has all paths
989
- *
990
- * @param {string | PathEvent | (string | PathEvent)[]} target Array of Events as strings or pre-parsed
991
- * @param has Target must have all these paths
992
- * @return {boolean} Whether there is any overlap
993
- */
994
- static hasAll(target, ...has) {
995
- return has.filter((h) => PathEvent.has(target, h)).length == has.length;
996
- }
997
- /**
998
- * Same as `has` but raises an error if there is no overlap
999
- *
1000
- * @param {string | string[]} target Array of Events as strings or pre-parsed
1001
- * @param has Target must have at least one of these path
1002
- */
1003
- static hasFatal(target, ...has) {
1004
- if (!PathEvent.has(target, ...has)) throw new PathError(`Requires one of: ${makeArray(has).join(", ")}`);
1005
- }
1006
- /**
1007
- * Same as `hasAll` but raises an error if the target is missing any paths
1008
- *
1009
- * @param {string | string[]} target Array of Events as strings or pre-parsed
1010
- * @param has Target must have all these paths
1011
- */
1012
- static hasAllFatal(target, ...has) {
1013
- if (!PathEvent.hasAll(target, ...has)) throw new PathError(`Requires all: ${makeArray(has).join(", ")}`);
1014
- }
1015
- /**
1016
- * Create event string from its components
1017
- *
1018
- * @param {string | string[]} path Event path
1019
- * @param {Method} methods Event method
1020
- * @return {string} String representation of Event
1021
- */
1022
- static toString(path, methods) {
1023
- let p2 = makeArray(path).filter((p22) => p22 != null).join("/");
1024
- p2 = p2 == null ? void 0 : p2.trim().replaceAll(/\/{2,}/g, "/").replaceAll(/(^\/|\/$)/g, "");
1025
- if (methods == null ? void 0 : methods.length) p2 += `:${makeArray(methods).map((m) => m.toLowerCase()).join("")}`;
1026
- return p2;
1027
- }
1028
- /**
1029
- * Filter a set of paths based on this event
1030
- *
1031
- * @param {string | PathEvent | (string | PathEvent)[]} target Array of events that will filtered
1032
- * @return {boolean} Whether there is any overlap
1033
- */
1034
- filter(target) {
1035
- return PathEvent.filter(target, this);
1036
- }
1037
- /**
1038
- * Create event string from its components
1039
- *
1040
- * @return {string} String representation of Event
1041
- */
1042
- toString() {
1043
- return PathEvent.toString(this.fullPath, this.methods);
1044
- }
1045
- }
1046
- class PathEventEmitter {
1047
- constructor() {
1048
- __publicField2(this, "listeners", []);
1049
- }
1050
- emit(event, ...args) {
1051
- const parsed = new PathEvent(event);
1052
- this.listeners.filter((l) => PathEvent.has(l[0], event)).forEach(async (l) => l[1](parsed, ...args));
1053
- }
1054
- off(listener) {
1055
- this.listeners = this.listeners.filter((l) => l[1] != listener);
1056
- }
1057
- on(event, listener) {
1058
- makeArray(event).forEach((e) => this.listeners.push([new PathEvent(e), listener]));
1059
- return () => this.off(listener);
1060
- }
1061
- once(event, listener) {
1062
- return new Promise((res) => {
1063
- const unsubscribe = this.on(event, (event2, ...args) => {
1064
- res(args.length < 2 ? args[0] : args);
1065
- if (listener) listener(event2, ...args);
1066
- unsubscribe();
1067
- });
1068
- });
1069
- }
1070
- relayEvents(emitter) {
1071
- emitter.on("*", (event, ...args) => this.emit(event, ...args));
1072
- }
1073
- }
1074
- class Api extends Http {
1075
- constructor(url = location.origin, opts = {}) {
1076
- super({ ...(opts == null ? void 0 : opts.http) || {}, url });
1077
- __publicField(this, "emitter", new PathEventEmitter());
1078
- __publicField(this, "pending", {});
1079
- __publicField(this, "storageKey");
1080
- __publicField(this, "host");
1081
- __publicField(this, "_token", null);
1082
- __publicField(this, "emit", this.emitter.emit.bind(this.emitter));
1083
- __publicField(this, "off", this.emitter.off.bind(this.emitter));
1084
- __publicField(this, "on", this.emitter.on.bind(this.emitter));
1085
- __publicField(this, "once", this.emitter.once.bind(this.emitter));
1086
- __publicField(this, "relayEvents", this.emitter.relayEvents.bind(this.emitter));
1087
- this.url = url;
1088
- this.opts = opts;
1089
- this.host = new URL(url).host;
1090
- this.storageKey = `momentum:token:${this.host}`;
1091
- if (opts.persist && localStorage) {
1092
- const token = localStorage.getItem(this.storageKey);
1093
- if (token) this.token = token;
1094
- }
1095
- }
1096
- get sameOrigin() {
1097
- if (typeof window == "undefined" || !(window == null ? void 0 : window.location)) return false;
1098
- return window.location.host == this.host;
1099
- }
1100
- /** Current API token */
1101
- get token() {
1102
- return this._token;
1103
- }
1104
- set token(token) {
1105
- if (token == this._token) return;
1106
- this._token = token;
1107
- this.headers["Authorization"] = token ? `Bearer ${token}` : null;
1108
- if (this.opts.persist && localStorage) {
1109
- if (token) localStorage.setItem(this.storageKey, token);
1110
- else localStorage.removeItem(this.storageKey);
1111
- }
1112
- this.emit(PES`api/token:${token ? "u" : "d"}`, token);
1113
- }
1114
- /**
1115
- * Fetch current Momentum status
1116
- * @return {Promise<Health>}
1117
- */
1118
- healthcheck() {
1119
- return this.request({ url: "/api/healthcheck" }).then((resp) => {
1120
- this.emit(PES`api/healthcheck:r`, resp);
1121
- return resp;
1122
- });
1123
- }
1124
- /**
1125
- * Create API request
1126
- * @param {HttpRequestOptions} options Request options
1127
- * @return {Promise} Response
1128
- */
1129
- request(options) {
1130
- const key = JSONSanitize(options);
1131
- const method = options.method == "GET" ? "r" : options.method == "POST" ? "c" : options.method == "DELETE" ? "d" : "u";
1132
- if (this.pending[key] != null) return this.pending[key];
1133
- this.pending[key] = super.request({ ...options, credentials: "include" }).then((response) => {
1134
- this.emit(PES`api/response:${method}`, { request: options, response });
1135
- return options.decode === false ? response : response.data;
1136
- }).catch((err) => {
1137
- const e = (err == null ? void 0 : err.data) || err;
1138
- this.emit(PES`api/error:${method}`, { request: options, error: e });
1139
- throw e;
1140
- }).finally(() => delete this.pending[key]);
1141
- this.emit(PES`api/request:${method}`, { request: options, response: this.pending[key] });
1142
- return this.pending[key];
1143
- }
1144
- }
1145
- var ActionType = /* @__PURE__ */ ((ActionType2) => {
1146
- ActionType2[ActionType2["CRON"] = 0] = "CRON";
1147
- ActionType2[ActionType2["EVENT"] = 1] = "EVENT";
1148
- ActionType2[ActionType2["DELETE"] = 2] = "DELETE";
1149
- ActionType2[ActionType2["GET"] = 3] = "GET";
1150
- ActionType2[ActionType2["PATCH"] = 4] = "PATCH";
1151
- ActionType2[ActionType2["POST"] = 5] = "POST";
1152
- ActionType2[ActionType2["PUT"] = 6] = "PUT";
1153
- return ActionType2;
1154
- })(ActionType || {});
1155
- class Actions extends PathEventEmitter {
1156
- constructor(api) {
1157
- super();
1158
- __publicField(this, "api");
1159
- __publicField(this, "cache", new Cache("_id"));
1160
- this.api = typeof api == "string" ? new Api(api) : api;
1161
- }
1162
- /**
1163
- * All saved actions
1164
- * @param {boolean} reload Will use cached response if false
1165
- * @return {Promise<Action[]>} List of saved actions
1166
- */
1167
- async all(reload) {
1168
- if (!reload && this.cache.complete) return this.cache.all();
1169
- return this.api.request({ url: `/api/` + PES`actions` }).then((resp) => {
1170
- this.cache.addAll(resp);
1171
- this.emit(PES`actions:r`, resp || []);
1172
- return resp;
1173
- });
1174
- }
1175
- /**
1176
- * Manually trigger an actions execution
1177
- * @param {string} id Action ID
1178
- * @param {HttpRequestOptions} opts Additional arguments
1179
- * @return {Promise<ActionResult>} All action output including console logs & return
1180
- */
1181
- debug(id, opts = {}) {
1182
- return this.api.request({ url: "/api/" + PES`actions/debug/${id}`, method: "POST", ...opts });
1183
- }
1184
- /**
1185
- * Delete an existing action
1186
- * @param {string} id Action ID
1187
- * @return {Promise<void>} Delete complete
1188
- */
1189
- delete(id) {
1190
- if (!id) throw new Error("Cannot delete action, missing ID");
1191
- return this.api.request({ url: `/api/` + PES`actions/${id}`, method: "DELETE" }).then(() => {
1192
- this.cache.delete(id);
1193
- this.emit(PES`actions/${id}:d`, id);
1194
- });
1195
- }
1196
- /**
1197
- * Fetch action info
1198
- * @param {string} id Action ID
1199
- * @param {boolean} reload Will use cached response if false
1200
- * @return {Promise<Action | null>} Requested action
1201
- */
1202
- read(id, reload) {
1203
- if (!id) throw new Error("Cannot read action, missing ID");
1204
- const cached = this.cache.get(id);
1205
- if (!reload && cached) return Promise.resolve(cached);
1206
- return this.api.request({ url: `/api/` + PES`actions/${id}` }).then((action) => {
1207
- if (action) this.cache.add(action);
1208
- this.emit(PES`actions/${id}:r`, action);
1209
- return action;
1210
- });
1211
- }
1212
- /**
1213
- * Run an HTTP action
1214
- * @param {string} path HTTP path excluding `/api/actions/run`
1215
- * @param {HttpRequestOptions} opts HTTP options
1216
- * @return {Promise<T>} HTTP response
1217
- */
1218
- run(path, opts = {}) {
1219
- return this.api.request({ ...opts, url: "/api/" + PES`actions/run/${path}` });
1220
- }
1221
- /**
1222
- * Update an action
1223
- * @param {Action} action The new action
1224
- * @return {Promise<Action>} Saved action
1225
- */
1226
- update(action) {
1227
- return this.api.request({
1228
- url: `/api/` + PES`actions/${action._id}`,
1229
- method: "POST",
1230
- body: action
1231
- }).then((action2) => {
1232
- if (action2) this.cache.add(action2);
1233
- this.emit(PES`actions/${action2._id}:u`, action2);
1234
- return action2;
1235
- });
1236
- }
1237
- }
1238
- class Ai extends PathEventEmitter {
1239
- constructor(api) {
1240
- super();
1241
- __publicField(this, "api");
1242
- this.api = typeof api == "string" ? new Api(api) : api;
1243
- }
1244
- /**
1245
- * Ask the AI assistant a question
1246
- * @param {string} question Users question
1247
- * @param {any} context Additional data to aid response
1248
- * @return {Promise<string>} AI's response
1249
- */
1250
- ask(question, context) {
1251
- if (!question) throw new Error("Cannot ask AI, missing question");
1252
- return this.api.request({ url: `/api/` + PES`ai`, method: "POST", body: {
1253
- question,
1254
- context
1255
- } }).then((response) => {
1256
- this.emit(PES`ai:c`, { question, context, response });
1257
- return response;
1258
- });
1259
- }
1260
- /**
1261
- * Clear AI assistant memory & context
1262
- * @return {Promise<void>} Resolves once complete
1263
- */
1264
- clear() {
1265
- return this.api.request({ url: "/api/" + PES`ai`, method: "DELETE" }).then(() => this.emit(PES`ai:d`, this.api.token));
1266
- }
1267
- /**
1268
- * Current chat history
1269
- * @return {Promise<{role: string, content: string}[]>}
1270
- */
1271
- history() {
1272
- return this.api.request({ url: "/api/" + PES`ai` }).then((resp) => {
1273
- this.emit(PES`ai:r`, resp);
1274
- return resp;
1275
- });
1276
- }
1277
- /**
1278
- * Get model info
1279
- * @return {Promise<{host: string, model: string}>} Model Info
1280
- */
1281
- info() {
1282
- return this.api.request({ url: "/api/ai/info" });
1283
- }
1284
- }
1285
- class Analytics extends PathEventEmitter {
1286
- constructor(api) {
1287
- super();
1288
- __publicField(this, "api");
1289
- this.api = typeof api == "string" ? new Api(api) : api;
1290
- }
1291
- /**
1292
- * Perform IP trace
1293
- * @param {string} ip IP address to trace
1294
- * @return {Promise<IpTrace>} Trace results
1295
- */
1296
- ipTrace(ip) {
1297
- if (!ip) throw new Error("Cannot trace, missing IP");
1298
- return this.api.request({ url: `/api/` + PES`analytics/trace/${ip}` }).then((resp) => {
1299
- this.emit(PES`analytics/trace/${ip}:r`, resp);
1300
- return resp;
1301
- });
1302
- }
1303
- }
1304
- class Token extends PathEventEmitter {
1305
- constructor(api) {
1306
- super();
1307
- this.api = api;
1308
- }
1309
- /**
1310
- * Fetch all tokens for user
1311
- * @param {string} username User to search
1312
- * @return {Promise<UserToken[]>} List of tokens
1313
- */
1314
- all(username) {
1315
- return this.api.request({ url: "/" + PES`api/auth/tokens/${username}` }).then((resp) => {
1316
- this.emit(PES`token/${username}:r`, resp);
1317
- return resp;
1318
- });
1319
- }
1320
- /**
1321
- * Create a new user token
1322
- * @param {{name: string, owner: string, expire: null | Date}} token Token settings
1323
- * @return {Promise<UserToken>} Crated token
1324
- */
1325
- create(token) {
1326
- return this.api.request({ url: "/" + PES`api/auth/tokens/${token.owner}`, body: token }).then((resp) => {
1327
- this.emit(PES`token/${token.owner}:c`, token);
1328
- return resp;
1329
- });
1330
- }
1331
- /**
1332
- * Delete an existing user token
1333
- * @param {string} id Token ID
1334
- * @return {Promise<void>} Resolves once complete
1335
- */
1336
- delete(id) {
1337
- return this.api.request({ url: "/" + PES`api/auth/tokens/${id}`, method: "DELETE" }).then(() => this.emit(PES`token/${id}:d`, id));
1338
- }
1339
- }
1340
- class Totp {
1341
- constructor(api) {
1342
- /**
1343
- * Enable 2FA for user
1344
- * @param {string} username User to reset
1345
- * @return {Promise<void>} Resolves once complete
1346
- */
1347
- __publicField(this, "enable", this.reset);
1348
- this.api = api;
1349
- }
1350
- /**
1351
- * Disable 2FA for user
1352
- * @param {string} username User to disable 2FA for
1353
- * @return {Promise<void>} Resolves once complete
1354
- */
1355
- disable(username) {
1356
- return this.api.request({ url: "/" + PES`api/auth/totp/${username}`, method: "DELETE" });
1357
- }
1358
- /**
1359
- * Reset users 2FA
1360
- * @param {string} username User to reset
1361
- * @return {Promise<void>} Resolves once complete
1362
- */
1363
- reset(username) {
1364
- return this.api.request({ url: "/" + PES`api/auth/totp/${username}`, method: "POST" });
1365
- }
1366
- /**
1367
- * Setup 2FA authentication method
1368
- * @param {string} username User to setup
1369
- * @param {string} method Authenticator type
1370
- * @param {string | null} totp null to being process, 2FA code to validate method
1371
- * @return {Promise<void>} Resolves once complete
1372
- */
1373
- setup(username, method = "app", totp) {
1374
- return this.api.request({ url: "/" + PES`api/auth/totp/${username}`, body: clean({
1375
- method,
1376
- totp
1377
- }) });
1378
- }
1379
- }
1380
- class Auth extends PathEventEmitter {
1381
- constructor(api, opts = {}) {
1382
- super();
1383
- __publicField(this, "api");
1384
- /** Manage user tokens */
1385
- __publicField(this, "token");
1386
- /** Manage user 2FA */
1387
- __publicField(this, "totp");
1388
- __publicField(this, "_permissions", []);
1389
- __publicField(this, "_user");
1390
- // Permission helpers
1391
- __publicField(this, "filter", (...events) => PathEvent.filter(this.permissions, ...events));
1392
- __publicField(this, "has", (...events) => PathEvent.has(this.permissions, ...events));
1393
- __publicField(this, "hasAll", (...events) => PathEvent.hasAll(this.permissions, ...events));
1394
- __publicField(this, "hasFatal", (...events) => PathEvent.hasFatal(this.permissions, ...events));
1395
- __publicField(this, "hasAllFatal", (...events) => PathEvent.hasAllFatal(this.permissions, ...events));
1396
- this.opts = opts;
1397
- this.api = typeof api == "string" ? new Api(api) : api;
1398
- this.token = new Token(this.api);
1399
- this.totp = new Totp(this.api);
1400
- this.relayEvents(this.token);
1401
- this.opts = {
1402
- loginUrl: this.api.url + "/ui/login",
1403
- ...this.opts
1404
- };
1405
- this.api.addInterceptor((resp, next) => {
1406
- const blacklist = [
1407
- "/api/auth/login",
1408
- "/api/auth/password",
1409
- "/api/auth/totp"
1410
- ];
1411
- if (resp.status == 401 && !blacklist.find((url) => resp.url.includes(url)))
1412
- this.emit(PES`auth/session-expired:d`, this.api.token);
1413
- next();
1414
- });
1415
- if (this.api.token) this.session(this.api.token, true);
1416
- else this.user = null;
1417
- this.api.on("api/token", (event, token) => {
1418
- if (token) this.session(token, true).catch(() => {
1419
- });
1420
- else this.user = null;
1421
- });
1422
- }
1423
- /** Get current user permissions */
1424
- get permissions() {
1425
- return this._permissions;
1426
- }
1427
- set permissions(perms) {
1428
- this._permissions = perms;
1429
- this.emit(PES`auth/permissions:u`, this._permissions);
1430
- }
1431
- /** Get current user, undefined if not yet initialized */
1432
- get user() {
1433
- return this._user;
1434
- }
1435
- /** Update user info without changing the session */
1436
- set user(user) {
1437
- if (!isEqual(this.user, user)) {
1438
- this._user = user ? user : null;
1439
- this.emit(PES`auth/user:u`, this._user);
1440
- }
1441
- }
1442
- /**
1443
- * Check if origin is recognized & whitelisted
1444
- * @param {string} host Origin to check
1445
- * @return {Promise<void>} Resolves in known, 401 code otherwise
1446
- */
1447
- knownHost(host = location.origin) {
1448
- if (host.startsWith("/")) return Promise.resolve();
1449
- return this.api.request({ url: `/api/auth/known-host?host=${encodeURI(new URL(host).origin)}` });
1450
- }
1451
- /**
1452
- * Login a user & return the account
1453
- * @param {string} username username
1454
- * @param {string} password user's password
1455
- * @param {{totp: string, expire: null | number | Date}} opts 2FA code and expiry options (null to never expire)
1456
- * @return {Promise<User | null>} User account on success
1457
- */
1458
- login(username, password, opts) {
1459
- if (!username || !password) throw new Error("Cannot login, missing username or password");
1460
- return this.api.request({
1461
- url: "/api/auth/login",
1462
- headers: { Authorization: void 0 },
1463
- method: "POST",
1464
- body: clean({
1465
- username: username.trim(),
1466
- password: password.trim(),
1467
- ...opts
1468
- }, true)
1469
- }).then(async (resp) => {
1470
- this.api.token = (resp == null ? void 0 : resp.token) || null;
1471
- const user = await this.once("auth/user");
1472
- this.emit(PES`auth/login/${username}:u`, user);
1473
- return user;
1474
- });
1475
- }
1476
- /**
1477
- * Login via Momentum single sign on
1478
- * @param {string} host Host origin attempting to login
1479
- * @return {Promise<string>} Token on success
1480
- */
1481
- loginRedirect(host = location.origin) {
1482
- return new Promise((res, rej) => {
1483
- var _a;
1484
- let origin = new URL(this.opts.loginUrl).origin, listener, win;
1485
- window.addEventListener("message", listener = (event) => {
1486
- const data = (event == null ? void 0 : event.data) || {};
1487
- if (event.origin != origin || data.sender != origin) return;
1488
- if (!data.token) return rej("Unknown response from login");
1489
- this.api.token = data.token;
1490
- window.removeEventListener("message", listener);
1491
- win.close();
1492
- res(data.token);
1493
- });
1494
- win = window.open(encodeURI(`${(_a = this.opts) == null ? void 0 : _a.loginUrl}?redirect=postmessage&host=${host}`), "_blank");
1495
- if (!win) {
1496
- window.removeEventListener("message", listener);
1497
- return rej("Unable to open login");
1498
- }
1499
- });
1500
- }
1501
- /**
1502
- * Logout current user
1503
- */
1504
- logout() {
1505
- this.emit(PES`auth/logout:d`, this.user);
1506
- this.api.token = null;
1507
- this.api.request({ url: "/api/auth/logout", method: "DELETE" });
1508
- this.user = null;
1509
- }
1510
- /**
1511
- * Create a new user with login
1512
- * @param {Partial<User> & {password: string}} user User data with password
1513
- * @return {Promise<User>} Registered user data
1514
- */
1515
- async register(user) {
1516
- var _a;
1517
- if (!user.username || !user.password) throw new Error("Cannot register user, missing username or password");
1518
- const u = await this.api.request({ url: "/api/auth/register", body: { ...user } });
1519
- if ((_a = u == null ? void 0 : u.image) == null ? void 0 : _a.startsWith("/")) u.image = `${this.api.url}${u.image}${!this.api.sameOrigin && this.api.token ? `?token=${this.api.token}` : ""}`;
1520
- this.user = u;
1521
- this.permissions = [];
1522
- this.emit(PES`auth/register:u`, u);
1523
- return u;
1524
- }
1525
- reset(emailOrPass, token) {
1526
- if (!emailOrPass) throw new Error("Cannot reset password, missing email or token");
1527
- return this.api.request({
1528
- url: "/api/auth/reset",
1529
- headers: { "Authorization": token ? `Bearer ${token}` : void 0 },
1530
- body: {
1531
- email: token ? void 0 : emailOrPass,
1532
- password: token ? emailOrPass : void 0
1533
- }
1534
- }).then(() => {
1535
- this.emit(PES`auth/reset:${token ? "u" : "c"}`, token || emailOrPass);
1536
- });
1537
- }
1538
- /**
1539
- * Get session information
1540
- * @param {string} token Token to fetch session info for
1541
- * @param {boolean} set Set as current active session
1542
- * @return {Promise<{token: string, user: User, permissions: string[], custom: any} | null>} Session information
1543
- */
1544
- async session(token, set = false) {
1545
- if (!token) token = this.api.token;
1546
- const session = await this.api.request({
1547
- url: "/api/auth/session",
1548
- headers: token ? { "Authorization": `Bearer ${token}` } : void 0
1549
- });
1550
- this.emit(PES`auth/session:r`, session);
1551
- if (set) {
1552
- this.api.token = token;
1553
- if (session == null ? void 0 : session.user) session.user.image = `${this.api.url}${session.user.image}${!this.api.sameOrigin && this.api.token ? `?token=${this.api.token}` : ""}`;
1554
- this.user = (session == null ? void 0 : session.user) || null;
1555
- this.permissions = (session == null ? void 0 : session.permissions) || [];
1556
- if (session) this.emit(PES`auth/login:c`, session.user);
1557
- }
1558
- return session;
1559
- }
1560
- /**
1561
- * Update password for user
1562
- * @param {string} username User to reset
1563
- * @param {string} password New user password
1564
- * @param {string} oldPassword Old password for validation
1565
- * @return {Promise<void>} Resolves once complete
1566
- */
1567
- async updatePassword(username, password, oldPassword) {
1568
- if (!username || !password) throw new Error("Cannot update password, missing username or password");
1569
- return this.api.request({
1570
- url: "/api/auth/password",
1571
- body: { username, password, oldPassword }
1572
- }).then((resp) => {
1573
- this.emit(PES`auth/reset:u`, resp == null ? void 0 : resp.token);
1574
- if (resp == null ? void 0 : resp.token) this.api.token = resp.token;
1575
- });
1576
- }
1577
- }
1578
- class Client extends PathEventEmitter {
1579
- constructor(api, settings) {
1580
- super();
1581
- __publicField(this, "_notifications", false);
1582
- __publicField(this, "_platform");
1583
- __publicField(this, "_pwa");
1584
- this.api = api;
1585
- this.settings = settings;
1586
- this.pushSubscription.then((resp) => this.notifications = !!resp);
1587
- }
1588
- /** Check if iframed */
1589
- get iframe() {
1590
- return (parent == null ? void 0 : parent.location) != location;
1591
- }
1592
- /** Check if mobile device */
1593
- get mobile() {
1594
- return ["android", "ios"].includes(this.platform);
1595
- }
1596
- /** Are notifications enabled */
1597
- get notifications() {
1598
- return this._notifications;
1599
- }
1600
- set notifications(enabled) {
1601
- this._notifications = enabled;
1602
- this.emit(PES`client/notifications:${enabled ? "c" : "d"}`, enabled);
1603
- }
1604
- /** Get the current platform type */
1605
- get platform() {
1606
- if (!this._platform) {
1607
- const userAgent = navigator.userAgent || navigator.vendor;
1608
- if (/windows/i.test(userAgent)) this._platform = "windows";
1609
- else if (/android/i.test(userAgent)) this._platform = "android";
1610
- else if (/iPad|iPhone|iPod/.test(userAgent)) this._platform = "ios";
1611
- else if (/macintosh|mac os x/i.test(userAgent)) this._platform = "mac";
1612
- else if (/linux/i.test(userAgent)) this._platform = "linux";
1613
- else this._platform = "unknown";
1614
- }
1615
- return this._platform;
1616
- }
1617
- /** Get Push Subscription info */
1618
- get pushSubscription() {
1619
- var _a;
1620
- if (!((_a = navigator.serviceWorker) == null ? void 0 : _a.controller)) return Promise.resolve(null);
1621
- return navigator.serviceWorker.ready.then((sw) => {
1622
- var _a2;
1623
- return (_a2 = sw == null ? void 0 : sw.pushManager) == null ? void 0 : _a2.getSubscription();
1624
- });
1625
- }
1626
- /** Check if running as a PWA */
1627
- get pwa() {
1628
- if (this._pwa == null)
1629
- this._pwa = matchMedia("(display-mode: standalone)").matches || (navigator == null ? void 0 : navigator.standalone) || document.referrer.includes("android-app://");
1630
- return this._pwa;
1631
- }
1632
- /**
1633
- * Inject the client theme settings, meta tags & PWA prompt
1634
- * @param opts Injection options: reload - use cached settings or reload; pwa - disabled auto pwa prompt
1635
- * @return {Promise<void>} Resolves on completion
1636
- */
1637
- async init(opts = {}) {
1638
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1639
- opts = {
1640
- reload: void 0,
1641
- pwa: true,
1642
- ...opts
1643
- };
1644
- const meta = (key, name, value) => {
1645
- const exists = document.querySelector(`meta[${key}="${name}"]`);
1646
- if (value === void 0 || exists) return exists;
1647
- const meta2 = document.createElement("meta");
1648
- meta2.setAttribute(key, name);
1649
- meta2.content = value;
1650
- document.head.append(meta2);
1651
- };
1652
- if (!this.settings.cache.keys().length) opts.reload = true;
1653
- let settings = await (opts.reload ? this.settings.all(false, true) : this.settings.cache);
1654
- if (opts.reload == null) this.settings.all(false, true).then(() => this.init({ reload: false }));
1655
- if (settings["title"]) document.querySelectorAll(".momentum-title").forEach((el) => el.innerText = el.innerText.includes("|") ? `${el.innerText.split("|")[0].trim()} | ${settings["title"]}` : settings["title"]);
1656
- if (settings["description"]) document.querySelectorAll(".momentum-description").forEach((el) => el.innerText = settings["description"]);
1657
- if (settings["version"]) document.querySelectorAll(".momentum-version").forEach((el) => el.innerText = settings["version"]);
1658
- if (settings["logo"]) document.querySelectorAll(".momentum-logo").forEach((el) => el.src = settings["logo"]);
1659
- meta("name", "description", settings["description"]);
1660
- meta("itemprop", "name", settings["title"]);
1661
- meta("itemprop", "description", settings["description"]);
1662
- meta("itemprop", "image", `${settings["public_url"]}/favicon.png`);
1663
- meta("property", "og:type", "website");
1664
- meta("property", "og:url", settings["public_url"]);
1665
- meta("property", "og:image", `${settings["public_url"]}/favicon.png`);
1666
- meta("property", "og:title", settings["title"]);
1667
- meta("property", "og:description", settings["description"]);
1668
- meta("name", "twitter:card", "summary_large_image");
1669
- meta("name", "twitter:title", settings["title"]);
1670
- meta("name", "twitter:description", settings["description"]);
1671
- meta("name", "twitter:image", `${settings["public_url"]}/favicon.png`);
1672
- if (settings["pwa"]) {
1673
- meta("name", "mobile-web-app-capable", "yes");
1674
- meta("name", "apple-mobile-web-app-status-bar-style", "default");
1675
- meta("name", "apple-mobile-web-app-title", settings["title"]);
1676
- meta("name", "apple-touch-icon", `${settings["public_url"]}/favicon.png`);
1677
- meta("name", "apple-touch-startup-image", `${settings["public_url"]}/favicon.png`);
1678
- if (!document.querySelector('link[rel="manifest"]')) {
1679
- const link = document.createElement("link");
1680
- link.setAttribute("rel", "manifest");
1681
- link.setAttribute("href", this.settings.api.url + "/manifest.json");
1682
- document.head.append(link);
1683
- }
1684
- if (opts.pwa && !this.iframe && !this.pwa && this.mobile) setTimeout(() => {
1685
- const dismissed = !!localStorage.getItem("momentum:install-prompt");
1686
- if (!dismissed) this.pwaPrompt();
1687
- }, 6e4);
1688
- }
1689
- meta("name", "theme-color", (_a = settings["theme"]) == null ? void 0 : _a.background);
1690
- document.body.classList.add(((_b = settings["theme"]) == null ? void 0 : _b.darkMode) ? "theme-dark" : "theme-light");
1691
- document.body.classList.remove(((_c = settings["theme"]) == null ? void 0 : _c.darkMode) ? "theme-light" : "theme-dark");
1692
- const style = document.querySelector("style.momentum-theme") || document.createElement("style");
1693
- style.classList.add("momentum-theme");
1694
- style.innerHTML = `
1695
- :root {
1696
- --theme-backdrop: ${(_d = settings["theme"]) == null ? void 0 : _d.background} !important;
1697
- --theme-primary: ${(_e = settings["theme"]) == null ? void 0 : _e.primary} !important;
1698
- --theme-accent: ${(_f = settings["theme"]) == null ? void 0 : _f.accent} !important;
1699
- --theme-contrast: ${blackOrWhite((_g = settings["theme"]) == null ? void 0 : _g.background)} !important;
1700
- --theme-primary-contrast: ${blackOrWhite((_h = settings["theme"]) == null ? void 0 : _h.primary)} !important;
1701
- --theme-accent-contrast: ${blackOrWhite((_i = settings["theme"]) == null ? void 0 : _i.accent)} !important;
1702
- }
1703
- `;
1704
- if (!style.parentElement) document.head.append(style);
1705
- this.emit(PES`client/inject:c`, this.platform);
1706
- }
1707
- /**
1708
- * Create UI prompt for user to install as PWA
1709
- * @param platform Platform prompt, leave blank to auto-detect
1710
- */
1711
- pwaPrompt(platform) {
1712
- if (document.querySelector(".momentum-pwa-prompt")) return;
1713
- const url = this.settings.api.url;
1714
- const settings = this.settings.cache;
1715
- const android = (platform || this.platform) == "android";
1716
- let style = document.querySelector("style.momentum-pwa");
1717
- if (!style) {
1718
- style = document.createElement("style");
1719
- style.innerHTML = `
1720
- .momentum-pwa-prompt-backdrop {
1721
- position: fixed;
1722
- display: relative;
1723
- left: 0;
1724
- top: 0;
1725
- right: 0;
1726
- bottom: 0;
1727
- background: rgba(0,0,0,.5);
1728
- z-index: 9999;
1729
- animation: fadeIn 0.5s ease-in-out forwards;
1730
- opacity: 0;
1731
- }
1732
- .momentum-pwa-prompt-backdrop.exit {
1733
- animation: fadeOut 0.5s ease-in-out forwards !important;
1734
- }
1735
- .momentum-pwa-prompt {
1736
- position: fixed;
1737
- background: #fff;
1738
- color: black;
1739
- bottom: 0;
1740
- left: 50%;
1741
- width: min(100vw, 450px);
1742
- transform: translate(-50%, 0);
1743
- animation: slideUp 0.5s ease-in-out forwards;
1744
- }
1745
- .momentum-pwa-prompt.exit {
1746
- animation: slideDown 0.5s ease-in-out forwards !important;
1747
- }
1748
- .momentum-pwa-prompt img {
1749
- width: 18px;
1750
- height: 18px;
1751
- }
1752
- .momentum-pwa-prompt h1 {
1753
- font-size: 1.25rem;
1754
- font-weight: bold;
1755
- }
1756
- .momentum-pwa-prompt-close {
1757
- position: absolute;
1758
- right: 5px;
1759
- top: 10px;
1760
- background: transparent;
1761
- border: none;
1762
- cursor: pointer;
1763
- }
1764
-
1765
- @keyframes fadeIn {
1766
- from { opacity: 0; }
1767
- to { opacity: 1; }
1768
- }
1769
- @keyframes fadeOut {
1770
- from { opacity: 1; }
1771
- to { opacity: 0; }
1772
- }
1773
-
1774
- @keyframes slideUp {
1775
- from { transform: translate(-50%, 100%); }
1776
- to { transform: translate(-50%, 0); }
1777
- }
1778
- @keyframes slideDown {
1779
- from { transform: translate(-50%, 0); }
1780
- to { transform: translate(-50%, 100%); }
1781
- }
1782
- `;
1783
- document.head.append(style);
1784
- }
1785
- const backdrop = document.createElement("div");
1786
- backdrop.classList.add("momentum-pwa-prompt-backdrop");
1787
- const prompt = document.createElement("div");
1788
- prompt.classList.add("momentum-pwa-prompt");
1789
- prompt.innerHTML = `
1790
- <div style="display: flex; padding: 1rem; align-items: center">
1791
- <img src="${settings.logo.startsWith("/") ? url : ""}${settings.logo}" alt="Logo" style="height: 40px; width: auto; margin-right: .5rem;" />
1792
- <h1 style="margin: 0">Install ${settings.title}</h1>
1793
- </div>
1794
- <div style="display: flex; flex-direction: column; align-items: center">
1795
- <div style="border-top: 2px solid #00000020; border-bottom: 2px solid #00000020; padding: 0 1rem">
1796
- <p style="margin-top: 1rem; text-align: center">This website can be installed as an App! Add it to your home screen for quick access & fullscreen use.</p>
1797
- </div>
1798
- <table style="margin: 1.5rem 0">
1799
- <tr>
1800
- <td style="width: 50px; text-align: center">
1801
- ${android ? '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="black" style="transform: scale(1.5)"><path d="M480-160q-33 0-56.5-23.5T400-240q0-33 23.5-56.5T480-320q33 0 56.5 23.5T560-240q0 33-23.5 56.5T480-160Zm0-240q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm0-240q-33 0-56.5-23.5T400-720q0-33 23.5-56.5T480-800q33 0 56.5 23.5T560-720q0 33-23.5 56.5T480-640Z"/></svg>' : '<svg viewBox="0 0 566 670" xmlns="http://www.w3.org/2000/svg" fill="#0B76FC" height="40px"><path d="M255 12c4-4 10-8 16-8s12 3 16 8l94 89c3 4 6 7 8 12 2 6 0 14-5 19-7 8-20 9-28 2l-7-7-57-60 2 54v276c0 12-10 22-22 22-12 1-24-10-23-22V110l1-43-60 65c-5 5-13 8-21 6a19 19 0 0 1-16-17c-1-7 2-13 7-18l95-91z" /><path d="M43 207c16-17 40-23 63-23h83v46h-79c-12 0-25 3-33 13-8 9-10 21-10 33v260c0 13 0 27 6 38 5 12 18 18 30 19l14 1h302c14 0 28 0 40-8 11-7 16-21 16-34V276c0-11-2-24-9-33-8-10-22-13-34-13h-78v-46h75c13 0 25 1 37 4 16 4 31 13 41 27 11 17 14 37 14 57v280c0 20-3 41-15 58a71 71 0 0 1-45 27c-11 2-23 3-34 3H109c-19-1-40-4-56-15-14-9-23-23-27-38-4-12-5-25-5-38V270c1-22 6-47 22-63z" /></svg>'}
1802
- </td>
1803
- <td>
1804
- <p style="margin: 1rem 0">1) ${android ? "Open the dropdown menu" : 'Press the "Share" button'}</p>
1805
- </td>
1806
- </tr>
1807
- <tr>
1808
- <td style="width: 50px; text-align: center">
1809
- ${android ? '<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="black" style="transform: scale(-1.5, 1.5)"><path d="M280-40q-33 0-56.5-23.5T200-120v-720q0-33 23.5-56.5T280-920h280v80H280v40h280v80H280v480h400v-80h80v200q0 33-23.5 56.5T680-40H280Zm0-120v40h400v-40H280Zm440-240L520-600l56-56 104 104v-288h80v288l104-104 56 56-200 200ZM280-800v-40 40Zm0 640v40-40Z"/></svg>' : '<svg viewBox="0 0 578 584" xmlns="http://www.w3.org/2000/svg" fill="black" height="34px"><path d="M101 35l19-1h333c12 0 23 0 35 3 17 3 34 12 44 27 13 16 16 38 16 58v329c0 19 0 39-8 57a65 65 0 0 1-37 37c-18 7-38 7-57 7H130c-21 1-44 0-63-10-14-7-25-20-30-34-6-15-8-30-8-45V121c1-21 5-44 19-61 13-16 33-23 53-25m7 46c-10 1-19 6-24 14-7 8-9 20-9 31v334c0 12 2 25 10 34 9 10 23 12 35 12h336c14 1 30-3 38-15 6-9 8-20 8-31V125c0-12-2-24-10-33-9-9-22-12-35-12H121l-13 1z" /><path d="M271 161c9-11 31-10 38 4 3 5 3 11 3 17v87h88c7 0 16 1 21 7 6 6 7 14 6 22a21 21 0 0 1-10 14c-5 4-11 5-17 5h-88v82c0 7-1 15-6 20-10 10-29 10-37-2-3-6-4-13-4-19v-81h-87c-8-1-17-3-23-9-5-6-6-15-4-22a21 21 0 0 1 11-14c6-3 13-3 19-3h84v-88c0-7 1-14 6-20z" /></svg>'}
1810
- </td>
1811
- <td>
1812
- <p style="margin: 1rem 0">2) Press "Add to Home Screen"</p>
1813
- </td>
1814
- </tr>
1815
- </table>
1816
- </div>`;
1817
- const close = document.createElement("button");
1818
- close.classList.add("momentum-pwa-prompt-close");
1819
- close.innerText = "x";
1820
- close.onclick = () => {
1821
- prompt.classList.add("exit");
1822
- backdrop.classList.add("exit");
1823
- localStorage.setItem("momentum:install-prompt", "dismissed");
1824
- setTimeout(() => {
1825
- prompt.remove();
1826
- backdrop.remove();
1827
- this.emit(PES`client/pwa:d`, platform);
1828
- }, 500);
1829
- };
1830
- prompt.append(close);
1831
- backdrop.append(prompt);
1832
- document.body.append(backdrop);
1833
- this.emit(PES`client/pwa:c`, platform);
1834
- }
1835
- /**
1836
- * Enable device notifications
1837
- * @return {Promise<null>} Resolves on success
1838
- */
1839
- async enableNotifications() {
1840
- const granted = await Notification.requestPermission();
1841
- if (!granted) return null;
1842
- const sw = await navigator.serviceWorker.ready;
1843
- const subscription = (await sw.pushManager.subscribe({
1844
- userVisibleOnly: true,
1845
- applicationServerKey: this.settings.cache["push_public_key"]
1846
- })).toJSON();
1847
- return this.api.request({ url: "/api/notifications", body: subscription }).then(() => this.notifications = true);
1848
- }
1849
- /**
1850
- * Disable device notifications
1851
- * @return {Promise<void>} Resolves on success
1852
- */
1853
- async disableNotifications() {
1854
- var _a;
1855
- const subscription = await this.pushSubscription;
1856
- subscription == null ? void 0 : subscription.unsubscribe();
1857
- return this.api.request({ url: "/api/notifications", method: "DELETE", body: {
1858
- p256dh: (_a = subscription == null ? void 0 : subscription.toJSON().keys) == null ? void 0 : _a["p256dh"]
1859
- } }).then(() => this.notifications = false);
1860
- }
1861
- }
1862
- class Schemas extends PathEventEmitter {
1863
- constructor(api) {
1864
- super();
1865
- this.api = api;
1866
- }
1867
- delete(path) {
1868
- if (!path) throw new Error("Cannot delete schema, missing collection path");
1869
- return this.api.request({ url: `/api/` + PES`schema/${path}`, method: "DELETE" }).then(() => this.emit(PES`schema/${path}:d`, path));
1870
- }
1871
- read(pathOrTree) {
1872
- return this.api.request({ url: "/api/" + PES`schema/${typeof pathOrTree == "string" ? pathOrTree : ""}` + (pathOrTree === true ? `?tree=${pathOrTree}` : "") }).then((resp) => {
1873
- this.emit(PES`schema/${typeof pathOrTree == "string" ? pathOrTree : ""}:r`, resp);
1874
- return resp;
1875
- });
1876
- }
1877
- update(schema) {
1878
- if (!schema.path) throw new Error("Cannot update schema, missing collection path");
1879
- return this.api.request({ url: "/api/" + PES`schema/${schema.path}`, body: schema }).then((resp) => {
1880
- this.emit(PES`schema/${schema.path}:${schema._id ? "u" : "c"}`, resp);
1881
- return resp;
1882
- });
1883
- }
1884
- }
1885
- class Data extends PathEventEmitter {
1886
- constructor(api) {
1887
- super();
1888
- __publicField(this, "api");
1889
- __publicField(this, "schema");
1890
- this.api = typeof api == "string" ? new Api(api) : api;
1891
- this.schema = new Schemas(this.api);
1892
- }
1893
- create(collection, document2) {
1894
- if (!collection || !document2) throw new Error("Cannot create document, missing collection or document");
1895
- return this.api.request({
1896
- url: `/api/` + PES`data/${collection}`,
1897
- method: "POST",
1898
- body: document2
1899
- }).then((resp) => {
1900
- this.emit(PES`data/${collection}:c`, resp);
1901
- return resp;
1902
- });
1903
- }
1904
- delete(collection, id) {
1905
- if (!collection || !id) throw new Error("Cannot delete document, missing collection or ID");
1906
- return this.api.request({
1907
- url: `/api/` + PES`data/${collection}/${id}`,
1908
- method: "DELETE"
1909
- }).then(() => this.emit(PES`data/${collection}/${id}:d`, id));
1910
- }
1911
- read(collection, id) {
1912
- if (!collection) throw new Error("Cannot read documents, missing collection");
1913
- return this.api.request({ url: `/api/` + PES`data/${collection}/${id}` }).then((resp) => {
1914
- this.emit(PES`data/${collection}/${id}:r`, collection, resp);
1915
- return resp;
1916
- });
1917
- }
1918
- update(collection, document2, append) {
1919
- if (!collection || !document2) throw new Error("Cannot update document, missing collection or document");
1920
- return this.api.request({
1921
- url: `/api/` + PES`data/${collection}/${document2._id}`,
1922
- method: append ? "PATCH" : "PUT",
1923
- body: document2
1924
- }).then((resp) => {
1925
- this.emit(PES`data/${collection}/${document2._id}:u`, resp);
1926
- return resp;
1927
- });
1928
- }
1929
- raw(collection, query) {
1930
- if (!collection || !query) throw new Error("Cannot execute raw query, missing collection or query");
1931
- const mode = query.operand.startsWith("find") ? "r" : query.operand == "insert" ? "c" : query.operand.startsWith("delete") ? "d" : "u";
1932
- return this.api.request({ url: `/api/` + PES`data/${collection}` + "?raw", body: query }).then((resp) => {
1933
- this.emit(PES`data/${collection}:${mode}`, resp);
1934
- return resp;
1935
- });
1936
- }
1937
- }
1938
- class Discounts extends PathEventEmitter {
1939
- constructor(api) {
1940
- super();
1941
- this.api = api;
1942
- }
1943
- all() {
1944
- return this.api.request({
1945
- url: `/api/payments/discounts`,
1946
- method: "GET"
1947
- }).then((resp) => {
1948
- this.emit(`discounts:r`, resp);
1949
- return resp;
1950
- });
1951
- }
1952
- create(discount) {
1953
- return this.api.request({
1954
- url: "/api/payments/discounts",
1955
- method: "POST",
1956
- body: discount
1957
- }).then((resp) => {
1958
- this.emit(`discounts/${resp.code}:c`, resp);
1959
- return resp;
1960
- });
1961
- }
1962
- delete(discount) {
1963
- const code = typeof discount == "string" ? discount : discount.code;
1964
- return this.api.request({
1965
- url: `/api/payments/discounts/${code}`,
1966
- method: "DELETE"
1967
- }).then(() => {
1968
- this.emit(`discounts/${code}:d`, code);
1969
- });
1970
- }
1971
- read(code) {
1972
- return this.api.request({
1973
- url: `/api/payments/discounts/${code}`,
1974
- method: "GET"
1975
- }).then((resp) => {
1976
- this.emit(`discounts/${code}:r`, resp);
1977
- return resp;
1978
- });
1979
- }
1980
- update(discount) {
1981
- return this.api.request({
1982
- url: "/api/payments/discounts",
1983
- method: "PATCH",
1984
- body: discount
1985
- }).then((resp) => {
1986
- this.emit(`discounts/${resp.code}:u`, resp);
1987
- return resp;
1988
- });
1989
- }
1990
- }
1991
- class Email extends PathEventEmitter {
1992
- constructor(api) {
1993
- super();
1994
- __publicField(this, "api");
1995
- this.api = typeof api == "string" ? new Api(api) : api;
1996
- }
1997
- /**
1998
- * Send Email
1999
- * @param {Mail} email Email to send
2000
- * @return {Promise<any>} Response
2001
- */
2002
- send(email) {
2003
- if (!email.to && !email.bcc || !email.body) throw new Error("Cannot send email, missing address or body");
2004
- return this.api.request({ url: "/api/email", body: email }).then((response) => {
2005
- var _a;
2006
- this.emit(PES`email/${(_a = email.body) == null ? void 0 : _a.template}:c`, { email, response });
2007
- return response;
2008
- });
2009
- }
2010
- }
2011
- class Forms extends PathEventEmitter {
2012
- constructor(api) {
2013
- super();
2014
- __publicField(this, "api");
2015
- __publicField(this, "cache", new Cache("_id"));
2016
- this.api = typeof api == "string" ? new Api(api) : api;
2017
- }
2018
- all(pathOrTree) {
2019
- return this.api.request({ url: "/api/" + PES`forms/${typeof pathOrTree == "string" ? pathOrTree : ""}` + (pathOrTree === true ? `?tree=${pathOrTree}` : "") }).then((resp) => {
2020
- this.emit(PES`forms/${typeof pathOrTree == "string" ? pathOrTree : ""}:r`, resp);
2021
- return resp;
2022
- });
2023
- }
2024
- delete(key) {
2025
- if (!key) throw new Error("Cannot delete form, missing path");
2026
- return this.api.request({ url: `/api/` + PES`forms/${key}`, method: "DELETE" }).then(() => {
2027
- this.cache.delete(key);
2028
- this.emit(PES`forms/${key}:d`, key);
2029
- });
2030
- }
2031
- read(path, reload = false) {
2032
- if (!path) throw new Error("Cannot read form, missing path");
2033
- if (!reload && this.cache.get(path)) return Promise.resolve(this.cache.get(path));
2034
- return this.api.request({ url: `/api/` + PES`forms/${path}` }).then((form) => {
2035
- if (form) this.cache.add(form);
2036
- this.emit(PES`forms/${path}:r`, form);
2037
- return form;
2038
- });
2039
- }
2040
- update(form) {
2041
- if (!form.path) throw new Error("Cannot update form, missing path");
2042
- return this.api.request({ url: `/api/` + PES`forms/${form.path}`, body: form }).then((f) => {
2043
- if (f) this.cache.add(f);
2044
- this.emit(`/api/` + PES`settings/${form.path}:${form._id ? "u" : "c"}`, f);
2045
- return f;
2046
- });
2047
- }
2048
- }
2049
- class Groups extends PathEventEmitter {
2050
- constructor(api) {
2051
- super();
2052
- __publicField(this, "api");
2053
- __publicField(this, "cache", new Cache("name"));
2054
- this.api = typeof api == "string" ? new Api(api) : api;
2055
- }
2056
- async all(reload) {
2057
- if (!reload && this.cache.complete) return this.cache.all();
2058
- return this.api.request({ url: `/api/` + PES`groups` }).then((resp) => {
2059
- this.cache.addAll(resp);
2060
- this.emit(PES`groups:r`, resp || []);
2061
- return resp;
2062
- });
2063
- }
2064
- delete(name) {
2065
- if (!name) throw new Error("Cannot delete group, missing name");
2066
- return this.api.request({
2067
- url: `/api/` + PES`groups/${name}`,
2068
- method: "DELETE"
2069
- }).then(() => {
2070
- this.cache.delete(name);
2071
- this.emit(PES`groups/${name}:d`);
2072
- });
2073
- }
2074
- create(group) {
2075
- if (!group.name) throw new Error("Cannot create group, missing name");
2076
- return this.api.request({
2077
- url: `/api/` + PES`groups/${group.name}`,
2078
- method: "POST",
2079
- body: group
2080
- }).then((resp) => {
2081
- this.cache.add(resp);
2082
- this.emit(PES`groups/${group.name}:c`, resp);
2083
- return resp;
2084
- });
2085
- }
2086
- async read(name, reload) {
2087
- if (!name) throw new Error("Cannot read group, missing name");
2088
- if (!reload && this.cache.get(name)) return this.cache.get(name);
2089
- return this.api.request({ url: `/api/` + PES`groups/${name}` }).then((resp) => {
2090
- this.cache.add(resp);
2091
- this.emit(PES`groups/${name}:r`, resp);
2092
- return resp;
2093
- });
2094
- }
2095
- update(group) {
2096
- if (!group.name) throw new Error("Cannot update group, missing name");
2097
- return this.api.request({
2098
- url: `/api/` + PES`groups/${group.name}`,
2099
- method: "PATCH",
2100
- body: group
2101
- }).then((resp) => {
2102
- this.cache.add(resp);
2103
- this.emit(PES`groups/${group.name}:u`, resp);
2104
- return resp;
2105
- });
2106
- }
2107
- }
2108
- class Logger extends PathEventEmitter {
2109
- constructor(api, channel, logLevel) {
2110
- super();
2111
- __publicField(this, "api");
2112
- __publicField(this, "console", {
2113
- debug: console.debug,
2114
- log: console.log,
2115
- info: console.info,
2116
- warn: console.warn,
2117
- error: console.error
2118
- });
2119
- this.channel = channel;
2120
- if (channel.toLowerCase() == "server") throw new Error('"Server" namespace is reserved');
2121
- this.api = typeof api == "string" ? new Api(api) : api;
2122
- if (logLevel != null && logLevel && logLevel != "NONE") {
2123
- if (LOG_LEVEL[logLevel] >= 0) {
2124
- console.error = (...args) => {
2125
- this.console.error(...args);
2126
- this.error(args);
2127
- };
2128
- window.addEventListener("unhandledrejection", async (event) => {
2129
- var _a, _b, _c, _d;
2130
- let log = ((_a = event.reason) == null ? void 0 : _a.stack) || event.reason;
2131
- if ((_b = event.reason) == null ? void 0 : _b.url)
2132
- log = `${event.reason.method} ${event.reason.url} -> ${event.reason.code}
2133
-
2134
- ${log}`;
2135
- ((_c = event.reason) == null ? void 0 : _c.code) == null || ((_d = event.reason) == null ? void 0 : _d.code) >= 500 ? this.error(log) : this.warn(log);
2136
- });
2137
- }
2138
- if (LOG_LEVEL[logLevel] >= 1) {
2139
- console.warn = (...args) => {
2140
- this.console.warn(...args);
2141
- this.warn(args);
2142
- };
2143
- }
2144
- if (LOG_LEVEL[logLevel] >= 2) {
2145
- console.info = (...args) => {
2146
- this.console.info(...args);
2147
- this.info(args);
2148
- };
2149
- }
2150
- if (LOG_LEVEL[logLevel] >= 3) {
2151
- console.log = (...args) => {
2152
- this.console.log(...args);
2153
- this.log(args);
2154
- };
2155
- }
2156
- if (LOG_LEVEL[logLevel] >= 4) {
2157
- console.debug = (...args) => {
2158
- this.console.debug(...args);
2159
- this.debug(args);
2160
- };
2161
- }
2162
- }
2163
- }
2164
- buildLog(level, log) {
2165
- return {
2166
- time: (/* @__PURE__ */ new Date()).getTime(),
2167
- level,
2168
- log,
2169
- ctx: {
2170
- cores: (navigator == null ? void 0 : navigator.hardwareConcurrency) ?? null,
2171
- mem: (navigator == null ? void 0 : navigator.deviceMemory) ?? null,
2172
- res: [window.innerWidth, window.innerHeight],
2173
- url: location.href
2174
- }
2175
- };
2176
- }
2177
- create(log, channel = this.channel) {
2178
- if (channel.toLowerCase() == "server") throw new Error('"Server" namespace is reserved');
2179
- return this.api.request({ url: `/api/` + PES`logs/${channel}`, body: log }).then(() => this.emit(PES`logs/${channel}:c`, log)).catch(() => {
2180
- });
2181
- }
2182
- channels() {
2183
- return this.api.request({ url: "/api/" + PES`logs/channels` });
2184
- }
2185
- delete(channel = this.channel) {
2186
- return this.api.request({ url: `/api/` + PES`logs/${channel}`, method: "DELETE" }).then(() => this.emit(PES`logs/${channel}:d`));
2187
- }
2188
- read(channel = this.channel) {
2189
- return this.api.request({ url: `/api/` + PES`logs/${channel}` }).then((logs) => {
2190
- this.emit(PES`logs/${channel}:r`, logs);
2191
- return logs;
2192
- });
2193
- }
2194
- // Console =========================================================================================================
2195
- debug(log, channel = this.channel) {
2196
- return this.create(this.buildLog(LOG_LEVEL.DEBUG, log), channel);
2197
- }
2198
- log(log, channel = this.channel) {
2199
- return this.create(this.buildLog(LOG_LEVEL.LOG, log), channel);
2200
- }
2201
- info(log, channel = this.channel) {
2202
- return this.create(this.buildLog(LOG_LEVEL.INFO, log), channel);
2203
- }
2204
- warn(log, channel = this.channel) {
2205
- return this.create(this.buildLog(LOG_LEVEL.WARN, log), channel);
2206
- }
2207
- error(log, channel = this.channel) {
2208
- return this.create(this.buildLog(LOG_LEVEL.ERROR, log), channel);
2209
- }
2210
- }
2211
- class Payments extends PathEventEmitter {
2212
- constructor(api, opts = {}) {
2213
- super();
2214
- __publicField(this, "api");
2215
- __publicField(this, "discounts");
2216
- /** Stripe object */
2217
- __publicField(this, "stripe");
2218
- /** Public stripe token */
2219
- __publicField(this, "token");
2220
- this.opts = opts;
2221
- this.api = typeof api == "string" ? new Api(api) : api;
2222
- this.opts = {
2223
- paymentUrl: this.api.url + "/ui/payments/checkout",
2224
- ...this.opts
2225
- };
2226
- this.discounts = new Discounts(this.api);
2227
- this.relayEvents(this.discounts);
2228
- }
2229
- /**
2230
- * Initialize stripe API
2231
- * @return {Promise<any>} Returns stripe API
2232
- * @private
2233
- */
2234
- async init() {
2235
- await new Promise((res) => {
2236
- if (this.stripe) return res(window["Stripe"]);
2237
- const stripeScript = document.createElement("script");
2238
- stripeScript.src = "https://js.stripe.com/v3/";
2239
- stripeScript.setAttribute("crossorigin", "anonymous");
2240
- stripeScript.onload = () => res();
2241
- document.head.appendChild(stripeScript);
2242
- }).then(() => this.stripe = window["Stripe"]);
2243
- return this.stripe(this.token);
2244
- }
2245
- /**
2246
- * Create a stripe client secret to complete transaction
2247
- * @param {string} id Transaction ID
2248
- * @return {Promise<string>} Client secret
2249
- * @private
2250
- */
2251
- createSecret(id) {
2252
- return this.api.request({ url: `/api/payments/init/${id || ""}`, method: "POST" }).then((resp) => resp.token);
2253
- }
2254
- /**
2255
- * Create/Update a transaction
2256
- * @param {Optional<Transaction, "subtotal" | "total">} transaction Transaction information
2257
- * @return {Promise<string>} Completed translation information
2258
- */
2259
- checkout(transaction) {
2260
- return this.api.request({
2261
- url: `/api/payments/transactions/${transaction._id || ""}`,
2262
- method: transaction._id ? "PATCH" : "POST",
2263
- body: transaction
2264
- }).then((resp) => {
2265
- this.emit(PES`payments:c`, resp);
2266
- return resp;
2267
- });
2268
- }
2269
- /**
2270
- * Get translation history
2271
- * @param {string} username Limit history to user
2272
- * @return {Promise<Transaction[]>} List of translations
2273
- */
2274
- async history(username) {
2275
- return this.api.request({ url: `/api/payments/transactions/${username || ""}` }).then((resp) => {
2276
- this.emit(PES`payments/${username}:r`, resp);
2277
- return resp;
2278
- });
2279
- }
2280
- /**
2281
- * Send recipient transaction receipt or invoice
2282
- * @param {string} id Translation ID
2283
- * @return {Promise<void>} Returns once complete
2284
- */
2285
- notify(id) {
2286
- return this.api.request({ url: `/api/payments/notify/${id || ""}`, method: "POST" });
2287
- }
2288
- /**
2289
- * Retrieve a list of available products
2290
- * @param {string | number} id Limit to specific product
2291
- * @return {Promise<any>} List of products or single product if ID is used
2292
- */
2293
- products(id) {
2294
- return this.api.request({ url: `/api/payments/products/${id || ""}` }).then((resp) => {
2295
- this.emit(PES`products/${id ?? ""}:r`, resp);
2296
- return resp;
2297
- });
2298
- }
2299
- /**
2300
- * Process payment programmatically
2301
- * @param {string} id Transaction ID
2302
- * @param {Card} card Credit card information
2303
- * @return {Promise<any>} Stripe confirmation
2304
- */
2305
- async payment(id, card) {
2306
- const [client, secret] = await Promise.all([this.init(), this.createSecret(id)]);
2307
- return client.confirmPayment({
2308
- clientSecret: secret,
2309
- confirmParams: {
2310
- payment_method: {
2311
- card: { ...card, details: void 0 },
2312
- billing_details: card.details || {}
2313
- }
2314
- }
2315
- });
2316
- }
2317
- /**
2318
- * Process payment using Stripe form
2319
- * @param {string} id Transaction ID
2320
- * @param {string} element DOM element to inject form into
2321
- * @return {Promise<() => Promise<any>>} Callback to submit form
2322
- */
2323
- async paymentForm(id, element) {
2324
- const [client, secret] = await Promise.all([this.init(), this.createSecret(id)]);
2325
- const form = client.elements({ clientSecret: secret });
2326
- form.create("payment").mount(element);
2327
- return (redirect = location.href) => client.confirmPayment({
2328
- elements: form,
2329
- redirect: "if_required",
2330
- confirmParams: { return_url: redirect + "?payment_status=success" }
2331
- });
2332
- }
2333
- /**
2334
- * Complete payment via Momentum's payment page
2335
- * @param {string} id Transaction ID
2336
- * @param {string} host Host origin attempting to login
2337
- * @return {Promise<string>} Translation ID on success
2338
- */
2339
- paymentRedirect(id, host = location.origin) {
2340
- return new Promise(async (res, rej) => {
2341
- var _a;
2342
- let origin = new URL(this.opts.paymentUrl).origin, listener, win;
2343
- window.addEventListener("message", listener = (event) => {
2344
- const data = (event == null ? void 0 : event.data) || {};
2345
- if (event.origin != origin || data.sender != origin) return;
2346
- if (!data.response) return rej("Unknown response from payment page");
2347
- window.removeEventListener("message", listener);
2348
- win.close();
2349
- res(data.response);
2350
- });
2351
- win = window.open(encodeURI(`${(_a = this.opts) == null ? void 0 : _a.paymentUrl}?token=${id}&host=${host}`), "_blank");
2352
- if (!win) {
2353
- window.removeEventListener("message", listener);
2354
- return rej("Unable to open payment page");
2355
- }
2356
- });
2357
- }
2358
- /**
2359
- * Refund a transaction
2360
- * @param {string} id Transaction number to refund
2361
- * @return {PromiseProgress<any>}
2362
- */
2363
- refund(id) {
2364
- return this.api.request({ url: `/api/payments/transactions/${id || ""}`, method: "DELETE" }).then((resp) => {
2365
- this.emit(PES`products/${id ?? ""}:d`, resp);
2366
- return resp;
2367
- });
2368
- }
2369
- }
2370
- class Pdf extends PathEventEmitter {
2371
- constructor(api) {
2372
- super();
2373
- __publicField(this, "api");
2374
- this.api = typeof api == "string" ? new Api(api) : api;
2375
- }
2376
- createPdf(body, options) {
2377
- return this.api.request({ url: `/api/` + PES`pdf`, body: { ...body, options } }).then(async (resp) => {
2378
- if (options == null ? void 0 : options.download) {
2379
- let filename = (options == null ? void 0 : options.filename) || timestampFilename();
2380
- if (!filename.endsWith(".pdf")) filename += ".pdf";
2381
- downloadFile(resp, filename);
2382
- }
2383
- this.emit(PES`pdf:c`, resp);
2384
- return resp;
2385
- });
2386
- }
2387
- fromHtml(html, options = {}) {
2388
- if (!html) throw new Error("Cannot create PDF, missing HTML");
2389
- return this.createPdf({ html }, options);
2390
- }
2391
- fromTemplate(template, data, options = {}) {
2392
- if (!template) throw new Error("Cannot create PDF, missing template");
2393
- return this.createPdf({ template, data }, options);
2394
- }
2395
- fromUrl(url, options = {}) {
2396
- if (!url) throw new Error("Cannot create PDF, missing URL");
2397
- return this.createPdf({ url }, options);
2398
- }
2399
- }
2400
- class Phone extends PathEventEmitter {
2401
- constructor(api) {
2402
- super();
2403
- __publicField(this, "api");
2404
- this.api = typeof api == "string" ? new Api(api) : api;
2405
- }
2406
- sms(message) {
2407
- return this.api.request({ url: "/api/" + PES`phone/sms`, body: message }).then((resp) => this.emit(PES`sms/${message.to}`, resp));
2408
- }
2409
- voice(message) {
2410
- return this.api.request({ url: "/api/" + PES`phone/voice`, body: message }).then((resp) => this.emit(PES`voice/${message.to}`, resp));
2411
- }
2412
- }
2413
- const _Socket = class _Socket {
2414
- constructor(api) {
2415
- __publicField(this, "api");
2416
- __publicField(this, "url");
2417
- __publicField(this, "connection");
2418
- __publicField(this, "open", false);
2419
- this.api = typeof api == "string" ? new Api(api) : api;
2420
- this.url = this.api.url.replace("http", "ws");
2421
- this.api.on("api/token", () => this.connect());
2422
- this.connect();
2423
- }
2424
- close() {
2425
- var _a;
2426
- if (this.open) console.debug("Disconnected from Momentum");
2427
- this.open = false;
2428
- (_a = this.connection) == null ? void 0 : _a.close();
2429
- this.connection = void 0;
2430
- }
2431
- connect() {
2432
- if (this.open) this.close();
2433
- if (navigator.onLine) {
2434
- this.connection = new WebSocket(this.url + (this.api.token ? `?token=${this.api.token}` : ""));
2435
- this.connection.onclose = this.close;
2436
- this.connection.onmessage = this.handle;
2437
- this.connection.onopen = () => {
2438
- this.open = true;
2439
- clearTimeout(timeout);
2440
- console.debug("Connected to Momentum");
2441
- };
2442
- }
2443
- const timeout = setTimeout(() => {
2444
- if (this.open) return;
2445
- this.close();
2446
- this.connect();
2447
- }, _Socket.pollingSpeed);
2448
- }
2449
- handle(...args) {
2450
- console.log(args);
2451
- }
2452
- send(channel, payload) {
2453
- var _a;
2454
- (_a = this.connection) == null ? void 0 : _a.send(JSON.stringify({
2455
- token: this.api.token,
2456
- channel,
2457
- payload
2458
- }));
2459
- }
2460
- };
2461
- __publicField(_Socket, "pollingSpeed", 3e4);
2462
- let Socket = _Socket;
2463
- let Storage$1 = class Storage extends PathEventEmitter {
2464
- constructor(api, path = "storage") {
2465
- super();
2466
- __publicField(this, "api");
2467
- this.path = path;
2468
- this.api = typeof api == "string" ? new Api(api) : api;
2469
- }
2470
- copy(source, destination) {
2471
- if (!source || !destination) throw new Error("Cannot copy file or folder, missing source or destination");
2472
- return this.api.request({ url: "/api/" + PES`${this.path}/${destination}`, body: { from: source } }).then((response) => {
2473
- this.emit(PES`${this.path}/${destination}:c`, response);
2474
- return response;
2475
- });
2476
- }
2477
- delete(path) {
2478
- if (!path) throw new Error("Cannot delete file or folder, missing path");
2479
- return this.api.request({ url: "/api/" + PES`${this.path}/${path}`, method: "DELETE" }).then(() => {
2480
- this.emit(PES`${this.path}/${path}:d`, path);
2481
- });
2482
- }
2483
- download(path, opts = {}) {
2484
- if (!path) throw new Error("Cannot download file, missing path");
2485
- return this.api.request({ ...opts, url: "/api/" + PES`${this.path}/${path}`, decode: false }).then(async (response) => {
2486
- const blob = await response.blob();
2487
- const name = opts.downloadAs || path.split("/").pop();
2488
- this.emit(PES`${this.path}/${path}:r`, blob);
2489
- downloadFile(blob, name);
2490
- return response;
2491
- });
2492
- }
2493
- list(path) {
2494
- if (!path) path = "/";
2495
- return this.api.request({ url: "/api/" + PES`${this.path}/${path}` + "?list" }).then((resp) => {
2496
- this.emit(PES`${this.path}/${path}:r`, resp);
2497
- return resp;
2498
- });
2499
- }
2500
- open(path, target = "_blank") {
2501
- if (!path) throw new Error("Cannot download file, missing path");
2502
- const link = `${this.api.url}/api/` + PES`${this.path}/${path}${!this.api.sameOrigin && this.api.token ? `?token=${this.api.token}` : ""}`;
2503
- if (!target) return link;
2504
- this.emit(PES`${this.path}/${path}:r`, path);
2505
- return window.open(link, target);
2506
- }
2507
- mkdir(path) {
2508
- if (!path) throw new Error("Cannot make directory, missing path");
2509
- return this.api.request({ url: "/api/" + PES`${this.path}/${path}`, body: { directory: true } }).then((resp) => {
2510
- this.emit(PES`${this.path}/${path}:c`, resp);
2511
- return resp;
2512
- });
2513
- }
2514
- move(source, destination) {
2515
- if (!source || !destination) throw new Error("Cannot move file or folder, missing source or destination");
2516
- if (source == destination) return this.list(destination);
2517
- return this.api.request({ url: "/api/" + PES`${this.path}/${source}`, method: "PATCH", body: { move: destination } }).then((response) => {
2518
- this.emit(PES`${this.path}/${source}:u`, response);
2519
- return response;
2520
- });
2521
- }
2522
- upload(files, opts) {
2523
- return new PromiseProgress(async (res, rej, prog) => {
2524
- if (!files) files = await fileBrowser(typeof opts == "object" ? opts : void 0);
2525
- if (!files || Array.isArray(files) && !files.length) return [];
2526
- const path = (opts && typeof opts == "object" ? opts == null ? void 0 : opts.path : opts) || "/";
2527
- return uploadWithProgress({
2528
- url: `${this.api.url}/api/` + PES`${this.path}/${path}`,
2529
- files: makeArray(files),
2530
- headers: this.api.headers
2531
- }).onProgress((p) => {
2532
- prog(p);
2533
- }).then((resp) => {
2534
- this.emit(PES`${this.path}/${path}:c`, resp);
2535
- res(resp);
2536
- }).catch((err) => rej(err));
2537
- });
2538
- }
2539
- };
2540
- class Users extends PathEventEmitter {
2541
- constructor(api) {
2542
- super();
2543
- __publicField(this, "api");
2544
- __publicField(this, "cache", new Cache("username"));
2545
- this.api = typeof api == "string" ? new Api(api) : api;
2546
- }
2547
- async all(reload) {
2548
- if (!reload && this.cache.complete) return this.cache.all();
2549
- return this.api.request({ url: "/api/" + PES`users` }).then((resp) => {
2550
- resp == null ? void 0 : resp.forEach((r) => {
2551
- r.image = `${this.api.url}${r.image}${!this.api.sameOrigin && this.api.token ? `?token=${this.api.token}` : ""}`;
2552
- return r;
2553
- });
2554
- this.cache.addAll(resp);
2555
- this.emit(PES`users:r`, resp || []);
2556
- return resp;
2557
- });
2558
- }
2559
- delete(username) {
2560
- if (!username) throw new Error("Cannot delete user, missing username");
2561
- return this.api.request({
2562
- url: "/api/" + PES`users/${username}`,
2563
- method: "DELETE"
2564
- }).then(() => {
2565
- this.cache.delete(username);
2566
- this.emit(PES`users/${username}:d`, username);
2567
- });
2568
- }
2569
- async read(username, reload) {
2570
- if (!username) throw new Error("Cannot read user, missing username");
2571
- if (!reload && this.cache.get(username)) return this.cache.get(username);
2572
- return this.api.request({ url: "/api/" + PES`users/${username}` }).then((resp) => {
2573
- if (resp) {
2574
- resp.image = `${this.api.url}${resp.image}${!this.api.sameOrigin && this.api.token ? `?token=${this.api.token}` : ""}`;
2575
- this.cache.add(resp);
2576
- }
2577
- this.emit(PES`users/${username}:r`, resp);
2578
- return resp;
2579
- });
2580
- }
2581
- update(user) {
2582
- if (!user.username) throw new Error("Cannot update user, missing username");
2583
- return this.api.request({
2584
- url: `/api/` + PES`users/${user.username}`,
2585
- method: "PATCH",
2586
- body: user
2587
- }).then((resp) => {
2588
- if (resp) {
2589
- resp.image = this.api.url + resp.image + `?token=${this.api.token}`;
2590
- this.cache.add(resp);
2591
- }
2592
- this.emit(PES`users/${user.username}:${resp._id ? "u" : "c"}`, resp);
2593
- return resp;
2594
- });
2595
- }
2596
- uploadImage(username, file) {
2597
- if (!username || !file) throw new Error("Cannot update user image, missing username or file");
2598
- return uploadWithProgress({
2599
- url: this.api.url + `/api/` + PES`users/${username}/image`,
2600
- files: [file],
2601
- headers: this.api.headers
2602
- });
2603
- }
2604
- }
2605
- class Settings extends PathEventEmitter {
2606
- constructor(api) {
2607
- super();
2608
- __publicField(this, "api");
2609
- __publicField(this, "cache");
2610
- this.api = typeof api == "string" ? new Api(api) : api;
2611
- this.cache = new Cache("key", { storageKey: `momentum:settings:${this.api.host}` });
2612
- this.api.on("api/token", () => this.all(false, true));
2613
- }
2614
- async all(detailed, reload) {
2615
- if (!reload && !detailed && this.cache.complete) return this.cache;
2616
- return this.api.request({ url: `/api/` + PES`settings` + (detailed ? "?detailed" : "") }).then((resp) => {
2617
- this.cache.clear();
2618
- if (resp) Object.keys(resp).forEach((key) => this.cache.set(key, detailed ? resp[key].value : resp[key]));
2619
- this.cache.complete = true;
2620
- this.emit(PES`settings:r`, resp || []);
2621
- return resp;
2622
- });
2623
- }
2624
- delete(key) {
2625
- if (!key) throw new Error("Cannot delete setting, missing key");
2626
- return this.api.request({ url: `/api/` + PES`settings/${key}`, method: "DELETE" }).then(() => {
2627
- this.cache.delete(key);
2628
- this.emit(PES`settings/${key}:d`, key);
2629
- });
2630
- }
2631
- read(key, reload = false) {
2632
- if (!key) throw new Error("Cannot read setting, missing key");
2633
- if (!reload && this.cache.get(key)) return this.cache.get(key);
2634
- return this.api.request({ url: `/api/` + PES`settings/${key}` }).then((variable) => {
2635
- if (variable) this.cache.set(variable.key, variable.value);
2636
- this.emit(PES`settings/${key}:r`, variable);
2637
- return variable;
2638
- });
2639
- }
2640
- update(variable) {
2641
- if (!variable.key) throw new Error("Cannot update setting, missing key");
2642
- return this.api.request({ url: `/api/` + PES`settings/${variable.key}`, body: variable }).then((variable2) => {
2643
- if (variable2) this.cache.set(variable2.key, variable2.value);
2644
- this.emit(`/api/` + PES`settings/${variable2.key}:${variable2._id ? "u" : "c"}`, variable2);
2645
- return variable2;
2646
- });
2647
- }
2648
- }
2649
- class Static extends Storage$1 {
2650
- constructor(api) {
2651
- super(api, "static");
2652
- }
2653
- }
2654
- class Momentum extends PathEventEmitter {
2655
- constructor(url, opts) {
2656
- super();
2657
- __publicField(this, "api");
2658
- __publicField(this, "actions");
2659
- __publicField(this, "ai");
2660
- __publicField(this, "analytics");
2661
- __publicField(this, "auth");
2662
- __publicField(this, "client");
2663
- __publicField(this, "data");
2664
- __publicField(this, "email");
2665
- __publicField(this, "forms");
2666
- __publicField(this, "groups");
2667
- __publicField(this, "logger");
2668
- __publicField(this, "payments");
2669
- __publicField(this, "phone");
2670
- __publicField(this, "pdf");
2671
- __publicField(this, "settings");
2672
- __publicField(this, "socket");
2673
- __publicField(this, "static");
2674
- __publicField(this, "storage");
2675
- __publicField(this, "users");
2676
- this.api = new Api(url, opts);
2677
- this.actions = new Actions(this.api);
2678
- this.ai = new Ai(this.api);
2679
- this.analytics = new Analytics(this.api);
2680
- this.auth = new Auth(this.api, opts);
2681
- this.data = new Data(this.api);
2682
- this.email = new Email(this.api);
2683
- this.forms = new Forms(this.api);
2684
- this.groups = new Groups(this.api);
2685
- this.logger = new Logger(this.api, (opts == null ? void 0 : opts.app) || "client", opts == null ? void 0 : opts.logLevel);
2686
- this.payments = new Payments(this.api);
2687
- this.pdf = new Pdf(this.api);
2688
- this.phone = new Phone(this.api);
2689
- this.settings = new Settings(this.api);
2690
- if (opts == null ? void 0 : opts.socket) this.socket = new Socket(this.api);
2691
- this.static = new Static(this.api);
2692
- this.storage = new Storage$1(this.api);
2693
- this.client = new Client(this.api, this.settings);
2694
- this.users = new Users(this.api);
2695
- this.relayEvents(this.actions);
2696
- this.relayEvents(this.ai);
2697
- this.relayEvents(this.analytics);
2698
- this.relayEvents(this.api);
2699
- this.relayEvents(this.auth);
2700
- this.relayEvents(this.client);
2701
- this.relayEvents(this.data);
2702
- this.relayEvents(this.email);
2703
- this.relayEvents(this.groups);
2704
- this.relayEvents(this.logger);
2705
- this.relayEvents(this.payments);
2706
- this.relayEvents(this.pdf);
2707
- this.relayEvents(this.phone);
2708
- this.relayEvents(this.settings);
2709
- this.relayEvents(this.static);
2710
- this.relayEvents(this.storage);
2711
- this.relayEvents(this.users);
2712
- this.users.on(`*`, () => {
2713
- if (!this.auth.user) return;
2714
- const cached = this.users.cache.get(this.auth.user.username);
2715
- if (cached) this.auth.user = cached;
2716
- });
2717
- this.settings.on("settings:r", (event, value) => {
2718
- var _a;
2719
- this.payments.token = ((_a = value["stripe_token"]) == null ? void 0 : _a.value) || value["stripe_token"];
2720
- });
2721
- if ((opts == null ? void 0 : opts.worker) !== false && "serviceWorker" in navigator) {
2722
- navigator.serviceWorker.register((opts == null ? void 0 : opts.worker) || "/momentum.worker.js").catch(() => console.warn("Unable to load momentum worker, some features may be limited."));
2723
- }
2724
- }
2725
- }
2726
- exports2.ActionType = ActionType;
2727
- exports2.Actions = Actions;
2728
- exports2.Ai = Ai;
2729
- exports2.Analytics = Analytics;
2730
- exports2.Api = Api;
2731
- exports2.Auth = Auth;
2732
- exports2.Client = Client;
2733
- exports2.Data = Data;
2734
- exports2.Discounts = Discounts;
2735
- exports2.Email = Email;
2736
- exports2.Forms = Forms;
2737
- exports2.Groups = Groups;
2738
- exports2.Logger = Logger;
2739
- exports2.Momentum = Momentum;
2740
- exports2.PE = PE;
2741
- exports2.PES = PES;
2742
- exports2.PathEvent = PathEvent;
2743
- exports2.PathEventEmitter = PathEventEmitter;
2744
- exports2.Payments = Payments;
2745
- exports2.Pdf = Pdf;
2746
- exports2.Phone = Phone;
2747
- exports2.Settings = Settings;
2748
- exports2.Socket = Socket;
2749
- exports2.Static = Static;
2750
- exports2.Storage = Storage$1;
2751
- exports2.Token = Token;
2752
- exports2.Totp = Totp;
2753
- exports2.Users = Users;
2754
- Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
2755
- });