@sweidos/eidos 1.0.34 → 1.2.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 (53) hide show
  1. package/README.md +171 -89
  2. package/dist/action.js +197 -91
  3. package/dist/async-storage-adapter.js +15 -12
  4. package/dist/cli.js +102 -0
  5. package/dist/devtools.js +1009 -551
  6. package/dist/eidos-sw.js +280 -188
  7. package/dist/eidos.cjs +15 -0
  8. package/dist/idb.js +59 -56
  9. package/dist/index.d.ts +135 -18
  10. package/dist/index.js +46 -42
  11. package/dist/nextjs.js +1 -10
  12. package/dist/push.cjs +120 -0
  13. package/dist/push.d.ts +28 -0
  14. package/dist/push.js +113 -0
  15. package/dist/query.cjs +131 -0
  16. package/dist/query.js +121 -41
  17. package/dist/queue-storage.js +5 -4
  18. package/dist/react/Devtools.d.ts +1 -1
  19. package/dist/react/Provider.js +11 -7
  20. package/dist/react/hooks.js +48 -38
  21. package/dist/react-native.js +47 -53
  22. package/dist/replay.js +15 -0
  23. package/dist/resource.js +77 -79
  24. package/dist/runtime.js +39 -28
  25. package/dist/store-slices.js +43 -0
  26. package/dist/store.js +32 -49
  27. package/dist/stores.js +25 -22
  28. package/dist/sveltekit.js +22 -6
  29. package/dist/sw-bridge.js +64 -49
  30. package/dist/testing.cjs +165 -0
  31. package/dist/testing.js +140 -70
  32. package/dist/version.js +4 -3
  33. package/dist/vite.cjs +48 -0
  34. package/dist/vite.js +45 -29
  35. package/package.json +57 -28
  36. package/dist/action.js.map +0 -1
  37. package/dist/async-storage-adapter.js.map +0 -1
  38. package/dist/eidos.cjs.js +0 -14
  39. package/dist/eidos.cjs.js.map +0 -1
  40. package/dist/idb.js.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/query.cjs.js +0 -48
  43. package/dist/queue-storage.js.map +0 -1
  44. package/dist/react/Provider.js.map +0 -1
  45. package/dist/react/hooks.js.map +0 -1
  46. package/dist/resource.js.map +0 -1
  47. package/dist/runtime.js.map +0 -1
  48. package/dist/store.js.map +0 -1
  49. package/dist/stores.js.map +0 -1
  50. package/dist/sw-bridge.js.map +0 -1
  51. package/dist/testing.cjs.js +0 -86
  52. package/dist/version.js.map +0 -1
  53. package/dist/vite.cjs.js +0 -31
