@rei-standard/amsg-client 2.8.0 → 2.9.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +40 -8
- package/dist/index.d.cts +51 -8
- package/dist/index.d.ts +51 -8
- package/dist/index.mjs +40 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -97,6 +97,7 @@ var ReiClient = class {
|
|
|
97
97
|
this._userKey = null;
|
|
98
98
|
this._instantEncryption = instantEncryption;
|
|
99
99
|
this._instantClientToken = typeof config.instantClientToken === "string" && config.instantClientToken ? config.instantClientToken : "";
|
|
100
|
+
this._serverToken = typeof config.serverToken === "string" && config.serverToken ? config.serverToken : "";
|
|
100
101
|
this._maxPayloadBytes = normalizeMaxPayloadBytes(config.maxPayloadBytes);
|
|
101
102
|
this._lowLevelWarned = /* @__PURE__ */ new Set();
|
|
102
103
|
}
|
|
@@ -110,6 +111,17 @@ var ReiClient = class {
|
|
|
110
111
|
_resolveBaseUrl(endpointName) {
|
|
111
112
|
return this._customBaseUrls[endpointName] || this._baseUrl;
|
|
112
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Attach the single-user shared secret to amsg-server endpoint requests.
|
|
116
|
+
* Never applied to the instant path (that uses instantClientToken).
|
|
117
|
+
* @private
|
|
118
|
+
* @param {Record<string, string>} headers
|
|
119
|
+
* @returns {Record<string, string>}
|
|
120
|
+
*/
|
|
121
|
+
_withServerToken(headers) {
|
|
122
|
+
if (this._serverToken) headers["X-Client-Token"] = this._serverToken;
|
|
123
|
+
return headers;
|
|
124
|
+
}
|
|
113
125
|
// ─── Initialisation ─────────────────────────────────────────────
|
|
114
126
|
/**
|
|
115
127
|
* Fetch the user-specific encryption key.
|
|
@@ -128,7 +140,7 @@ var ReiClient = class {
|
|
|
128
140
|
}
|
|
129
141
|
const res = await fetch(`${this._baseUrl}/get-user-key`, {
|
|
130
142
|
method: "GET",
|
|
131
|
-
headers: { "X-User-Id": this._userId }
|
|
143
|
+
headers: this._withServerToken({ "X-User-Id": this._userId })
|
|
132
144
|
});
|
|
133
145
|
const json = await res.json();
|
|
134
146
|
if (!json.success) throw new Error(json.error?.message || "Failed to fetch user key");
|
|
@@ -138,6 +150,26 @@ var ReiClient = class {
|
|
|
138
150
|
}
|
|
139
151
|
this._userKey = this._hexToUint8Array(userKey);
|
|
140
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Fetch the amsg-server worker's own VAPID public key.
|
|
155
|
+
*
|
|
156
|
+
* A browser needs this as `applicationServerKey` when creating a Web Push
|
|
157
|
+
* subscription. Each self-hosted worker owns its VAPID keypair, so pull the
|
|
158
|
+
* key at runtime rather than baking it into the frontend. Sends
|
|
159
|
+
* `X-Client-Token` when a `serverToken` is configured.
|
|
160
|
+
*
|
|
161
|
+
* @returns {Promise<string>} The base64url VAPID public key.
|
|
162
|
+
* @throws {Error} When the worker has no VAPID public key configured (503).
|
|
163
|
+
*/
|
|
164
|
+
async getVapidPublicKey() {
|
|
165
|
+
const res = await fetch(`${this._baseUrl}/vapid-public-key`, {
|
|
166
|
+
method: "GET",
|
|
167
|
+
headers: this._withServerToken({})
|
|
168
|
+
});
|
|
169
|
+
const json = await res.json();
|
|
170
|
+
if (!json.success) throw new Error(json.error?.message || "Failed to fetch VAPID public key");
|
|
171
|
+
return json.publicKey;
|
|
172
|
+
}
|
|
141
173
|
// ─── Public API ─────────────────────────────────────────────────
|
|
142
174
|
/**
|
|
143
175
|
* Schedule a message.
|
|
@@ -165,12 +197,12 @@ var ReiClient = class {
|
|
|
165
197
|
const encrypted = await this._encrypt(json);
|
|
166
198
|
const res = await fetch(`${this._baseUrl}/schedule-message`, {
|
|
167
199
|
method: "POST",
|
|
168
|
-
headers: {
|
|
200
|
+
headers: this._withServerToken({
|
|
169
201
|
"Content-Type": "application/json",
|
|
170
202
|
"X-User-Id": this._userId,
|
|
171
203
|
"X-Payload-Encrypted": "true",
|
|
172
204
|
"X-Encryption-Version": "1"
|
|
173
|
-
},
|
|
205
|
+
}),
|
|
174
206
|
body: JSON.stringify(encrypted)
|
|
175
207
|
});
|
|
176
208
|
return res.json();
|
|
@@ -508,12 +540,12 @@ var ReiClient = class {
|
|
|
508
540
|
const encrypted = await this._encrypt(json);
|
|
509
541
|
const res = await fetch(`${this._baseUrl}/update-message?id=${encodeURIComponent(uuid)}`, {
|
|
510
542
|
method: "PUT",
|
|
511
|
-
headers: {
|
|
543
|
+
headers: this._withServerToken({
|
|
512
544
|
"Content-Type": "application/json",
|
|
513
545
|
"X-User-Id": this._userId,
|
|
514
546
|
"X-Payload-Encrypted": "true",
|
|
515
547
|
"X-Encryption-Version": "1"
|
|
516
|
-
},
|
|
548
|
+
}),
|
|
517
549
|
body: JSON.stringify(encrypted)
|
|
518
550
|
});
|
|
519
551
|
return res.json();
|
|
@@ -527,7 +559,7 @@ var ReiClient = class {
|
|
|
527
559
|
async cancelMessage(uuid) {
|
|
528
560
|
const res = await fetch(`${this._baseUrl}/cancel-message?id=${encodeURIComponent(uuid)}`, {
|
|
529
561
|
method: "DELETE",
|
|
530
|
-
headers: { "X-User-Id": this._userId }
|
|
562
|
+
headers: this._withServerToken({ "X-User-Id": this._userId })
|
|
531
563
|
});
|
|
532
564
|
return res.json();
|
|
533
565
|
}
|
|
@@ -549,11 +581,11 @@ var ReiClient = class {
|
|
|
549
581
|
const url = `${this._baseUrl}/messages${qs ? "?" + qs : ""}`;
|
|
550
582
|
const res = await fetch(url, {
|
|
551
583
|
method: "GET",
|
|
552
|
-
headers: {
|
|
584
|
+
headers: this._withServerToken({
|
|
553
585
|
"X-User-Id": this._userId,
|
|
554
586
|
"X-Response-Encrypted": "true",
|
|
555
587
|
"X-Encryption-Version": "1"
|
|
556
|
-
}
|
|
588
|
+
})
|
|
557
589
|
});
|
|
558
590
|
const json = await res.json();
|
|
559
591
|
if (!json?.success || json?.encrypted !== true) return json;
|
package/dist/index.d.cts
CHANGED
|
@@ -75,6 +75,11 @@ const TEXT_ENCODER = new TextEncoder();
|
|
|
75
75
|
* inside any frontend bundle that uses it, so
|
|
76
76
|
* devtools can read it. Use for casual URL-direct
|
|
77
77
|
* abuse only.
|
|
78
|
+
* @property {string} [serverToken] - Optional shared secret for a single-user amsg-server.
|
|
79
|
+
* When set, sent as the `X-Client-Token` header on
|
|
80
|
+
* amsg-server endpoints (schedule / messages / update /
|
|
81
|
+
* cancel / user-key / init). Not applied to the instant
|
|
82
|
+
* path (that uses `instantClientToken`).
|
|
78
83
|
* @property {number|null} [maxPayloadBytes=null] - Optional local UTF-8 byte cap for outgoing request
|
|
79
84
|
* payloads before encryption. `null` / omitted means
|
|
80
85
|
* no SDK-level request-size limit.
|
|
@@ -367,6 +372,10 @@ class ReiClient {
|
|
|
367
372
|
? config.instantClientToken
|
|
368
373
|
: '';
|
|
369
374
|
/** @private */
|
|
375
|
+
this._serverToken = typeof config.serverToken === 'string' && config.serverToken
|
|
376
|
+
? config.serverToken
|
|
377
|
+
: '';
|
|
378
|
+
/** @private */
|
|
370
379
|
this._maxPayloadBytes = normalizeMaxPayloadBytes(config.maxPayloadBytes);
|
|
371
380
|
/**
|
|
372
381
|
* Per-instance latch (set of method names already warned). The
|
|
@@ -387,6 +396,18 @@ class ReiClient {
|
|
|
387
396
|
return this._customBaseUrls[endpointName] || this._baseUrl;
|
|
388
397
|
}
|
|
389
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Attach the single-user shared secret to amsg-server endpoint requests.
|
|
401
|
+
* Never applied to the instant path (that uses instantClientToken).
|
|
402
|
+
* @private
|
|
403
|
+
* @param {Record<string, string>} headers
|
|
404
|
+
* @returns {Record<string, string>}
|
|
405
|
+
*/
|
|
406
|
+
_withServerToken(headers) {
|
|
407
|
+
if (this._serverToken) headers['X-Client-Token'] = this._serverToken;
|
|
408
|
+
return headers;
|
|
409
|
+
}
|
|
410
|
+
|
|
390
411
|
// ─── Initialisation ─────────────────────────────────────────────
|
|
391
412
|
|
|
392
413
|
/**
|
|
@@ -407,7 +428,7 @@ class ReiClient {
|
|
|
407
428
|
|
|
408
429
|
const res = await fetch(`${this._baseUrl}/get-user-key`, {
|
|
409
430
|
method: 'GET',
|
|
410
|
-
headers: { 'X-User-Id': this._userId }
|
|
431
|
+
headers: this._withServerToken({ 'X-User-Id': this._userId })
|
|
411
432
|
});
|
|
412
433
|
|
|
413
434
|
const json = await res.json();
|
|
@@ -421,6 +442,28 @@ class ReiClient {
|
|
|
421
442
|
this._userKey = this._hexToUint8Array(userKey);
|
|
422
443
|
}
|
|
423
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Fetch the amsg-server worker's own VAPID public key.
|
|
447
|
+
*
|
|
448
|
+
* A browser needs this as `applicationServerKey` when creating a Web Push
|
|
449
|
+
* subscription. Each self-hosted worker owns its VAPID keypair, so pull the
|
|
450
|
+
* key at runtime rather than baking it into the frontend. Sends
|
|
451
|
+
* `X-Client-Token` when a `serverToken` is configured.
|
|
452
|
+
*
|
|
453
|
+
* @returns {Promise<string>} The base64url VAPID public key.
|
|
454
|
+
* @throws {Error} When the worker has no VAPID public key configured (503).
|
|
455
|
+
*/
|
|
456
|
+
async getVapidPublicKey() {
|
|
457
|
+
const res = await fetch(`${this._baseUrl}/vapid-public-key`, {
|
|
458
|
+
method: 'GET',
|
|
459
|
+
headers: this._withServerToken({})
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const json = await res.json();
|
|
463
|
+
if (!json.success) throw new Error(json.error?.message || 'Failed to fetch VAPID public key');
|
|
464
|
+
return json.publicKey;
|
|
465
|
+
}
|
|
466
|
+
|
|
424
467
|
// ─── Public API ─────────────────────────────────────────────────
|
|
425
468
|
|
|
426
469
|
/**
|
|
@@ -450,12 +493,12 @@ class ReiClient {
|
|
|
450
493
|
|
|
451
494
|
const res = await fetch(`${this._baseUrl}/schedule-message`, {
|
|
452
495
|
method: 'POST',
|
|
453
|
-
headers: {
|
|
496
|
+
headers: this._withServerToken({
|
|
454
497
|
'Content-Type': 'application/json',
|
|
455
498
|
'X-User-Id': this._userId,
|
|
456
499
|
'X-Payload-Encrypted': 'true',
|
|
457
500
|
'X-Encryption-Version': '1'
|
|
458
|
-
},
|
|
501
|
+
}),
|
|
459
502
|
body: JSON.stringify(encrypted)
|
|
460
503
|
});
|
|
461
504
|
|
|
@@ -883,12 +926,12 @@ class ReiClient {
|
|
|
883
926
|
|
|
884
927
|
const res = await fetch(`${this._baseUrl}/update-message?id=${encodeURIComponent(uuid)}`, {
|
|
885
928
|
method: 'PUT',
|
|
886
|
-
headers: {
|
|
929
|
+
headers: this._withServerToken({
|
|
887
930
|
'Content-Type': 'application/json',
|
|
888
931
|
'X-User-Id': this._userId,
|
|
889
932
|
'X-Payload-Encrypted': 'true',
|
|
890
933
|
'X-Encryption-Version': '1'
|
|
891
|
-
},
|
|
934
|
+
}),
|
|
892
935
|
body: JSON.stringify(encrypted)
|
|
893
936
|
});
|
|
894
937
|
|
|
@@ -904,7 +947,7 @@ class ReiClient {
|
|
|
904
947
|
async cancelMessage(uuid) {
|
|
905
948
|
const res = await fetch(`${this._baseUrl}/cancel-message?id=${encodeURIComponent(uuid)}`, {
|
|
906
949
|
method: 'DELETE',
|
|
907
|
-
headers: { 'X-User-Id': this._userId }
|
|
950
|
+
headers: this._withServerToken({ 'X-User-Id': this._userId })
|
|
908
951
|
});
|
|
909
952
|
|
|
910
953
|
return res.json();
|
|
@@ -930,11 +973,11 @@ class ReiClient {
|
|
|
930
973
|
|
|
931
974
|
const res = await fetch(url, {
|
|
932
975
|
method: 'GET',
|
|
933
|
-
headers: {
|
|
976
|
+
headers: this._withServerToken({
|
|
934
977
|
'X-User-Id': this._userId,
|
|
935
978
|
'X-Response-Encrypted': 'true',
|
|
936
979
|
'X-Encryption-Version': '1'
|
|
937
|
-
}
|
|
980
|
+
})
|
|
938
981
|
});
|
|
939
982
|
|
|
940
983
|
const json = await res.json();
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,11 @@ const TEXT_ENCODER = new TextEncoder();
|
|
|
75
75
|
* inside any frontend bundle that uses it, so
|
|
76
76
|
* devtools can read it. Use for casual URL-direct
|
|
77
77
|
* abuse only.
|
|
78
|
+
* @property {string} [serverToken] - Optional shared secret for a single-user amsg-server.
|
|
79
|
+
* When set, sent as the `X-Client-Token` header on
|
|
80
|
+
* amsg-server endpoints (schedule / messages / update /
|
|
81
|
+
* cancel / user-key / init). Not applied to the instant
|
|
82
|
+
* path (that uses `instantClientToken`).
|
|
78
83
|
* @property {number|null} [maxPayloadBytes=null] - Optional local UTF-8 byte cap for outgoing request
|
|
79
84
|
* payloads before encryption. `null` / omitted means
|
|
80
85
|
* no SDK-level request-size limit.
|
|
@@ -367,6 +372,10 @@ class ReiClient {
|
|
|
367
372
|
? config.instantClientToken
|
|
368
373
|
: '';
|
|
369
374
|
/** @private */
|
|
375
|
+
this._serverToken = typeof config.serverToken === 'string' && config.serverToken
|
|
376
|
+
? config.serverToken
|
|
377
|
+
: '';
|
|
378
|
+
/** @private */
|
|
370
379
|
this._maxPayloadBytes = normalizeMaxPayloadBytes(config.maxPayloadBytes);
|
|
371
380
|
/**
|
|
372
381
|
* Per-instance latch (set of method names already warned). The
|
|
@@ -387,6 +396,18 @@ class ReiClient {
|
|
|
387
396
|
return this._customBaseUrls[endpointName] || this._baseUrl;
|
|
388
397
|
}
|
|
389
398
|
|
|
399
|
+
/**
|
|
400
|
+
* Attach the single-user shared secret to amsg-server endpoint requests.
|
|
401
|
+
* Never applied to the instant path (that uses instantClientToken).
|
|
402
|
+
* @private
|
|
403
|
+
* @param {Record<string, string>} headers
|
|
404
|
+
* @returns {Record<string, string>}
|
|
405
|
+
*/
|
|
406
|
+
_withServerToken(headers) {
|
|
407
|
+
if (this._serverToken) headers['X-Client-Token'] = this._serverToken;
|
|
408
|
+
return headers;
|
|
409
|
+
}
|
|
410
|
+
|
|
390
411
|
// ─── Initialisation ─────────────────────────────────────────────
|
|
391
412
|
|
|
392
413
|
/**
|
|
@@ -407,7 +428,7 @@ class ReiClient {
|
|
|
407
428
|
|
|
408
429
|
const res = await fetch(`${this._baseUrl}/get-user-key`, {
|
|
409
430
|
method: 'GET',
|
|
410
|
-
headers: { 'X-User-Id': this._userId }
|
|
431
|
+
headers: this._withServerToken({ 'X-User-Id': this._userId })
|
|
411
432
|
});
|
|
412
433
|
|
|
413
434
|
const json = await res.json();
|
|
@@ -421,6 +442,28 @@ class ReiClient {
|
|
|
421
442
|
this._userKey = this._hexToUint8Array(userKey);
|
|
422
443
|
}
|
|
423
444
|
|
|
445
|
+
/**
|
|
446
|
+
* Fetch the amsg-server worker's own VAPID public key.
|
|
447
|
+
*
|
|
448
|
+
* A browser needs this as `applicationServerKey` when creating a Web Push
|
|
449
|
+
* subscription. Each self-hosted worker owns its VAPID keypair, so pull the
|
|
450
|
+
* key at runtime rather than baking it into the frontend. Sends
|
|
451
|
+
* `X-Client-Token` when a `serverToken` is configured.
|
|
452
|
+
*
|
|
453
|
+
* @returns {Promise<string>} The base64url VAPID public key.
|
|
454
|
+
* @throws {Error} When the worker has no VAPID public key configured (503).
|
|
455
|
+
*/
|
|
456
|
+
async getVapidPublicKey() {
|
|
457
|
+
const res = await fetch(`${this._baseUrl}/vapid-public-key`, {
|
|
458
|
+
method: 'GET',
|
|
459
|
+
headers: this._withServerToken({})
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const json = await res.json();
|
|
463
|
+
if (!json.success) throw new Error(json.error?.message || 'Failed to fetch VAPID public key');
|
|
464
|
+
return json.publicKey;
|
|
465
|
+
}
|
|
466
|
+
|
|
424
467
|
// ─── Public API ─────────────────────────────────────────────────
|
|
425
468
|
|
|
426
469
|
/**
|
|
@@ -450,12 +493,12 @@ class ReiClient {
|
|
|
450
493
|
|
|
451
494
|
const res = await fetch(`${this._baseUrl}/schedule-message`, {
|
|
452
495
|
method: 'POST',
|
|
453
|
-
headers: {
|
|
496
|
+
headers: this._withServerToken({
|
|
454
497
|
'Content-Type': 'application/json',
|
|
455
498
|
'X-User-Id': this._userId,
|
|
456
499
|
'X-Payload-Encrypted': 'true',
|
|
457
500
|
'X-Encryption-Version': '1'
|
|
458
|
-
},
|
|
501
|
+
}),
|
|
459
502
|
body: JSON.stringify(encrypted)
|
|
460
503
|
});
|
|
461
504
|
|
|
@@ -883,12 +926,12 @@ class ReiClient {
|
|
|
883
926
|
|
|
884
927
|
const res = await fetch(`${this._baseUrl}/update-message?id=${encodeURIComponent(uuid)}`, {
|
|
885
928
|
method: 'PUT',
|
|
886
|
-
headers: {
|
|
929
|
+
headers: this._withServerToken({
|
|
887
930
|
'Content-Type': 'application/json',
|
|
888
931
|
'X-User-Id': this._userId,
|
|
889
932
|
'X-Payload-Encrypted': 'true',
|
|
890
933
|
'X-Encryption-Version': '1'
|
|
891
|
-
},
|
|
934
|
+
}),
|
|
892
935
|
body: JSON.stringify(encrypted)
|
|
893
936
|
});
|
|
894
937
|
|
|
@@ -904,7 +947,7 @@ class ReiClient {
|
|
|
904
947
|
async cancelMessage(uuid) {
|
|
905
948
|
const res = await fetch(`${this._baseUrl}/cancel-message?id=${encodeURIComponent(uuid)}`, {
|
|
906
949
|
method: 'DELETE',
|
|
907
|
-
headers: { 'X-User-Id': this._userId }
|
|
950
|
+
headers: this._withServerToken({ 'X-User-Id': this._userId })
|
|
908
951
|
});
|
|
909
952
|
|
|
910
953
|
return res.json();
|
|
@@ -930,11 +973,11 @@ class ReiClient {
|
|
|
930
973
|
|
|
931
974
|
const res = await fetch(url, {
|
|
932
975
|
method: 'GET',
|
|
933
|
-
headers: {
|
|
976
|
+
headers: this._withServerToken({
|
|
934
977
|
'X-User-Id': this._userId,
|
|
935
978
|
'X-Response-Encrypted': 'true',
|
|
936
979
|
'X-Encryption-Version': '1'
|
|
937
|
-
}
|
|
980
|
+
})
|
|
938
981
|
});
|
|
939
982
|
|
|
940
983
|
const json = await res.json();
|
package/dist/index.mjs
CHANGED
|
@@ -75,6 +75,7 @@ var ReiClient = class {
|
|
|
75
75
|
this._userKey = null;
|
|
76
76
|
this._instantEncryption = instantEncryption;
|
|
77
77
|
this._instantClientToken = typeof config.instantClientToken === "string" && config.instantClientToken ? config.instantClientToken : "";
|
|
78
|
+
this._serverToken = typeof config.serverToken === "string" && config.serverToken ? config.serverToken : "";
|
|
78
79
|
this._maxPayloadBytes = normalizeMaxPayloadBytes(config.maxPayloadBytes);
|
|
79
80
|
this._lowLevelWarned = /* @__PURE__ */ new Set();
|
|
80
81
|
}
|
|
@@ -88,6 +89,17 @@ var ReiClient = class {
|
|
|
88
89
|
_resolveBaseUrl(endpointName) {
|
|
89
90
|
return this._customBaseUrls[endpointName] || this._baseUrl;
|
|
90
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Attach the single-user shared secret to amsg-server endpoint requests.
|
|
94
|
+
* Never applied to the instant path (that uses instantClientToken).
|
|
95
|
+
* @private
|
|
96
|
+
* @param {Record<string, string>} headers
|
|
97
|
+
* @returns {Record<string, string>}
|
|
98
|
+
*/
|
|
99
|
+
_withServerToken(headers) {
|
|
100
|
+
if (this._serverToken) headers["X-Client-Token"] = this._serverToken;
|
|
101
|
+
return headers;
|
|
102
|
+
}
|
|
91
103
|
// ─── Initialisation ─────────────────────────────────────────────
|
|
92
104
|
/**
|
|
93
105
|
* Fetch the user-specific encryption key.
|
|
@@ -106,7 +118,7 @@ var ReiClient = class {
|
|
|
106
118
|
}
|
|
107
119
|
const res = await fetch(`${this._baseUrl}/get-user-key`, {
|
|
108
120
|
method: "GET",
|
|
109
|
-
headers: { "X-User-Id": this._userId }
|
|
121
|
+
headers: this._withServerToken({ "X-User-Id": this._userId })
|
|
110
122
|
});
|
|
111
123
|
const json = await res.json();
|
|
112
124
|
if (!json.success) throw new Error(json.error?.message || "Failed to fetch user key");
|
|
@@ -116,6 +128,26 @@ var ReiClient = class {
|
|
|
116
128
|
}
|
|
117
129
|
this._userKey = this._hexToUint8Array(userKey);
|
|
118
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Fetch the amsg-server worker's own VAPID public key.
|
|
133
|
+
*
|
|
134
|
+
* A browser needs this as `applicationServerKey` when creating a Web Push
|
|
135
|
+
* subscription. Each self-hosted worker owns its VAPID keypair, so pull the
|
|
136
|
+
* key at runtime rather than baking it into the frontend. Sends
|
|
137
|
+
* `X-Client-Token` when a `serverToken` is configured.
|
|
138
|
+
*
|
|
139
|
+
* @returns {Promise<string>} The base64url VAPID public key.
|
|
140
|
+
* @throws {Error} When the worker has no VAPID public key configured (503).
|
|
141
|
+
*/
|
|
142
|
+
async getVapidPublicKey() {
|
|
143
|
+
const res = await fetch(`${this._baseUrl}/vapid-public-key`, {
|
|
144
|
+
method: "GET",
|
|
145
|
+
headers: this._withServerToken({})
|
|
146
|
+
});
|
|
147
|
+
const json = await res.json();
|
|
148
|
+
if (!json.success) throw new Error(json.error?.message || "Failed to fetch VAPID public key");
|
|
149
|
+
return json.publicKey;
|
|
150
|
+
}
|
|
119
151
|
// ─── Public API ─────────────────────────────────────────────────
|
|
120
152
|
/**
|
|
121
153
|
* Schedule a message.
|
|
@@ -143,12 +175,12 @@ var ReiClient = class {
|
|
|
143
175
|
const encrypted = await this._encrypt(json);
|
|
144
176
|
const res = await fetch(`${this._baseUrl}/schedule-message`, {
|
|
145
177
|
method: "POST",
|
|
146
|
-
headers: {
|
|
178
|
+
headers: this._withServerToken({
|
|
147
179
|
"Content-Type": "application/json",
|
|
148
180
|
"X-User-Id": this._userId,
|
|
149
181
|
"X-Payload-Encrypted": "true",
|
|
150
182
|
"X-Encryption-Version": "1"
|
|
151
|
-
},
|
|
183
|
+
}),
|
|
152
184
|
body: JSON.stringify(encrypted)
|
|
153
185
|
});
|
|
154
186
|
return res.json();
|
|
@@ -486,12 +518,12 @@ var ReiClient = class {
|
|
|
486
518
|
const encrypted = await this._encrypt(json);
|
|
487
519
|
const res = await fetch(`${this._baseUrl}/update-message?id=${encodeURIComponent(uuid)}`, {
|
|
488
520
|
method: "PUT",
|
|
489
|
-
headers: {
|
|
521
|
+
headers: this._withServerToken({
|
|
490
522
|
"Content-Type": "application/json",
|
|
491
523
|
"X-User-Id": this._userId,
|
|
492
524
|
"X-Payload-Encrypted": "true",
|
|
493
525
|
"X-Encryption-Version": "1"
|
|
494
|
-
},
|
|
526
|
+
}),
|
|
495
527
|
body: JSON.stringify(encrypted)
|
|
496
528
|
});
|
|
497
529
|
return res.json();
|
|
@@ -505,7 +537,7 @@ var ReiClient = class {
|
|
|
505
537
|
async cancelMessage(uuid) {
|
|
506
538
|
const res = await fetch(`${this._baseUrl}/cancel-message?id=${encodeURIComponent(uuid)}`, {
|
|
507
539
|
method: "DELETE",
|
|
508
|
-
headers: { "X-User-Id": this._userId }
|
|
540
|
+
headers: this._withServerToken({ "X-User-Id": this._userId })
|
|
509
541
|
});
|
|
510
542
|
return res.json();
|
|
511
543
|
}
|
|
@@ -527,11 +559,11 @@ var ReiClient = class {
|
|
|
527
559
|
const url = `${this._baseUrl}/messages${qs ? "?" + qs : ""}`;
|
|
528
560
|
const res = await fetch(url, {
|
|
529
561
|
method: "GET",
|
|
530
|
-
headers: {
|
|
562
|
+
headers: this._withServerToken({
|
|
531
563
|
"X-User-Id": this._userId,
|
|
532
564
|
"X-Response-Encrypted": "true",
|
|
533
565
|
"X-Encryption-Version": "1"
|
|
534
|
-
}
|
|
566
|
+
})
|
|
535
567
|
});
|
|
536
568
|
const json = await res.json();
|
|
537
569
|
if (!json?.success || json?.encrypted !== true) return json;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rei-standard/amsg-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0-next.1",
|
|
4
4
|
"description": "ReiStandard Active Messaging browser client SDK — also re-exports shared push types, builders, and guards from @rei-standard/amsg-shared",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|