@uengage.io/platform-sdk 0.15.0 → 1.0.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.
- package/README.md +90 -0
- package/dist/client.d.ts +11 -0
- package/dist/client.js +1 -1
- package/dist/errors.d.ts +17 -0
- package/dist/errors.js +21 -2
- package/dist/events/client.d.ts +81 -0
- package/dist/events/client.js +216 -0
- package/dist/events/index.d.ts +15 -0
- package/dist/events/index.js +41 -0
- package/dist/events/schema.d.ts +58 -0
- package/dist/events/schema.js +67 -0
- package/dist/realtime/connect.d.ts +106 -0
- package/dist/realtime/connect.js +450 -0
- package/dist/realtime/endpoints.d.ts +25 -0
- package/dist/realtime/endpoints.js +31 -0
- package/dist/realtime/envelope.d.ts +54 -0
- package/dist/realtime/envelope.js +77 -0
- package/dist/realtime/index.d.ts +37 -0
- package/dist/realtime/index.js +49 -0
- package/dist/realtime/protocol.d.ts +73 -0
- package/dist/realtime/protocol.js +89 -0
- package/package.json +38 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Dependency-free envelope guard for the browser realtime client.
|
|
4
|
+
*
|
|
5
|
+
* This mirrors `@uengage/common`'s `platformEventSchema` and the SDK's own
|
|
6
|
+
* `events/schema.ts`, but hand-rolled: the `/realtime` subpath ships with
|
|
7
|
+
* zero runtime dependencies (no zod, no Node built-ins) so it stays a few
|
|
8
|
+
* KB in a frontend bundle. Change one, change all three.
|
|
9
|
+
*
|
|
10
|
+
* NO DOMAIN CROSS-CHECK, deliberately — this is the one mirror that does
|
|
11
|
+
* not carry the resource→domain map, and it is not an oversight:
|
|
12
|
+
*
|
|
13
|
+
* - It would be checking the wrong thing. The producing SDK derives
|
|
14
|
+
* `domain` from `type` and the consuming service re-validates the pair
|
|
15
|
+
* before it ever publishes to a channel. By the time an envelope
|
|
16
|
+
* reaches a browser the pair has been checked twice server-side; a
|
|
17
|
+
* third check can only reject, never repair.
|
|
18
|
+
* - It would rot dangerously. A browser bundle sits in someone's cache
|
|
19
|
+
* for weeks. Baking today's map into it means that the day a new
|
|
20
|
+
* domain ships, every un-refreshed tab starts silently dropping live
|
|
21
|
+
* events for it — a stale client rejecting the future, which is the
|
|
22
|
+
* failure mode `validatePlatformEvent` is careful to avoid even
|
|
23
|
+
* server-side.
|
|
24
|
+
*
|
|
25
|
+
* So the guard is structural only: shapes and types, not membership.
|
|
26
|
+
* `packages/platform-sdk/test/events/domain-map.test.ts` asserts that
|
|
27
|
+
* every canonical domain is accepted, and that an unlisted one is too.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.asRealtimeEvent = asRealtimeEvent;
|
|
31
|
+
exports.isNewer = isNewer;
|
|
32
|
+
/** ULID: Crockford base32, 26 chars, excludes I/L/O/U. */
|
|
33
|
+
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
34
|
+
/** Dotted `resource.operation`, e.g. `order.status_changed`. */
|
|
35
|
+
const EVENT_TYPE_RE = /^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/;
|
|
36
|
+
/**
|
|
37
|
+
* Structural check on an untrusted payload. Returns the event or null —
|
|
38
|
+
* never throws, because a single malformed frame must not tear down a
|
|
39
|
+
* live subscription.
|
|
40
|
+
*/
|
|
41
|
+
function asRealtimeEvent(value) {
|
|
42
|
+
if (typeof value !== 'object' || value === null)
|
|
43
|
+
return null;
|
|
44
|
+
const v = value;
|
|
45
|
+
if (typeof v.id !== 'string' || !ULID_RE.test(v.id))
|
|
46
|
+
return null;
|
|
47
|
+
if (typeof v.type !== 'string' || !EVENT_TYPE_RE.test(v.type))
|
|
48
|
+
return null;
|
|
49
|
+
if (typeof v.domain !== 'string' || v.domain.length === 0)
|
|
50
|
+
return null;
|
|
51
|
+
if (typeof v.source !== 'string' || v.source.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
if (typeof v.version !== 'number' || !Number.isInteger(v.version) || v.version < 1)
|
|
54
|
+
return null;
|
|
55
|
+
if (typeof v.occurredAt !== 'string' || v.occurredAt.length === 0)
|
|
56
|
+
return null;
|
|
57
|
+
if (typeof v.tenantId !== 'string' || v.tenantId.length === 0)
|
|
58
|
+
return null;
|
|
59
|
+
if (typeof v.data !== 'object' || v.data === null || Array.isArray(v.data))
|
|
60
|
+
return null;
|
|
61
|
+
return v;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Ordering/dedupe guard, keyed on the envelope's monotonic ULID.
|
|
65
|
+
*
|
|
66
|
+
* ULIDs are lexicographically sortable by mint time, so a plain string
|
|
67
|
+
* compare orders events without parsing timestamps or knowing anything
|
|
68
|
+
* about the domain. This is what makes at-least-once delivery and the
|
|
69
|
+
* snapshot/stream race both harmless: whichever arrives second with an
|
|
70
|
+
* id <= the one already rendered is dropped.
|
|
71
|
+
*/
|
|
72
|
+
function isNewer(candidateId, seenId) {
|
|
73
|
+
if (seenId === undefined)
|
|
74
|
+
return true;
|
|
75
|
+
return candidateId > seenId;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW52ZWxvcGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVhbHRpbWUvZW52ZWxvcGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTBCRzs7QUF5QkgsMENBWUM7QUFXRCwwQkFHQztBQWpERCwwREFBMEQ7QUFDMUQsTUFBTSxPQUFPLEdBQUcsMEJBQTBCLENBQUM7QUFFM0MsZ0VBQWdFO0FBQ2hFLE1BQU0sYUFBYSxHQUFHLG9DQUFvQyxDQUFDO0FBYzNEOzs7O0dBSUc7QUFDSCxTQUFnQixlQUFlLENBQUMsS0FBYztJQUM1QyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzdELE1BQU0sQ0FBQyxHQUFHLEtBQWdDLENBQUM7SUFDM0MsSUFBSSxPQUFPLENBQUMsQ0FBQyxFQUFFLEtBQUssUUFBUSxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDakUsSUFBSSxPQUFPLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDM0UsSUFBSSxPQUFPLENBQUMsQ0FBQyxNQUFNLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUN2RSxJQUFJLE9BQU8sQ0FBQyxDQUFDLE1BQU0sS0FBSyxRQUFRLElBQUksQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3ZFLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxLQUFLLFFBQVEsSUFBSSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEdBQUcsQ0FBQztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ2hHLElBQUksT0FBTyxDQUFDLENBQUMsVUFBVSxLQUFLLFFBQVEsSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDL0UsSUFBSSxPQUFPLENBQUMsQ0FBQyxRQUFRLEtBQUssUUFBUSxJQUFJLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUMzRSxJQUFJLE9BQU8sQ0FBQyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxJQUFJLENBQUM7SUFDeEYsT0FBTyxDQUE2QixDQUFDO0FBQ3ZDLENBQUM7QUFFRDs7Ozs7Ozs7R0FRRztBQUNILFNBQWdCLE9BQU8sQ0FBQyxXQUFtQixFQUFFLE1BQTBCO0lBQ3JFLElBQUksTUFBTSxLQUFLLFNBQVM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUN0QyxPQUFPLFdBQVcsR0FBRyxNQUFNLENBQUM7QUFDOUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRGVwZW5kZW5jeS1mcmVlIGVudmVsb3BlIGd1YXJkIGZvciB0aGUgYnJvd3NlciByZWFsdGltZSBjbGllbnQuXG4gKlxuICogVGhpcyBtaXJyb3JzIGBAdWVuZ2FnZS9jb21tb25gJ3MgYHBsYXRmb3JtRXZlbnRTY2hlbWFgIGFuZCB0aGUgU0RLJ3Mgb3duXG4gKiBgZXZlbnRzL3NjaGVtYS50c2AsIGJ1dCBoYW5kLXJvbGxlZDogdGhlIGAvcmVhbHRpbWVgIHN1YnBhdGggc2hpcHMgd2l0aFxuICogemVybyBydW50aW1lIGRlcGVuZGVuY2llcyAobm8gem9kLCBubyBOb2RlIGJ1aWx0LWlucykgc28gaXQgc3RheXMgYSBmZXdcbiAqIEtCIGluIGEgZnJvbnRlbmQgYnVuZGxlLiBDaGFuZ2Ugb25lLCBjaGFuZ2UgYWxsIHRocmVlLlxuICpcbiAqIE5PIERPTUFJTiBDUk9TUy1DSEVDSywgZGVsaWJlcmF0ZWx5IOKAlCB0aGlzIGlzIHRoZSBvbmUgbWlycm9yIHRoYXQgZG9lc1xuICogbm90IGNhcnJ5IHRoZSByZXNvdXJjZeKGkmRvbWFpbiBtYXAsIGFuZCBpdCBpcyBub3QgYW4gb3ZlcnNpZ2h0OlxuICpcbiAqICAgLSBJdCB3b3VsZCBiZSBjaGVja2luZyB0aGUgd3JvbmcgdGhpbmcuIFRoZSBwcm9kdWNpbmcgU0RLIGRlcml2ZXNcbiAqICAgICBgZG9tYWluYCBmcm9tIGB0eXBlYCBhbmQgdGhlIGNvbnN1bWluZyBzZXJ2aWNlIHJlLXZhbGlkYXRlcyB0aGUgcGFpclxuICogICAgIGJlZm9yZSBpdCBldmVyIHB1Ymxpc2hlcyB0byBhIGNoYW5uZWwuIEJ5IHRoZSB0aW1lIGFuIGVudmVsb3BlXG4gKiAgICAgcmVhY2hlcyBhIGJyb3dzZXIgdGhlIHBhaXIgaGFzIGJlZW4gY2hlY2tlZCB0d2ljZSBzZXJ2ZXItc2lkZTsgYVxuICogICAgIHRoaXJkIGNoZWNrIGNhbiBvbmx5IHJlamVjdCwgbmV2ZXIgcmVwYWlyLlxuICogICAtIEl0IHdvdWxkIHJvdCBkYW5nZXJvdXNseS4gQSBicm93c2VyIGJ1bmRsZSBzaXRzIGluIHNvbWVvbmUncyBjYWNoZVxuICogICAgIGZvciB3ZWVrcy4gQmFraW5nIHRvZGF5J3MgbWFwIGludG8gaXQgbWVhbnMgdGhhdCB0aGUgZGF5IGEgbmV3XG4gKiAgICAgZG9tYWluIHNoaXBzLCBldmVyeSB1bi1yZWZyZXNoZWQgdGFiIHN0YXJ0cyBzaWxlbnRseSBkcm9wcGluZyBsaXZlXG4gKiAgICAgZXZlbnRzIGZvciBpdCDigJQgYSBzdGFsZSBjbGllbnQgcmVqZWN0aW5nIHRoZSBmdXR1cmUsIHdoaWNoIGlzIHRoZVxuICogICAgIGZhaWx1cmUgbW9kZSBgdmFsaWRhdGVQbGF0Zm9ybUV2ZW50YCBpcyBjYXJlZnVsIHRvIGF2b2lkIGV2ZW5cbiAqICAgICBzZXJ2ZXItc2lkZS5cbiAqXG4gKiBTbyB0aGUgZ3VhcmQgaXMgc3RydWN0dXJhbCBvbmx5OiBzaGFwZXMgYW5kIHR5cGVzLCBub3QgbWVtYmVyc2hpcC5cbiAqIGBwYWNrYWdlcy9wbGF0Zm9ybS1zZGsvdGVzdC9ldmVudHMvZG9tYWluLW1hcC50ZXN0LnRzYCBhc3NlcnRzIHRoYXRcbiAqIGV2ZXJ5IGNhbm9uaWNhbCBkb21haW4gaXMgYWNjZXB0ZWQsIGFuZCB0aGF0IGFuIHVubGlzdGVkIG9uZSBpcyB0b28uXG4gKi9cblxuLyoqIFVMSUQ6IENyb2NrZm9yZCBiYXNlMzIsIDI2IGNoYXJzLCBleGNsdWRlcyBJL0wvTy9VLiAqL1xuY29uc3QgVUxJRF9SRSA9IC9eWzAtOUEtSEpLTU5QLVRWLVpdezI2fSQvO1xuXG4vKiogRG90dGVkIGByZXNvdXJjZS5vcGVyYXRpb25gLCBlLmcuIGBvcmRlci5zdGF0dXNfY2hhbmdlZGAuICovXG5jb25zdCBFVkVOVF9UWVBFX1JFID0gL15bYS16XVthLXowLTlfXSpcXC5bYS16XVthLXowLTlfXSokLztcblxuLyoqIFRoZSBwbGF0Zm9ybSBldmVudC1idXMgZW52ZWxvcGUsIGFzIGl0IGFycml2ZXMgYXQgYSBicm93c2VyLiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWFsdGltZUV2ZW50IHtcbiAgaWQ6IHN0cmluZztcbiAgdHlwZTogc3RyaW5nO1xuICBkb21haW46IHN0cmluZztcbiAgc291cmNlOiBzdHJpbmc7XG4gIHZlcnNpb246IG51bWJlcjtcbiAgb2NjdXJyZWRBdDogc3RyaW5nO1xuICB0ZW5hbnRJZDogc3RyaW5nO1xuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLyoqXG4gKiBTdHJ1Y3R1cmFsIGNoZWNrIG9uIGFuIHVudHJ1c3RlZCBwYXlsb2FkLiBSZXR1cm5zIHRoZSBldmVudCBvciBudWxsIOKAlFxuICogbmV2ZXIgdGhyb3dzLCBiZWNhdXNlIGEgc2luZ2xlIG1hbGZvcm1lZCBmcmFtZSBtdXN0IG5vdCB0ZWFyIGRvd24gYVxuICogbGl2ZSBzdWJzY3JpcHRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhc1JlYWx0aW1lRXZlbnQodmFsdWU6IHVua25vd24pOiBSZWFsdGltZUV2ZW50IHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgdmFsdWUgIT09ICdvYmplY3QnIHx8IHZhbHVlID09PSBudWxsKSByZXR1cm4gbnVsbDtcbiAgY29uc3QgdiA9IHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICBpZiAodHlwZW9mIHYuaWQgIT09ICdzdHJpbmcnIHx8ICFVTElEX1JFLnRlc3Qodi5pZCkpIHJldHVybiBudWxsO1xuICBpZiAodHlwZW9mIHYudHlwZSAhPT0gJ3N0cmluZycgfHwgIUVWRU5UX1RZUEVfUkUudGVzdCh2LnR5cGUpKSByZXR1cm4gbnVsbDtcbiAgaWYgKHR5cGVvZiB2LmRvbWFpbiAhPT0gJ3N0cmluZycgfHwgdi5kb21haW4ubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgaWYgKHR5cGVvZiB2LnNvdXJjZSAhPT0gJ3N0cmluZycgfHwgdi5zb3VyY2UubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgaWYgKHR5cGVvZiB2LnZlcnNpb24gIT09ICdudW1iZXInIHx8ICFOdW1iZXIuaXNJbnRlZ2VyKHYudmVyc2lvbikgfHwgdi52ZXJzaW9uIDwgMSkgcmV0dXJuIG51bGw7XG4gIGlmICh0eXBlb2Ygdi5vY2N1cnJlZEF0ICE9PSAnc3RyaW5nJyB8fCB2Lm9jY3VycmVkQXQubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgaWYgKHR5cGVvZiB2LnRlbmFudElkICE9PSAnc3RyaW5nJyB8fCB2LnRlbmFudElkLmxlbmd0aCA9PT0gMCkgcmV0dXJuIG51bGw7XG4gIGlmICh0eXBlb2Ygdi5kYXRhICE9PSAnb2JqZWN0JyB8fCB2LmRhdGEgPT09IG51bGwgfHwgQXJyYXkuaXNBcnJheSh2LmRhdGEpKSByZXR1cm4gbnVsbDtcbiAgcmV0dXJuIHYgYXMgdW5rbm93biBhcyBSZWFsdGltZUV2ZW50O1xufVxuXG4vKipcbiAqIE9yZGVyaW5nL2RlZHVwZSBndWFyZCwga2V5ZWQgb24gdGhlIGVudmVsb3BlJ3MgbW9ub3RvbmljIFVMSUQuXG4gKlxuICogVUxJRHMgYXJlIGxleGljb2dyYXBoaWNhbGx5IHNvcnRhYmxlIGJ5IG1pbnQgdGltZSwgc28gYSBwbGFpbiBzdHJpbmdcbiAqIGNvbXBhcmUgb3JkZXJzIGV2ZW50cyB3aXRob3V0IHBhcnNpbmcgdGltZXN0YW1wcyBvciBrbm93aW5nIGFueXRoaW5nXG4gKiBhYm91dCB0aGUgZG9tYWluLiBUaGlzIGlzIHdoYXQgbWFrZXMgYXQtbGVhc3Qtb25jZSBkZWxpdmVyeSBhbmQgdGhlXG4gKiBzbmFwc2hvdC9zdHJlYW0gcmFjZSBib3RoIGhhcm1sZXNzOiB3aGljaGV2ZXIgYXJyaXZlcyBzZWNvbmQgd2l0aCBhblxuICogaWQgPD0gdGhlIG9uZSBhbHJlYWR5IHJlbmRlcmVkIGlzIGRyb3BwZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc05ld2VyKGNhbmRpZGF0ZUlkOiBzdHJpbmcsIHNlZW5JZDogc3RyaW5nIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gIGlmIChzZWVuSWQgPT09IHVuZGVmaW5lZCkgcmV0dXJuIHRydWU7XG4gIHJldHVybiBjYW5kaWRhdGVJZCA+IHNlZW5JZDtcbn1cbiJdfQ==
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@uengage.io/platform-sdk/realtime` — browser-safe realtime client.
|
|
3
|
+
*
|
|
4
|
+
* A thin client for the platform's AppSync Events API: it owns the wire
|
|
5
|
+
* protocol, the keepalive watchdog, reconnect with jittered backoff,
|
|
6
|
+
* resubscribe, token refresh, snapshot catch-up on every (re)connect,
|
|
7
|
+
* and ULID-based ordering/dedupe. Apps own rendering and channel names.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { realtime } from '@uengage.io/platform-sdk/realtime';
|
|
11
|
+
*
|
|
12
|
+
* const client = realtime.connect({
|
|
13
|
+
* env: 'prod',
|
|
14
|
+
* getToken: () => session.jwt(),
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* const sub = client.subscribe(`/orders/${orderId}`, {
|
|
18
|
+
* onUpdate(event, meta) { render(event.data); },
|
|
19
|
+
* onError(err) { showOffline(err); },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* sub.unsubscribe();
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* This subpath is deliberately isolated from the SDK's main entry: zero
|
|
26
|
+
* runtime dependencies, no Node built-ins, no server auth code, so it
|
|
27
|
+
* stays a few KB in a frontend bundle and works unchanged in React
|
|
28
|
+
* Native. Do not import from `../` here.
|
|
29
|
+
*/
|
|
30
|
+
import { connect } from './connect';
|
|
31
|
+
export declare const realtime: {
|
|
32
|
+
connect: typeof connect;
|
|
33
|
+
};
|
|
34
|
+
export { connect, jitteredBackoff, type RealtimeClient, type RealtimeConnectOptions, type Subscription, type SubscribeOptions, type UpdateMeta, type MinimalWebSocket, type WebSocketCtor, } from './connect';
|
|
35
|
+
export { asRealtimeEvent, isNewer, type RealtimeEvent } from './envelope';
|
|
36
|
+
export { API_BASE, endpointsFor, type RealtimeEndpoints, type RealtimeEnv } from './endpoints';
|
|
37
|
+
export { EVENT_WS_SUBPROTOCOL, authHeader, authSubprotocol, base64UrlEncode } from './protocol';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.base64UrlEncode = exports.authSubprotocol = exports.authHeader = exports.EVENT_WS_SUBPROTOCOL = exports.endpointsFor = exports.API_BASE = exports.isNewer = exports.asRealtimeEvent = exports.jitteredBackoff = exports.connect = exports.realtime = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `@uengage.io/platform-sdk/realtime` — browser-safe realtime client.
|
|
6
|
+
*
|
|
7
|
+
* A thin client for the platform's AppSync Events API: it owns the wire
|
|
8
|
+
* protocol, the keepalive watchdog, reconnect with jittered backoff,
|
|
9
|
+
* resubscribe, token refresh, snapshot catch-up on every (re)connect,
|
|
10
|
+
* and ULID-based ordering/dedupe. Apps own rendering and channel names.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { realtime } from '@uengage.io/platform-sdk/realtime';
|
|
14
|
+
*
|
|
15
|
+
* const client = realtime.connect({
|
|
16
|
+
* env: 'prod',
|
|
17
|
+
* getToken: () => session.jwt(),
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* const sub = client.subscribe(`/orders/${orderId}`, {
|
|
21
|
+
* onUpdate(event, meta) { render(event.data); },
|
|
22
|
+
* onError(err) { showOffline(err); },
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* sub.unsubscribe();
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* This subpath is deliberately isolated from the SDK's main entry: zero
|
|
29
|
+
* runtime dependencies, no Node built-ins, no server auth code, so it
|
|
30
|
+
* stays a few KB in a frontend bundle and works unchanged in React
|
|
31
|
+
* Native. Do not import from `../` here.
|
|
32
|
+
*/
|
|
33
|
+
const connect_1 = require("./connect");
|
|
34
|
+
exports.realtime = { connect: connect_1.connect };
|
|
35
|
+
var connect_2 = require("./connect");
|
|
36
|
+
Object.defineProperty(exports, "connect", { enumerable: true, get: function () { return connect_2.connect; } });
|
|
37
|
+
Object.defineProperty(exports, "jitteredBackoff", { enumerable: true, get: function () { return connect_2.jitteredBackoff; } });
|
|
38
|
+
var envelope_1 = require("./envelope");
|
|
39
|
+
Object.defineProperty(exports, "asRealtimeEvent", { enumerable: true, get: function () { return envelope_1.asRealtimeEvent; } });
|
|
40
|
+
Object.defineProperty(exports, "isNewer", { enumerable: true, get: function () { return envelope_1.isNewer; } });
|
|
41
|
+
var endpoints_1 = require("./endpoints");
|
|
42
|
+
Object.defineProperty(exports, "API_BASE", { enumerable: true, get: function () { return endpoints_1.API_BASE; } });
|
|
43
|
+
Object.defineProperty(exports, "endpointsFor", { enumerable: true, get: function () { return endpoints_1.endpointsFor; } });
|
|
44
|
+
var protocol_1 = require("./protocol");
|
|
45
|
+
Object.defineProperty(exports, "EVENT_WS_SUBPROTOCOL", { enumerable: true, get: function () { return protocol_1.EVENT_WS_SUBPROTOCOL; } });
|
|
46
|
+
Object.defineProperty(exports, "authHeader", { enumerable: true, get: function () { return protocol_1.authHeader; } });
|
|
47
|
+
Object.defineProperty(exports, "authSubprotocol", { enumerable: true, get: function () { return protocol_1.authSubprotocol; } });
|
|
48
|
+
Object.defineProperty(exports, "base64UrlEncode", { enumerable: true, get: function () { return protocol_1.base64UrlEncode; } });
|
|
49
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVhbHRpbWUvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0Qkc7QUFDSCx1Q0FBb0M7QUFFdkIsUUFBQSxRQUFRLEdBQUcsRUFBRSxPQUFPLEVBQVAsaUJBQU8sRUFBRSxDQUFDO0FBRXBDLHFDQVVtQjtBQVRqQixrR0FBQSxPQUFPLE9BQUE7QUFDUCwwR0FBQSxlQUFlLE9BQUE7QUFTakIsdUNBQTBFO0FBQWpFLDJHQUFBLGVBQWUsT0FBQTtBQUFFLG1HQUFBLE9BQU8sT0FBQTtBQUNqQyx5Q0FBK0Y7QUFBdEYscUdBQUEsUUFBUSxPQUFBO0FBQUUseUdBQUEsWUFBWSxPQUFBO0FBQy9CLHVDQUFnRztBQUF2RixnSEFBQSxvQkFBb0IsT0FBQTtBQUFFLHNHQUFBLFVBQVUsT0FBQTtBQUFFLDJHQUFBLGVBQWUsT0FBQTtBQUFFLDJHQUFBLGVBQWUsT0FBQSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogYEB1ZW5nYWdlLmlvL3BsYXRmb3JtLXNkay9yZWFsdGltZWAg4oCUIGJyb3dzZXItc2FmZSByZWFsdGltZSBjbGllbnQuXG4gKlxuICogQSB0aGluIGNsaWVudCBmb3IgdGhlIHBsYXRmb3JtJ3MgQXBwU3luYyBFdmVudHMgQVBJOiBpdCBvd25zIHRoZSB3aXJlXG4gKiBwcm90b2NvbCwgdGhlIGtlZXBhbGl2ZSB3YXRjaGRvZywgcmVjb25uZWN0IHdpdGggaml0dGVyZWQgYmFja29mZixcbiAqIHJlc3Vic2NyaWJlLCB0b2tlbiByZWZyZXNoLCBzbmFwc2hvdCBjYXRjaC11cCBvbiBldmVyeSAocmUpY29ubmVjdCxcbiAqIGFuZCBVTElELWJhc2VkIG9yZGVyaW5nL2RlZHVwZS4gQXBwcyBvd24gcmVuZGVyaW5nIGFuZCBjaGFubmVsIG5hbWVzLlxuICpcbiAqIGBgYHRzXG4gKiBpbXBvcnQgeyByZWFsdGltZSB9IGZyb20gJ0B1ZW5nYWdlLmlvL3BsYXRmb3JtLXNkay9yZWFsdGltZSc7XG4gKlxuICogY29uc3QgY2xpZW50ID0gcmVhbHRpbWUuY29ubmVjdCh7XG4gKiAgIGVudjogJ3Byb2QnLFxuICogICBnZXRUb2tlbjogKCkgPT4gc2Vzc2lvbi5qd3QoKSxcbiAqIH0pO1xuICpcbiAqIGNvbnN0IHN1YiA9IGNsaWVudC5zdWJzY3JpYmUoYC9vcmRlcnMvJHtvcmRlcklkfWAsIHtcbiAqICAgb25VcGRhdGUoZXZlbnQsIG1ldGEpIHsgcmVuZGVyKGV2ZW50LmRhdGEpOyB9LFxuICogICBvbkVycm9yKGVycikgeyBzaG93T2ZmbGluZShlcnIpOyB9LFxuICogfSk7XG4gKlxuICogc3ViLnVuc3Vic2NyaWJlKCk7XG4gKiBgYGBcbiAqXG4gKiBUaGlzIHN1YnBhdGggaXMgZGVsaWJlcmF0ZWx5IGlzb2xhdGVkIGZyb20gdGhlIFNESydzIG1haW4gZW50cnk6IHplcm9cbiAqIHJ1bnRpbWUgZGVwZW5kZW5jaWVzLCBubyBOb2RlIGJ1aWx0LWlucywgbm8gc2VydmVyIGF1dGggY29kZSwgc28gaXRcbiAqIHN0YXlzIGEgZmV3IEtCIGluIGEgZnJvbnRlbmQgYnVuZGxlIGFuZCB3b3JrcyB1bmNoYW5nZWQgaW4gUmVhY3RcbiAqIE5hdGl2ZS4gRG8gbm90IGltcG9ydCBmcm9tIGAuLi9gIGhlcmUuXG4gKi9cbmltcG9ydCB7IGNvbm5lY3QgfSBmcm9tICcuL2Nvbm5lY3QnO1xuXG5leHBvcnQgY29uc3QgcmVhbHRpbWUgPSB7IGNvbm5lY3QgfTtcblxuZXhwb3J0IHtcbiAgY29ubmVjdCxcbiAgaml0dGVyZWRCYWNrb2ZmLFxuICB0eXBlIFJlYWx0aW1lQ2xpZW50LFxuICB0eXBlIFJlYWx0aW1lQ29ubmVjdE9wdGlvbnMsXG4gIHR5cGUgU3Vic2NyaXB0aW9uLFxuICB0eXBlIFN1YnNjcmliZU9wdGlvbnMsXG4gIHR5cGUgVXBkYXRlTWV0YSxcbiAgdHlwZSBNaW5pbWFsV2ViU29ja2V0LFxuICB0eXBlIFdlYlNvY2tldEN0b3IsXG59IGZyb20gJy4vY29ubmVjdCc7XG5leHBvcnQgeyBhc1JlYWx0aW1lRXZlbnQsIGlzTmV3ZXIsIHR5cGUgUmVhbHRpbWVFdmVudCB9IGZyb20gJy4vZW52ZWxvcGUnO1xuZXhwb3J0IHsgQVBJX0JBU0UsIGVuZHBvaW50c0ZvciwgdHlwZSBSZWFsdGltZUVuZHBvaW50cywgdHlwZSBSZWFsdGltZUVudiB9IGZyb20gJy4vZW5kcG9pbnRzJztcbmV4cG9ydCB7IEVWRU5UX1dTX1NVQlBST1RPQ09MLCBhdXRoSGVhZGVyLCBhdXRoU3VicHJvdG9jb2wsIGJhc2U2NFVybEVuY29kZSB9IGZyb20gJy4vcHJvdG9jb2wnO1xuIl19
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AppSync Events WebSocket wire protocol, as documented at
|
|
3
|
+
* https://docs.aws.amazon.com/appsync/latest/eventapi/event-api-websocket-protocol.html
|
|
4
|
+
*
|
|
5
|
+
* Everything here is pure data + string manipulation: no I/O, no
|
|
6
|
+
* dependencies, no Node built-ins. The socket lifecycle lives in
|
|
7
|
+
* `connect.ts`.
|
|
8
|
+
*/
|
|
9
|
+
/** WebSocket subprotocol that selects the Events (not GraphQL) protocol. */
|
|
10
|
+
export declare const EVENT_WS_SUBPROTOCOL = "aws-appsync-event-ws";
|
|
11
|
+
/**
|
|
12
|
+
* AppSync takes connection auth as a *subprotocol*, because a browser
|
|
13
|
+
* WebSocket cannot set request headers. The auth header object is
|
|
14
|
+
* JSON-encoded, base64url-encoded, and prefixed with `header-`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function authSubprotocol(header: Record<string, string>): string;
|
|
17
|
+
/**
|
|
18
|
+
* The auth object AppSync expects, for both the connection handshake and
|
|
19
|
+
* each `subscribe` frame. `host` must be the API's HTTP domain (not the
|
|
20
|
+
* realtime domain) — AppSync validates the signature/token against it.
|
|
21
|
+
*/
|
|
22
|
+
export declare function authHeader(httpHost: string, token: string): Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* base64url with padding stripped. Uses `btoa` over UTF-8 bytes rather
|
|
25
|
+
* than `Buffer`, which does not exist in a browser.
|
|
26
|
+
*/
|
|
27
|
+
export declare function base64UrlEncode(input: string): string;
|
|
28
|
+
export interface ConnectionAckFrame {
|
|
29
|
+
type: 'connection_ack';
|
|
30
|
+
/**
|
|
31
|
+
* How long the server will tolerate silence before it closes the
|
|
32
|
+
* connection. The client watchdog uses this rather than a hard-coded
|
|
33
|
+
* 60s so a server-side change doesn't strand us.
|
|
34
|
+
*/
|
|
35
|
+
connectionTimeoutMs?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface DataFrame {
|
|
38
|
+
type: 'data';
|
|
39
|
+
id: string;
|
|
40
|
+
/**
|
|
41
|
+
* The published payload, JSON-encoded *inside* the already-JSON frame.
|
|
42
|
+
* Double-encoded on the wire; `parseDataFrameEvent` unwraps both.
|
|
43
|
+
*/
|
|
44
|
+
event: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ErrorFrame {
|
|
47
|
+
type: 'connection_error' | 'subscribe_error' | 'publish_error';
|
|
48
|
+
id?: string;
|
|
49
|
+
errors?: Array<{
|
|
50
|
+
errorType?: string;
|
|
51
|
+
message?: string;
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
export type ServerFrame = ConnectionAckFrame | DataFrame | ErrorFrame | {
|
|
55
|
+
type: 'ka';
|
|
56
|
+
} | {
|
|
57
|
+
type: 'subscribe_success';
|
|
58
|
+
id: string;
|
|
59
|
+
} | {
|
|
60
|
+
type: 'unsubscribe_success';
|
|
61
|
+
id: string;
|
|
62
|
+
} | {
|
|
63
|
+
type: string;
|
|
64
|
+
[k: string]: unknown;
|
|
65
|
+
};
|
|
66
|
+
export declare function parseServerFrame(raw: string): ServerFrame | null;
|
|
67
|
+
/** Unwrap the inner JSON of a `data` frame. Null if it isn't parseable. */
|
|
68
|
+
export declare function parseDataFrameEvent(frame: DataFrame): unknown;
|
|
69
|
+
/** Human-readable text from an error frame, for `onError`. */
|
|
70
|
+
export declare function errorFrameMessage(frame: ErrorFrame): string;
|
|
71
|
+
export declare function connectionInitFrame(): string;
|
|
72
|
+
export declare function subscribeFrame(id: string, channel: string, auth: Record<string, string>): string;
|
|
73
|
+
export declare function unsubscribeFrame(id: string): string;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The AppSync Events WebSocket wire protocol, as documented at
|
|
4
|
+
* https://docs.aws.amazon.com/appsync/latest/eventapi/event-api-websocket-protocol.html
|
|
5
|
+
*
|
|
6
|
+
* Everything here is pure data + string manipulation: no I/O, no
|
|
7
|
+
* dependencies, no Node built-ins. The socket lifecycle lives in
|
|
8
|
+
* `connect.ts`.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.EVENT_WS_SUBPROTOCOL = void 0;
|
|
12
|
+
exports.authSubprotocol = authSubprotocol;
|
|
13
|
+
exports.authHeader = authHeader;
|
|
14
|
+
exports.base64UrlEncode = base64UrlEncode;
|
|
15
|
+
exports.parseServerFrame = parseServerFrame;
|
|
16
|
+
exports.parseDataFrameEvent = parseDataFrameEvent;
|
|
17
|
+
exports.errorFrameMessage = errorFrameMessage;
|
|
18
|
+
exports.connectionInitFrame = connectionInitFrame;
|
|
19
|
+
exports.subscribeFrame = subscribeFrame;
|
|
20
|
+
exports.unsubscribeFrame = unsubscribeFrame;
|
|
21
|
+
/** WebSocket subprotocol that selects the Events (not GraphQL) protocol. */
|
|
22
|
+
exports.EVENT_WS_SUBPROTOCOL = 'aws-appsync-event-ws';
|
|
23
|
+
/**
|
|
24
|
+
* AppSync takes connection auth as a *subprotocol*, because a browser
|
|
25
|
+
* WebSocket cannot set request headers. The auth header object is
|
|
26
|
+
* JSON-encoded, base64url-encoded, and prefixed with `header-`.
|
|
27
|
+
*/
|
|
28
|
+
function authSubprotocol(header) {
|
|
29
|
+
return `header-${base64UrlEncode(JSON.stringify(header))}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The auth object AppSync expects, for both the connection handshake and
|
|
33
|
+
* each `subscribe` frame. `host` must be the API's HTTP domain (not the
|
|
34
|
+
* realtime domain) — AppSync validates the signature/token against it.
|
|
35
|
+
*/
|
|
36
|
+
function authHeader(httpHost, token) {
|
|
37
|
+
return { host: httpHost, Authorization: token };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* base64url with padding stripped. Uses `btoa` over UTF-8 bytes rather
|
|
41
|
+
* than `Buffer`, which does not exist in a browser.
|
|
42
|
+
*/
|
|
43
|
+
function base64UrlEncode(input) {
|
|
44
|
+
const bytes = new TextEncoder().encode(input);
|
|
45
|
+
let binary = '';
|
|
46
|
+
for (let i = 0; i < bytes.length; i++)
|
|
47
|
+
binary += String.fromCharCode(bytes[i]);
|
|
48
|
+
return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
49
|
+
}
|
|
50
|
+
function parseServerFrame(raw) {
|
|
51
|
+
try {
|
|
52
|
+
const parsed = JSON.parse(raw);
|
|
53
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
54
|
+
return null;
|
|
55
|
+
const frame = parsed;
|
|
56
|
+
if (typeof frame.type !== 'string')
|
|
57
|
+
return null;
|
|
58
|
+
return parsed;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** Unwrap the inner JSON of a `data` frame. Null if it isn't parseable. */
|
|
65
|
+
function parseDataFrameEvent(frame) {
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(frame.event);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/** Human-readable text from an error frame, for `onError`. */
|
|
74
|
+
function errorFrameMessage(frame) {
|
|
75
|
+
const parts = (frame.errors ?? [])
|
|
76
|
+
.map((e) => e.message ?? e.errorType)
|
|
77
|
+
.filter((m) => typeof m === 'string' && m.length > 0);
|
|
78
|
+
return parts.length > 0 ? parts.join('; ') : frame.type;
|
|
79
|
+
}
|
|
80
|
+
function connectionInitFrame() {
|
|
81
|
+
return JSON.stringify({ type: 'connection_init' });
|
|
82
|
+
}
|
|
83
|
+
function subscribeFrame(id, channel, auth) {
|
|
84
|
+
return JSON.stringify({ type: 'subscribe', id, channel, authorization: auth });
|
|
85
|
+
}
|
|
86
|
+
function unsubscribeFrame(id) {
|
|
87
|
+
return JSON.stringify({ type: 'unsubscribe', id });
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdG9jb2wuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVhbHRpbWUvcHJvdG9jb2wudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7O0dBT0c7OztBQVVILDBDQUVDO0FBT0QsZ0NBRUM7QUFNRCwwQ0FLQztBQXVDRCw0Q0FVQztBQUdELGtEQU1DO0FBR0QsOENBS0M7QUFFRCxrREFFQztBQUVELHdDQUVDO0FBRUQsNENBRUM7QUE1R0QsNEVBQTRFO0FBQy9ELFFBQUEsb0JBQW9CLEdBQUcsc0JBQXNCLENBQUM7QUFFM0Q7Ozs7R0FJRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxNQUE4QjtJQUM1RCxPQUFPLFVBQVUsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDO0FBQzdELENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLFFBQWdCLEVBQUUsS0FBYTtJQUN4RCxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxhQUFhLEVBQUUsS0FBSyxFQUFFLENBQUM7QUFDbEQsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxLQUFhO0lBQzNDLE1BQU0sS0FBSyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlDLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztJQUNoQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUU7UUFBRSxNQUFNLElBQUksTUFBTSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMvRSxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztBQUNqRixDQUFDO0FBdUNELFNBQWdCLGdCQUFnQixDQUFDLEdBQVc7SUFDMUMsSUFBSSxDQUFDO1FBQ0gsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQVksQ0FBQztRQUMxQyxJQUFJLE9BQU8sTUFBTSxLQUFLLFFBQVEsSUFBSSxNQUFNLEtBQUssSUFBSTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQy9ELE1BQU0sS0FBSyxHQUFHLE1BQTRCLENBQUM7UUFDM0MsSUFBSSxPQUFPLEtBQUssQ0FBQyxJQUFJLEtBQUssUUFBUTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ2hELE9BQU8sTUFBcUIsQ0FBQztJQUMvQixDQUFDO0lBQUMsTUFBTSxDQUFDO1FBQ1AsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0FBQ0gsQ0FBQztBQUVELDJFQUEyRTtBQUMzRSxTQUFnQixtQkFBbUIsQ0FBQyxLQUFnQjtJQUNsRCxJQUFJLENBQUM7UUFDSCxPQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBWSxDQUFDO0lBQzVDLENBQUM7SUFBQyxNQUFNLENBQUM7UUFDUCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7QUFDSCxDQUFDO0FBRUQsOERBQThEO0FBQzlELFNBQWdCLGlCQUFpQixDQUFDLEtBQWlCO0lBQ2pELE1BQU0sS0FBSyxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sSUFBSSxFQUFFLENBQUM7U0FDL0IsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxJQUFJLENBQUMsQ0FBQyxTQUFTLENBQUM7U0FDcEMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFlLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUNyRSxPQUFPLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDO0FBQzFELENBQUM7QUFFRCxTQUFnQixtQkFBbUI7SUFDakMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FBQztBQUNyRCxDQUFDO0FBRUQsU0FBZ0IsY0FBYyxDQUFDLEVBQVUsRUFBRSxPQUFlLEVBQUUsSUFBNEI7SUFDdEYsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLGFBQWEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ2pGLENBQUM7QUFFRCxTQUFnQixnQkFBZ0IsQ0FBQyxFQUFVO0lBQ3pDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUNyRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUaGUgQXBwU3luYyBFdmVudHMgV2ViU29ja2V0IHdpcmUgcHJvdG9jb2wsIGFzIGRvY3VtZW50ZWQgYXRcbiAqIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9hcHBzeW5jL2xhdGVzdC9ldmVudGFwaS9ldmVudC1hcGktd2Vic29ja2V0LXByb3RvY29sLmh0bWxcbiAqXG4gKiBFdmVyeXRoaW5nIGhlcmUgaXMgcHVyZSBkYXRhICsgc3RyaW5nIG1hbmlwdWxhdGlvbjogbm8gSS9PLCBub1xuICogZGVwZW5kZW5jaWVzLCBubyBOb2RlIGJ1aWx0LWlucy4gVGhlIHNvY2tldCBsaWZlY3ljbGUgbGl2ZXMgaW5cbiAqIGBjb25uZWN0LnRzYC5cbiAqL1xuXG4vKiogV2ViU29ja2V0IHN1YnByb3RvY29sIHRoYXQgc2VsZWN0cyB0aGUgRXZlbnRzIChub3QgR3JhcGhRTCkgcHJvdG9jb2wuICovXG5leHBvcnQgY29uc3QgRVZFTlRfV1NfU1VCUFJPVE9DT0wgPSAnYXdzLWFwcHN5bmMtZXZlbnQtd3MnO1xuXG4vKipcbiAqIEFwcFN5bmMgdGFrZXMgY29ubmVjdGlvbiBhdXRoIGFzIGEgKnN1YnByb3RvY29sKiwgYmVjYXVzZSBhIGJyb3dzZXJcbiAqIFdlYlNvY2tldCBjYW5ub3Qgc2V0IHJlcXVlc3QgaGVhZGVycy4gVGhlIGF1dGggaGVhZGVyIG9iamVjdCBpc1xuICogSlNPTi1lbmNvZGVkLCBiYXNlNjR1cmwtZW5jb2RlZCwgYW5kIHByZWZpeGVkIHdpdGggYGhlYWRlci1gLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXV0aFN1YnByb3RvY29sKGhlYWRlcjogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IHN0cmluZyB7XG4gIHJldHVybiBgaGVhZGVyLSR7YmFzZTY0VXJsRW5jb2RlKEpTT04uc3RyaW5naWZ5KGhlYWRlcikpfWA7XG59XG5cbi8qKlxuICogVGhlIGF1dGggb2JqZWN0IEFwcFN5bmMgZXhwZWN0cywgZm9yIGJvdGggdGhlIGNvbm5lY3Rpb24gaGFuZHNoYWtlIGFuZFxuICogZWFjaCBgc3Vic2NyaWJlYCBmcmFtZS4gYGhvc3RgIG11c3QgYmUgdGhlIEFQSSdzIEhUVFAgZG9tYWluIChub3QgdGhlXG4gKiByZWFsdGltZSBkb21haW4pIOKAlCBBcHBTeW5jIHZhbGlkYXRlcyB0aGUgc2lnbmF0dXJlL3Rva2VuIGFnYWluc3QgaXQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhdXRoSGVhZGVyKGh0dHBIb3N0OiBzdHJpbmcsIHRva2VuOiBzdHJpbmcpOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHtcbiAgcmV0dXJuIHsgaG9zdDogaHR0cEhvc3QsIEF1dGhvcml6YXRpb246IHRva2VuIH07XG59XG5cbi8qKlxuICogYmFzZTY0dXJsIHdpdGggcGFkZGluZyBzdHJpcHBlZC4gVXNlcyBgYnRvYWAgb3ZlciBVVEYtOCBieXRlcyByYXRoZXJcbiAqIHRoYW4gYEJ1ZmZlcmAsIHdoaWNoIGRvZXMgbm90IGV4aXN0IGluIGEgYnJvd3Nlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJhc2U2NFVybEVuY29kZShpbnB1dDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgYnl0ZXMgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoaW5wdXQpO1xuICBsZXQgYmluYXJ5ID0gJyc7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYnl0ZXMubGVuZ3RoOyBpKyspIGJpbmFyeSArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ5dGVzW2ldKTtcbiAgcmV0dXJuIGJ0b2EoYmluYXJ5KS5yZXBsYWNlKC9cXCsvZywgJy0nKS5yZXBsYWNlKC9cXC8vZywgJ18nKS5yZXBsYWNlKC89KyQvLCAnJyk7XG59XG5cbi8vIOKUgOKUgOKUgCBGcmFtZXMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbmV4cG9ydCBpbnRlcmZhY2UgQ29ubmVjdGlvbkFja0ZyYW1lIHtcbiAgdHlwZTogJ2Nvbm5lY3Rpb25fYWNrJztcbiAgLyoqXG4gICAqIEhvdyBsb25nIHRoZSBzZXJ2ZXIgd2lsbCB0b2xlcmF0ZSBzaWxlbmNlIGJlZm9yZSBpdCBjbG9zZXMgdGhlXG4gICAqIGNvbm5lY3Rpb24uIFRoZSBjbGllbnQgd2F0Y2hkb2cgdXNlcyB0aGlzIHJhdGhlciB0aGFuIGEgaGFyZC1jb2RlZFxuICAgKiA2MHMgc28gYSBzZXJ2ZXItc2lkZSBjaGFuZ2UgZG9lc24ndCBzdHJhbmQgdXMuXG4gICAqL1xuICBjb25uZWN0aW9uVGltZW91dE1zPzogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERhdGFGcmFtZSB7XG4gIHR5cGU6ICdkYXRhJztcbiAgaWQ6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBwdWJsaXNoZWQgcGF5bG9hZCwgSlNPTi1lbmNvZGVkICppbnNpZGUqIHRoZSBhbHJlYWR5LUpTT04gZnJhbWUuXG4gICAqIERvdWJsZS1lbmNvZGVkIG9uIHRoZSB3aXJlOyBgcGFyc2VEYXRhRnJhbWVFdmVudGAgdW53cmFwcyBib3RoLlxuICAgKi9cbiAgZXZlbnQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFcnJvckZyYW1lIHtcbiAgdHlwZTogJ2Nvbm5lY3Rpb25fZXJyb3InIHwgJ3N1YnNjcmliZV9lcnJvcicgfCAncHVibGlzaF9lcnJvcic7XG4gIGlkPzogc3RyaW5nO1xuICBlcnJvcnM/OiBBcnJheTx7IGVycm9yVHlwZT86IHN0cmluZzsgbWVzc2FnZT86IHN0cmluZyB9Pjtcbn1cblxuZXhwb3J0IHR5cGUgU2VydmVyRnJhbWUgPVxuICB8IENvbm5lY3Rpb25BY2tGcmFtZVxuICB8IERhdGFGcmFtZVxuICB8IEVycm9yRnJhbWVcbiAgfCB7IHR5cGU6ICdrYScgfVxuICB8IHsgdHlwZTogJ3N1YnNjcmliZV9zdWNjZXNzJzsgaWQ6IHN0cmluZyB9XG4gIHwgeyB0eXBlOiAndW5zdWJzY3JpYmVfc3VjY2Vzcyc7IGlkOiBzdHJpbmcgfVxuICB8IHsgdHlwZTogc3RyaW5nOyBbazogc3RyaW5nXTogdW5rbm93biB9O1xuXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VTZXJ2ZXJGcmFtZShyYXc6IHN0cmluZyk6IFNlcnZlckZyYW1lIHwgbnVsbCB7XG4gIHRyeSB7XG4gICAgY29uc3QgcGFyc2VkID0gSlNPTi5wYXJzZShyYXcpIGFzIHVua25vd247XG4gICAgaWYgKHR5cGVvZiBwYXJzZWQgIT09ICdvYmplY3QnIHx8IHBhcnNlZCA9PT0gbnVsbCkgcmV0dXJuIG51bGw7XG4gICAgY29uc3QgZnJhbWUgPSBwYXJzZWQgYXMgeyB0eXBlPzogdW5rbm93biB9O1xuICAgIGlmICh0eXBlb2YgZnJhbWUudHlwZSAhPT0gJ3N0cmluZycpIHJldHVybiBudWxsO1xuICAgIHJldHVybiBwYXJzZWQgYXMgU2VydmVyRnJhbWU7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBudWxsO1xuICB9XG59XG5cbi8qKiBVbndyYXAgdGhlIGlubmVyIEpTT04gb2YgYSBgZGF0YWAgZnJhbWUuIE51bGwgaWYgaXQgaXNuJ3QgcGFyc2VhYmxlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlRGF0YUZyYW1lRXZlbnQoZnJhbWU6IERhdGFGcmFtZSk6IHVua25vd24ge1xuICB0cnkge1xuICAgIHJldHVybiBKU09OLnBhcnNlKGZyYW1lLmV2ZW50KSBhcyB1bmtub3duO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxufVxuXG4vKiogSHVtYW4tcmVhZGFibGUgdGV4dCBmcm9tIGFuIGVycm9yIGZyYW1lLCBmb3IgYG9uRXJyb3JgLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGVycm9yRnJhbWVNZXNzYWdlKGZyYW1lOiBFcnJvckZyYW1lKTogc3RyaW5nIHtcbiAgY29uc3QgcGFydHMgPSAoZnJhbWUuZXJyb3JzID8/IFtdKVxuICAgIC5tYXAoKGUpID0+IGUubWVzc2FnZSA/PyBlLmVycm9yVHlwZSlcbiAgICAuZmlsdGVyKChtKTogbSBpcyBzdHJpbmcgPT4gdHlwZW9mIG0gPT09ICdzdHJpbmcnICYmIG0ubGVuZ3RoID4gMCk7XG4gIHJldHVybiBwYXJ0cy5sZW5ndGggPiAwID8gcGFydHMuam9pbignOyAnKSA6IGZyYW1lLnR5cGU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjb25uZWN0aW9uSW5pdEZyYW1lKCk6IHN0cmluZyB7XG4gIHJldHVybiBKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdjb25uZWN0aW9uX2luaXQnIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3Vic2NyaWJlRnJhbWUoaWQ6IHN0cmluZywgY2hhbm5lbDogc3RyaW5nLCBhdXRoOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+KTogc3RyaW5nIHtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHsgdHlwZTogJ3N1YnNjcmliZScsIGlkLCBjaGFubmVsLCBhdXRob3JpemF0aW9uOiBhdXRoIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gdW5zdWJzY3JpYmVGcmFtZShpZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHsgdHlwZTogJ3Vuc3Vic2NyaWJlJywgaWQgfSk7XG59XG4iXX0=
|
package/package.json
CHANGED
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uengage.io/platform-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Client SDK for the uEngage platform API (audit, business, zones, wallet, auth). Single createClient(...) factory; OAuth2 client_credentials, static Bearer, or legacy session-token auth modes.",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Client SDK for the uEngage platform API (audit, business, zones, wallet, auth, events). Single createClient(...) factory; OAuth2 client_credentials, static Bearer, or legacy session-token auth modes. Browser-safe realtime client at the /realtime subpath.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"./events": {
|
|
13
|
+
"types": "./dist/events/index.d.ts",
|
|
14
|
+
"default": "./dist/events/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./realtime": {
|
|
17
|
+
"types": "./dist/realtime/index.d.ts",
|
|
18
|
+
"default": "./dist/realtime/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"typesVersions": {
|
|
23
|
+
"*": {
|
|
24
|
+
"events": [
|
|
25
|
+
"./dist/events/index.d.ts"
|
|
26
|
+
],
|
|
27
|
+
"realtime": [
|
|
28
|
+
"./dist/realtime/index.d.ts"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
7
32
|
"files": [
|
|
8
33
|
"dist/",
|
|
9
34
|
"README.md"
|
|
@@ -18,6 +43,8 @@
|
|
|
18
43
|
"sdk",
|
|
19
44
|
"audit",
|
|
20
45
|
"business",
|
|
46
|
+
"events",
|
|
47
|
+
"realtime",
|
|
21
48
|
"hmac"
|
|
22
49
|
],
|
|
23
50
|
"dependencies": {
|
|
@@ -27,12 +54,21 @@
|
|
|
27
54
|
"@uengage.io/js-logger": "0.10.0"
|
|
28
55
|
},
|
|
29
56
|
"devDependencies": {
|
|
57
|
+
"@aws-sdk/client-sns": "^3.668.0",
|
|
30
58
|
"@types/jest": "^29.5.14",
|
|
31
59
|
"@types/node": "^20.14.10",
|
|
32
60
|
"jest": "^29.7.0",
|
|
33
61
|
"ts-jest": "^29.2.5",
|
|
34
62
|
"typescript": "^5.5.4"
|
|
35
63
|
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@aws-sdk/client-sns": "^3.0.0"
|
|
66
|
+
},
|
|
67
|
+
"peerDependenciesMeta": {
|
|
68
|
+
"@aws-sdk/client-sns": {
|
|
69
|
+
"optional": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
36
72
|
"scripts": {
|
|
37
73
|
"build": "tsc",
|
|
38
74
|
"typecheck": "tsc --noEmit",
|