@uengage.io/platform-sdk 0.15.0 → 2.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 +13 -0
- package/dist/client.js +4 -1
- package/dist/config.d.ts +0 -5
- package/dist/config.js +14 -3
- 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/http.js +25 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- 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/dist/upsell/client.d.ts +44 -0
- package/dist/upsell/client.js +136 -0
- package/dist/upsell/index.d.ts +2 -0
- package/dist/upsell/index.js +7 -0
- package/dist/upsell/schema.d.ts +203 -0
- package/dist/upsell/schema.js +12 -0
- package/dist/version.d.ts +7 -1
- package/dist/version.js +8 -2
- package/package.json +38 -2
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.API_BASE = void 0;
|
|
4
|
+
exports.endpointsFor = endpointsFor;
|
|
5
|
+
/**
|
|
6
|
+
* TODO(event-bus): populate `httpDomain` / `realtimeDomain` per
|
|
7
|
+
* environment from the `RealtimeEventApiHttpDns-{env}` and
|
|
8
|
+
* `RealtimeEventApiRealtimeDns-{env}` outputs of `UengageRealtimeService-{env}`
|
|
9
|
+
* once the stack has been deployed there.
|
|
10
|
+
*/
|
|
11
|
+
const ENDPOINTS = {
|
|
12
|
+
dev: null,
|
|
13
|
+
uat: null,
|
|
14
|
+
prod: null,
|
|
15
|
+
};
|
|
16
|
+
/** Platform API base per environment — known ahead of any deploy. */
|
|
17
|
+
exports.API_BASE = {
|
|
18
|
+
dev: 'https://api.dev.platform.uengage.io',
|
|
19
|
+
uat: 'https://api.uat.platform.uengage.io',
|
|
20
|
+
prod: 'https://api.platform.uengage.io',
|
|
21
|
+
};
|
|
22
|
+
function endpointsFor(env) {
|
|
23
|
+
const found = ENDPOINTS[env];
|
|
24
|
+
if (!found) {
|
|
25
|
+
throw new Error(`realtime.connect: no endpoints registered for env "${env}". ` +
|
|
26
|
+
'Pass {endpoints: {httpDomain, realtimeDomain, apiBase}} explicitly, or fill in ' +
|
|
27
|
+
"src/realtime/endpoints.ts from the realtime stack's RealtimeEventApi*Dns outputs.");
|
|
28
|
+
}
|
|
29
|
+
return found;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW5kcG9pbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3JlYWx0aW1lL2VuZHBvaW50cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUEyQ0Esb0NBVUM7QUE3QkQ7Ozs7O0dBS0c7QUFDSCxNQUFNLFNBQVMsR0FBa0Q7SUFDL0QsR0FBRyxFQUFFLElBQUk7SUFDVCxHQUFHLEVBQUUsSUFBSTtJQUNULElBQUksRUFBRSxJQUFJO0NBQ1gsQ0FBQztBQUVGLHFFQUFxRTtBQUN4RCxRQUFBLFFBQVEsR0FBZ0M7SUFDbkQsR0FBRyxFQUFFLHFDQUFxQztJQUMxQyxHQUFHLEVBQUUscUNBQXFDO0lBQzFDLElBQUksRUFBRSxpQ0FBaUM7Q0FDeEMsQ0FBQztBQUVGLFNBQWdCLFlBQVksQ0FBQyxHQUFnQjtJQUMzQyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ1gsTUFBTSxJQUFJLEtBQUssQ0FDYixzREFBc0QsR0FBRyxLQUFLO1lBQzVELGlGQUFpRjtZQUNqRixtRkFBbUYsQ0FDdEYsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFBlci1lbnZpcm9ubWVudCByZWFsdGltZSBlbmRwb2ludHMuXG4gKlxuICogRnJvbnRlbmRzIHBhc3MgYGNvbm5lY3QoeyBlbnY6ICdwcm9kJyB9KWAgYW5kIGdldCBVUkxzIGZyb20gaGVyZSDigJQgbm9cbiAqIGhvc3RuYW1lcyBvciBBUk5zIGluIGFwcCBjb2RlLlxuICpcbiAqIEFwcFN5bmMgYXNzaWducyB0aGUgRXZlbnQgQVBJJ3MgRE5TIG5hbWVzIGF0IGNyZWF0ZSB0aW1lXG4gKiAoYDxhcGlJZD4uYXBwc3luYy1hcGkuPHJlZ2lvbj4uYW1hem9uYXdzLmNvbWAgYW5kIHRoZSBtYXRjaGluZ1xuICogYGFwcHN5bmMtcmVhbHRpbWUtYXBpYCBob3N0KSwgc28gdGhleSBjYW5ub3QgYmUga25vd24gYmVmb3JlIHRoZSBzdGFja1xuICogaXMgZGVwbG95ZWQuIFVudGlsIGBzZXJ2aWNlcy9yZWFsdGltZWAgaGFzIGJlZW4gZGVwbG95ZWQgdG8gYW5cbiAqIGVudmlyb25tZW50IGl0cyBlbnRyeSBzdGF5cyBudWxsIGFuZCBgY29ubmVjdCh7IGVudiB9KWAgdGhyb3dzIHdpdGhcbiAqIGluc3RydWN0aW9uczsgYGNvbm5lY3QoeyBlbmRwb2ludHMgfSlgIGFsd2F5cyB3b3Jrcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSZWFsdGltZUVuZHBvaW50cyB7XG4gIC8qKiBBcHBTeW5jIEV2ZW50IEFQSSBIVFRQIGRvbWFpbi4gQWxzbyB0aGUgYGhvc3RgIGluIHRoZSBhdXRoIGhlYWRlci4gKi9cbiAgaHR0cERvbWFpbjogc3RyaW5nO1xuICAvKiogQXBwU3luYyBFdmVudCBBUEkgcmVhbHRpbWUgKFdlYlNvY2tldCkgZG9tYWluLiAqL1xuICByZWFsdGltZURvbWFpbjogc3RyaW5nO1xuICAvKiogUGxhdGZvcm0gQVBJIGJhc2UgVVJMLCB1c2VkIGZvciB0aGUgbGFzdC12YWx1ZSBzbmFwc2hvdCBmZXRjaC4gKi9cbiAgYXBpQmFzZTogc3RyaW5nO1xufVxuXG5leHBvcnQgdHlwZSBSZWFsdGltZUVudiA9ICdkZXYnIHwgJ3VhdCcgfCAncHJvZCc7XG5cbi8qKlxuICogVE9ETyhldmVudC1idXMpOiBwb3B1bGF0ZSBgaHR0cERvbWFpbmAgLyBgcmVhbHRpbWVEb21haW5gIHBlclxuICogZW52aXJvbm1lbnQgZnJvbSB0aGUgYFJlYWx0aW1lRXZlbnRBcGlIdHRwRG5zLXtlbnZ9YCBhbmRcbiAqIGBSZWFsdGltZUV2ZW50QXBpUmVhbHRpbWVEbnMte2Vudn1gIG91dHB1dHMgb2YgYFVlbmdhZ2VSZWFsdGltZVNlcnZpY2Ute2Vudn1gXG4gKiBvbmNlIHRoZSBzdGFjayBoYXMgYmVlbiBkZXBsb3llZCB0aGVyZS5cbiAqL1xuY29uc3QgRU5EUE9JTlRTOiBSZWNvcmQ8UmVhbHRpbWVFbnYsIFJlYWx0aW1lRW5kcG9pbnRzIHwgbnVsbD4gPSB7XG4gIGRldjogbnVsbCxcbiAgdWF0OiBudWxsLFxuICBwcm9kOiBudWxsLFxufTtcblxuLyoqIFBsYXRmb3JtIEFQSSBiYXNlIHBlciBlbnZpcm9ubWVudCDigJQga25vd24gYWhlYWQgb2YgYW55IGRlcGxveS4gKi9cbmV4cG9ydCBjb25zdCBBUElfQkFTRTogUmVjb3JkPFJlYWx0aW1lRW52LCBzdHJpbmc+ID0ge1xuICBkZXY6ICdodHRwczovL2FwaS5kZXYucGxhdGZvcm0udWVuZ2FnZS5pbycsXG4gIHVhdDogJ2h0dHBzOi8vYXBpLnVhdC5wbGF0Zm9ybS51ZW5nYWdlLmlvJyxcbiAgcHJvZDogJ2h0dHBzOi8vYXBpLnBsYXRmb3JtLnVlbmdhZ2UuaW8nLFxufTtcblxuZXhwb3J0IGZ1bmN0aW9uIGVuZHBvaW50c0ZvcihlbnY6IFJlYWx0aW1lRW52KTogUmVhbHRpbWVFbmRwb2ludHMge1xuICBjb25zdCBmb3VuZCA9IEVORFBPSU5UU1tlbnZdO1xuICBpZiAoIWZvdW5kKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYHJlYWx0aW1lLmNvbm5lY3Q6IG5vIGVuZHBvaW50cyByZWdpc3RlcmVkIGZvciBlbnYgXCIke2Vudn1cIi4gYCArXG4gICAgICAgICdQYXNzIHtlbmRwb2ludHM6IHtodHRwRG9tYWluLCByZWFsdGltZURvbWFpbiwgYXBpQmFzZX19IGV4cGxpY2l0bHksIG9yIGZpbGwgaW4gJyArXG4gICAgICAgIFwic3JjL3JlYWx0aW1lL2VuZHBvaW50cy50cyBmcm9tIHRoZSByZWFsdGltZSBzdGFjaydzIFJlYWx0aW1lRXZlbnRBcGkqRG5zIG91dHB1dHMuXCIsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gZm91bmQ7XG59XG4iXX0=
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency-free envelope guard for the browser realtime client.
|
|
3
|
+
*
|
|
4
|
+
* This mirrors `@uengage/common`'s `platformEventSchema` and the SDK's own
|
|
5
|
+
* `events/schema.ts`, but hand-rolled: the `/realtime` subpath ships with
|
|
6
|
+
* zero runtime dependencies (no zod, no Node built-ins) so it stays a few
|
|
7
|
+
* KB in a frontend bundle. Change one, change all three.
|
|
8
|
+
*
|
|
9
|
+
* NO DOMAIN CROSS-CHECK, deliberately — this is the one mirror that does
|
|
10
|
+
* not carry the resource→domain map, and it is not an oversight:
|
|
11
|
+
*
|
|
12
|
+
* - It would be checking the wrong thing. The producing SDK derives
|
|
13
|
+
* `domain` from `type` and the consuming service re-validates the pair
|
|
14
|
+
* before it ever publishes to a channel. By the time an envelope
|
|
15
|
+
* reaches a browser the pair has been checked twice server-side; a
|
|
16
|
+
* third check can only reject, never repair.
|
|
17
|
+
* - It would rot dangerously. A browser bundle sits in someone's cache
|
|
18
|
+
* for weeks. Baking today's map into it means that the day a new
|
|
19
|
+
* domain ships, every un-refreshed tab starts silently dropping live
|
|
20
|
+
* events for it — a stale client rejecting the future, which is the
|
|
21
|
+
* failure mode `validatePlatformEvent` is careful to avoid even
|
|
22
|
+
* server-side.
|
|
23
|
+
*
|
|
24
|
+
* So the guard is structural only: shapes and types, not membership.
|
|
25
|
+
* `packages/platform-sdk/test/events/domain-map.test.ts` asserts that
|
|
26
|
+
* every canonical domain is accepted, and that an unlisted one is too.
|
|
27
|
+
*/
|
|
28
|
+
/** The platform event-bus envelope, as it arrives at a browser. */
|
|
29
|
+
export interface RealtimeEvent {
|
|
30
|
+
id: string;
|
|
31
|
+
type: string;
|
|
32
|
+
domain: string;
|
|
33
|
+
source: string;
|
|
34
|
+
version: number;
|
|
35
|
+
occurredAt: string;
|
|
36
|
+
tenantId: string;
|
|
37
|
+
data: Record<string, unknown>;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Structural check on an untrusted payload. Returns the event or null —
|
|
41
|
+
* never throws, because a single malformed frame must not tear down a
|
|
42
|
+
* live subscription.
|
|
43
|
+
*/
|
|
44
|
+
export declare function asRealtimeEvent(value: unknown): RealtimeEvent | null;
|
|
45
|
+
/**
|
|
46
|
+
* Ordering/dedupe guard, keyed on the envelope's monotonic ULID.
|
|
47
|
+
*
|
|
48
|
+
* ULIDs are lexicographically sortable by mint time, so a plain string
|
|
49
|
+
* compare orders events without parsing timestamps or knowing anything
|
|
50
|
+
* about the domain. This is what makes at-least-once delivery and the
|
|
51
|
+
* snapshot/stream race both harmless: whichever arrives second with an
|
|
52
|
+
* id <= the one already rendered is dropped.
|
|
53
|
+
*/
|
|
54
|
+
export declare function isNewer(candidateId: string, seenId: string | undefined): boolean;
|
|
@@ -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=
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type PlatformAuth, type PlatformAuthInput, type PlatformConfigInput } from '../config';
|
|
2
|
+
import type { Placement, PlacementDeleteInput, PlacementRecord, PlacementUpsertInput, PlacementsQuery, SuggestionsInput, SuggestionsResult, UpsellEventsInput } from './schema';
|
|
3
|
+
export interface UpsellClient {
|
|
4
|
+
config(input: PlatformConfigInput): UpsellClient;
|
|
5
|
+
auth(input: PlatformAuthInput | PlatformAuth): UpsellClient;
|
|
6
|
+
/** GET /v1/upsell/placements - resolved placements for a channel + tenant. */
|
|
7
|
+
placements(query: PlacementsQuery): Promise<Placement[]>;
|
|
8
|
+
/** POST /v1/upsell/suggestions - items for one placement given the live cart. */
|
|
9
|
+
suggest(input: SuggestionsInput): Promise<SuggestionsResult>;
|
|
10
|
+
/**
|
|
11
|
+
* POST /v1/upsell/events - report shown / added / ignored for a
|
|
12
|
+
* rendered placement. Fire-and-forget; feeds attach-rate measurement
|
|
13
|
+
* and the weight tuning that follows it.
|
|
14
|
+
*/
|
|
15
|
+
reportEvents(input: UpsellEventsInput): Promise<{
|
|
16
|
+
accepted: number;
|
|
17
|
+
}>;
|
|
18
|
+
/** GET /v1/upsell/admin/placements - raw config rows (service-actor only). */
|
|
19
|
+
adminListPlacements(opts?: {
|
|
20
|
+
parentId?: number;
|
|
21
|
+
}): Promise<PlacementRecord[]>;
|
|
22
|
+
/** PUT /v1/upsell/admin/placements - create/replace a config row (service-actor only). */
|
|
23
|
+
adminUpsertPlacement(input: PlacementUpsertInput): Promise<PlacementRecord>;
|
|
24
|
+
/** DELETE /v1/upsell/admin/placements - throws UpsellApiError(404) if absent. */
|
|
25
|
+
adminDeletePlacement(input: PlacementDeleteInput): Promise<void>;
|
|
26
|
+
}
|
|
27
|
+
export declare class UpsellApiError extends Error {
|
|
28
|
+
readonly status: number;
|
|
29
|
+
readonly body: string;
|
|
30
|
+
constructor(status: number, body: string);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the `upsell` namespace.
|
|
34
|
+
*
|
|
35
|
+
* Shape and contract mirror {@link createZonesClient} - lazy config
|
|
36
|
+
* resolution via {@link ConfigState}, shared 401-retry via
|
|
37
|
+
* {@link sendWithAuthRetry}, immutable per-call config; no globals.
|
|
38
|
+
*
|
|
39
|
+
* Reads (`placements`, `suggest`) accept user or service tokens —
|
|
40
|
+
* channel apps call them with customer session JWTs. Admin methods
|
|
41
|
+
* require a service-actor token; the server answers 403 otherwise and
|
|
42
|
+
* we surface it as {@link UpsellApiError}.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createUpsellClient(input?: PlatformConfigInput): UpsellClient;
|