package/dist/action.js CHANGED
@@ -1,69 +1,99 @@
1
- import { useEidosStore as d } from "./store.js";
2
- import { getSwRegistration as b } from "./sw-bridge.js";
3
- import { idbClearQueue as g, idbRemoveFromQueue as Q, idbUpdateQueueItem as h, idbGetPendingItems as I, idbGetQueue as R, idbAddToQueue as k } from "./idb.js";
4
- import { _getQueueStorage as v } from "./queue-storage.js";
5
- const l = /* @__PURE__ */ new Map(), f = /* @__PURE__ */ new Map(), y = /* @__PURE__ */ new Map(), S = {
6
- add: (e) => k(e),
7
- getAll: () => R(),
8
- getPending: () => I(),
9
- update: (e, t) => h(e, t),
10
- remove: (e) => Q(e),
11
- clear: () => g()
12
- };
13
- function o() {
14
- return v() ?? S;
1
+ import { useEidosStore as y } from "./store.js";
2
+ import { getSwRegistration as _ } from "./sw-bridge.js";
3
+ import { idbQueueStorage as S } from "./idb.js";
4
+ import { _getQueueStorage as M } from "./queue-storage.js";
5
+ var h = /* @__PURE__ */ new Map(), k = /* @__PURE__ */ new Map(), C = /* @__PURE__ */ new Map(), Q = /* @__PURE__ */ new Map(), x = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map();
6
+ function u() {
7
+ return M() ?? S;
15
8
  }
16
9
  function m() {
17
10
  return crypto.randomUUID();
18
11
  }
12
+ function v(e, t, i) {
13
+ return e(...t, i);
14
+ }
19
15
  function U(e, t) {
20
- const r = t.name || e.name || m();
21
- l.set(r, e), t.onRollback && f.set(r, t.onRollback), t.onConflict && y.set(r, t.onConflict);
22
- const u = async (...a) => {
23
- var i, s;
24
- const { isOnline: n } = d.getState();
25
- if ((i = t.onOptimistic) == null || i.call(t, ...a), t.reliability === "neverLose") {
26
- if (!n)
27
- return p(r, r, a, t);
28
- try {
29
- return await e(...a);
30
- } catch {
31
- return p(r, r, a, t);
32
- }
16
+ const i = t.name || e.name || m(), a = t.namespace ? `${t.namespace}::${i}` : i;
17
+ h.set(a, e), x.set(a, t), t.onRollback && k.set(a, t.onRollback), t.onConflict && C.set(a, t.onConflict), t.conflict && Q.set(a, t.conflict);
18
+ const c = async (...n) => {
19
+ const { isOnline: s } = y.getState(), l = t.reliability === "neverLose" || t.cancellable, o = l ? m() : "";
20
+ let d;
21
+ if (t.cancellable) {
22
+ const f = new AbortController();
23
+ p.set(o, f), d = f.signal;
33
24
  }
25
+ const g = {
26
+ idempotencyKey: o,
27
+ attempt: 0,
28
+ signal: d
29
+ };
30
+ t.onOptimistic?.(...n, g);
34
31
  try {
35
- return await e(...a);
36
- } catch (w) {
37
- throw (s = t.onRollback) == null || s.call(t, ...a), w;
32
+ if (t.reliability === "neverLose") {
33
+ if (!s) return R(a, a, n, t, o);
34
+ try {
35
+ return await v(e, n, g);
36
+ } catch (f) {
37
+ if (A(f)) throw f;
38
+ return R(a, a, n, t, o);
39
+ }
40
+ }
41
+ try {
42
+ return l ? await v(e, n, g) : await e(...n);
43
+ } catch (f) {
44
+ throw t.onRollback?.(...n), f;
45
+ }
46
+ } finally {
47
+ t.cancellable && p.delete(o);
38
48
  }
49
+ }, r = async (n) => {
50
+ const s = p.get(n);
51
+ if (s)
52
+ return s.abort(), !0;
53
+ const l = (await u().getAll()).find((o) => o.idempotencyKey === n && o.status === "pending");
54
+ return l ? (y.getState().removeQueueItem(l.id), await u().remove(l.id), !0) : !1;
39
55
  };
40
- return Object.defineProperty(u, "id", { value: r, writable: !1 }), Object.defineProperty(u, "config", { value: t, writable: !1 }), u;
56
+ return Object.defineProperty(c, "id", {
57
+ value: a,
58
+ writable: !1
59
+ }), Object.defineProperty(c, "config", {
60
+ value: t,
61
+ writable: !1
62
+ }), Object.defineProperty(c, "cancel", {
63
+ value: r,
64
+ writable: !1
65
+ }), c;
41
66
  }
42
- async function p(e, t, r, u) {
43
- const a = m(), n = {
44
- id: a,
67
+ async function R(e, t, i, a, c) {
68
+ const r = m(), n = {
69
+ schemaVersion: 2,
70
+ id: r,
45
71
  actionId: e,
46
72
  actionName: t,
47
- args: r,
73
+ idempotencyKey: c,
74
+ args: i,
48
75
  queuedAt: Date.now(),
49
76
  retryCount: 0,
50
- maxRetries: u.maxRetries ?? 3,
77
+ maxRetries: a.maxRetries ?? 3,
51
78
  status: "pending",
52
- priority: u.priority ?? "normal"
79
+ priority: a.priority ?? "normal"
53
80
  };
54
- await o().add(n), d.getState().addQueueItem(n);
81
+ await u().add(n), y.getState().addQueueItem(n);
55
82
  try {
56
- const i = b();
57
- i && "sync" in i && await i.sync.register("eidos-queue-replay");
83
+ const s = _();
84
+ s && "sync" in s && await s.sync.register("eidos-queue-replay");
58
85
  } catch {
59
86
  }
60
87
  return {
61
88
  queued: !0,
62
- id: a,
89
+ id: r,
63
90
  message: `"${t}" queued — will execute when online`
64
91
  };
65
92
  }
66
- function x(e) {
93
+ function A(e) {
94
+ return e instanceof DOMException && e.name === "AbortError";
95
+ }
96
+ function K(e) {
67
97
  if (e instanceof Response) return e.status >= 400 && e.status < 500;
68
98
  if (typeof e == "object" && e !== null) {
69
99
  const t = e.status;
@@ -71,76 +101,152 @@ function x(e) {
71
101
  }
72
102
  return !1;
73
103
  }
74
- function C(e) {
104
+ function O(e) {
75
105
  return Math.min(2e3 * 2 ** e, 3e5) * (0.8 + Math.random() * 0.4);
76
106
  }
77
- let c = !1;
78
- async function j() {
79
- const e = d.getState();
80
- if (!e.isOnline || c)
81
- return { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0, conflicted: 0 };
82
- c = !0;
107
+ function w() {
108
+ return {
109
+ attempted: 0,
110
+ succeeded: 0,
111
+ failed: 0,
112
+ retrying: 0,
113
+ skipped: 0,
114
+ conflicted: 0,
115
+ cancelled: 0
116
+ };
117
+ }
118
+ var b = !1, q = "eidos-queue-replay";
119
+ async function $() {
120
+ const e = y.getState();
121
+ if (!e.isOnline) return w();
122
+ if (typeof navigator < "u" && navigator.locks) return navigator.locks.request(q, { ifAvailable: !0 }, async (t) => t ? I(e) : w());
123
+ if (b) return w();
124
+ b = !0;
83
125
  try {
84
- return await M(e);
126
+ return await I(e);
85
127
  } finally {
86
- c = !1;
128
+ b = !1;
87
129
  }
88
130
  }
89
- async function _(e, t) {
90
- var u;
91
- const r = l.get(e.actionId);
92
- if (!r) return "skipped";
131
+ async function E(e, t) {
132
+ const i = h.get(e.actionId);
133
+ if (!i) return "skipped";
134
+ const a = x.get(e.actionId)?.cancellable;
135
+ let c;
136
+ if (a) {
137
+ const n = new AbortController();
138
+ p.set(e.idempotencyKey, n), c = n.signal;
139
+ }
140
+ const r = {
141
+ idempotencyKey: e.idempotencyKey,
142
+ attempt: e.retryCount,
143
+ signal: c
144
+ };
93
145
  try {
94
- await r(...e.args);
95
- const a = Date.now();
96
- return t.updateQueueItem(e.id, { status: "succeeded", completedAt: a }), await o().update(e.id, { status: "succeeded", completedAt: a }), setTimeout(() => {
97
- t.removeQueueItem(e.id), o().remove(e.id);
146
+ await v(i, e.args, r);
147
+ const n = Date.now();
148
+ return t.updateQueueItem(e.id, {
149
+ status: "succeeded",
150
+ completedAt: n
151
+ }), await u().update(e.id, {
152
+ status: "succeeded",
153
+ completedAt: n
154
+ }), setTimeout(() => {
155
+ t.removeQueueItem(e.id), u().remove(e.id);
98
156
  }, 3e3), "succeeded";
99
- } catch (a) {
100
- if (x(a)) {
101
- const i = y.get(e.actionId);
102
- if (i && i(a, e.args) === "skip")
103
- return t.removeQueueItem(e.id), await o().remove(e.id), "conflicted";
157
+ } catch (n) {
158
+ if (A(n))
159
+ return t.removeQueueItem(e.id), await u().remove(e.id), "cancelled";
160
+ if (K(n)) {
161
+ const l = Q.get(e.actionId);
162
+ let o;
163
+ if (l) switch (l.strategy) {
164
+ case "serverWins":
165
+ o = "skip";
166
+ break;
167
+ case "clientWins":
168
+ case "lastWriteWins":
169
+ o = "retry";
170
+ break;
171
+ case "merge":
172
+ case "custom": {
173
+ const d = {
174
+ error: n,
175
+ args: e.args,
176
+ attempt: e.retryCount,
177
+ idempotencyKey: e.idempotencyKey
178
+ };
179
+ o = l.resolve?.(d) ?? "retry";
180
+ break;
181
+ }
182
+ }
183
+ else {
184
+ const d = C.get(e.actionId);
185
+ d && (o = d(n, e.args));
186
+ }
187
+ if (o === "skip")
188
+ return t.removeQueueItem(e.id), await u().remove(e.id), "conflicted";
189
+ o && typeof o == "object" && (e.args = o.resolved, t.updateQueueItem(e.id, { args: o.resolved }), await u().update(e.id, { args: o.resolved }));
104
190
  }
105
- const n = e.retryCount + 1;
106
- if (n >= e.maxRetries)
107
- return t.updateQueueItem(e.id, { status: "failed", error: String(a), retryCount: n }), await o().update(e.id, { status: "failed", error: String(a), retryCount: n }), (u = f.get(e.actionId)) == null || u(...e.args), "failed";
191
+ const s = e.retryCount + 1;
192
+ if (s >= e.maxRetries)
193
+ return t.updateQueueItem(e.id, {
194
+ status: "failed",
195
+ error: String(n),
196
+ retryCount: s
197
+ }), await u().update(e.id, {
198
+ status: "failed",
199
+ error: String(n),
200
+ retryCount: s
201
+ }), k.get(e.actionId)?.(...e.args), "failed";
108
202
  {
109
- const i = Date.now() + C(n);
110
- return t.updateQueueItem(e.id, { status: "pending", retryCount: n, nextRetryAt: i }), await o().update(e.id, { status: "pending", retryCount: n, nextRetryAt: i }), "retrying";
203
+ const l = Date.now() + O(s);
204
+ return t.updateQueueItem(e.id, {
205
+ status: "pending",
206
+ retryCount: s,
207
+ nextRetryAt: l
208
+ }), await u().update(e.id, {
209
+ status: "pending",
210
+ retryCount: s,
211
+ nextRetryAt: l
212
+ }), "retrying";
111
213
  }
214
+ } finally {
215
+ a && p.delete(e.idempotencyKey);
112
216
  }
113
217
  }
114
- async function A(e, t, r) {
218
+ async function D(e, t, i) {
115
219
  if (e.length === 0) return;
116
- const u = e.filter((n) => l.has(n.actionId));
117
- if (r.skipped += e.length - u.length, u.length > 0) {
118
- t.batchUpdateQueueItems(u.map((n) => ({ id: n.id, update: { status: "replaying" } })));
119
- for (const n of u)
120
- o().update(n.id, { status: "replaying" });
220
+ const a = e.filter((r) => h.has(r.actionId));
221
+ if (i.skipped += e.length - a.length, a.length > 0) {
222
+ t.batchUpdateQueueItems(a.map((r) => ({
223
+ id: r.id,
224
+ update: { status: "replaying" }
225
+ })));
226
+ for (const r of a) u().update(r.id, { status: "replaying" });
121
227
  }
122
- const a = await Promise.allSettled(u.map((n) => _(n, t)));
123
- for (const n of a) {
124
- const i = n.status === "fulfilled" ? n.value : "failed";
125
- i === "skipped" ? r.skipped++ : i === "conflicted" ? r.conflicted++ : (r.attempted++, r[i]++);
228
+ const c = await Promise.allSettled(a.map((r) => E(r, t)));
229
+ for (const r of c) {
230
+ const n = r.status === "fulfilled" ? r.value : "failed";
231
+ n === "skipped" ? i.skipped++ : n === "conflicted" ? i.conflicted++ : n === "cancelled" ? i.cancelled++ : (i.attempted++, i[n]++);
126
232
  }
127
233
  }
128
- async function M(e) {
129
- const t = await o().getPending(), r = Date.now(), u = t.filter(
130
- (n) => n.retryCount < n.maxRetries && (!n.nextRetryAt || n.nextRetryAt <= r)
131
- ), a = { attempted: 0, succeeded: 0, failed: 0, retrying: 0, skipped: 0, conflicted: 0 };
132
- for (const n of ["high", "normal", "low"]) {
133
- const i = u.filter((s) => (s.priority ?? "normal") === n);
134
- await A(i, e, a);
135
- }
136
- return a;
234
+ async function I(e) {
235
+ const t = await u().getPending(), i = Date.now(), a = t.filter((r) => r.retryCount < r.maxRetries && (!r.nextRetryAt || r.nextRetryAt <= i)), c = w();
236
+ for (const r of [
237
+ "high",
238
+ "normal",
239
+ "low"
240
+ ]) await D(a.filter((n) => (n.priority ?? "normal") === r), e, c);
241
+ return c;
137
242
  }
138
243
  async function T() {
139
- await o().clear(), d.getState().hydrateQueue([]);
244
+ await u().clear(), y.getState().hydrateQueue([]);
140
245
  }
141
246
  export {
142
247
  U as action,
143
248
  T as clearQueue,
144
- j as replayQueue
249
+ $ as replayQueue
145
250
  };
146
- //# sourceMappingURL=action.js.map
251
+
252
+ //# sourceMappingURL=action.js.map
@@ -1,5 +1,4 @@
1
- const i = "@eidos:queue";
2
- class l {
1
+ var i = "@eidos:queue", l = class {
3
2
  constructor(t) {
4
3
  this.storage = t;
5
4
  }
@@ -15,28 +14,32 @@ class l {
15
14
  await this.storage.setItem(i, JSON.stringify(t));
16
15
  }
17
16
  async add(t) {
18
- const e = await this.readAll();
19
- e.push(t), await this.writeAll(e);
17
+ const a = await this.readAll();
18
+ a.push(t), await this.writeAll(a);
20
19
  }
21
20
  async getAll() {
22
21
  return this.readAll();
23
22
  }
24
23
  async getPending() {
25
- return (await this.readAll()).filter((e) => e.status === "pending" || e.status === "failed");
24
+ return (await this.readAll()).filter((t) => t.status === "pending" || t.status === "failed");
26
25
  }
27
- async update(t, e) {
28
- const a = await this.readAll(), s = a.findIndex((r) => r.id === t);
29
- s !== -1 && (a[s] = { ...a[s], ...e }), await this.writeAll(a);
26
+ async update(t, a) {
27
+ const e = await this.readAll(), s = e.findIndex((r) => r.id === t);
28
+ s !== -1 && (e[s] = {
29
+ ...e[s],
30
+ ...a
31
+ }), await this.writeAll(e);
30
32
  }
31
33
  async remove(t) {
32
- const e = await this.readAll();
33
- await this.writeAll(e.filter((a) => a.id !== t));
34
+ const a = await this.readAll();
35
+ await this.writeAll(a.filter((e) => e.id !== t));
34
36
  }
35
37
  async clear() {
36
38
  await this.storage.removeItem(i);
37
39
  }
38
- }
40
+ };
39
41
  export {
40
42
  l as AsyncStorageQueueStorage
41
43
  };
42
- //# sourceMappingURL=async-storage-adapter.js.map
44
+
45
+ //# sourceMappingURL=async-storage-adapter.js.map
package/dist/cli.js ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import { generateKeyPairSync } from "node:crypto";
3
+ import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { createInterface } from "node:readline/promises";
6
+ //#region src/cli.ts
7
+ var PUBLIC_KEY_NAME = "EIDOS_VAPID_PUBLIC_KEY";
8
+ var PRIVATE_KEY_NAME = "EIDOS_VAPID_PRIVATE_KEY";
9
+ function base64UrlFromBuffer(buf) {
10
+ return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
11
+ }
12
+ function base64UrlToBuffer(b64url) {
13
+ const b64 = (b64url + "=".repeat((4 - b64url.length % 4) % 4)).replace(/-/g, "+").replace(/_/g, "/");
14
+ return Buffer.from(b64, "base64");
15
+ }
16
+ /** Pads a base64url-encoded big-endian integer to `length` bytes (leading zeros). */
17
+ function padTo(b64url, length) {
18
+ const buf = base64UrlToBuffer(b64url);
19
+ if (buf.length === length) return buf;
20
+ const padded = Buffer.alloc(length);
21
+ buf.copy(padded, length - buf.length);
22
+ return padded;
23
+ }
24
+ function generateVapidKeys() {
25
+ const { publicKey, privateKey } = generateKeyPairSync("ec", { namedCurve: "prime256v1" });
26
+ const pubJwk = publicKey.export({ format: "jwk" });
27
+ const privJwk = privateKey.export({ format: "jwk" });
28
+ const x = padTo(pubJwk.x, 32);
29
+ const y = padTo(pubJwk.y, 32);
30
+ const point = Buffer.concat([
31
+ Buffer.from([4]),
32
+ x,
33
+ y
34
+ ]);
35
+ const d = padTo(privJwk.d, 32);
36
+ return {
37
+ publicKey: base64UrlFromBuffer(point),
38
+ privateKey: base64UrlFromBuffer(d)
39
+ };
40
+ }
41
+ function detectEnvPrefix(cwd) {
42
+ if (existsSync(resolve(cwd, "next.config.js")) || existsSync(resolve(cwd, "next.config.ts"))) return "NEXT_PUBLIC_";
43
+ if (existsSync(resolve(cwd, "vite.config.ts")) || existsSync(resolve(cwd, "vite.config.js"))) return "VITE_";
44
+ if (existsSync(resolve(cwd, "svelte.config.js"))) return "PUBLIC_";
45
+ if (existsSync(resolve(cwd, "nuxt.config.ts")) || existsSync(resolve(cwd, "nuxt.config.js"))) return "NUXT_PUBLIC_";
46
+ return "";
47
+ }
48
+ function pickEnvFile(cwd) {
49
+ if (existsSync(resolve(cwd, ".env.local"))) return resolve(cwd, ".env.local");
50
+ if (existsSync(resolve(cwd, ".env"))) return resolve(cwd, ".env");
51
+ return resolve(cwd, ".env.local");
52
+ }
53
+ async function confirm(message) {
54
+ const rl = createInterface({
55
+ input: process.stdin,
56
+ output: process.stdout
57
+ });
58
+ const answer = await rl.question(`${message} (type "yes" to continue): `);
59
+ rl.close();
60
+ return answer.trim().toLowerCase() === "yes";
61
+ }
62
+ async function generateVapidKeysCommand() {
63
+ const cwd = process.cwd();
64
+ const publicKeyName = `${detectEnvPrefix(cwd)}${PUBLIC_KEY_NAME}`;
65
+ const force = process.argv.includes("--force");
66
+ const envFile = pickEnvFile(cwd);
67
+ const existing = existsSync(envFile) ? readFileSync(envFile, "utf8") : "";
68
+ const hasPublic = new RegExp(`^${publicKeyName}=`, "m").test(existing);
69
+ const hasPrivate = new RegExp(`^${PRIVATE_KEY_NAME}=`, "m").test(existing);
70
+ if (hasPublic && hasPrivate) {
71
+ if (!force) {
72
+ console.log(`VAPID keys already configured in ${envFile} — nothing to do.`);
73
+ console.log("Pass --force to regenerate (this invalidates ALL existing push subscriptions).");
74
+ return;
75
+ }
76
+ if (!await confirm(`⚠ Regenerating VAPID keys will invalidate ALL existing push subscriptions in ${envFile}. Continue?`)) {
77
+ console.log("Aborted.");
78
+ return;
79
+ }
80
+ }
81
+ const { publicKey, privateKey } = generateVapidKeys();
82
+ const lines = [`${publicKeyName}=${publicKey}`, `${PRIVATE_KEY_NAME}=${privateKey}`];
83
+ if (hasPublic && hasPrivate) writeFileSync(envFile, `${existing.split("\n").filter((line) => !line.startsWith(`${publicKeyName}=`) && !line.startsWith(`${PRIVATE_KEY_NAME}=`)).join("\n").replace(/\n+$/, "")}\n${lines.join("\n")}\n`);
84
+ else appendFileSync(envFile, `${existing.length > 0 && !existing.endsWith("\n") ? "\n" : ""}${lines.join("\n")}\n`);
85
+ console.log(`✓ VAPID keys written to ${envFile}`);
86
+ console.log("");
87
+ console.log(` ${publicKeyName}=${publicKey}`);
88
+ console.log(` ${PRIVATE_KEY_NAME}=${privateKey}`);
89
+ console.log("");
90
+ console.log(`Give ${PRIVATE_KEY_NAME} and ${publicKeyName} to your backend.`);
91
+ console.log("Backend needs a VAPID-capable web-push library (any language) to send notifications using subscription objects received via onSubscribe.");
92
+ }
93
+ var command = process.argv[2];
94
+ switch (command) {
95
+ case "generate-vapid-keys":
96
+ await generateVapidKeysCommand();
97
+ break;
98
+ default:
99
+ console.log("Usage: eidos generate-vapid-keys [--force]");
100
+ process.exit(command ? 1 : 0);
101
+ }
102
+ //#endregion