@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,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createEventsClient = createEventsClient;
|
|
4
|
+
const client_sns_1 = require("@aws-sdk/client-sns");
|
|
5
|
+
const ulid_1 = require("ulid");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const schema_1 = require("./schema");
|
|
8
|
+
/** SNS caps PublishBatch at 10 entries per call. */
|
|
9
|
+
const SNS_BATCH_MAX = 10;
|
|
10
|
+
/**
|
|
11
|
+
* SNS caps a single message at 256 KB, and a whole PublishBatch request
|
|
12
|
+
* at the same 256 KB across all its entries.
|
|
13
|
+
*/
|
|
14
|
+
const SNS_MAX_BYTES = 262_144;
|
|
15
|
+
/**
|
|
16
|
+
* Headroom left for the `type` / `domain` / `source` message attributes,
|
|
17
|
+
* which count toward the limit alongside the body. A few hundred bytes
|
|
18
|
+
* covers them; being conservative here costs nothing, since an envelope
|
|
19
|
+
* anywhere near the cap is a call-site mistake either way.
|
|
20
|
+
*/
|
|
21
|
+
const ATTRIBUTE_ALLOWANCE_BYTES = 1_024;
|
|
22
|
+
const MAX_MESSAGE_BYTES = SNS_MAX_BYTES - ATTRIBUTE_ALLOWANCE_BYTES;
|
|
23
|
+
/**
|
|
24
|
+
* Byte length of a UTF-8 string. `TextEncoder` rather than
|
|
25
|
+
* `Buffer.byteLength` so this file carries no Node built-in.
|
|
26
|
+
*/
|
|
27
|
+
const encoder = new TextEncoder();
|
|
28
|
+
function byteLength(value) {
|
|
29
|
+
return encoder.encode(value).length;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Monotonic within this process: two events minted in the same
|
|
33
|
+
* millisecond still sort in emission order. Downstream consumers use the
|
|
34
|
+
* envelope `id` as the ordering and dedupe key, so this is load-bearing,
|
|
35
|
+
* not a nicety.
|
|
36
|
+
*/
|
|
37
|
+
const nextUlid = (0, ulid_1.monotonicFactory)();
|
|
38
|
+
/**
|
|
39
|
+
* Build an isolated events client. Reads `PLATFORM_EVENTS_TOPIC_ARN` and
|
|
40
|
+
* friends from the environment for anything not passed explicitly, so a
|
|
41
|
+
* Lambda whose deploy stack injected the ARN needs no arguments.
|
|
42
|
+
*/
|
|
43
|
+
function createEventsClient(input = {}) {
|
|
44
|
+
let client = input.snsClient;
|
|
45
|
+
function topicArn() {
|
|
46
|
+
const arn = input.topicArn ?? env('PLATFORM_EVENTS_TOPIC_ARN');
|
|
47
|
+
if (!arn) {
|
|
48
|
+
throw new errors_1.ConfigError('events.publish: no topic ARN. Pass {topicArn} to createEventsClient or set PLATFORM_EVENTS_TOPIC_ARN.');
|
|
49
|
+
}
|
|
50
|
+
return arn;
|
|
51
|
+
}
|
|
52
|
+
function sns() {
|
|
53
|
+
if (!client) {
|
|
54
|
+
const region = input.region ?? regionFromArn(topicArn()) ?? env('AWS_REGION') ?? env('AWS_DEFAULT_REGION');
|
|
55
|
+
client = new client_sns_1.SNSClient(region ? { region } : {});
|
|
56
|
+
}
|
|
57
|
+
return client;
|
|
58
|
+
}
|
|
59
|
+
function source(override) {
|
|
60
|
+
return (override ??
|
|
61
|
+
input.source ??
|
|
62
|
+
env('PLATFORM_EVENTS_SOURCE') ??
|
|
63
|
+
env('SERVICE_NAME') ??
|
|
64
|
+
'platform-sdk');
|
|
65
|
+
}
|
|
66
|
+
function buildEnvelope(type, data, opts) {
|
|
67
|
+
const domain = (0, schema_1.domainForEventType)(type);
|
|
68
|
+
if (!domain) {
|
|
69
|
+
throw new errors_1.ValidationError(`events.publish: cannot route event type "${type}". It must be a dotted ` +
|
|
70
|
+
'"<resource>.<operation>" name whose resource maps to a known bus domain ' +
|
|
71
|
+
'(order, customer, menu, offer, loyalty, usage). Adding a domain is a one-line ' +
|
|
72
|
+
'edit in events/schema.ts and its two mirrors.');
|
|
73
|
+
}
|
|
74
|
+
const candidate = {
|
|
75
|
+
id: nextUlid(),
|
|
76
|
+
type,
|
|
77
|
+
domain,
|
|
78
|
+
source: source(opts.source),
|
|
79
|
+
version: schema_1.PLATFORM_EVENT_VERSION,
|
|
80
|
+
occurredAt: opts.occurredAt ?? isoNow(),
|
|
81
|
+
tenantId: opts.tenantId,
|
|
82
|
+
data,
|
|
83
|
+
};
|
|
84
|
+
const result = schema_1.platformEventSchema.safeParse(candidate);
|
|
85
|
+
if (!result.success) {
|
|
86
|
+
throw new errors_1.ValidationError(`events.publish: invalid envelope for "${type}"`, {
|
|
87
|
+
issues: result.error.issues,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return result.data;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Serialize and size-check one envelope.
|
|
94
|
+
*
|
|
95
|
+
* Checked before the publish rather than after the rejection because
|
|
96
|
+
* SNS's own error for an oversized message names neither the event nor
|
|
97
|
+
* the offending field, and on the PHP side the same failure disappears
|
|
98
|
+
* into `error_log`. Better to say which event and how big.
|
|
99
|
+
*/
|
|
100
|
+
function serialize(event) {
|
|
101
|
+
const message = JSON.stringify(event);
|
|
102
|
+
const size = byteLength(message);
|
|
103
|
+
if (size > MAX_MESSAGE_BYTES) {
|
|
104
|
+
throw new errors_1.ValidationError(`events.publish: event ${event.id} ("${event.type}") serializes to ${size} bytes, ` +
|
|
105
|
+
`over the ${MAX_MESSAGE_BYTES}-byte ceiling (SNS caps a message at 256KB including ` +
|
|
106
|
+
'attributes). Put the payload somewhere addressable and reference it from `data`.');
|
|
107
|
+
}
|
|
108
|
+
return message;
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
async publish(type, data, opts) {
|
|
112
|
+
const event = buildEnvelope(type, data, opts);
|
|
113
|
+
const message = serialize(event);
|
|
114
|
+
const arn = topicArn();
|
|
115
|
+
try {
|
|
116
|
+
await sns().send(new client_sns_1.PublishCommand({
|
|
117
|
+
TopicArn: arn,
|
|
118
|
+
Message: message,
|
|
119
|
+
MessageAttributes: messageAttributes(event),
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
throw new errors_1.EventPublishError(`events.publish: SNS publish failed for "${type}"`, {
|
|
124
|
+
failedEventIds: [event.id],
|
|
125
|
+
cause: err,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return event;
|
|
129
|
+
},
|
|
130
|
+
async publishBatch(events) {
|
|
131
|
+
if (events.length === 0)
|
|
132
|
+
return [];
|
|
133
|
+
const envelopes = events.map((e) => buildEnvelope(e.type, e.data, e));
|
|
134
|
+
// Serialize (and size-check) everything up front, so an oversized
|
|
135
|
+
// event fails the call before any of its siblings are published.
|
|
136
|
+
const messages = new Map(envelopes.map((event) => [event.id, serialize(event)]));
|
|
137
|
+
const arn = topicArn();
|
|
138
|
+
const failed = [];
|
|
139
|
+
let firstError;
|
|
140
|
+
for (const group of chunkByBytes(envelopes, messages)) {
|
|
141
|
+
const entries = group.map((event) => ({
|
|
142
|
+
Id: event.id,
|
|
143
|
+
Message: messages.get(event.id),
|
|
144
|
+
MessageAttributes: messageAttributes(event),
|
|
145
|
+
}));
|
|
146
|
+
try {
|
|
147
|
+
const resp = await sns().send(new client_sns_1.PublishBatchCommand({ TopicArn: arn, PublishBatchRequestEntries: entries }));
|
|
148
|
+
for (const f of resp.Failed ?? []) {
|
|
149
|
+
if (f.Id)
|
|
150
|
+
failed.push(f.Id);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
firstError = firstError ?? err;
|
|
155
|
+
for (const event of group)
|
|
156
|
+
failed.push(event.id);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (failed.length > 0) {
|
|
160
|
+
throw new errors_1.EventPublishError(`events.publishBatch: ${failed.length}/${envelopes.length} event(s) did not reach the bus`, { failedEventIds: failed, cause: firstError });
|
|
161
|
+
}
|
|
162
|
+
return envelopes;
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function messageAttributes(event) {
|
|
167
|
+
return {
|
|
168
|
+
type: { DataType: 'String', StringValue: event.type },
|
|
169
|
+
domain: { DataType: 'String', StringValue: event.domain },
|
|
170
|
+
source: { DataType: 'String', StringValue: event.source },
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/** `arn:aws:sns:<region>:<account>:<name>` → `<region>`. */
|
|
174
|
+
function regionFromArn(arn) {
|
|
175
|
+
const parts = arn.split(':');
|
|
176
|
+
return parts.length >= 4 && parts[3] ? parts[3] : undefined;
|
|
177
|
+
}
|
|
178
|
+
/** UTC ISO 8601, seconds precision — the format the envelope schema pins. */
|
|
179
|
+
function isoNow() {
|
|
180
|
+
return new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
181
|
+
}
|
|
182
|
+
function env(name) {
|
|
183
|
+
if (typeof process === 'undefined')
|
|
184
|
+
return undefined;
|
|
185
|
+
const value = process.env?.[name];
|
|
186
|
+
return value === '' ? undefined : value;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Group envelopes into PublishBatch calls bounded by BOTH limits: at most
|
|
190
|
+
* 10 entries, and at most 256 KB of combined payload.
|
|
191
|
+
*
|
|
192
|
+
* The byte bound matters as soon as payloads get rich — ten 30 KB
|
|
193
|
+
* envelopes are each individually legal and collectively over the
|
|
194
|
+
* request cap, and SNS rejects the whole call rather than the overflow.
|
|
195
|
+
*/
|
|
196
|
+
function chunkByBytes(envelopes, messages) {
|
|
197
|
+
const out = [];
|
|
198
|
+
let current = [];
|
|
199
|
+
let currentBytes = 0;
|
|
200
|
+
for (const event of envelopes) {
|
|
201
|
+
const size = byteLength(messages.get(event.id)) + ATTRIBUTE_ALLOWANCE_BYTES;
|
|
202
|
+
const full = current.length >= SNS_BATCH_MAX;
|
|
203
|
+
const wouldOverflow = current.length > 0 && currentBytes + size > SNS_MAX_BYTES;
|
|
204
|
+
if (full || wouldOverflow) {
|
|
205
|
+
out.push(current);
|
|
206
|
+
current = [];
|
|
207
|
+
currentBytes = 0;
|
|
208
|
+
}
|
|
209
|
+
current.push(event);
|
|
210
|
+
currentBytes += size;
|
|
211
|
+
}
|
|
212
|
+
if (current.length > 0)
|
|
213
|
+
out.push(current);
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V2ZW50cy9jbGllbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUEySUEsZ0RBa0pDO0FBN1JELG9EQU02QjtBQUM3QiwrQkFBd0M7QUFDeEMsc0NBQTRFO0FBQzVFLHFDQUtrQjtBQUVsQixvREFBb0Q7QUFDcEQsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFDO0FBRXpCOzs7R0FHRztBQUNILE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQztBQUU5Qjs7Ozs7R0FLRztBQUNILE1BQU0seUJBQXlCLEdBQUcsS0FBSyxDQUFDO0FBRXhDLE1BQU0saUJBQWlCLEdBQUcsYUFBYSxHQUFHLHlCQUF5QixDQUFDO0FBRXBFOzs7R0FHRztBQUNILE1BQU0sT0FBTyxHQUFHLElBQUksV0FBVyxFQUFFLENBQUM7QUFFbEMsU0FBUyxVQUFVLENBQUMsS0FBYTtJQUMvQixPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDO0FBQ3RDLENBQUM7QUFFRDs7Ozs7R0FLRztBQUNILE1BQU0sUUFBUSxHQUFHLElBQUEsdUJBQWdCLEdBQUUsQ0FBQztBQW1GcEM7Ozs7R0FJRztBQUNILFNBQWdCLGtCQUFrQixDQUFDLFFBQTJCLEVBQUU7SUFDOUQsSUFBSSxNQUFNLEdBQTBCLEtBQUssQ0FBQyxTQUFTLENBQUM7SUFFcEQsU0FBUyxRQUFRO1FBQ2YsTUFBTSxHQUFHLEdBQUcsS0FBSyxDQUFDLFFBQVEsSUFBSSxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQztRQUMvRCxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDVCxNQUFNLElBQUksb0JBQVcsQ0FDbkIsdUdBQXVHLENBQ3hHLENBQUM7UUFDSixDQUFDO1FBQ0QsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQsU0FBUyxHQUFHO1FBQ1YsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxNQUFNLEdBQ1YsS0FBSyxDQUFDLE1BQU0sSUFBSSxhQUFhLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksR0FBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDOUYsTUFBTSxHQUFHLElBQUksc0JBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELENBQUM7UUFDRCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsU0FBUyxNQUFNLENBQUMsUUFBaUI7UUFDL0IsT0FBTyxDQUNMLFFBQVE7WUFDUixLQUFLLENBQUMsTUFBTTtZQUNaLEdBQUcsQ0FBQyx3QkFBd0IsQ0FBQztZQUM3QixHQUFHLENBQUMsY0FBYyxDQUFDO1lBQ25CLGNBQWMsQ0FDZixDQUFDO0lBQ0osQ0FBQztJQUVELFNBQVMsYUFBYSxDQUNwQixJQUFZLEVBQ1osSUFBNkIsRUFDN0IsSUFBb0I7UUFFcEIsTUFBTSxNQUFNLEdBQUcsSUFBQSwyQkFBa0IsRUFBQyxJQUFJLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDWixNQUFNLElBQUksd0JBQWUsQ0FDdkIsNENBQTRDLElBQUkseUJBQXlCO2dCQUN2RSwwRUFBMEU7Z0JBQzFFLGdGQUFnRjtnQkFDaEYsK0NBQStDLENBQ2xELENBQUM7UUFDSixDQUFDO1FBQ0QsTUFBTSxTQUFTLEdBQUc7WUFDaEIsRUFBRSxFQUFFLFFBQVEsRUFBRTtZQUNkLElBQUk7WUFDSixNQUFNO1lBQ04sTUFBTSxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDO1lBQzNCLE9BQU8sRUFBRSwrQkFBc0I7WUFDL0IsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLElBQUksTUFBTSxFQUFFO1lBQ3ZDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUTtZQUN2QixJQUFJO1NBQ0wsQ0FBQztRQUNGLE1BQU0sTUFBTSxHQUFHLDRCQUFtQixDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUN4RCxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSx3QkFBZSxDQUFDLHlDQUF5QyxJQUFJLEdBQUcsRUFBRTtnQkFDMUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTTthQUM1QixDQUFDLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsU0FBUyxTQUFTLENBQUMsS0FBb0I7UUFDckMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0QyxNQUFNLElBQUksR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDakMsSUFBSSxJQUFJLEdBQUcsaUJBQWlCLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksd0JBQWUsQ0FDdkIseUJBQXlCLEtBQUssQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDLElBQUksb0JBQW9CLElBQUksVUFBVTtnQkFDakYsWUFBWSxpQkFBaUIsdURBQXVEO2dCQUNwRixrRkFBa0YsQ0FDckYsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBRUQsT0FBTztRQUNMLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxJQUFJO1lBQzVCLE1BQU0sS0FBSyxHQUFHLGFBQWEsQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQzlDLE1BQU0sT0FBTyxHQUFHLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUNqQyxNQUFNLEdBQUcsR0FBRyxRQUFRLEVBQUUsQ0FBQztZQUN2QixJQUFJLENBQUM7Z0JBQ0gsTUFBTSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQ2QsSUFBSSwyQkFBYyxDQUFDO29CQUNqQixRQUFRLEVBQUUsR0FBRztvQkFDYixPQUFPLEVBQUUsT0FBTztvQkFDaEIsaUJBQWlCLEVBQUUsaUJBQWlCLENBQUMsS0FBSyxDQUFDO2lCQUM1QyxDQUFDLENBQ0gsQ0FBQztZQUNKLENBQUM7WUFBQyxPQUFPLEdBQUcsRUFBRSxDQUFDO2dCQUNiLE1BQU0sSUFBSSwwQkFBaUIsQ0FBQywyQ0FBMkMsSUFBSSxHQUFHLEVBQUU7b0JBQzlFLGNBQWMsRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7b0JBQzFCLEtBQUssRUFBRSxHQUFHO2lCQUNYLENBQUMsQ0FBQztZQUNMLENBQUM7WUFDRCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxLQUFLLENBQUMsWUFBWSxDQUFDLE1BQU07WUFDdkIsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUM7Z0JBQUUsT0FBTyxFQUFFLENBQUM7WUFDbkMsTUFBTSxTQUFTLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3RFLGtFQUFrRTtZQUNsRSxpRUFBaUU7WUFDakUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxFQUFFLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNqRixNQUFNLEdBQUcsR0FBRyxRQUFRLEVBQUUsQ0FBQztZQUV2QixNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7WUFDNUIsSUFBSSxVQUFtQixDQUFDO1lBQ3hCLEtBQUssTUFBTSxLQUFLLElBQUksWUFBWSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDO2dCQUN0RCxNQUFNLE9BQU8sR0FBK0IsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztvQkFDaEUsRUFBRSxFQUFFLEtBQUssQ0FBQyxFQUFFO29CQUNaLE9BQU8sRUFBRSxRQUFRLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQVc7b0JBQ3pDLGlCQUFpQixFQUFFLGlCQUFpQixDQUFDLEtBQUssQ0FBQztpQkFDNUMsQ0FBQyxDQUFDLENBQUM7Z0JBQ0osSUFBSSxDQUFDO29CQUNILE1BQU0sSUFBSSxHQUFHLE1BQU0sR0FBRyxFQUFFLENBQUMsSUFBSSxDQUMzQixJQUFJLGdDQUFtQixDQUFDLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRSwwQkFBMEIsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUNoRixDQUFDO29CQUNGLEtBQUssTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sSUFBSSxFQUFFLEVBQUUsQ0FBQzt3QkFDbEMsSUFBSSxDQUFDLENBQUMsRUFBRTs0QkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDOUIsQ0FBQztnQkFDSCxDQUFDO2dCQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7b0JBQ2IsVUFBVSxHQUFHLFVBQVUsSUFBSSxHQUFHLENBQUM7b0JBQy9CLEtBQUssTUFBTSxLQUFLLElBQUksS0FBSzt3QkFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDbkQsQ0FBQztZQUNILENBQUM7WUFFRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSwwQkFBaUIsQ0FDekIsd0JBQXdCLE1BQU0sQ0FBQyxNQUFNLElBQUksU0FBUyxDQUFDLE1BQU0saUNBQWlDLEVBQzFGLEVBQUUsY0FBYyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsVUFBVSxFQUFFLENBQzlDLENBQUM7WUFDSixDQUFDO1lBQ0QsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztLQUNGLENBQUM7QUFDSixDQUFDO0FBRUQsU0FBUyxpQkFBaUIsQ0FBQyxLQUFvQjtJQUM3QyxPQUFPO1FBQ0wsSUFBSSxFQUFFLEVBQUUsUUFBUSxFQUFFLFFBQVEsRUFBRSxXQUFXLEVBQUUsS0FBSyxDQUFDLElBQUksRUFBRTtRQUNyRCxNQUFNLEVBQUUsRUFBRSxRQUFRLEVBQUUsUUFBUSxFQUFFLFdBQVcsRUFBRSxLQUFLLENBQUMsTUFBTSxFQUFFO1FBQ3pELE1BQU0sRUFBRSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUU7S0FDMUQsQ0FBQztBQUNKLENBQUM7QUFFRCw0REFBNEQ7QUFDNUQsU0FBUyxhQUFhLENBQUMsR0FBVztJQUNoQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzdCLE9BQU8sS0FBSyxDQUFDLE1BQU0sSUFBSSxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUM5RCxDQUFDO0FBRUQsNkVBQTZFO0FBQzdFLFNBQVMsTUFBTTtJQUNiLE9BQU8sSUFBSSxJQUFJLEVBQUUsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFDO0FBQzVELENBQUM7QUFFRCxTQUFTLEdBQUcsQ0FBQyxJQUFZO0lBQ3ZCLElBQUksT0FBTyxPQUFPLEtBQUssV0FBVztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ3JELE1BQU0sS0FBSyxHQUFJLE9BQXdELENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDcEYsT0FBTyxLQUFLLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztBQUMxQyxDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILFNBQVMsWUFBWSxDQUNuQixTQUEwQixFQUMxQixRQUE2QjtJQUU3QixNQUFNLEdBQUcsR0FBc0IsRUFBRSxDQUFDO0lBQ2xDLElBQUksT0FBTyxHQUFvQixFQUFFLENBQUM7SUFDbEMsSUFBSSxZQUFZLEdBQUcsQ0FBQyxDQUFDO0lBRXJCLEtBQUssTUFBTSxLQUFLLElBQUksU0FBUyxFQUFFLENBQUM7UUFDOUIsTUFBTSxJQUFJLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBVyxDQUFDLEdBQUcseUJBQXlCLENBQUM7UUFDdEYsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxhQUFhLENBQUM7UUFDN0MsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLElBQUksWUFBWSxHQUFHLElBQUksR0FBRyxhQUFhLENBQUM7UUFDaEYsSUFBSSxJQUFJLElBQUksYUFBYSxFQUFFLENBQUM7WUFDMUIsR0FBRyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNsQixPQUFPLEdBQUcsRUFBRSxDQUFDO1lBQ2IsWUFBWSxHQUFHLENBQUMsQ0FBQztRQUNuQixDQUFDO1FBQ0QsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNwQixZQUFZLElBQUksSUFBSSxDQUFDO0lBQ3ZCLENBQUM7SUFDRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQztRQUFFLEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDMUMsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgU05TQ2xpZW50LFxuICBQdWJsaXNoQ29tbWFuZCxcbiAgUHVibGlzaEJhdGNoQ29tbWFuZCxcbiAgdHlwZSBQdWJsaXNoQmF0Y2hSZXF1ZXN0RW50cnksXG4gIHR5cGUgTWVzc2FnZUF0dHJpYnV0ZVZhbHVlLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtc25zJztcbmltcG9ydCB7IG1vbm90b25pY0ZhY3RvcnkgfSBmcm9tICd1bGlkJztcbmltcG9ydCB7IENvbmZpZ0Vycm9yLCBFdmVudFB1Ymxpc2hFcnJvciwgVmFsaWRhdGlvbkVycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcbmltcG9ydCB7XG4gIGRvbWFpbkZvckV2ZW50VHlwZSxcbiAgcGxhdGZvcm1FdmVudFNjaGVtYSxcbiAgUExBVEZPUk1fRVZFTlRfVkVSU0lPTixcbiAgdHlwZSBQbGF0Zm9ybUV2ZW50LFxufSBmcm9tICcuL3NjaGVtYSc7XG5cbi8qKiBTTlMgY2FwcyBQdWJsaXNoQmF0Y2ggYXQgMTAgZW50cmllcyBwZXIgY2FsbC4gKi9cbmNvbnN0IFNOU19CQVRDSF9NQVggPSAxMDtcblxuLyoqXG4gKiBTTlMgY2FwcyBhIHNpbmdsZSBtZXNzYWdlIGF0IDI1NiBLQiwgYW5kIGEgd2hvbGUgUHVibGlzaEJhdGNoIHJlcXVlc3RcbiAqIGF0IHRoZSBzYW1lIDI1NiBLQiBhY3Jvc3MgYWxsIGl0cyBlbnRyaWVzLlxuICovXG5jb25zdCBTTlNfTUFYX0JZVEVTID0gMjYyXzE0NDtcblxuLyoqXG4gKiBIZWFkcm9vbSBsZWZ0IGZvciB0aGUgYHR5cGVgIC8gYGRvbWFpbmAgLyBgc291cmNlYCBtZXNzYWdlIGF0dHJpYnV0ZXMsXG4gKiB3aGljaCBjb3VudCB0b3dhcmQgdGhlIGxpbWl0IGFsb25nc2lkZSB0aGUgYm9keS4gQSBmZXcgaHVuZHJlZCBieXRlc1xuICogY292ZXJzIHRoZW07IGJlaW5nIGNvbnNlcnZhdGl2ZSBoZXJlIGNvc3RzIG5vdGhpbmcsIHNpbmNlIGFuIGVudmVsb3BlXG4gKiBhbnl3aGVyZSBuZWFyIHRoZSBjYXAgaXMgYSBjYWxsLXNpdGUgbWlzdGFrZSBlaXRoZXIgd2F5LlxuICovXG5jb25zdCBBVFRSSUJVVEVfQUxMT1dBTkNFX0JZVEVTID0gMV8wMjQ7XG5cbmNvbnN0IE1BWF9NRVNTQUdFX0JZVEVTID0gU05TX01BWF9CWVRFUyAtIEFUVFJJQlVURV9BTExPV0FOQ0VfQllURVM7XG5cbi8qKlxuICogQnl0ZSBsZW5ndGggb2YgYSBVVEYtOCBzdHJpbmcuIGBUZXh0RW5jb2RlcmAgcmF0aGVyIHRoYW5cbiAqIGBCdWZmZXIuYnl0ZUxlbmd0aGAgc28gdGhpcyBmaWxlIGNhcnJpZXMgbm8gTm9kZSBidWlsdC1pbi5cbiAqL1xuY29uc3QgZW5jb2RlciA9IG5ldyBUZXh0RW5jb2RlcigpO1xuXG5mdW5jdGlvbiBieXRlTGVuZ3RoKHZhbHVlOiBzdHJpbmcpOiBudW1iZXIge1xuICByZXR1cm4gZW5jb2Rlci5lbmNvZGUodmFsdWUpLmxlbmd0aDtcbn1cblxuLyoqXG4gKiBNb25vdG9uaWMgd2l0aGluIHRoaXMgcHJvY2VzczogdHdvIGV2ZW50cyBtaW50ZWQgaW4gdGhlIHNhbWVcbiAqIG1pbGxpc2Vjb25kIHN0aWxsIHNvcnQgaW4gZW1pc3Npb24gb3JkZXIuIERvd25zdHJlYW0gY29uc3VtZXJzIHVzZSB0aGVcbiAqIGVudmVsb3BlIGBpZGAgYXMgdGhlIG9yZGVyaW5nIGFuZCBkZWR1cGUga2V5LCBzbyB0aGlzIGlzIGxvYWQtYmVhcmluZyxcbiAqIG5vdCBhIG5pY2V0eS5cbiAqL1xuY29uc3QgbmV4dFVsaWQgPSBtb25vdG9uaWNGYWN0b3J5KCk7XG5cbi8qKiBXaGF0IGEgY2FsbCBzaXRlIHN1cHBsaWVzOyB0aGUgU0RLIGRlcml2ZXMgZXZlcnl0aGluZyBlbHNlLiAqL1xuZXhwb3J0IGludGVyZmFjZSBQdWJsaXNoT3B0aW9ucyB7XG4gIC8qKiB1RW5nYWdlIGJ1c2luZXNzIGlkIHRoZSBldmVudCBiZWxvbmdzIHRvLiAqL1xuICB0ZW5hbnRJZDogc3RyaW5nO1xuICAvKipcbiAgICogV2hlbiB0aGUgdGhpbmcgaGFwcGVuZWQsIGlmIGl0IHdhc24ndCBub3cg4oCUIGUuZy4gcmVwbGF5aW5nIGFcbiAgICogdHJhbnNpdGlvbiByZWFkIGJhY2sgb2ZmIGEgREIgcm93LiBVVEMgSVNPIDg2MDEuIERlZmF1bHRzIHRvIHRoZVxuICAgKiBtb21lbnQgYHB1Ymxpc2goKWAgd2FzIGNhbGxlZC5cbiAgICovXG4gIG9jY3VycmVkQXQ/OiBzdHJpbmc7XG4gIC8qKiBPdmVycmlkZXMgdGhlIGNsaWVudC1sZXZlbCBgc291cmNlYCBmb3IgdGhpcyBvbmUgZXZlbnQuICovXG4gIHNvdXJjZT86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQdWJsaXNoQmF0Y2hJbnB1dCBleHRlbmRzIFB1Ymxpc2hPcHRpb25zIHtcbiAgdHlwZTogc3RyaW5nO1xuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmVudHNDbGllbnRJbnB1dCB7XG4gIC8qKlxuICAgKiBCdXMgdG9waWMgQVJOLiBEZWZhdWx0cyB0byBgUExBVEZPUk1fRVZFTlRTX1RPUElDX0FSTmAuXG4gICAqL1xuICB0b3BpY0Fybj86IHN0cmluZztcbiAgLyoqXG4gICAqIEFXUyByZWdpb24uIERlZmF1bHRzIHRvIHRoZSByZWdpb24gZW1iZWRkZWQgaW4gYHRvcGljQXJuYCwgdGhlblxuICAgKiBgQVdTX1JFR0lPTmAgLyBgQVdTX0RFRkFVTFRfUkVHSU9OYC4gUmFyZWx5IG5lZWRzIHNldHRpbmcuXG4gICAqL1xuICByZWdpb24/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBXaGljaCBzeXN0ZW0gaXMgZW1pdHRpbmcuIERlZmF1bHRzIHRvIGBQTEFURk9STV9FVkVOVFNfU09VUkNFYCwgdGhlblxuICAgKiBgU0VSVklDRV9OQU1FYCAoc2V0IG9uIGV2ZXJ5IHBsYXRmb3JtIExhbWJkYSBieSBgTGFtYmRhU2VydmljZWApLFxuICAgKiB0aGVuIGAncGxhdGZvcm0tc2RrJ2AuXG4gICAqL1xuICBzb3VyY2U/OiBzdHJpbmc7XG4gIC8qKiBJbmplY3QgYSBwcmUtYnVpbHQgU05TIGNsaWVudCAodGVzdHMsIGN1c3RvbSBjcmVkZW50aWFscy9yZXRyeSBjb25maWcpLiAqL1xuICBzbnNDbGllbnQ/OiBTTlNDbGllbnQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRzQ2xpZW50IHtcbiAgLyoqXG4gICAqIFB1Ymxpc2ggb25lIGV2ZW50IG9udG8gdGhlIHBsYXRmb3JtIGV2ZW50IGJ1cy5cbiAgICpcbiAgICogQnVpbGRzIHRoZSBlbnZlbG9wZSAobW9ub3RvbmljIFVMSUQgYGlkYCwgYG9jY3VycmVkQXRgLCBgdmVyc2lvbmAsXG4gICAqIGBkb21haW5gIGRlcml2ZWQgZnJvbSB0aGUgYHR5cGVgIHByZWZpeCksIHZhbGlkYXRlcyBpdCwgYW5kIHB1Ymxpc2hlc1xuICAgKiB3aXRoIGB0eXBlYCAvIGBkb21haW5gIC8gYHNvdXJjZWAgc2V0IGFzIFNOUyBtZXNzYWdlIGF0dHJpYnV0ZXMgc29cbiAgICogY29uc3VtZXIgZmlsdGVyIHBvbGljaWVzIG1hdGNoIHdpdGhvdXQgZGVzZXJpYWxpc2luZyB0aGUgYm9keS5cbiAgICpcbiAgICogVEhST1dTIG9uIGZhaWx1cmUg4oCUIGl0IGRvZXMgbm90IGZhaWwgb3Blbi4gRmFpbC1vcGVuIGlzIHRoZSBjYWxsZXInc1xuICAgKiBjYWxsIGFuZCBpdCBkaWZmZXJzIGJ5IGNhbGwgc2l0ZTogYSBsZWdhY3kgb3JkZXItc3RhdHVzIHRyYW5zaXRpb25cbiAgICogbXVzdCBuZXZlciBiZSBibG9ja2VkIGJ5IGEgYnVzIG91dGFnZSAod3JhcCBpbiB0cnkvY2F0Y2ggYW5kIGxvZyksXG4gICAqIHdoZXJlYXMgYSBzZXJ2aWNlIHRoYXQgbmVlZHMgdGhlIGV2ZW50IGRlbGl2ZXJlZCBtYXkgd2FudCB0byByZXRyeS5cbiAgICogVGhlIFBIUCBTREsncyBidWZmZXJlZCBjbGllbnQgbWFrZXMgdGhlIGZhaWwtb3BlbiBjaG9pY2UgZXhwbGljaXRseVxuICAgKiBmb3IgdGhlIGxlZ2FjeSByZXF1ZXN0IHBhdGguXG4gICAqXG4gICAqIEB0aHJvd3Mge0NvbmZpZ0Vycm9yfSBubyB0b3BpYyBBUk4gY29uZmlndXJlZFxuICAgKiBAdGhyb3dzIHtWYWxpZGF0aW9uRXJyb3J9IHRoZSBlbnZlbG9wZSBmYWlsZWQgc2NoZW1hIHZhbGlkYXRpb25cbiAgICogQHRocm93cyB7RXZlbnRQdWJsaXNoRXJyb3J9IFNOUyByZWplY3RlZCBvciBlcnJvcmVkIG9uIHRoZSBwdWJsaXNoXG4gICAqL1xuICBwdWJsaXNoKFxuICAgIHR5cGU6IHN0cmluZyxcbiAgICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBvcHRzOiBQdWJsaXNoT3B0aW9ucyxcbiAgKTogUHJvbWlzZTxQbGF0Zm9ybUV2ZW50PjtcbiAgLyoqXG4gICAqIFB1Ymxpc2ggbWFueSBldmVudHMgaW4gb25lIHJvdW5kIHRyaXAsIGNodW5rZWQgYXQgU05TJ3MgMTAtcGVyLWNhbGxcbiAgICogYFB1Ymxpc2hCYXRjaGAgbGltaXQuXG4gICAqXG4gICAqIEFsbC1vci1ub3RoaW5nIGl0IGlzIE5PVDogY2h1bmtzIGFyZSBhdHRlbXB0ZWQgaW5kZXBlbmRlbnRseSwgYW5kIGFcbiAgICogcGFydGlhbCBmYWlsdXJlIHRocm93cyBgRXZlbnRQdWJsaXNoRXJyb3JgIGNhcnJ5aW5nIHRoZSBpZHMgdGhhdCBkaWRcbiAgICogbm90IGxhbmQgaW4gYGZhaWxlZEV2ZW50SWRzYC4gRW52ZWxvcGUgdmFsaWRhdGlvbiBydW5zIG92ZXIgdGhlIHdob2xlXG4gICAqIGlucHV0IGZpcnN0LCBzbyBhIG1hbGZvcm1lZCBldmVudCBmYWlscyB0aGUgY2FsbCBiZWZvcmUgYW55dGhpbmcgaXNcbiAgICogcHVibGlzaGVkLlxuICAgKlxuICAgKiBAdGhyb3dzIHtDb25maWdFcnJvcn0gbm8gdG9waWMgQVJOIGNvbmZpZ3VyZWRcbiAgICogQHRocm93cyB7VmFsaWRhdGlvbkVycm9yfSBhbnkgZW52ZWxvcGUgZmFpbGVkIHNjaGVtYSB2YWxpZGF0aW9uXG4gICAqIEB0aHJvd3Mge0V2ZW50UHVibGlzaEVycm9yfSBvbmUgb3IgbW9yZSBldmVudHMgZGlkIG5vdCByZWFjaCB0aGUgYnVzXG4gICAqL1xuICBwdWJsaXNoQmF0Y2goZXZlbnRzOiBQdWJsaXNoQmF0Y2hJbnB1dFtdKTogUHJvbWlzZTxQbGF0Zm9ybUV2ZW50W10+O1xufVxuXG4vKipcbiAqIEJ1aWxkIGFuIGlzb2xhdGVkIGV2ZW50cyBjbGllbnQuIFJlYWRzIGBQTEFURk9STV9FVkVOVFNfVE9QSUNfQVJOYCBhbmRcbiAqIGZyaWVuZHMgZnJvbSB0aGUgZW52aXJvbm1lbnQgZm9yIGFueXRoaW5nIG5vdCBwYXNzZWQgZXhwbGljaXRseSwgc28gYVxuICogTGFtYmRhIHdob3NlIGRlcGxveSBzdGFjayBpbmplY3RlZCB0aGUgQVJOIG5lZWRzIG5vIGFyZ3VtZW50cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUV2ZW50c0NsaWVudChpbnB1dDogRXZlbnRzQ2xpZW50SW5wdXQgPSB7fSk6IEV2ZW50c0NsaWVudCB7XG4gIGxldCBjbGllbnQ6IFNOU0NsaWVudCB8IHVuZGVmaW5lZCA9IGlucHV0LnNuc0NsaWVudDtcblxuICBmdW5jdGlvbiB0b3BpY0FybigpOiBzdHJpbmcge1xuICAgIGNvbnN0IGFybiA9IGlucHV0LnRvcGljQXJuID8/IGVudignUExBVEZPUk1fRVZFTlRTX1RPUElDX0FSTicpO1xuICAgIGlmICghYXJuKSB7XG4gICAgICB0aHJvdyBuZXcgQ29uZmlnRXJyb3IoXG4gICAgICAgICdldmVudHMucHVibGlzaDogbm8gdG9waWMgQVJOLiBQYXNzIHt0b3BpY0Fybn0gdG8gY3JlYXRlRXZlbnRzQ2xpZW50IG9yIHNldCBQTEFURk9STV9FVkVOVFNfVE9QSUNfQVJOLicsXG4gICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gYXJuO1xuICB9XG5cbiAgZnVuY3Rpb24gc25zKCk6IFNOU0NsaWVudCB7XG4gICAgaWYgKCFjbGllbnQpIHtcbiAgICAgIGNvbnN0IHJlZ2lvbiA9XG4gICAgICAgIGlucHV0LnJlZ2lvbiA/PyByZWdpb25Gcm9tQXJuKHRvcGljQXJuKCkpID8/IGVudignQVdTX1JFR0lPTicpID8/IGVudignQVdTX0RFRkFVTFRfUkVHSU9OJyk7XG4gICAgICBjbGllbnQgPSBuZXcgU05TQ2xpZW50KHJlZ2lvbiA/IHsgcmVnaW9uIH0gOiB7fSk7XG4gICAgfVxuICAgIHJldHVybiBjbGllbnQ7XG4gIH1cblxuICBmdW5jdGlvbiBzb3VyY2Uob3ZlcnJpZGU/OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiAoXG4gICAgICBvdmVycmlkZSA/P1xuICAgICAgaW5wdXQuc291cmNlID8/XG4gICAgICBlbnYoJ1BMQVRGT1JNX0VWRU5UU19TT1VSQ0UnKSA/P1xuICAgICAgZW52KCdTRVJWSUNFX05BTUUnKSA/P1xuICAgICAgJ3BsYXRmb3JtLXNkaydcbiAgICApO1xuICB9XG5cbiAgZnVuY3Rpb24gYnVpbGRFbnZlbG9wZShcbiAgICB0eXBlOiBzdHJpbmcsXG4gICAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4sXG4gICAgb3B0czogUHVibGlzaE9wdGlvbnMsXG4gICk6IFBsYXRmb3JtRXZlbnQge1xuICAgIGNvbnN0IGRvbWFpbiA9IGRvbWFpbkZvckV2ZW50VHlwZSh0eXBlKTtcbiAgICBpZiAoIWRvbWFpbikge1xuICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgICAgYGV2ZW50cy5wdWJsaXNoOiBjYW5ub3Qgcm91dGUgZXZlbnQgdHlwZSBcIiR7dHlwZX1cIi4gSXQgbXVzdCBiZSBhIGRvdHRlZCBgICtcbiAgICAgICAgICAnXCI8cmVzb3VyY2U+LjxvcGVyYXRpb24+XCIgbmFtZSB3aG9zZSByZXNvdXJjZSBtYXBzIHRvIGEga25vd24gYnVzIGRvbWFpbiAnICtcbiAgICAgICAgICAnKG9yZGVyLCBjdXN0b21lciwgbWVudSwgb2ZmZXIsIGxveWFsdHksIHVzYWdlKS4gQWRkaW5nIGEgZG9tYWluIGlzIGEgb25lLWxpbmUgJyArXG4gICAgICAgICAgJ2VkaXQgaW4gZXZlbnRzL3NjaGVtYS50cyBhbmQgaXRzIHR3byBtaXJyb3JzLicsXG4gICAgICApO1xuICAgIH1cbiAgICBjb25zdCBjYW5kaWRhdGUgPSB7XG4gICAgICBpZDogbmV4dFVsaWQoKSxcbiAgICAgIHR5cGUsXG4gICAgICBkb21haW4sXG4gICAgICBzb3VyY2U6IHNvdXJjZShvcHRzLnNvdXJjZSksXG4gICAgICB2ZXJzaW9uOiBQTEFURk9STV9FVkVOVF9WRVJTSU9OLFxuICAgICAgb2NjdXJyZWRBdDogb3B0cy5vY2N1cnJlZEF0ID8/IGlzb05vdygpLFxuICAgICAgdGVuYW50SWQ6IG9wdHMudGVuYW50SWQsXG4gICAgICBkYXRhLFxuICAgIH07XG4gICAgY29uc3QgcmVzdWx0ID0gcGxhdGZvcm1FdmVudFNjaGVtYS5zYWZlUGFyc2UoY2FuZGlkYXRlKTtcbiAgICBpZiAoIXJlc3VsdC5zdWNjZXNzKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKGBldmVudHMucHVibGlzaDogaW52YWxpZCBlbnZlbG9wZSBmb3IgXCIke3R5cGV9XCJgLCB7XG4gICAgICAgIGlzc3VlczogcmVzdWx0LmVycm9yLmlzc3VlcyxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0LmRhdGE7XG4gIH1cblxuICAvKipcbiAgICogU2VyaWFsaXplIGFuZCBzaXplLWNoZWNrIG9uZSBlbnZlbG9wZS5cbiAgICpcbiAgICogQ2hlY2tlZCBiZWZvcmUgdGhlIHB1Ymxpc2ggcmF0aGVyIHRoYW4gYWZ0ZXIgdGhlIHJlamVjdGlvbiBiZWNhdXNlXG4gICAqIFNOUydzIG93biBlcnJvciBmb3IgYW4gb3ZlcnNpemVkIG1lc3NhZ2UgbmFtZXMgbmVpdGhlciB0aGUgZXZlbnQgbm9yXG4gICAqIHRoZSBvZmZlbmRpbmcgZmllbGQsIGFuZCBvbiB0aGUgUEhQIHNpZGUgdGhlIHNhbWUgZmFpbHVyZSBkaXNhcHBlYXJzXG4gICAqIGludG8gYGVycm9yX2xvZ2AuIEJldHRlciB0byBzYXkgd2hpY2ggZXZlbnQgYW5kIGhvdyBiaWcuXG4gICAqL1xuICBmdW5jdGlvbiBzZXJpYWxpemUoZXZlbnQ6IFBsYXRmb3JtRXZlbnQpOiBzdHJpbmcge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBKU09OLnN0cmluZ2lmeShldmVudCk7XG4gICAgY29uc3Qgc2l6ZSA9IGJ5dGVMZW5ndGgobWVzc2FnZSk7XG4gICAgaWYgKHNpemUgPiBNQVhfTUVTU0FHRV9CWVRFUykge1xuICAgICAgdGhyb3cgbmV3IFZhbGlkYXRpb25FcnJvcihcbiAgICAgICAgYGV2ZW50cy5wdWJsaXNoOiBldmVudCAke2V2ZW50LmlkfSAoXCIke2V2ZW50LnR5cGV9XCIpIHNlcmlhbGl6ZXMgdG8gJHtzaXplfSBieXRlcywgYCArXG4gICAgICAgICAgYG92ZXIgdGhlICR7TUFYX01FU1NBR0VfQllURVN9LWJ5dGUgY2VpbGluZyAoU05TIGNhcHMgYSBtZXNzYWdlIGF0IDI1NktCIGluY2x1ZGluZyBgICtcbiAgICAgICAgICAnYXR0cmlidXRlcykuIFB1dCB0aGUgcGF5bG9hZCBzb21ld2hlcmUgYWRkcmVzc2FibGUgYW5kIHJlZmVyZW5jZSBpdCBmcm9tIGBkYXRhYC4nLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIG1lc3NhZ2U7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIGFzeW5jIHB1Ymxpc2godHlwZSwgZGF0YSwgb3B0cykge1xuICAgICAgY29uc3QgZXZlbnQgPSBidWlsZEVudmVsb3BlKHR5cGUsIGRhdGEsIG9wdHMpO1xuICAgICAgY29uc3QgbWVzc2FnZSA9IHNlcmlhbGl6ZShldmVudCk7XG4gICAgICBjb25zdCBhcm4gPSB0b3BpY0FybigpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgc25zKCkuc2VuZChcbiAgICAgICAgICBuZXcgUHVibGlzaENvbW1hbmQoe1xuICAgICAgICAgICAgVG9waWNBcm46IGFybixcbiAgICAgICAgICAgIE1lc3NhZ2U6IG1lc3NhZ2UsXG4gICAgICAgICAgICBNZXNzYWdlQXR0cmlidXRlczogbWVzc2FnZUF0dHJpYnV0ZXMoZXZlbnQpLFxuICAgICAgICAgIH0pLFxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgIHRocm93IG5ldyBFdmVudFB1Ymxpc2hFcnJvcihgZXZlbnRzLnB1Ymxpc2g6IFNOUyBwdWJsaXNoIGZhaWxlZCBmb3IgXCIke3R5cGV9XCJgLCB7XG4gICAgICAgICAgZmFpbGVkRXZlbnRJZHM6IFtldmVudC5pZF0sXG4gICAgICAgICAgY2F1c2U6IGVycixcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZXZlbnQ7XG4gICAgfSxcblxuICAgIGFzeW5jIHB1Ymxpc2hCYXRjaChldmVudHMpIHtcbiAgICAgIGlmIChldmVudHMubGVuZ3RoID09PSAwKSByZXR1cm4gW107XG4gICAgICBjb25zdCBlbnZlbG9wZXMgPSBldmVudHMubWFwKChlKSA9PiBidWlsZEVudmVsb3BlKGUudHlwZSwgZS5kYXRhLCBlKSk7XG4gICAgICAvLyBTZXJpYWxpemUgKGFuZCBzaXplLWNoZWNrKSBldmVyeXRoaW5nIHVwIGZyb250LCBzbyBhbiBvdmVyc2l6ZWRcbiAgICAgIC8vIGV2ZW50IGZhaWxzIHRoZSBjYWxsIGJlZm9yZSBhbnkgb2YgaXRzIHNpYmxpbmdzIGFyZSBwdWJsaXNoZWQuXG4gICAgICBjb25zdCBtZXNzYWdlcyA9IG5ldyBNYXAoZW52ZWxvcGVzLm1hcCgoZXZlbnQpID0+IFtldmVudC5pZCwgc2VyaWFsaXplKGV2ZW50KV0pKTtcbiAgICAgIGNvbnN0IGFybiA9IHRvcGljQXJuKCk7XG5cbiAgICAgIGNvbnN0IGZhaWxlZDogc3RyaW5nW10gPSBbXTtcbiAgICAgIGxldCBmaXJzdEVycm9yOiB1bmtub3duO1xuICAgICAgZm9yIChjb25zdCBncm91cCBvZiBjaHVua0J5Qnl0ZXMoZW52ZWxvcGVzLCBtZXNzYWdlcykpIHtcbiAgICAgICAgY29uc3QgZW50cmllczogUHVibGlzaEJhdGNoUmVxdWVzdEVudHJ5W10gPSBncm91cC5tYXAoKGV2ZW50KSA9PiAoe1xuICAgICAgICAgIElkOiBldmVudC5pZCxcbiAgICAgICAgICBNZXNzYWdlOiBtZXNzYWdlcy5nZXQoZXZlbnQuaWQpIGFzIHN0cmluZyxcbiAgICAgICAgICBNZXNzYWdlQXR0cmlidXRlczogbWVzc2FnZUF0dHJpYnV0ZXMoZXZlbnQpLFxuICAgICAgICB9KSk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IHNucygpLnNlbmQoXG4gICAgICAgICAgICBuZXcgUHVibGlzaEJhdGNoQ29tbWFuZCh7IFRvcGljQXJuOiBhcm4sIFB1Ymxpc2hCYXRjaFJlcXVlc3RFbnRyaWVzOiBlbnRyaWVzIH0pLFxuICAgICAgICAgICk7XG4gICAgICAgICAgZm9yIChjb25zdCBmIG9mIHJlc3AuRmFpbGVkID8/IFtdKSB7XG4gICAgICAgICAgICBpZiAoZi5JZCkgZmFpbGVkLnB1c2goZi5JZCk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgICBmaXJzdEVycm9yID0gZmlyc3RFcnJvciA/PyBlcnI7XG4gICAgICAgICAgZm9yIChjb25zdCBldmVudCBvZiBncm91cCkgZmFpbGVkLnB1c2goZXZlbnQuaWQpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChmYWlsZWQubGVuZ3RoID4gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXZlbnRQdWJsaXNoRXJyb3IoXG4gICAgICAgICAgYGV2ZW50cy5wdWJsaXNoQmF0Y2g6ICR7ZmFpbGVkLmxlbmd0aH0vJHtlbnZlbG9wZXMubGVuZ3RofSBldmVudChzKSBkaWQgbm90IHJlYWNoIHRoZSBidXNgLFxuICAgICAgICAgIHsgZmFpbGVkRXZlbnRJZHM6IGZhaWxlZCwgY2F1c2U6IGZpcnN0RXJyb3IgfSxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBlbnZlbG9wZXM7XG4gICAgfSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gbWVzc2FnZUF0dHJpYnV0ZXMoZXZlbnQ6IFBsYXRmb3JtRXZlbnQpOiBSZWNvcmQ8c3RyaW5nLCBNZXNzYWdlQXR0cmlidXRlVmFsdWU+IHtcbiAgcmV0dXJuIHtcbiAgICB0eXBlOiB7IERhdGFUeXBlOiAnU3RyaW5nJywgU3RyaW5nVmFsdWU6IGV2ZW50LnR5cGUgfSxcbiAgICBkb21haW46IHsgRGF0YVR5cGU6ICdTdHJpbmcnLCBTdHJpbmdWYWx1ZTogZXZlbnQuZG9tYWluIH0sXG4gICAgc291cmNlOiB7IERhdGFUeXBlOiAnU3RyaW5nJywgU3RyaW5nVmFsdWU6IGV2ZW50LnNvdXJjZSB9LFxuICB9O1xufVxuXG4vKiogYGFybjphd3M6c25zOjxyZWdpb24+OjxhY2NvdW50Pjo8bmFtZT5gIOKGkiBgPHJlZ2lvbj5gLiAqL1xuZnVuY3Rpb24gcmVnaW9uRnJvbUFybihhcm46IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnRzID0gYXJuLnNwbGl0KCc6Jyk7XG4gIHJldHVybiBwYXJ0cy5sZW5ndGggPj0gNCAmJiBwYXJ0c1szXSA/IHBhcnRzWzNdIDogdW5kZWZpbmVkO1xufVxuXG4vKiogVVRDIElTTyA4NjAxLCBzZWNvbmRzIHByZWNpc2lvbiDigJQgdGhlIGZvcm1hdCB0aGUgZW52ZWxvcGUgc2NoZW1hIHBpbnMuICovXG5mdW5jdGlvbiBpc29Ob3coKTogc3RyaW5nIHtcbiAgcmV0dXJuIG5ldyBEYXRlKCkudG9JU09TdHJpbmcoKS5yZXBsYWNlKC9cXC5cXGR7M31aJC8sICdaJyk7XG59XG5cbmZ1bmN0aW9uIGVudihuYW1lOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBpZiAodHlwZW9mIHByb2Nlc3MgPT09ICd1bmRlZmluZWQnKSByZXR1cm4gdW5kZWZpbmVkO1xuICBjb25zdCB2YWx1ZSA9IChwcm9jZXNzIGFzIHsgZW52PzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPiB9KS5lbnY/LltuYW1lXTtcbiAgcmV0dXJuIHZhbHVlID09PSAnJyA/IHVuZGVmaW5lZCA6IHZhbHVlO1xufVxuXG4vKipcbiAqIEdyb3VwIGVudmVsb3BlcyBpbnRvIFB1Ymxpc2hCYXRjaCBjYWxscyBib3VuZGVkIGJ5IEJPVEggbGltaXRzOiBhdCBtb3N0XG4gKiAxMCBlbnRyaWVzLCBhbmQgYXQgbW9zdCAyNTYgS0Igb2YgY29tYmluZWQgcGF5bG9hZC5cbiAqXG4gKiBUaGUgYnl0ZSBib3VuZCBtYXR0ZXJzIGFzIHNvb24gYXMgcGF5bG9hZHMgZ2V0IHJpY2gg4oCUIHRlbiAzMCBLQlxuICogZW52ZWxvcGVzIGFyZSBlYWNoIGluZGl2aWR1YWxseSBsZWdhbCBhbmQgY29sbGVjdGl2ZWx5IG92ZXIgdGhlXG4gKiByZXF1ZXN0IGNhcCwgYW5kIFNOUyByZWplY3RzIHRoZSB3aG9sZSBjYWxsIHJhdGhlciB0aGFuIHRoZSBvdmVyZmxvdy5cbiAqL1xuZnVuY3Rpb24gY2h1bmtCeUJ5dGVzKFxuICBlbnZlbG9wZXM6IFBsYXRmb3JtRXZlbnRbXSxcbiAgbWVzc2FnZXM6IE1hcDxzdHJpbmcsIHN0cmluZz4sXG4pOiBQbGF0Zm9ybUV2ZW50W11bXSB7XG4gIGNvbnN0IG91dDogUGxhdGZvcm1FdmVudFtdW10gPSBbXTtcbiAgbGV0IGN1cnJlbnQ6IFBsYXRmb3JtRXZlbnRbXSA9IFtdO1xuICBsZXQgY3VycmVudEJ5dGVzID0gMDtcblxuICBmb3IgKGNvbnN0IGV2ZW50IG9mIGVudmVsb3Blcykge1xuICAgIGNvbnN0IHNpemUgPSBieXRlTGVuZ3RoKG1lc3NhZ2VzLmdldChldmVudC5pZCkgYXMgc3RyaW5nKSArIEFUVFJJQlVURV9BTExPV0FOQ0VfQllURVM7XG4gICAgY29uc3QgZnVsbCA9IGN1cnJlbnQubGVuZ3RoID49IFNOU19CQVRDSF9NQVg7XG4gICAgY29uc3Qgd291bGRPdmVyZmxvdyA9IGN1cnJlbnQubGVuZ3RoID4gMCAmJiBjdXJyZW50Qnl0ZXMgKyBzaXplID4gU05TX01BWF9CWVRFUztcbiAgICBpZiAoZnVsbCB8fCB3b3VsZE92ZXJmbG93KSB7XG4gICAgICBvdXQucHVzaChjdXJyZW50KTtcbiAgICAgIGN1cnJlbnQgPSBbXTtcbiAgICAgIGN1cnJlbnRCeXRlcyA9IDA7XG4gICAgfVxuICAgIGN1cnJlbnQucHVzaChldmVudCk7XG4gICAgY3VycmVudEJ5dGVzICs9IHNpemU7XG4gIH1cbiAgaWYgKGN1cnJlbnQubGVuZ3RoID4gMCkgb3V0LnB1c2goY3VycmVudCk7XG4gIHJldHVybiBvdXQ7XG59XG4iXX0=
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type EventsClient } from './client';
|
|
2
|
+
export { createEventsClient, type EventsClient, type EventsClientInput, type PublishOptions, type PublishBatchInput, } from './client';
|
|
3
|
+
export { platformEventSchema, domainForEventType, DOMAIN_BY_RESOURCE, PLATFORM_EVENT_TYPES, PLATFORM_EVENT_VERSION, type PlatformEvent, type PlatformEventType, } from './schema';
|
|
4
|
+
/**
|
|
5
|
+
* Lazily-built default events client, configured entirely from the
|
|
6
|
+
* environment (`PLATFORM_EVENTS_TOPIC_ARN`, `PLATFORM_EVENTS_SOURCE`).
|
|
7
|
+
*
|
|
8
|
+
* Lazy because constructing it eagerly would build an SNS client — and
|
|
9
|
+
* read config that may not be set — in every process that merely imports
|
|
10
|
+
* the SDK. Use `createEventsClient(...)` when you need an isolated client
|
|
11
|
+
* with its own topic, region, or injected SNS client.
|
|
12
|
+
*/
|
|
13
|
+
export declare const events: EventsClient;
|
|
14
|
+
/** Test-only: drop the memoised default client so env changes take effect. */
|
|
15
|
+
export declare function _resetEventsSingleton(): void;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.events = exports.PLATFORM_EVENT_VERSION = exports.PLATFORM_EVENT_TYPES = exports.DOMAIN_BY_RESOURCE = exports.domainForEventType = exports.platformEventSchema = exports.createEventsClient = void 0;
|
|
4
|
+
exports._resetEventsSingleton = _resetEventsSingleton;
|
|
5
|
+
const client_1 = require("./client");
|
|
6
|
+
var client_2 = require("./client");
|
|
7
|
+
Object.defineProperty(exports, "createEventsClient", { enumerable: true, get: function () { return client_2.createEventsClient; } });
|
|
8
|
+
var schema_1 = require("./schema");
|
|
9
|
+
Object.defineProperty(exports, "platformEventSchema", { enumerable: true, get: function () { return schema_1.platformEventSchema; } });
|
|
10
|
+
Object.defineProperty(exports, "domainForEventType", { enumerable: true, get: function () { return schema_1.domainForEventType; } });
|
|
11
|
+
Object.defineProperty(exports, "DOMAIN_BY_RESOURCE", { enumerable: true, get: function () { return schema_1.DOMAIN_BY_RESOURCE; } });
|
|
12
|
+
Object.defineProperty(exports, "PLATFORM_EVENT_TYPES", { enumerable: true, get: function () { return schema_1.PLATFORM_EVENT_TYPES; } });
|
|
13
|
+
Object.defineProperty(exports, "PLATFORM_EVENT_VERSION", { enumerable: true, get: function () { return schema_1.PLATFORM_EVENT_VERSION; } });
|
|
14
|
+
let singleton;
|
|
15
|
+
/**
|
|
16
|
+
* Lazily-built default events client, configured entirely from the
|
|
17
|
+
* environment (`PLATFORM_EVENTS_TOPIC_ARN`, `PLATFORM_EVENTS_SOURCE`).
|
|
18
|
+
*
|
|
19
|
+
* Lazy because constructing it eagerly would build an SNS client — and
|
|
20
|
+
* read config that may not be set — in every process that merely imports
|
|
21
|
+
* the SDK. Use `createEventsClient(...)` when you need an isolated client
|
|
22
|
+
* with its own topic, region, or injected SNS client.
|
|
23
|
+
*/
|
|
24
|
+
exports.events = {
|
|
25
|
+
publish(type, data, opts) {
|
|
26
|
+
return defaultClient().publish(type, data, opts);
|
|
27
|
+
},
|
|
28
|
+
publishBatch(batch) {
|
|
29
|
+
return defaultClient().publishBatch(batch);
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
function defaultClient() {
|
|
33
|
+
if (!singleton)
|
|
34
|
+
singleton = (0, client_1.createEventsClient)();
|
|
35
|
+
return singleton;
|
|
36
|
+
}
|
|
37
|
+
/** Test-only: drop the memoised default client so env changes take effect. */
|
|
38
|
+
function _resetEventsSingleton() {
|
|
39
|
+
singleton = undefined;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXZlbnRzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQTZDQSxzREFFQztBQS9DRCxxQ0FBaUU7QUFFakUsbUNBTWtCO0FBTGhCLDRHQUFBLGtCQUFrQixPQUFBO0FBTXBCLG1DQVFrQjtBQVBoQiw2R0FBQSxtQkFBbUIsT0FBQTtBQUNuQiw0R0FBQSxrQkFBa0IsT0FBQTtBQUNsQiw0R0FBQSxrQkFBa0IsT0FBQTtBQUNsQiw4R0FBQSxvQkFBb0IsT0FBQTtBQUNwQixnSEFBQSxzQkFBc0IsT0FBQTtBQUt4QixJQUFJLFNBQW1DLENBQUM7QUFFeEM7Ozs7Ozs7O0dBUUc7QUFDVSxRQUFBLE1BQU0sR0FBaUI7SUFDbEMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSTtRQUN0QixPQUFPLGFBQWEsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFDRCxZQUFZLENBQUMsS0FBSztRQUNoQixPQUFPLGFBQWEsRUFBRSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM3QyxDQUFDO0NBQ0YsQ0FBQztBQUVGLFNBQVMsYUFBYTtJQUNwQixJQUFJLENBQUMsU0FBUztRQUFFLFNBQVMsR0FBRyxJQUFBLDJCQUFrQixHQUFFLENBQUM7SUFDakQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELDhFQUE4RTtBQUM5RSxTQUFnQixxQkFBcUI7SUFDbkMsU0FBUyxHQUFHLFNBQVMsQ0FBQztBQUN4QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgY3JlYXRlRXZlbnRzQ2xpZW50LCB0eXBlIEV2ZW50c0NsaWVudCB9IGZyb20gJy4vY2xpZW50JztcblxuZXhwb3J0IHtcbiAgY3JlYXRlRXZlbnRzQ2xpZW50LFxuICB0eXBlIEV2ZW50c0NsaWVudCxcbiAgdHlwZSBFdmVudHNDbGllbnRJbnB1dCxcbiAgdHlwZSBQdWJsaXNoT3B0aW9ucyxcbiAgdHlwZSBQdWJsaXNoQmF0Y2hJbnB1dCxcbn0gZnJvbSAnLi9jbGllbnQnO1xuZXhwb3J0IHtcbiAgcGxhdGZvcm1FdmVudFNjaGVtYSxcbiAgZG9tYWluRm9yRXZlbnRUeXBlLFxuICBET01BSU5fQllfUkVTT1VSQ0UsXG4gIFBMQVRGT1JNX0VWRU5UX1RZUEVTLFxuICBQTEFURk9STV9FVkVOVF9WRVJTSU9OLFxuICB0eXBlIFBsYXRmb3JtRXZlbnQsXG4gIHR5cGUgUGxhdGZvcm1FdmVudFR5cGUsXG59IGZyb20gJy4vc2NoZW1hJztcblxubGV0IHNpbmdsZXRvbjogRXZlbnRzQ2xpZW50IHwgdW5kZWZpbmVkO1xuXG4vKipcbiAqIExhemlseS1idWlsdCBkZWZhdWx0IGV2ZW50cyBjbGllbnQsIGNvbmZpZ3VyZWQgZW50aXJlbHkgZnJvbSB0aGVcbiAqIGVudmlyb25tZW50IChgUExBVEZPUk1fRVZFTlRTX1RPUElDX0FSTmAsIGBQTEFURk9STV9FVkVOVFNfU09VUkNFYCkuXG4gKlxuICogTGF6eSBiZWNhdXNlIGNvbnN0cnVjdGluZyBpdCBlYWdlcmx5IHdvdWxkIGJ1aWxkIGFuIFNOUyBjbGllbnQg4oCUIGFuZFxuICogcmVhZCBjb25maWcgdGhhdCBtYXkgbm90IGJlIHNldCDigJQgaW4gZXZlcnkgcHJvY2VzcyB0aGF0IG1lcmVseSBpbXBvcnRzXG4gKiB0aGUgU0RLLiBVc2UgYGNyZWF0ZUV2ZW50c0NsaWVudCguLi4pYCB3aGVuIHlvdSBuZWVkIGFuIGlzb2xhdGVkIGNsaWVudFxuICogd2l0aCBpdHMgb3duIHRvcGljLCByZWdpb24sIG9yIGluamVjdGVkIFNOUyBjbGllbnQuXG4gKi9cbmV4cG9ydCBjb25zdCBldmVudHM6IEV2ZW50c0NsaWVudCA9IHtcbiAgcHVibGlzaCh0eXBlLCBkYXRhLCBvcHRzKSB7XG4gICAgcmV0dXJuIGRlZmF1bHRDbGllbnQoKS5wdWJsaXNoKHR5cGUsIGRhdGEsIG9wdHMpO1xuICB9LFxuICBwdWJsaXNoQmF0Y2goYmF0Y2gpIHtcbiAgICByZXR1cm4gZGVmYXVsdENsaWVudCgpLnB1Ymxpc2hCYXRjaChiYXRjaCk7XG4gIH0sXG59O1xuXG5mdW5jdGlvbiBkZWZhdWx0Q2xpZW50KCk6IEV2ZW50c0NsaWVudCB7XG4gIGlmICghc2luZ2xldG9uKSBzaW5nbGV0b24gPSBjcmVhdGVFdmVudHNDbGllbnQoKTtcbiAgcmV0dXJuIHNpbmdsZXRvbjtcbn1cblxuLyoqIFRlc3Qtb25seTogZHJvcCB0aGUgbWVtb2lzZWQgZGVmYXVsdCBjbGllbnQgc28gZW52IGNoYW5nZXMgdGFrZSBlZmZlY3QuICovXG5leHBvcnQgZnVuY3Rpb24gX3Jlc2V0RXZlbnRzU2luZ2xldG9uKCk6IHZvaWQge1xuICBzaW5nbGV0b24gPSB1bmRlZmluZWQ7XG59XG4iXX0=
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Dotted `resource.operation`, e.g. `order.status_changed`. */
|
|
3
|
+
export declare const EVENT_TYPE_RE: RegExp;
|
|
4
|
+
export declare const platformEventSchema: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
type: z.ZodString;
|
|
7
|
+
domain: z.ZodString;
|
|
8
|
+
source: z.ZodString;
|
|
9
|
+
version: z.ZodNumber;
|
|
10
|
+
occurredAt: z.ZodString;
|
|
11
|
+
tenantId: z.ZodString;
|
|
12
|
+
data: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
type: string;
|
|
15
|
+
id: string;
|
|
16
|
+
domain: string;
|
|
17
|
+
source: string;
|
|
18
|
+
version: number;
|
|
19
|
+
occurredAt: string;
|
|
20
|
+
tenantId: string;
|
|
21
|
+
data: Record<string, unknown>;
|
|
22
|
+
}, {
|
|
23
|
+
type: string;
|
|
24
|
+
id: string;
|
|
25
|
+
domain: string;
|
|
26
|
+
source: string;
|
|
27
|
+
version: number;
|
|
28
|
+
occurredAt: string;
|
|
29
|
+
tenantId: string;
|
|
30
|
+
data: Record<string, unknown>;
|
|
31
|
+
}>;
|
|
32
|
+
export type PlatformEvent = z.infer<typeof platformEventSchema>;
|
|
33
|
+
/** Event types the bus carries in phase 1. */
|
|
34
|
+
export declare const PLATFORM_EVENT_TYPES: readonly ["order.created", "order.status_changed"];
|
|
35
|
+
export type PlatformEventType = (typeof PLATFORM_EVENT_TYPES)[number];
|
|
36
|
+
/** Current envelope version stamped on everything this SDK publishes. */
|
|
37
|
+
export declare const PLATFORM_EVENT_VERSION = 1;
|
|
38
|
+
/**
|
|
39
|
+
* Resource prefix → bus domain.
|
|
40
|
+
*
|
|
41
|
+
* An explicit map, not a pluralisation rule: the platform's domains are
|
|
42
|
+
* not uniformly plural (`orders` and `customers` are, `menu`, `loyalty`
|
|
43
|
+
* and `usage` are not).
|
|
44
|
+
*
|
|
45
|
+
* Copied from `packages/common/src/events/domains.json`, which is the
|
|
46
|
+
* single source of truth, because this package is published to npm and
|
|
47
|
+
* cannot import from a private workspace package. Exported so
|
|
48
|
+
* `test/events/domain-map.test.ts` can assert it against that JSON — the
|
|
49
|
+
* suite fails the moment the two drift.
|
|
50
|
+
*/
|
|
51
|
+
export declare const DOMAIN_BY_RESOURCE: Readonly<Record<string, string>>;
|
|
52
|
+
/**
|
|
53
|
+
* The domain an event type belongs to, or null for a malformed type or
|
|
54
|
+
* an unregistered resource prefix. `publish()` treats null as an error:
|
|
55
|
+
* emitting onto a domain that does not exist is a call-site mistake, and
|
|
56
|
+
* nothing downstream is subscribed to catch it.
|
|
57
|
+
*/
|
|
58
|
+
export declare function domainForEventType(type: string): string | null;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DOMAIN_BY_RESOURCE = exports.PLATFORM_EVENT_VERSION = exports.PLATFORM_EVENT_TYPES = exports.platformEventSchema = exports.EVENT_TYPE_RE = void 0;
|
|
4
|
+
exports.domainForEventType = domainForEventType;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
/**
|
|
7
|
+
* Platform event-bus envelope, publisher side.
|
|
8
|
+
*
|
|
9
|
+
* This mirrors `@uengage/common`'s `platformEventSchema` field for field.
|
|
10
|
+
* It is duplicated rather than imported because `@uengage/common` is a
|
|
11
|
+
* private workspace package and this SDK is published to npm — the same
|
|
12
|
+
* reason `audit/schema.ts` lives here instead of in common. The two are
|
|
13
|
+
* kept honest by `services/realtime/test/envelope.test.ts`, which
|
|
14
|
+
* validates an SDK-built envelope against the common schema.
|
|
15
|
+
*/
|
|
16
|
+
/** ULID: Crockford base32, 26 chars, excludes I/L/O/U. */
|
|
17
|
+
const ULID_RE = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
18
|
+
/** Dotted `resource.operation`, e.g. `order.status_changed`. */
|
|
19
|
+
exports.EVENT_TYPE_RE = /^[a-z][a-z0-9_]*\.[a-z][a-z0-9_]*$/;
|
|
20
|
+
exports.platformEventSchema = zod_1.z.object({
|
|
21
|
+
id: zod_1.z.string().regex(ULID_RE, 'must be a ULID'),
|
|
22
|
+
type: zod_1.z.string().regex(exports.EVENT_TYPE_RE, 'must be "<resource>.<operation>"'),
|
|
23
|
+
domain: zod_1.z.string().regex(/^[a-z][a-z0-9_]*$/, 'must be a lowercase domain token'),
|
|
24
|
+
source: zod_1.z.string().min(1),
|
|
25
|
+
version: zod_1.z.number().int().positive(),
|
|
26
|
+
occurredAt: zod_1.z.string().datetime({ offset: false }),
|
|
27
|
+
tenantId: zod_1.z.string().min(1),
|
|
28
|
+
data: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
29
|
+
});
|
|
30
|
+
/** Event types the bus carries in phase 1. */
|
|
31
|
+
exports.PLATFORM_EVENT_TYPES = ['order.created', 'order.status_changed'];
|
|
32
|
+
/** Current envelope version stamped on everything this SDK publishes. */
|
|
33
|
+
exports.PLATFORM_EVENT_VERSION = 1;
|
|
34
|
+
/**
|
|
35
|
+
* Resource prefix → bus domain.
|
|
36
|
+
*
|
|
37
|
+
* An explicit map, not a pluralisation rule: the platform's domains are
|
|
38
|
+
* not uniformly plural (`orders` and `customers` are, `menu`, `loyalty`
|
|
39
|
+
* and `usage` are not).
|
|
40
|
+
*
|
|
41
|
+
* Copied from `packages/common/src/events/domains.json`, which is the
|
|
42
|
+
* single source of truth, because this package is published to npm and
|
|
43
|
+
* cannot import from a private workspace package. Exported so
|
|
44
|
+
* `test/events/domain-map.test.ts` can assert it against that JSON — the
|
|
45
|
+
* suite fails the moment the two drift.
|
|
46
|
+
*/
|
|
47
|
+
exports.DOMAIN_BY_RESOURCE = {
|
|
48
|
+
order: 'orders',
|
|
49
|
+
customer: 'customers',
|
|
50
|
+
menu: 'menu',
|
|
51
|
+
offer: 'offers',
|
|
52
|
+
loyalty: 'loyalty',
|
|
53
|
+
usage: 'usage',
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* The domain an event type belongs to, or null for a malformed type or
|
|
57
|
+
* an unregistered resource prefix. `publish()` treats null as an error:
|
|
58
|
+
* emitting onto a domain that does not exist is a call-site mistake, and
|
|
59
|
+
* nothing downstream is subscribed to catch it.
|
|
60
|
+
*/
|
|
61
|
+
function domainForEventType(type) {
|
|
62
|
+
if (!exports.EVENT_TYPE_RE.test(type))
|
|
63
|
+
return null;
|
|
64
|
+
const resource = type.slice(0, type.indexOf('.'));
|
|
65
|
+
return exports.DOMAIN_BY_RESOURCE[resource] ?? null;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V2ZW50cy9zY2hlbWEudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBb0VBLGdEQUlDO0FBeEVELDZCQUF3QjtBQUV4Qjs7Ozs7Ozs7O0dBU0c7QUFFSCwwREFBMEQ7QUFDMUQsTUFBTSxPQUFPLEdBQUcsMEJBQTBCLENBQUM7QUFFM0MsZ0VBQWdFO0FBQ25ELFFBQUEsYUFBYSxHQUFHLG9DQUFvQyxDQUFDO0FBRXJELFFBQUEsbUJBQW1CLEdBQUcsT0FBQyxDQUFDLE1BQU0sQ0FBQztJQUMxQyxFQUFFLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLENBQUM7SUFDL0MsSUFBSSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMscUJBQWEsRUFBRSxrQ0FBa0MsQ0FBQztJQUN6RSxNQUFNLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxtQkFBbUIsRUFBRSxrQ0FBa0MsQ0FBQztJQUNqRixNQUFNLEVBQUUsT0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDekIsT0FBTyxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxRQUFRLEVBQUU7SUFDcEMsVUFBVSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLENBQUM7SUFDbEQsUUFBUSxFQUFFLE9BQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQzNCLElBQUksRUFBRSxPQUFDLENBQUMsTUFBTSxDQUFDLE9BQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7Q0FDeEMsQ0FBQyxDQUFDO0FBSUgsOENBQThDO0FBQ2pDLFFBQUEsb0JBQW9CLEdBQUcsQ0FBQyxlQUFlLEVBQUUsc0JBQXNCLENBQVUsQ0FBQztBQUl2Rix5RUFBeUU7QUFDNUQsUUFBQSxzQkFBc0IsR0FBRyxDQUFDLENBQUM7QUFFeEM7Ozs7Ozs7Ozs7OztHQVlHO0FBQ1UsUUFBQSxrQkFBa0IsR0FBcUM7SUFDbEUsS0FBSyxFQUFFLFFBQVE7SUFDZixRQUFRLEVBQUUsV0FBVztJQUNyQixJQUFJLEVBQUUsTUFBTTtJQUNaLEtBQUssRUFBRSxRQUFRO0lBQ2YsT0FBTyxFQUFFLFNBQVM7SUFDbEIsS0FBSyxFQUFFLE9BQU87Q0FDZixDQUFDO0FBRUY7Ozs7O0dBS0c7QUFDSCxTQUFnQixrQkFBa0IsQ0FBQyxJQUFZO0lBQzdDLElBQUksQ0FBQyxxQkFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQztJQUMzQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbEQsT0FBTywwQkFBa0IsQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLENBQUM7QUFDOUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuXG4vKipcbiAqIFBsYXRmb3JtIGV2ZW50LWJ1cyBlbnZlbG9wZSwgcHVibGlzaGVyIHNpZGUuXG4gKlxuICogVGhpcyBtaXJyb3JzIGBAdWVuZ2FnZS9jb21tb25gJ3MgYHBsYXRmb3JtRXZlbnRTY2hlbWFgIGZpZWxkIGZvciBmaWVsZC5cbiAqIEl0IGlzIGR1cGxpY2F0ZWQgcmF0aGVyIHRoYW4gaW1wb3J0ZWQgYmVjYXVzZSBgQHVlbmdhZ2UvY29tbW9uYCBpcyBhXG4gKiBwcml2YXRlIHdvcmtzcGFjZSBwYWNrYWdlIGFuZCB0aGlzIFNESyBpcyBwdWJsaXNoZWQgdG8gbnBtIOKAlCB0aGUgc2FtZVxuICogcmVhc29uIGBhdWRpdC9zY2hlbWEudHNgIGxpdmVzIGhlcmUgaW5zdGVhZCBvZiBpbiBjb21tb24uIFRoZSB0d28gYXJlXG4gKiBrZXB0IGhvbmVzdCBieSBgc2VydmljZXMvcmVhbHRpbWUvdGVzdC9lbnZlbG9wZS50ZXN0LnRzYCwgd2hpY2hcbiAqIHZhbGlkYXRlcyBhbiBTREstYnVpbHQgZW52ZWxvcGUgYWdhaW5zdCB0aGUgY29tbW9uIHNjaGVtYS5cbiAqL1xuXG4vKiogVUxJRDogQ3JvY2tmb3JkIGJhc2UzMiwgMjYgY2hhcnMsIGV4Y2x1ZGVzIEkvTC9PL1UuICovXG5jb25zdCBVTElEX1JFID0gL15bMC05QS1ISktNTlAtVFYtWl17MjZ9JC87XG5cbi8qKiBEb3R0ZWQgYHJlc291cmNlLm9wZXJhdGlvbmAsIGUuZy4gYG9yZGVyLnN0YXR1c19jaGFuZ2VkYC4gKi9cbmV4cG9ydCBjb25zdCBFVkVOVF9UWVBFX1JFID0gL15bYS16XVthLXowLTlfXSpcXC5bYS16XVthLXowLTlfXSokLztcblxuZXhwb3J0IGNvbnN0IHBsYXRmb3JtRXZlbnRTY2hlbWEgPSB6Lm9iamVjdCh7XG4gIGlkOiB6LnN0cmluZygpLnJlZ2V4KFVMSURfUkUsICdtdXN0IGJlIGEgVUxJRCcpLFxuICB0eXBlOiB6LnN0cmluZygpLnJlZ2V4KEVWRU5UX1RZUEVfUkUsICdtdXN0IGJlIFwiPHJlc291cmNlPi48b3BlcmF0aW9uPlwiJyksXG4gIGRvbWFpbjogei5zdHJpbmcoKS5yZWdleCgvXlthLXpdW2EtejAtOV9dKiQvLCAnbXVzdCBiZSBhIGxvd2VyY2FzZSBkb21haW4gdG9rZW4nKSxcbiAgc291cmNlOiB6LnN0cmluZygpLm1pbigxKSxcbiAgdmVyc2lvbjogei5udW1iZXIoKS5pbnQoKS5wb3NpdGl2ZSgpLFxuICBvY2N1cnJlZEF0OiB6LnN0cmluZygpLmRhdGV0aW1lKHsgb2Zmc2V0OiBmYWxzZSB9KSxcbiAgdGVuYW50SWQ6IHouc3RyaW5nKCkubWluKDEpLFxuICBkYXRhOiB6LnJlY29yZCh6LnN0cmluZygpLCB6LnVua25vd24oKSksXG59KTtcblxuZXhwb3J0IHR5cGUgUGxhdGZvcm1FdmVudCA9IHouaW5mZXI8dHlwZW9mIHBsYXRmb3JtRXZlbnRTY2hlbWE+O1xuXG4vKiogRXZlbnQgdHlwZXMgdGhlIGJ1cyBjYXJyaWVzIGluIHBoYXNlIDEuICovXG5leHBvcnQgY29uc3QgUExBVEZPUk1fRVZFTlRfVFlQRVMgPSBbJ29yZGVyLmNyZWF0ZWQnLCAnb3JkZXIuc3RhdHVzX2NoYW5nZWQnXSBhcyBjb25zdDtcblxuZXhwb3J0IHR5cGUgUGxhdGZvcm1FdmVudFR5cGUgPSAodHlwZW9mIFBMQVRGT1JNX0VWRU5UX1RZUEVTKVtudW1iZXJdO1xuXG4vKiogQ3VycmVudCBlbnZlbG9wZSB2ZXJzaW9uIHN0YW1wZWQgb24gZXZlcnl0aGluZyB0aGlzIFNESyBwdWJsaXNoZXMuICovXG5leHBvcnQgY29uc3QgUExBVEZPUk1fRVZFTlRfVkVSU0lPTiA9IDE7XG5cbi8qKlxuICogUmVzb3VyY2UgcHJlZml4IOKGkiBidXMgZG9tYWluLlxuICpcbiAqIEFuIGV4cGxpY2l0IG1hcCwgbm90IGEgcGx1cmFsaXNhdGlvbiBydWxlOiB0aGUgcGxhdGZvcm0ncyBkb21haW5zIGFyZVxuICogbm90IHVuaWZvcm1seSBwbHVyYWwgKGBvcmRlcnNgIGFuZCBgY3VzdG9tZXJzYCBhcmUsIGBtZW51YCwgYGxveWFsdHlgXG4gKiBhbmQgYHVzYWdlYCBhcmUgbm90KS5cbiAqXG4gKiBDb3BpZWQgZnJvbSBgcGFja2FnZXMvY29tbW9uL3NyYy9ldmVudHMvZG9tYWlucy5qc29uYCwgd2hpY2ggaXMgdGhlXG4gKiBzaW5nbGUgc291cmNlIG9mIHRydXRoLCBiZWNhdXNlIHRoaXMgcGFja2FnZSBpcyBwdWJsaXNoZWQgdG8gbnBtIGFuZFxuICogY2Fubm90IGltcG9ydCBmcm9tIGEgcHJpdmF0ZSB3b3Jrc3BhY2UgcGFja2FnZS4gRXhwb3J0ZWQgc29cbiAqIGB0ZXN0L2V2ZW50cy9kb21haW4tbWFwLnRlc3QudHNgIGNhbiBhc3NlcnQgaXQgYWdhaW5zdCB0aGF0IEpTT04g4oCUIHRoZVxuICogc3VpdGUgZmFpbHMgdGhlIG1vbWVudCB0aGUgdHdvIGRyaWZ0LlxuICovXG5leHBvcnQgY29uc3QgRE9NQUlOX0JZX1JFU09VUkNFOiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+PiA9IHtcbiAgb3JkZXI6ICdvcmRlcnMnLFxuICBjdXN0b21lcjogJ2N1c3RvbWVycycsXG4gIG1lbnU6ICdtZW51JyxcbiAgb2ZmZXI6ICdvZmZlcnMnLFxuICBsb3lhbHR5OiAnbG95YWx0eScsXG4gIHVzYWdlOiAndXNhZ2UnLFxufTtcblxuLyoqXG4gKiBUaGUgZG9tYWluIGFuIGV2ZW50IHR5cGUgYmVsb25ncyB0bywgb3IgbnVsbCBmb3IgYSBtYWxmb3JtZWQgdHlwZSBvclxuICogYW4gdW5yZWdpc3RlcmVkIHJlc291cmNlIHByZWZpeC4gYHB1Ymxpc2goKWAgdHJlYXRzIG51bGwgYXMgYW4gZXJyb3I6XG4gKiBlbWl0dGluZyBvbnRvIGEgZG9tYWluIHRoYXQgZG9lcyBub3QgZXhpc3QgaXMgYSBjYWxsLXNpdGUgbWlzdGFrZSwgYW5kXG4gKiBub3RoaW5nIGRvd25zdHJlYW0gaXMgc3Vic2NyaWJlZCB0byBjYXRjaCBpdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRvbWFpbkZvckV2ZW50VHlwZSh0eXBlOiBzdHJpbmcpOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKCFFVkVOVF9UWVBFX1JFLnRlc3QodHlwZSkpIHJldHVybiBudWxsO1xuICBjb25zdCByZXNvdXJjZSA9IHR5cGUuc2xpY2UoMCwgdHlwZS5pbmRleE9mKCcuJykpO1xuICByZXR1cm4gRE9NQUlOX0JZX1JFU09VUkNFW3Jlc291cmNlXSA/PyBudWxsO1xufVxuIl19
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { type RealtimeEvent } from './envelope';
|
|
2
|
+
import { type RealtimeEndpoints, type RealtimeEnv } from './endpoints';
|
|
3
|
+
/**
|
|
4
|
+
* The slice of the WebSocket API this client uses.
|
|
5
|
+
*
|
|
6
|
+
* Declared structurally rather than relying on a DOM lib: the SDK
|
|
7
|
+
* compiles against `lib: ES2022` only, and this keeps the client
|
|
8
|
+
* injectable so tests can drive the protocol with a fake socket.
|
|
9
|
+
*/
|
|
10
|
+
export interface MinimalWebSocket {
|
|
11
|
+
readyState: number;
|
|
12
|
+
send(data: string): void;
|
|
13
|
+
close(code?: number, reason?: string): void;
|
|
14
|
+
onopen: ((ev: unknown) => void) | null;
|
|
15
|
+
onmessage: ((ev: {
|
|
16
|
+
data: unknown;
|
|
17
|
+
}) => void) | null;
|
|
18
|
+
onerror: ((ev: unknown) => void) | null;
|
|
19
|
+
onclose: ((ev: {
|
|
20
|
+
code?: number;
|
|
21
|
+
reason?: string;
|
|
22
|
+
}) => void) | null;
|
|
23
|
+
}
|
|
24
|
+
export type WebSocketCtor = new (url: string, protocols?: string | string[]) => MinimalWebSocket;
|
|
25
|
+
/** Where an event handed to `onUpdate` came from. */
|
|
26
|
+
export interface UpdateMeta {
|
|
27
|
+
channel: string;
|
|
28
|
+
/**
|
|
29
|
+
* `'snapshot'` — the channel's last value, fetched from the last-value
|
|
30
|
+
* cache on subscribe or after a reconnect. `'live'` — delivered over
|
|
31
|
+
* the socket.
|
|
32
|
+
*
|
|
33
|
+
* Apps generally don't need to branch on this; the SDK has already
|
|
34
|
+
* ordered and de-duplicated both sources by ULID. It's there for
|
|
35
|
+
* telemetry and for UIs that want to distinguish "restored" from
|
|
36
|
+
* "just happened".
|
|
37
|
+
*/
|
|
38
|
+
origin: 'snapshot' | 'live';
|
|
39
|
+
}
|
|
40
|
+
export interface SubscribeOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Fires once with the channel's latest known value (if any), then on
|
|
43
|
+
* every live event. Never fires with an event older than one already
|
|
44
|
+
* delivered on this subscription.
|
|
45
|
+
*/
|
|
46
|
+
onUpdate(event: RealtimeEvent, meta: UpdateMeta): void;
|
|
47
|
+
/**
|
|
48
|
+
* Subscription-level failures: a rejected subscribe, a malformed
|
|
49
|
+
* frame, a failed snapshot fetch. Transient socket drops are handled
|
|
50
|
+
* internally by the reconnect loop and are not surfaced here.
|
|
51
|
+
*/
|
|
52
|
+
onError?(error: Error): void;
|
|
53
|
+
/**
|
|
54
|
+
* Replace the built-in last-value fetch for this channel. Return null
|
|
55
|
+
* when there is no snapshot. Useful when a domain has a better source
|
|
56
|
+
* of truth than the cache — e.g. falling back to the order-details API
|
|
57
|
+
* for an order whose transitions predate bus instrumentation.
|
|
58
|
+
*/
|
|
59
|
+
getSnapshot?(channel: string): Promise<RealtimeEvent | null>;
|
|
60
|
+
}
|
|
61
|
+
export interface Subscription {
|
|
62
|
+
readonly channel: string;
|
|
63
|
+
unsubscribe(): void;
|
|
64
|
+
}
|
|
65
|
+
export interface RealtimeClient {
|
|
66
|
+
/**
|
|
67
|
+
* Subscribe to a channel. Channels are the only concept here — the
|
|
68
|
+
* realtime layer knows nothing about orders; `/orders/{id}` is a
|
|
69
|
+
* naming convention enforced by the service's namespace policy, not by
|
|
70
|
+
* this client.
|
|
71
|
+
*
|
|
72
|
+
* On this call, and again after every reconnect, the SDK opens the
|
|
73
|
+
* subscription *first* and only then fetches the channel's last value,
|
|
74
|
+
* so no event can fall between the snapshot and the stream.
|
|
75
|
+
*/
|
|
76
|
+
subscribe(channel: string, options: SubscribeOptions): Subscription;
|
|
77
|
+
/** Close the shared socket and stop reconnecting. */
|
|
78
|
+
close(): void;
|
|
79
|
+
}
|
|
80
|
+
export interface RealtimeConnectOptions {
|
|
81
|
+
/** Resolves endpoints from the built-in table. Mutually exclusive with `endpoints`. */
|
|
82
|
+
env?: RealtimeEnv;
|
|
83
|
+
/** Explicit endpoints, for environments not in the table. */
|
|
84
|
+
endpoints?: RealtimeEndpoints;
|
|
85
|
+
/**
|
|
86
|
+
* Supplies the platform JWT. Called on connect, on every (re)subscribe,
|
|
87
|
+
* and again after a token-expiry reconnect — so returning a fresh token
|
|
88
|
+
* from your session store is enough to keep a long-lived connection
|
|
89
|
+
* authenticated.
|
|
90
|
+
*/
|
|
91
|
+
getToken(): string | Promise<string>;
|
|
92
|
+
/** Inject a WebSocket implementation. Defaults to `globalThis.WebSocket`. */
|
|
93
|
+
webSocketImpl?: WebSocketCtor;
|
|
94
|
+
/** Inject a fetch implementation for snapshot fetches. Defaults to `globalThis.fetch`. */
|
|
95
|
+
fetchFn?: typeof fetch;
|
|
96
|
+
/** Backoff ceiling for reconnects. Default 30_000. */
|
|
97
|
+
maxReconnectDelayMs?: number;
|
|
98
|
+
}
|
|
99
|
+
export declare function connect(options: RealtimeConnectOptions): RealtimeClient;
|
|
100
|
+
/**
|
|
101
|
+
* Full-jitter exponential backoff. Full jitter (rather than
|
|
102
|
+
* delay ± jitter) matters here because every tab watching an order
|
|
103
|
+
* reconnects on the same server-side event; without it they retry in
|
|
104
|
+
* lockstep.
|
|
105
|
+
*/
|
|
106
|
+
export declare function jitteredBackoff(attempt: number, maxDelayMs: number): number;
|