@aws-amplify/backend-notifications 0.0.0-test-20260708085627

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +235 -0
  2. package/lib/campaign-association-asset/index.js +48413 -0
  3. package/lib/constants.d.ts +122 -0
  4. package/lib/constants.js +125 -0
  5. package/lib/construct.d.ts +283 -0
  6. package/lib/construct.js +824 -0
  7. package/lib/factory.d.ts +53 -0
  8. package/lib/factory.js +158 -0
  9. package/lib/handler-asset/index.js +530 -0
  10. package/lib/index.d.ts +7 -0
  11. package/lib/index.js +5 -0
  12. package/lib/lambda/campaign-association/handler.d.ts +29 -0
  13. package/lib/lambda/campaign-association/handler.js +80 -0
  14. package/lib/lambda/campaign-association/integration.d.ts +59 -0
  15. package/lib/lambda/campaign-association/integration.js +108 -0
  16. package/lib/lambda/campaign-association/onboarding.d.ts +25 -0
  17. package/lib/lambda/campaign-association/onboarding.js +74 -0
  18. package/lib/lambda/identify/device_resolver.d.ts +18 -0
  19. package/lib/lambda/identify/device_resolver.js +56 -0
  20. package/lib/lambda/identify/handler.d.ts +17 -0
  21. package/lib/lambda/identify/handler.js +124 -0
  22. package/lib/lambda/identify/mapping.d.ts +61 -0
  23. package/lib/lambda/identify/mapping.js +171 -0
  24. package/lib/lambda/identify/merge_resolver.d.ts +26 -0
  25. package/lib/lambda/identify/merge_resolver.js +36 -0
  26. package/lib/lambda/identify/principal.d.ts +68 -0
  27. package/lib/lambda/identify/principal.js +48 -0
  28. package/lib/lambda/identify/profile_resolver.d.ts +35 -0
  29. package/lib/lambda/identify/profile_resolver.js +65 -0
  30. package/lib/lambda/identify/types.d.ts +90 -0
  31. package/lib/lambda/identify/types.js +10 -0
  32. package/lib/lambda/identify/validation.d.ts +15 -0
  33. package/lib/lambda/identify/validation.js +99 -0
  34. package/lib/lambda/push/delivery.d.ts +49 -0
  35. package/lib/lambda/push/delivery.js +120 -0
  36. package/lib/lambda/push/device_lookup.d.ts +35 -0
  37. package/lib/lambda/push/device_lookup.js +88 -0
  38. package/lib/lambda/push/eum_client.d.ts +31 -0
  39. package/lib/lambda/push/eum_client.js +140 -0
  40. package/lib/lambda/push/event.d.ts +32 -0
  41. package/lib/lambda/push/event.js +122 -0
  42. package/lib/lambda/push/fixtures/real_journey_event.d.ts +19 -0
  43. package/lib/lambda/push/fixtures/real_journey_event.js +22 -0
  44. package/lib/lambda/push/handler.d.ts +15 -0
  45. package/lib/lambda/push/handler.js +86 -0
  46. package/lib/lambda/push/message_template.d.ts +72 -0
  47. package/lib/lambda/push/message_template.js +270 -0
  48. package/lib/lambda/push/payload.d.ts +25 -0
  49. package/lib/lambda/push/payload.js +53 -0
  50. package/lib/lambda/push/types.d.ts +153 -0
  51. package/lib/lambda/push/types.js +4 -0
  52. package/lib/lambda/shared/retry.d.ts +18 -0
  53. package/lib/lambda/shared/retry.js +45 -0
  54. package/lib/object_types.d.ts +63 -0
  55. package/lib/object_types.js +131 -0
  56. package/lib/push-handler-asset/index.js +75517 -0
  57. package/lib/types.d.ts +125 -0
  58. package/lib/types.js +2 -0
  59. package/package.json +49 -0
@@ -0,0 +1,270 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { DescribeCampaignCommand, } from '@aws-sdk/client-connectcampaignsv2';
4
+ import { ListIntegrationAssociationsCommand, } from '@aws-sdk/client-connect';
5
+ import { GetMessageTemplateCommand, ListMessageTemplatesCommand, RenderMessageTemplateCommand, } from '@aws-sdk/client-qconnect';
6
+ import { ACTIVE_VERSION_QUALIFIER, PUSH_CHANNEL_SUBTYPE, Q_MESSAGE_TEMPLATES_INTEGRATION_TYPE, } from '../../constants.js';
7
+ /** Max length of a single Q Connect render attribute value. */
8
+ const MAX_ATTRIBUTE_LENGTH = 32767;
9
+ /**
10
+ * Per-container cache of `campaignId -> knowledgeBaseId`. KB discovery
11
+ * (DescribeCampaign + ListIntegrationAssociations) is stable for a campaign's
12
+ * lifetime, so warm Lambda invocations skip the two lookups.
13
+ *
14
+ * TODO(prod): unbounded (one entry per distinct campaignId per container) — cap
15
+ * or TTL this before GA if a single container fronts many campaigns.
16
+ */
17
+ const kbIdByCampaign = new Map();
18
+ /**
19
+ * Discover the Q in Connect knowledge base backing a campaign's Connect
20
+ * instance, caching per container:
21
+ *
22
+ * CampaignId -> connectcampaignsv2 DescribeCampaign -> campaign.connectInstanceId
23
+ * -> connect ListIntegrationAssociations(Q_MESSAGE_TEMPLATES)
24
+ * -> IntegrationArn (arn:aws:wisdom:...:knowledge-base/<kbId>) -> kbId
25
+ *
26
+ * Returns `undefined` (never throws) when the instance id or the KB integration
27
+ * cannot be resolved — the caller then falls back to non-templated copy. If
28
+ * DescribeCampaign does not carry `connectInstanceId`, that is logged so the
29
+ * real shape can be inspected.
30
+ */
31
+ export const discoverKnowledgeBaseId = async (clients, campaignId) => {
32
+ const cached = kbIdByCampaign.get(campaignId);
33
+ if (cached) {
34
+ return cached;
35
+ }
36
+ const describe = await clients.campaigns.send(new DescribeCampaignCommand({ id: campaignId }));
37
+ const instanceId = describe.campaign?.connectInstanceId;
38
+ if (!instanceId) {
39
+ console.warn('[push] kb.discover.noInstanceId', JSON.stringify({
40
+ campaignId,
41
+ campaignKeys: Object.keys(describe.campaign ?? {}),
42
+ }));
43
+ return undefined;
44
+ }
45
+ const assoc = await clients.connect.send(new ListIntegrationAssociationsCommand({
46
+ InstanceId: instanceId,
47
+ IntegrationType: Q_MESSAGE_TEMPLATES_INTEGRATION_TYPE,
48
+ }));
49
+ // A Connect instance has at most one Q_MESSAGE_TEMPLATES binding, so page 1
50
+ // always carries it and we don't paginate. Surface a NextToken if that ever
51
+ // stops holding so the edge case is observable rather than a silent miss.
52
+ if (assoc.NextToken) {
53
+ console.warn('[push] kb.discover.multiplePages', JSON.stringify({ campaignId, instanceId }));
54
+ }
55
+ const integrationArn = assoc.IntegrationAssociationSummaryList?.find((a) => a.IntegrationArn)?.IntegrationArn;
56
+ // Only trust a well-formed Q in Connect knowledge-base ARN
57
+ // (arn:aws:wisdom:...:knowledge-base/<kbId>); anything else yields a garbage
58
+ // id that would fail three calls later at render time.
59
+ const kbId = integrationArn?.includes('knowledge-base/')
60
+ ? integrationArn.split('/').pop()
61
+ : undefined;
62
+ if (!kbId) {
63
+ console.warn('[push] kb.discover.noKnowledgeBase', JSON.stringify({ campaignId, instanceId, integrationArn }));
64
+ return undefined;
65
+ }
66
+ console.log('[push] kb.discover', JSON.stringify({ campaignId, instanceId, knowledgeBaseId: kbId }));
67
+ kbIdByCampaign.set(campaignId, kbId);
68
+ return kbId;
69
+ };
70
+ /**
71
+ * Find the PUSH message template in `knowledgeBaseId` whose name equals the
72
+ * journey `actionId` (the Custom-action block name). Pages ListMessageTemplates
73
+ * and filters client-side to `channelSubtype === PUSH`. Returns the matching
74
+ * template id, or `undefined` when none matches.
75
+ */
76
+ const findPushTemplateId = async (qconnect, knowledgeBaseId, actionId) => {
77
+ let nextToken;
78
+ do {
79
+ const res = await qconnect.send(new ListMessageTemplatesCommand({
80
+ knowledgeBaseId,
81
+ maxResults: 100,
82
+ nextToken,
83
+ }));
84
+ const match = res.messageTemplateSummaries?.find((s) => s.channelSubtype === PUSH_CHANNEL_SUBTYPE && s.name === actionId);
85
+ if (match?.messageTemplateId) {
86
+ return match.messageTemplateId;
87
+ }
88
+ nextToken = res.nextToken;
89
+ } while (nextToken);
90
+ return undefined;
91
+ };
92
+ /**
93
+ * Resolve the PUSH message template for a journey run: discover the knowledge
94
+ * base from the campaign, find the PUSH template whose name == the ActionId,
95
+ * and confirm it has an ACTIVE version. Returns `undefined` (never throws) when
96
+ * anything is missing — no campaign metadata, no KB integration, no matching
97
+ * template — so the caller falls back to the non-templated per-profile copy.
98
+ */
99
+ export const resolvePushTemplateContext = async (clients, campaign) => {
100
+ const campaignId = campaign.campaignId;
101
+ const actionId = campaign.actionId;
102
+ if (!campaignId || !actionId) {
103
+ console.log('[push] template.skip', JSON.stringify({
104
+ reason: 'missing campaignId or actionId',
105
+ campaignId: campaignId ?? null,
106
+ actionId: actionId ?? null,
107
+ }));
108
+ return undefined;
109
+ }
110
+ try {
111
+ const knowledgeBaseId = await discoverKnowledgeBaseId(clients, campaignId);
112
+ if (!knowledgeBaseId) {
113
+ return undefined;
114
+ }
115
+ const messageTemplateId = await findPushTemplateId(clients.qconnect, knowledgeBaseId, actionId);
116
+ if (!messageTemplateId) {
117
+ console.warn('[push] template.noMatch', JSON.stringify({ knowledgeBaseId, actionId }));
118
+ return undefined;
119
+ }
120
+ // Confirm an ACTIVE (published) version exists; if not, still render the
121
+ // latest content (GetMessageTemplate is diagnostic here, not a gate).
122
+ try {
123
+ await clients.qconnect.send(new GetMessageTemplateCommand({
124
+ knowledgeBaseId,
125
+ messageTemplateId: `${messageTemplateId}:${ACTIVE_VERSION_QUALIFIER}`,
126
+ }));
127
+ }
128
+ catch (err) {
129
+ console.warn('[push] template.noActiveVersion', JSON.stringify({
130
+ knowledgeBaseId,
131
+ messageTemplateId,
132
+ error: err instanceof Error ? err.message : 'unknown',
133
+ }));
134
+ }
135
+ console.log('[push] template.resolved', JSON.stringify({ knowledgeBaseId, messageTemplateId, actionId }));
136
+ return {
137
+ qconnect: clients.qconnect,
138
+ knowledgeBaseId,
139
+ messageTemplateId,
140
+ templateName: actionId,
141
+ };
142
+ }
143
+ catch (err) {
144
+ console.warn('[push] template.resolveError', JSON.stringify({
145
+ campaignId,
146
+ actionId,
147
+ error: err instanceof Error ? err.message : 'unknown',
148
+ }));
149
+ return undefined;
150
+ }
151
+ };
152
+ /**
153
+ * Flatten a profile's `CustomerData` into a flat `customAttributes` map for
154
+ * RenderMessageTemplate. Empirically only `{{Attributes.<flatKey>}}` variables
155
+ * interpolate (from `customAttributes`); the `{{Customer.*}}` namespace does not
156
+ * resolve here — so the profile's `firstName` and every `attributes.*` entry are
157
+ * passed as flat custom attributes (templates reference e.g.
158
+ * `{{Attributes.firstName}}`). Nested objects (`address`, `attributes`) are not
159
+ * added directly; `attributes` is merged one level deep. Non-string / empty
160
+ * values are dropped and values are capped at the render attribute-length limit.
161
+ */
162
+ export const buildCustomAttributes = (customerData) => {
163
+ const out = {};
164
+ if (!customerData) {
165
+ return out;
166
+ }
167
+ const add = (key, value) => {
168
+ if (typeof value === 'string' && value.length > 0) {
169
+ out[key] = value.slice(0, MAX_ATTRIBUTE_LENGTH);
170
+ }
171
+ };
172
+ for (const [key, value] of Object.entries(customerData)) {
173
+ if (key === 'attributes' || key === 'address') {
174
+ continue;
175
+ }
176
+ add(key, value);
177
+ }
178
+ const attributes = customerData.attributes;
179
+ if (attributes &&
180
+ typeof attributes === 'object' &&
181
+ !Array.isArray(attributes)) {
182
+ // attributes sub-keys overwrite top-level keys on collision (attributes is
183
+ // the authoritative custom-attribute store).
184
+ for (const [key, value] of Object.entries(attributes)) {
185
+ add(key, value);
186
+ }
187
+ }
188
+ return out;
189
+ };
190
+ /**
191
+ * Detects a Handlebars placeholder the renderer left unresolved, e.g. a
192
+ * `{{Attributes.firstName}}` var for a profile that has no `firstName`. Q Connect
193
+ * leaves such vars LITERAL in the output (and lists them in
194
+ * `attributesNotInterpolated`); shipping that raw text to a device is a bug, so
195
+ * copy that still contains one is rejected and the caller falls back to default.
196
+ */
197
+ const hasUnresolvedPlaceholder = (value) => /\{\{.*?\}\}/.test(value);
198
+ const toMessage = (content) => {
199
+ const title = content?.title;
200
+ const body = content?.body?.content;
201
+ if (typeof title === 'string' &&
202
+ title.length > 0 &&
203
+ typeof body === 'string' &&
204
+ body.length > 0 &&
205
+ !hasUnresolvedPlaceholder(title) &&
206
+ !hasUnresolvedPlaceholder(body)) {
207
+ return { title, body };
208
+ }
209
+ return undefined;
210
+ };
211
+ /**
212
+ * Render the resolved PUSH template for ONE profile and map the per-platform
213
+ * copy to push channels:
214
+ * - `push.apns` -> `APNS` (+ `APNS_SANDBOX`)
215
+ * - `push.fcm` -> `GCM`
216
+ *
217
+ * The profile's `CustomerData` is passed as flat `customAttributes` so
218
+ * `{{Attributes.<key>}}` variables personalize. Returns a partial per-channel
219
+ * map (only channels the template defines both a title and body for), or
220
+ * `undefined` (never throws) when there is no push content or the render fails —
221
+ * the caller then falls back to the non-templated copy for that profile.
222
+ */
223
+ export const renderProfileChannelMessages = async (ctx, target) => {
224
+ const customAttributes = buildCustomAttributes(target.customerData);
225
+ let res;
226
+ try {
227
+ res = await ctx.qconnect.send(new RenderMessageTemplateCommand({
228
+ knowledgeBaseId: ctx.knowledgeBaseId,
229
+ // Render the PUBLISHED version explicitly (verified: RenderMessageTemplate
230
+ // accepts the `:$ACTIVE_VERSION` qualifier) so a later saved draft can't
231
+ // silently change production copy.
232
+ messageTemplateId: `${ctx.messageTemplateId}:${ACTIVE_VERSION_QUALIFIER}`,
233
+ attributes: { customAttributes },
234
+ }));
235
+ }
236
+ catch (err) {
237
+ console.warn('[push] template.renderError', JSON.stringify({
238
+ templateName: ctx.templateName,
239
+ error: err instanceof Error ? err.message : 'unknown',
240
+ }));
241
+ return undefined;
242
+ }
243
+ const content = res.content;
244
+ const push = content?.push;
245
+ if (!push) {
246
+ return undefined;
247
+ }
248
+ const apns = toMessage(push.apns);
249
+ const fcm = toMessage(push.fcm);
250
+ const perChannel = {};
251
+ if (apns) {
252
+ perChannel.APNS = apns;
253
+ perChannel.APNS_SANDBOX = apns;
254
+ }
255
+ if (fcm) {
256
+ perChannel.GCM = fcm;
257
+ }
258
+ // Operational signal only: which channels the template rendered usable copy
259
+ // for, plus any template variables the renderer left un-interpolated (these
260
+ // are template-author-defined variable names, e.g. `Attributes.firstName`,
261
+ // not customer values). The rendered title/body are never logged.
262
+ console.log('[push] template.render', JSON.stringify({
263
+ templateName: ctx.templateName,
264
+ apnsRendered: Boolean(apns),
265
+ gcmRendered: Boolean(fcm),
266
+ attributesNotInterpolated: res.attributesNotInterpolated ?? [],
267
+ }));
268
+ return Object.keys(perChannel).length > 0 ? perChannel : undefined;
269
+ };
270
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzc2FnZV90ZW1wbGF0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvcHVzaC9tZXNzYWdlX3RlbXBsYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHFFQUFxRTtBQUNyRSxzQ0FBc0M7QUFFdEMsT0FBTyxFQUVMLHVCQUF1QixHQUN4QixNQUFNLG9DQUFvQyxDQUFDO0FBQzVDLE9BQU8sRUFFTCxrQ0FBa0MsR0FDbkMsTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQ0wseUJBQXlCLEVBQ3pCLDJCQUEyQixFQUUzQiw0QkFBNEIsR0FDN0IsTUFBTSwwQkFBMEIsQ0FBQztBQUVsQyxPQUFPLEVBQ0wsd0JBQXdCLEVBQ3hCLG9CQUFvQixFQUNwQixvQ0FBb0MsR0FDckMsTUFBTSxvQkFBb0IsQ0FBQztBQVE1QiwrREFBK0Q7QUFDL0QsTUFBTSxvQkFBb0IsR0FBRyxLQUFLLENBQUM7QUF5Qm5DOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztBQVFqRDs7Ozs7Ozs7Ozs7O0dBWUc7QUFDSCxNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLEVBQzFDLE9BQXVELEVBQ3ZELFVBQWtCLEVBQ1csRUFBRTtJQUMvQixNQUFNLE1BQU0sR0FBRyxjQUFjLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzlDLElBQUksTUFBTSxFQUFFLENBQUM7UUFDWCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLElBQUksQ0FDM0MsSUFBSSx1QkFBdUIsQ0FBQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUNoRCxDQUFDO0lBQ0YsTUFBTSxVQUFVLEdBQUcsUUFBUSxDQUFDLFFBQVEsRUFBRSxpQkFBaUIsQ0FBQztJQUN4RCxJQUFJLENBQUMsVUFBVSxF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QUFJLEVBQUU7S0FDL0QsQ0FBQyxDQUNILENBQUM7SUFFRixPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDckUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQge1xuICBDb25uZWN0Q2FtcGFpZ25zVjJDbGllbnQsXG4gIERlc2NyaWJlQ2FtcGFpZ25Db21tYW5kLFxufSBmcm9tICdAYXdzLXNkay9jbGllbnQtY29ubmVjdGNhbXBhaWduc3YyJztcbmltcG9ydCB7XG4gIENvbm5lY3RDbGllbnQsXG4gIExpc3RJbnRlZ3JhdGlvbkFzc29jaWF0aW9uc0NvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jb25uZWN0JztcbmltcG9ydCB7XG4gIEdldE1lc3NhZ2VUZW1wbGF0ZUNvbW1hbmQsXG4gIExpc3RNZXNzYWdlVGVtcGxhdGVzQ29tbWFuZCxcbiAgUUNvbm5lY3RDbGllbnQsXG4gIFJlbmRlck1lc3NhZ2VUZW1wbGF0ZUNvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1xY29ubmVjdCc7XG5cbmltcG9ydCB7XG4gIEFDVElWRV9WRVJTSU9OX1FVQUxJRklFUixcbiAgUFVTSF9DSEFOTkVMX1NVQlRZUEUsXG4gIFFfTUVTU0FHRV9URU1QTEFURVNfSU5URUdSQVRJT05fVFlQRSxcbn0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcbmltcG9ydCB7XG4gIENhbXBhaWduQ29udGV4dCxcbiAgUHJvZmlsZVRhcmdldCxcbiAgUHVzaENoYW5uZWxUeXBlLFxuICBQdXNoTWVzc2FnZSxcbn0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbi8qKiBNYXggbGVuZ3RoIG9mIGEgc2luZ2xlIFEgQ29ubmVjdCByZW5kZXIgYXR0cmlidXRlIHZhbHVlLiAqL1xuY29uc3QgTUFYX0FUVFJJQlVURV9MRU5HVEggPSAzMjc2NztcblxuLyoqIFRoZSBBV1MgY2xpZW50cyB0aGUgdGVtcGxhdGUgcmVzb2x2ZXIgbmVlZHMuICovXG5leHBvcnQgdHlwZSBUZW1wbGF0ZUNsaWVudHMgPSB7XG4gIGNhbXBhaWduczogQ29ubmVjdENhbXBhaWduc1YyQ2xpZW50O1xuICBjb25uZWN0OiBDb25uZWN0Q2xpZW50O1xuICBxY29ubmVjdDogUUNvbm5lY3RDbGllbnQ7XG59O1xuXG4vKipcbiAqIEEgcmVzb2x2ZWQgUSBpbiBDb25uZWN0IFBVU0ggbWVzc2FnZSB0ZW1wbGF0ZSBmb3Igb25lIGpvdXJuZXkgcnVuOiB0aGVcbiAqIGtub3dsZWRnZSBiYXNlICsgdGhlIHNwZWNpZmljIHRlbXBsYXRlIGlkIHRvIHJlbmRlciBwZXIgcHJvZmlsZS4gUHJvZHVjZWQgYnlcbiAqIHtAbGluayByZXNvbHZlUHVzaFRlbXBsYXRlQ29udGV4dH0gYW5kIGNhcnJpZWQgb24gdGhlIGRlbGl2ZXJ5IGRlcHMgc29cbiAqIHtAbGluayByZW5kZXJQcm9maWxlQ2hhbm5lbE1lc3NhZ2VzfSBjYW4gcmVuZGVyIHBlcnNvbmFsaXplZCBjb3B5IHBlciBwcm9maWxlLlxuICovXG5leHBvcnQgdHlwZSBQdXNoVGVtcGxhdGVDb250ZXh0ID0ge1xuICBxY29ubmVjdDogUUNvbm5lY3RDbGllbnQ7XG4gIC8qKiBUaGUgZGlzY292ZXJlZCBRIGluIENvbm5lY3Qga25vd2xlZGdlIGJhc2UgaWQuICovXG4gIGtub3dsZWRnZUJhc2VJZDogc3RyaW5nO1xuICAvKiogVGhlIFBVU0ggbWVzc2FnZSB0ZW1wbGF0ZSBpZCB3aG9zZSBuYW1lIG1hdGNoZWQgdGhlIGpvdXJuZXkgQWN0aW9uSWQuICovXG4gIG1lc3NhZ2VUZW1wbGF0ZUlkOiBzdHJpbmc7XG4gIC8qKiBUaGUgdGVtcGxhdGUgbmFtZSAoPT0gdGhlIEN1c3RvbS1hY3Rpb24gYmxvY2sgbmFtZSAvIEFjdGlvbklkKS4gKi9cbiAgdGVtcGxhdGVOYW1lOiBzdHJpbmc7XG59O1xuXG4vKipcbiAqIFBlci1jb250YWluZXIgY2FjaGUgb2YgYGNhbXBhaWduSWQgLT4ga25vd2xlZGdlQmFzZUlkYC4gS0IgZGlzY292ZXJ5XG4gKiAoRGVzY3JpYmVDYW1wYWlnbiArIExpc3RJbnRlZ3JhdGlvbkFzc29jaWF0aW9ucykgaXMgc3RhYmxlIGZvciBhIGNhbXBhaWduJ3NcbiAqIGxpZmV0aW1lLCBzbyB3YXJtIExhbWJkYSBpbnZvY2F0aW9ucyBza2lwIHRoZSB0d28gbG9va3Vwcy5cbiAqXG4gKiBUT0RPKHByb2QpOiB1bmJvdW5kZWQgKG9uZSBlbnRyeSBwZXIgZGlzdGluY3QgY2FtcGFpZ25JZCBwZXIgY29udGFpbmVyKSDigJQgY2FwXG4gKiBvciBUVEwgdGhpcyBiZWZvcmUgR0EgaWYgYSBzaW5nbGUgY29udGFpbmVyIGZyb250cyBtYW55IGNhbXBhaWducy5cbiAqL1xuY29uc3Qga2JJZEJ5Q2FtcGFpZ24gPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuXG4vKiogVGhlIHNoYXBlIHdlIHJlYWQgb3V0IG9mIGEgUSBDb25uZWN0IFBVU0ggdGVtcGxhdGUgcGxhdGZvcm0gZW50cnkuICovXG50eXBlIFBsYXRmb3JtQ29udGVudCA9IHtcbiAgdGl0bGU/OiBzdHJpbmc7XG4gIGJvZHk/OiB7IGNvbnRlbnQ/OiBzdHJpbmcgfTtcbn07XG5cbi8qKlxuICogRGlzY292ZXIgdGhlIFEgaW4gQ29ubmVjdCBrbm93bGVkZ2UgYmFzZSBiYWNraW5nIGEgY2FtcGFpZ24ncyBDb25uZWN0XG4gKiBpbnN0YW5jZSwgY2FjaGluZyBwZXIgY29udGFpbmVyOlxuICpcbiAqICAgQ2FtcGFpZ25JZCAtPiBjb25uZWN0Y2FtcGFpZ25zdjIgRGVzY3JpYmVDYW1wYWlnbiAtPiBjYW1wYWlnbi5jb25uZWN0SW5zdGFuY2VJZFxuICogICAgICAgICAgICAgIC0+IGNvbm5lY3QgTGlzdEludGVncmF0aW9uQXNzb2NpYXRpb25zKFFfTUVTU0FHRV9URU1QTEFURVMpXG4gKiAgICAgICAgICAgICAgLT4gSW50ZWdyYXRpb25Bcm4gKGFybjphd3M6d2lzZG9tOi4uLjprbm93bGVkZ2UtYmFzZS88a2JJZD4pIC0+IGtiSWRcbiAqXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIChuZXZlciB0aHJvd3MpIHdoZW4gdGhlIGluc3RhbmNlIGlkIG9yIHRoZSBLQiBpbnRlZ3JhdGlvblxuICogY2Fubm90IGJlIHJlc29sdmVkIOKAlCB0aGUgY2FsbGVyIHRoZW4gZmFsbHMgYmFjayB0byBub24tdGVtcGxhdGVkIGNvcHkuIElmXG4gKiBEZXNjcmliZUNhbXBhaWduIGRvZXMgbm90IGNhcnJ5IGBjb25uZWN0SW5zdGFuY2VJZGAsIHRoYXQgaXMgbG9nZ2VkIHNvIHRoZVxuICogcmVhbCBzaGFwZSBjYW4gYmUgaW5zcGVjdGVkLlxuICovXG5leHBvcnQgY29uc3QgZGlzY292ZXJLbm93bGVkZ2VCYXNlSWQgPSBhc3luYyAoXG4gIGNsaWVudHM6IFBpY2s8VGVtcGxhdGVDbGllbnRzLCAnY2FtcGFpZ25zJyB8ICdjb25uZWN0Jz4sXG4gIGNhbXBhaWduSWQ6IHN0cmluZyxcbik6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiA9PiB7XG4gIGNvbnN0IGNhY2hlZCA9IGtiSWRCeUNhbXBhaWduLmdldChjYW1wYWlnbklkKTtcbiAgaWYgKGNhY2hlZCkge1xuICAgIHJldHVybiBjYWNoZWQ7XG4gIH1cblxuICBjb25zdCBkZXNjcmliZSA9IGF3YWl0IGNsaWVudHMuY2FtcGFpZ25zLnNlbmQoXG4gICAgbmV3IERlc2NyaWJlQ2FtcGFpZ25Db21tYW5kKHsgaWQ6IGNhbXBhaWduSWQgfSksXG4gICk7XG4gIGNvbnN0IGluc3RhbmNlSWQgPSBkZXNjcmliZS5jYW1wYWlnbj8uY29ubmVjdEluc3RhbmNlSWQ7XG4gIGlmICghaW5zdGFuY2VJZCkge1xuICAgIGNvbnNvbGUud2FybihcbiAgICAgICdbcHVzaF0ga2IuZGlzY292ZXIubm9JbnN0YW5jZUlkJyxcbiAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgY2FtcGFpZ25JZCxcbiAgICAgICAgY2FtcGFpZ25LZXlzOiBPYmplY3Qua2V5cyhkZXNjcmliZS5jYW1wYWlnbiA/PyB7fSksXG4gICAgICB9KSxcbiAgICApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBhc3NvYyA9IGF3YWl0IGNsaWVudHMuY29ubmVjdC5zZW5kKFxuICAgIG5ldyBMaXN0SW50ZWdyYXRpb25Bc3NvY2lhdGlvbnNDb21tYW5kKHtcbiAgICAgIEluc3RhbmNlSWQ6IGluc3RhbmNlSWQsXG4gICAgICBJbnRlZ3JhdGlvblR5cGU6IFFfTUVTU0FHRV9URU1QTEFURVNfSU5URUdSQVRJT05fVFlQRSxcbiAgICB9KSxcbiAgKTtcbiAgLy8gQSBDb25uZWN0IGluc3RhbmNlIGhhcyBhdCBtb3N0IG9uZSBRX01FU1NBR0VfVEVNUExBVEVTIGJpbmRpbmcsIHNvIHBhZ2UgMVxuICAvLyBhbHdheXMgY2FycmllcyBpdCBhbmQgd2UgZG9uJ3QgcGFnaW5hdGUuIFN1cmZhY2UgYSBOZXh0VG9rZW4gaWYgdGhhdCBldmVyXG4gIC8vIHN0b3BzIGhvbGRpbmcgc28gdGhlIGVkZ2UgY2FzZSBpcyBvYnNlcnZhYmxlIHJhdGhlciB0aGFuIGEgc2lsZW50IG1pc3MuXG4gIGlmIChhc3NvYy5OZXh0VG9rZW4pIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICAnW3B1c2hdIGtiLmRpc2NvdmVyLm11bHRpcGxlUGFnZXMnLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoeyBjYW1wYWlnbklkLCBpbnN0YW5jZUlkIH0pLFxuICAgICk7XG4gIH1cbiAgY29uc3QgaW50ZWdyYXRpb25Bcm4gPSBhc3NvYy5JbnRlZ3JhdGlvbkFzc29jaWF0aW9uU3VtbWFyeUxpc3Q/LmZpbmQoXG4gICAgKGEpID0+IGEuSW50ZWdyYXRpb25Bcm4sXG4gICk/LkludGVncmF0aW9uQXJuO1xuICAvLyBPbmx5IHRydXN0IGEgd2VsbC1mb3JtZWQgUSBpbiBDb25uZWN0IGtub3dsZWRnZS1iYXNlIEFSTlxuICAvLyAoYXJuOmF3czp3aXNkb206Li4uOmtub3dsZWRnZS1iYXNlLzxrYklkPik7IGFueXRoaW5nIGVsc2UgeWllbGRzIGEgZ2FyYmFnZVxuICAvLyBpZCB0aGF0IHdvdWxkIGZhaWwgdGhyZWUgY2FsbHMgbGF0ZXIgYXQgcmVuZGVyIHRpbWUuXG4gIGNvbnN0IGtiSWQgPSBpbnRlZ3JhdGlvbkFybj8uaW5jbHVkZXMoJ2tub3dsZWRnZS1iYXNlLycpXG4gICAgPyBpbnRlZ3JhdGlvbkFybi5zcGxpdCgnLycpLnBvcCgpXG4gICAgOiB1bmRlZmluZWQ7XG5cbiAgaWYgKCFrYklkKSB7XG4gICAgY29uc29sZS53YXJuKFxuICAgICAgJ1twdXNoXSBrYi5kaXNjb3Zlci5ub0tub3dsZWRnZUJhc2UnLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoeyBjYW1wYWlnbklkLCBpbnN0YW5jZUlkLCBpbnRlZ3JhdGlvbkFybiB9KSxcbiAgICApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zb2xlLmxvZyhcbiAgICAnW3B1c2hdIGtiLmRpc2NvdmVyJyxcbiAgICBKU09OLnN0cmluZ2lmeSh7IGNhbXBhaWduSWQsIGluc3RhbmNlSWQsIGtub3dsZWRnZUJhc2VJZDoga2JJZCB9KSxcbiAgKTtcbiAga2JJZEJ5Q2FtcGFpZ24uc2V0KGNhbXBhaWduSWQsIGtiSWQpO1xuICByZXR1cm4ga2JJZDtcbn07XG5cbi8qKlxuICogRmluZCB0aGUgUFVTSCBtZXNzYWdlIHRlbXBsYXRlIGluIGBrbm93bGVkZ2VCYXNlSWRgIHdob3NlIG5hbWUgZXF1YWxzIHRoZVxuICogam91cm5leSBgYWN0aW9uSWRgICh0aGUgQ3VzdG9tLWFjdGlvbiBibG9jayBuYW1lKS4gUGFnZXMgTGlzdE1lc3NhZ2VUZW1wbGF0ZXNcbiAqIGFuZCBmaWx0ZXJzIGNsaWVudC1zaWRlIHRvIGBjaGFubmVsU3VidHlwZSA9PT0gUFVTSGAuIFJldHVybnMgdGhlIG1hdGNoaW5nXG4gKiB0ZW1wbGF0ZSBpZCwgb3IgYHVuZGVmaW5lZGAgd2hlbiBub25lIG1hdGNoZXMuXG4gKi9cbmNvbnN0IGZpbmRQdXNoVGVtcGxhdGVJZCA9IGFzeW5jIChcbiAgcWNvbm5lY3Q6IFFDb25uZWN0Q2xpZW50LFxuICBrbm93bGVkZ2VCYXNlSWQ6IHN0cmluZyxcbiAgYWN0aW9uSWQ6IHN0cmluZyxcbik6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiA9PiB7XG4gIGxldCBuZXh0VG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgZG8ge1xuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHFjb25uZWN0LnNlbmQoXG4gICAgICBuZXcgTGlzdE1lc3NhZ2VUZW1wbGF0ZXNDb21tYW5kKHtcbiAgICAgICAga25vd2xlZGdlQmFzZUlkLFxuICAgICAgICBtYXhSZXN1bHRzOiAxMDAsXG4gICAgICAgIG5leHRUb2tlbixcbiAgICAgIH0pLFxuICAgICk7XG4gICAgY29uc3QgbWF0Y2ggPSByZXMubWVzc2FnZVRlbXBsYXRlU3VtbWFyaWVzPy5maW5kKFxuICAgICAgKHMpID0+IHMuY2hhbm5lbFN1YnR5cGUgPT09IFBVU0hfQ0hBTk5FTF9TVUJUWVBFICYmIHMubmFtZSA9PT0gYWN0aW9uSWQsXG4gICAgKTtcbiAgICBpZiAobWF0Y2g/Lm1lc3NhZ2VUZW1wbGF0ZUlkKSB7XG4gICAgICByZXR1cm4gbWF0Y2gubWVzc2FnZVRlbXBsYXRlSWQ7XG4gICAgfVxuICAgIG5leHRUb2tlbiA9IHJlcy5uZXh0VG9rZW47XG4gIH0gd2hpbGUgKG5leHRUb2tlbik7XG4gIHJldHVybiB1bmRlZmluZWQ7XG59O1xuXG4vKipcbiAqIFJlc29sdmUgdGhlIFBVU0ggbWVzc2FnZSB0ZW1wbGF0ZSBmb3IgYSBqb3VybmV5IHJ1bjogZGlzY292ZXIgdGhlIGtub3dsZWRnZVxuICogYmFzZSBmcm9tIHRoZSBjYW1wYWlnbiwgZmluZCB0aGUgUFVTSCB0ZW1wbGF0ZSB3aG9zZSBuYW1lID09IHRoZSBBY3Rpb25JZCxcbiAqIGFuZCBjb25maXJtIGl0IGhhcyBhbiBBQ1RJVkUgdmVyc2lvbi4gUmV0dXJucyBgdW5kZWZpbmVkYCAobmV2ZXIgdGhyb3dzKSB3aGVuXG4gKiBhbnl0aGluZyBpcyBtaXNzaW5nIOKAlCBubyBjYW1wYWlnbiBtZXRhZGF0YSwgbm8gS0IgaW50ZWdyYXRpb24sIG5vIG1hdGNoaW5nXG4gKiB0ZW1wbGF0ZSDigJQgc28gdGhlIGNhbGxlciBmYWxscyBiYWNrIHRvIHRoZSBub24tdGVtcGxhdGVkIHBlci1wcm9maWxlIGNvcHkuXG4gKi9cbmV4cG9ydCBjb25zdCByZXNvbHZlUHVzaFRlbXBsYXRlQ29udGV4dCA9IGFzeW5jIChcbiAgY2xpZW50czogVGVtcGxhdGVDbGllbnRzLFxuICBjYW1wYWlnbjogQ2FtcGFpZ25Db250ZXh0LFxuKTogUHJvbWlzZTxQdXNoVGVtcGxhdGVDb250ZXh0IHwgdW5kZWZpbmVkPiA9PiB7XG4gIGNvbnN0IGNhbXBhaWduSWQgPSBjYW1wYWlnbi5jYW1wYWlnbklkO1xuICBjb25zdCBhY3Rpb25JZCA9IGNhbXBhaWduLmFjdGlvbklkO1xuICBpZiAoIWNhbXBhaWduSWQgfHwgIWFjdGlvbklkKSB7XG4gICAgY29uc29sZS5sb2coXG4gICAgICAnW3B1c2hdIHRlbXBsYXRlLnNraXAnLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICByZWFzb246ICdtaXNzaW5nIGNhbXBhaWduSWQgb3IgYWN0aW9uSWQnLFxuICAgICAgICBjYW1wYWlnbklkOiBjYW1wYWlnbklkID8/IG51bGwsXG4gICAgICAgIGFjdGlvbklkOiBhY3Rpb25JZCA/PyBudWxsLFxuICAgICAgfSksXG4gICAgKTtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBrbm93bGVkZ2VCYXNlSWQgPSBhd2FpdCBkaXNjb3Zlcktub3dsZWRnZUJhc2VJZChjbGllbnRzLCBjYW1wYWlnbklkKTtcbiAgICBpZiAoIWtub3dsZWRnZUJhc2VJZCkge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBjb25zdCBtZXNzYWdlVGVtcGxhdGVJZCA9IGF3YWl0IGZpbmRQdXNoVGVtcGxhdGVJZChcbiAgICAgIGNsaWVudHMucWNvbm5lY3QsXG4gICAgICBrbm93bGVkZ2VCYXNlSWQsXG4gICAgICBhY3Rpb25JZCxcbiAgICApO1xuICAgIGlmICghbWVzc2FnZVRlbXBsYXRlSWQpIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgJ1twdXNoXSB0ZW1wbGF0ZS5ub01hdGNoJyxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoeyBrbm93bGVkZ2VCYXNlSWQsIGFjdGlvbklkIH0pLFxuICAgICAgKTtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gQ29uZmlybSBhbiBBQ1RJVkUgKHB1Ymxpc2hlZCkgdmVyc2lvbiBleGlzdHM7IGlmIG5vdCwgc3RpbGwgcmVuZGVyIHRoZVxuICAgIC8vIGxhdGVzdCBjb250ZW50IChHZXRNZXNzYWdlVGVtcGxhdGUgaXMgZGlhZ25vc3RpYyBoZXJlLCBub3QgYSBnYXRlKS5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2xpZW50cy5xY29ubmVjdC5zZW5kKFxuICAgICAgICBuZXcgR2V0TWVzc2FnZVRlbXBsYXRlQ29tbWFuZCh7XG4gICAgICAgICAga25vd2xlZGdlQmFzZUlkLFxuICAgICAgICAgIG1lc3NhZ2VUZW1wbGF0ZUlkOiBgJHttZXNzYWdlVGVtcGxhdGVJZH06JHtBQ1RJVkVfVkVSU0lPTl9RVUFMSUZJRVJ9YCxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAnW3B1c2hdIHRlbXBsYXRlLm5vQWN0aXZlVmVyc2lvbicsXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICBrbm93bGVkZ2VCYXNlSWQsXG4gICAgICAgICAgbWVzc2FnZVRlbXBsYXRlSWQsXG4gICAgICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAndW5rbm93bicsXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZyhcbiAgICAgICdbcHVzaF0gdGVtcGxhdGUucmVzb2x2ZWQnLFxuICAgICAgSlNPTi5zdHJpbmdpZnkoeyBrbm93bGVkZ2VCYXNlSWQsIG1lc3NhZ2VUZW1wbGF0ZUlkLCBhY3Rpb25JZCB9KSxcbiAgICApO1xuICAgIHJldHVybiB7XG4gICAgICBxY29ubmVjdDogY2xpZW50cy5xY29ubmVjdCxcbiAgICAgIGtub3dsZWRnZUJhc2VJZCxcbiAgICAgIG1lc3NhZ2VUZW1wbGF0ZUlkLFxuICAgICAgdGVtcGxhdGVOYW1lOiBhY3Rpb25JZCxcbiAgICB9O1xuICB9IGNhdGNoIChlcnIpIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICAnW3B1c2hdIHRlbXBsYXRlLnJlc29sdmVFcnJvcicsXG4gICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIGNhbXBhaWduSWQsXG4gICAgICAgIGFjdGlvbklkLFxuICAgICAgICBlcnJvcjogZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubWVzc2FnZSA6ICd1bmtub3duJyxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufTtcblxuLyoqXG4gKiBGbGF0dGVuIGEgcHJvZmlsZSdzIGBDdXN0b21lckRhdGFgIGludG8gYSBmbGF0IGBjdXN0b21BdHRyaWJ1dGVzYCBtYXAgZm9yXG4gKiBSZW5kZXJNZXNzYWdlVGVtcGxhdGUuIEVtcGlyaWNhbGx5IG9ubHkgYHt7QXR0cmlidXRlcy48ZmxhdEtleT59fWAgdmFyaWFibGVzXG4gKiBpbnRlcnBvbGF0ZSAoZnJvbSBgY3VzdG9tQXR0cmlidXRlc2ApOyB0aGUgYHt7Q3VzdG9tZXIuKn19YCBuYW1lc3BhY2UgZG9lcyBub3RcbiAqIHJlc29sdmUgaGVyZSDigJQgc28gdGhlIHByb2ZpbGUncyBgZmlyc3ROYW1lYCBhbmQgZXZlcnkgYGF0dHJpYnV0ZXMuKmAgZW50cnkgYXJlXG4gKiBwYXNzZWQgYXMgZmxhdCBjdXN0b20gYXR0cmlidXRlcyAodGVtcGxhdGVzIHJlZmVyZW5jZSBlLmcuXG4gKiBge3tBdHRyaWJ1dGVzLmZpcnN0TmFtZX19YCkuIE5lc3RlZCBvYmplY3RzIChgYWRkcmVzc2AsIGBhdHRyaWJ1dGVzYCkgYXJlIG5vdFxuICogYWRkZWQgZGlyZWN0bHk7IGBhdHRyaWJ1dGVzYCBpcyBtZXJnZWQgb25lIGxldmVsIGRlZXAuIE5vbi1zdHJpbmcgLyBlbXB0eVxuICogdmFsdWVzIGFyZSBkcm9wcGVkIGFuZCB2YWx1ZXMgYXJlIGNhcHBlZCBhdCB0aGUgcmVuZGVyIGF0dHJpYnV0ZS1sZW5ndGggbGltaXQuXG4gKi9cbmV4cG9ydCBjb25zdCBidWlsZEN1c3RvbUF0dHJpYnV0ZXMgPSAoXG4gIGN1c3RvbWVyRGF0YT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9PiB7XG4gIGNvbnN0IG91dDogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9O1xuICBpZiAoIWN1c3RvbWVyRGF0YSkge1xuICAgIHJldHVybiBvdXQ7XG4gIH1cbiAgY29uc3QgYWRkID0gKGtleTogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IHZvaWQgPT4ge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLmxlbmd0aCA+IDApIHtcbiAgICAgIG91dFtrZXldID0gdmFsdWUuc2xpY2UoMCwgTUFYX0FUVFJJQlVURV9MRU5HVEgpO1xuICAgIH1cbiAgfTtcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoY3VzdG9tZXJEYXRhKSkge1xuICAgIGlmIChrZXkgPT09ICdhdHRyaWJ1dGVzJyB8fCBrZXkgPT09ICdhZGRyZXNzJykge1xuICAgICAgY29udGludWU7XG4gICAgfVxuICAgIGFkZChrZXksIHZhbHVlKTtcbiAgfVxuICBjb25zdCBhdHRyaWJ1dGVzID0gY3VzdG9tZXJEYXRhLmF0dHJpYnV0ZXM7XG4gIGlmIChcbiAgICBhdHRyaWJ1dGVzICYmXG4gICAgdHlwZW9mIGF0dHJpYnV0ZXMgPT09ICdvYmplY3QnICYmXG4gICAgIUFycmF5LmlzQXJyYXkoYXR0cmlidXRlcylcbiAgKSB7XG4gICAgLy8gYXR0cmlidXRlcyBzdWIta2V5cyBvdmVyd3JpdGUgdG9wLWxldmVsIGtleXMgb24gY29sbGlzaW9uIChhdHRyaWJ1dGVzIGlzXG4gICAgLy8gdGhlIGF1dGhvcml0YXRpdmUgY3VzdG9tLWF0dHJpYnV0ZSBzdG9yZSkuXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoXG4gICAgICBhdHRyaWJ1dGVzIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICAgICkpIHtcbiAgICAgIGFkZChrZXksIHZhbHVlKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG91dDtcbn07XG5cbi8qKlxuICogRGV0ZWN0cyBhIEhhbmRsZWJhcnMgcGxhY2Vob2xkZXIgdGhlIHJlbmRlcmVyIGxlZnQgdW5yZXNvbHZlZCwgZS5nLiBhXG4gKiBge3tBdHRyaWJ1dGVzLmZpcnN0TmFtZX19YCB2YXIgZm9yIGEgcHJvZmlsZSB0aGF0IGhhcyBubyBgZmlyc3ROYW1lYC4gUSBDb25uZWN0XG4gKiBsZWF2ZXMgc3VjaCB2YXJzIExJVEVSQUwgaW4gdGhlIG91dHB1dCAoYW5kIGxpc3RzIHRoZW0gaW5cbiAqIGBhdHRyaWJ1dGVzTm90SW50ZXJwb2xhdGVkYCk7IHNoaXBwaW5nIHRoYXQgcmF3IHRleHQgdG8gYSBkZXZpY2UgaXMgYSBidWcsIHNvXG4gKiBjb3B5IHRoYXQgc3RpbGwgY29udGFpbnMgb25lIGlzIHJlamVjdGVkIGFuZCB0aGUgY2FsbGVyIGZhbGxzIGJhY2sgdG8gZGVmYXVsdC5cbiAqL1xuY29uc3QgaGFzVW5yZXNvbHZlZFBsYWNlaG9sZGVyID0gKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuID0+XG4gIC9cXHtcXHsuKj9cXH1cXH0vLnRlc3QodmFsdWUpO1xuXG5jb25zdCB0b01lc3NhZ2UgPSAoY29udGVudD86IFBsYXRmb3JtQ29udGVudCk6IFB1c2hNZXNzYWdlIHwgdW5kZWZpbmVkID0+IHtcbiAgY29uc3QgdGl0bGUgPSBjb250ZW50Py50aXRsZTtcbiAgY29uc3QgYm9keSA9IGNvbnRlbnQ/LmJvZHk/LmNvbnRlbnQ7XG4gIGlmIChcbiAgICB0eXBlb2YgdGl0bGUgPT09ICdzdHJpbmcnICYmXG4gICAgdGl0bGUubGVuZ3RoID4gMCAmJlxuICAgIHR5cGVvZiBib2R5ID09PSAnc3RyaW5nJyAmJlxuICAgIGJvZHkubGVuZ3RoID4gMCAmJlxuICAgICFoYXNVbnJlc29sdmVkUGxhY2Vob2xkZXIodGl0bGUpICYmXG4gICAgIWhhc1VucmVzb2x2ZWRQbGFjZWhvbGRlcihib2R5KVxuICApIHtcbiAgICByZXR1cm4geyB0aXRsZSwgYm9keSB9O1xuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59O1xuXG4vKipcbiAqIFJlbmRlciB0aGUgcmVzb2x2ZWQgUFVTSCB0ZW1wbGF0ZSBmb3IgT05FIHByb2ZpbGUgYW5kIG1hcCB0aGUgcGVyLXBsYXRmb3JtXG4gKiBjb3B5IHRvIHB1c2ggY2hhbm5lbHM6XG4gKiAgIC0gYHB1c2guYXBuc2AgLT4gYEFQTlNgICgrIGBBUE5TX1NBTkRCT1hgKVxuICogICAtIGBwdXNoLmZjbWAgIC0+IGBHQ01gXG4gKlxuICogVGhlIHByb2ZpbGUncyBgQ3VzdG9tZXJEYXRhYCBpcyBwYXNzZWQgYXMgZmxhdCBgY3VzdG9tQXR0cmlidXRlc2Agc29cbiAqIGB7e0F0dHJpYnV0ZXMuPGtleT59fWAgdmFyaWFibGVzIHBlcnNvbmFsaXplLiBSZXR1cm5zIGEgcGFydGlhbCBwZXItY2hhbm5lbFxuICogbWFwIChvbmx5IGNoYW5uZWxzIHRoZSB0ZW1wbGF0ZSBkZWZpbmVzIGJvdGggYSB0aXRsZSBhbmQgYm9keSBmb3IpLCBvclxuICogYHVuZGVmaW5lZGAgKG5ldmVyIHRocm93cykgd2hlbiB0aGVyZSBpcyBubyBwdXNoIGNvbnRlbnQgb3IgdGhlIHJlbmRlciBmYWlscyDigJRcbiAqIHRoZSBjYWxsZXIgdGhlbiBmYWxscyBiYWNrIHRvIHRoZSBub24tdGVtcGxhdGVkIGNvcHkgZm9yIHRoYXQgcHJvZmlsZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHJlbmRlclByb2ZpbGVDaGFubmVsTWVzc2FnZXMgPSBhc3luYyAoXG4gIGN0eDogUHVzaFRlbXBsYXRlQ29udGV4dCxcbiAgdGFyZ2V0OiBQcm9maWxlVGFyZ2V0LFxuKTogUHJvbWlzZTxQYXJ0aWFsPFJlY29yZDxQdXNoQ2hhbm5lbFR5cGUsIFB1c2hNZXNzYWdlPj4gfCB1bmRlZmluZWQ+ID0+IHtcbiAgY29uc3QgY3VzdG9tQXR0cmlidXRlcyA9IGJ1aWxkQ3VzdG9tQXR0cmlidXRlcyh0YXJnZXQuY3VzdG9tZXJEYXRhKTtcblxuICBsZXQgcmVzO1xuICB0cnkge1xuICAgIHJlcyA9IGF3YWl0IGN0eC5xY29ubmVjdC5zZW5kKFxuICAgICAgbmV3IFJlbmRlck1lc3NhZ2VUZW1wbGF0ZUNvbW1hbmQoe1xuICAgICAgICBrbm93bGVkZ2VCYXNlSWQ6IGN0eC5rbm93bGVkZ2VCYXNlSWQsXG4gICAgICAgIC8vIFJlbmRlciB0aGUgUFVCTElTSEVEIHZlcnNpb24gZXhwbGljaXRseSAodmVyaWZpZWQ6IFJlbmRlck1lc3NhZ2VUZW1wbGF0ZVxuICAgICAgICAvLyBhY2NlcHRzIHRoZSBgOiRBQ1RJVkVfVkVSU0lPTmAgcXVhbGlmaWVyKSBzbyBhIGxhdGVyIHNhdmVkIGRyYWZ0IGNhbid0XG4gICAgICAgIC8vIHNpbGVudGx5IGNoYW5nZSBwcm9kdWN0aW9uIGNvcHkuXG4gICAgICAgIG1lc3NhZ2VUZW1wbGF0ZUlkOiBgJHtjdHgubWVzc2FnZVRlbXBsYXRlSWR9OiR7QUNUSVZFX1ZFUlNJT05fUVVBTElGSUVSfWAsXG4gICAgICAgIGF0dHJpYnV0ZXM6IHsgY3VzdG9tQXR0cmlidXRlcyB9LFxuICAgICAgfSksXG4gICAgKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS53YXJuKFxuICAgICAgJ1twdXNoXSB0ZW1wbGF0ZS5yZW5kZXJFcnJvcicsXG4gICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIHRlbXBsYXRlTmFtZTogY3R4LnRlbXBsYXRlTmFtZSxcbiAgICAgICAgZXJyb3I6IGVyciBpbnN0YW5jZW9mIEVycm9yID8gZXJyLm1lc3NhZ2UgOiAndW5rbm93bicsXG4gICAgICB9KSxcbiAgICApO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICBjb25zdCBjb250ZW50ID0gcmVzLmNvbnRlbnQgYXNcbiAgICB8IHsgcHVzaD86IHsgYXBucz86IFBsYXRmb3JtQ29udGVudDsgZmNtPzogUGxhdGZvcm1Db250ZW50IH0gfVxuICAgIHwgdW5kZWZpbmVkO1xuICBjb25zdCBwdXNoID0gY29udGVudD8ucHVzaDtcbiAgaWYgKCFwdXNoKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIGNvbnN0IGFwbnMgPSB0b01lc3NhZ2UocHVzaC5hcG5zKTtcbiAgY29uc3QgZmNtID0gdG9NZXNzYWdlKHB1c2guZmNtKTtcbiAgY29uc3QgcGVyQ2hhbm5lbDogUGFydGlhbDxSZWNvcmQ8UHVzaENoYW5uZWxUeXBlLCBQdXNoTWVzc2FnZT4+ID0ge307XG4gIGlmIChhcG5zKSB7XG4gICAgcGVyQ2hhbm5lbC5BUE5TID0gYXBucztcbiAgICBwZXJDaGFubmVsLkFQTlNfU0FOREJPWCA9IGFwbnM7XG4gIH1cbiAgaWYgKGZjbSkge1xuICAgIHBlckNoYW5uZWwuR0NNID0gZmNtO1xuICB9XG5cbiAgLy8gT3BlcmF0aW9uYWwgc2lnbmFsIG9ubHk6IHdoaWNoIGNoYW5uZWxzIHRoZSB0ZW1wbGF0ZSByZW5kZXJlZCB1c2FibGUgY29weVxuICAvLyBmb3IsIHBsdXMgYW55IHRlbXBsYXRlIHZhcmlhYmxlcyB0aGUgcmVuZGVyZXIgbGVmdCB1bi1pbnRlcnBvbGF0ZWQgKHRoZXNlXG4gIC8vIGFyZSB0ZW1wbGF0ZS1hdXRob3ItZGVmaW5lZCB2YXJpYWJsZSBuYW1lcywgZS5nLiBgQXR0cmlidXRlcy5maXJzdE5hbWVgLFxuICAvLyBub3QgY3VzdG9tZXIgdmFsdWVzKS4gVGhlIHJlbmRlcmVkIHRpdGxlL2JvZHkgYXJlIG5ldmVyIGxvZ2dlZC5cbiAgY29uc29sZS5sb2coXG4gICAgJ1twdXNoXSB0ZW1wbGF0ZS5yZW5kZXInLFxuICAgIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIHRlbXBsYXRlTmFtZTogY3R4LnRlbXBsYXRlTmFtZSxcbiAgICAgIGFwbnNSZW5kZXJlZDogQm9vbGVhbihhcG5zKSxcbiAgICAgIGdjbVJlbmRlcmVkOiBCb29sZWFuKGZjbSksXG4gICAgICBhdHRyaWJ1dGVzTm90SW50ZXJwb2xhdGVkOiByZXMuYXR0cmlidXRlc05vdEludGVycG9sYXRlZCA/PyBbXSxcbiAgICB9KSxcbiAgKTtcblxuICByZXR1cm4gT2JqZWN0LmtleXMocGVyQ2hhbm5lbCkubGVuZ3RoID4gMCA/IHBlckNoYW5uZWwgOiB1bmRlZmluZWQ7XG59O1xuIl19
@@ -0,0 +1,25 @@
1
+ import type { DirectMessageConfiguration } from '@aws-sdk/client-pinpoint';
2
+ import { PushChannelType, PushMessage } from './types.js';
3
+ /**
4
+ * Normalize a stored / event channel identifier to a Pinpoint push channel.
5
+ *
6
+ * The identify path stores whatever channel the client registered. Clients (and
7
+ * Firebase) use several spellings for Android push — `FCM` (the current Firebase
8
+ * Cloud Messaging name) is normalized to `GCM` (the Pinpoint channel that
9
+ * fronts FCM). Apple variants map to `APNS` / `APNS_SANDBOX`. Anything else
10
+ * (e.g. `IN_APP`, empty, unknown) yields `undefined` so the caller skips it.
11
+ */
12
+ export declare const normalizeChannelType: (raw: string | undefined) => PushChannelType | undefined;
13
+ /**
14
+ * Build the Pinpoint `DirectMessageConfiguration` for a single device, carrying
15
+ * only the platform message matching that device's channel.
16
+ *
17
+ * - `GCM` -> `GCMMessage` (Android / FCM)
18
+ * - `APNS` / `APNS_SANDBOX` -> `APNSMessage` (iOS)
19
+ *
20
+ * `title` / `body` map to the platform message's `Title` / `Body`; optional
21
+ * `data` maps to the platform `Data` map so the client receives the custom
22
+ * payload alongside the notification.
23
+ */
24
+ export declare const buildMessageConfiguration: (channelType: PushChannelType, message: PushMessage) => DirectMessageConfiguration;
25
+ //# sourceMappingURL=payload.d.ts.map
@@ -0,0 +1,53 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Normalize a stored / event channel identifier to a Pinpoint push channel.
5
+ *
6
+ * The identify path stores whatever channel the client registered. Clients (and
7
+ * Firebase) use several spellings for Android push — `FCM` (the current Firebase
8
+ * Cloud Messaging name) is normalized to `GCM` (the Pinpoint channel that
9
+ * fronts FCM). Apple variants map to `APNS` / `APNS_SANDBOX`. Anything else
10
+ * (e.g. `IN_APP`, empty, unknown) yields `undefined` so the caller skips it.
11
+ */
12
+ export const normalizeChannelType = (raw) => {
13
+ if (!raw) {
14
+ return undefined;
15
+ }
16
+ switch (raw.trim().toUpperCase()) {
17
+ case 'FCM':
18
+ case 'GCM':
19
+ return 'GCM';
20
+ case 'APNS':
21
+ return 'APNS';
22
+ case 'APNS_SANDBOX':
23
+ case 'APNSSANDBOX':
24
+ return 'APNS_SANDBOX';
25
+ default:
26
+ return undefined;
27
+ }
28
+ };
29
+ /**
30
+ * Build the Pinpoint `DirectMessageConfiguration` for a single device, carrying
31
+ * only the platform message matching that device's channel.
32
+ *
33
+ * - `GCM` -> `GCMMessage` (Android / FCM)
34
+ * - `APNS` / `APNS_SANDBOX` -> `APNSMessage` (iOS)
35
+ *
36
+ * `title` / `body` map to the platform message's `Title` / `Body`; optional
37
+ * `data` maps to the platform `Data` map so the client receives the custom
38
+ * payload alongside the notification.
39
+ */
40
+ export const buildMessageConfiguration = (channelType, message) => {
41
+ const common = {
42
+ Title: message.title,
43
+ Body: message.body,
44
+ ...(message.data ? { Data: message.data } : {}),
45
+ };
46
+ if (channelType === 'GCM') {
47
+ return { GCMMessage: { ...common, Priority: 'high' } };
48
+ }
49
+ // APNS and APNS_SANDBOX both use APNSMessage; the channel is selected per
50
+ // address via AddressConfiguration.ChannelType.
51
+ return { APNSMessage: common };
52
+ };
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF5bG9hZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvcHVzaC9wYXlsb2FkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHFFQUFxRTtBQUNyRSxzQ0FBc0M7QUFLdEM7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxDQUNsQyxHQUF1QixFQUNNLEVBQUU7SUFDL0IsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ1QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELFFBQVEsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7UUFDakMsS0FBSyxLQUFLLENBQUM7UUFDWCxLQUFLLEtBQUs7WUFDUixPQUFPLEtBQUssQ0FBQztRQUNmLEtBQUssTUFBTTtZQUNULE9BQU8sTUFBTSxDQUFDO1FBQ2hCLEtBQUssY0FBYyxDQUFDO1FBQ3BCLEtBQUssYUFBYTtZQUNoQixPQUFPLGNBQWMsQ0FBQztRQUN4QjtZQUNFLE9BQU8sU0FBUyxDQUFDO0lBQ3JCLENBQUM7QUFDSCxDQUFDLENBQUM7QUFFRjs7Ozs7Ozs7OztHQVVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0seUJBQXlCLEdBQUcsQ0FDdkMsV0FBNEIsRUFDNUIsT0FBb0IsRUFDUSxFQUFFO0lBQzlCLE1BQU0sTUFBTSxHQUFHO1FBQ2IsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1FBQ3BCLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtRQUNsQixHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7S0FDaEQsQ0FBQztJQUVGLElBQUksV0FBVyxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQzFCLE9BQU8sRUFBRSxVQUFVLEVBQUUsRUFBRSxHQUFHLE1BQU0sRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQztJQUN6RCxDQUFDO0lBQ0QsMEVBQTBFO0lBQzFFLGdEQUFnRDtJQUNoRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sRUFBRSxDQUFDO0FBQ2pDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuaW1wb3J0IHR5cGUgeyBEaXJlY3RNZXNzYWdlQ29uZmlndXJhdGlvbiB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1waW5wb2ludCc7XG5pbXBvcnQgeyBQdXNoQ2hhbm5lbFR5cGUsIFB1c2hNZXNzYWdlIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbi8qKlxuICogTm9ybWFsaXplIGEgc3RvcmVkIC8gZXZlbnQgY2hhbm5lbCBpZGVudGlmaWVyIHRvIGEgUGlucG9pbnQgcHVzaCBjaGFubmVsLlxuICpcbiAqIFRoZSBpZGVudGlmeSBwYXRoIHN0b3JlcyB3aGF0ZXZlciBjaGFubmVsIHRoZSBjbGllbnQgcmVnaXN0ZXJlZC4gQ2xpZW50cyAoYW5kXG4gKiBGaXJlYmFzZSkgdXNlIHNldmVyYWwgc3BlbGxpbmdzIGZvciBBbmRyb2lkIHB1c2gg4oCUIGBGQ01gICh0aGUgY3VycmVudCBGaXJlYmFzZVxuICogQ2xvdWQgTWVzc2FnaW5nIG5hbWUpIGlzIG5vcm1hbGl6ZWQgdG8gYEdDTWAgKHRoZSBQaW5wb2ludCBjaGFubmVsIHRoYXRcbiAqIGZyb250cyBGQ00pLiBBcHBsZSB2YXJpYW50cyBtYXAgdG8gYEFQTlNgIC8gYEFQTlNfU0FOREJPWGAuIEFueXRoaW5nIGVsc2VcbiAqIChlLmcuIGBJTl9BUFBgLCBlbXB0eSwgdW5rbm93bikgeWllbGRzIGB1bmRlZmluZWRgIHNvIHRoZSBjYWxsZXIgc2tpcHMgaXQuXG4gKi9cbmV4cG9ydCBjb25zdCBub3JtYWxpemVDaGFubmVsVHlwZSA9IChcbiAgcmF3OiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiBQdXNoQ2hhbm5lbFR5cGUgfCB1bmRlZmluZWQgPT4ge1xuICBpZiAoIXJhdykge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgc3dpdGNoIChyYXcudHJpbSgpLnRvVXBwZXJDYXNlKCkpIHtcbiAgICBjYXNlICdGQ00nOlxuICAgIGNhc2UgJ0dDTSc6XG4gICAgICByZXR1cm4gJ0dDTSc7XG4gICAgY2FzZSAnQVBOUyc6XG4gICAgICByZXR1cm4gJ0FQTlMnO1xuICAgIGNhc2UgJ0FQTlNfU0FOREJPWCc6XG4gICAgY2FzZSAnQVBOU1NBTkRCT1gnOlxuICAgICAgcmV0dXJuICdBUE5TX1NBTkRCT1gnO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59O1xuXG4vKipcbiAqIEJ1aWxkIHRoZSBQaW5wb2ludCBgRGlyZWN0TWVzc2FnZUNvbmZpZ3VyYXRpb25gIGZvciBhIHNpbmdsZSBkZXZpY2UsIGNhcnJ5aW5nXG4gKiBvbmx5IHRoZSBwbGF0Zm9ybSBtZXNzYWdlIG1hdGNoaW5nIHRoYXQgZGV2aWNlJ3MgY2hhbm5lbC5cbiAqXG4gKiAtIGBHQ01gIC0+IGBHQ01NZXNzYWdlYCAoQW5kcm9pZCAvIEZDTSlcbiAqIC0gYEFQTlNgIC8gYEFQTlNfU0FOREJPWGAgLT4gYEFQTlNNZXNzYWdlYCAoaU9TKVxuICpcbiAqIGB0aXRsZWAgLyBgYm9keWAgbWFwIHRvIHRoZSBwbGF0Zm9ybSBtZXNzYWdlJ3MgYFRpdGxlYCAvIGBCb2R5YDsgb3B0aW9uYWxcbiAqIGBkYXRhYCBtYXBzIHRvIHRoZSBwbGF0Zm9ybSBgRGF0YWAgbWFwIHNvIHRoZSBjbGllbnQgcmVjZWl2ZXMgdGhlIGN1c3RvbVxuICogcGF5bG9hZCBhbG9uZ3NpZGUgdGhlIG5vdGlmaWNhdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IGJ1aWxkTWVzc2FnZUNvbmZpZ3VyYXRpb24gPSAoXG4gIGNoYW5uZWxUeXBlOiBQdXNoQ2hhbm5lbFR5cGUsXG4gIG1lc3NhZ2U6IFB1c2hNZXNzYWdlLFxuKTogRGlyZWN0TWVzc2FnZUNvbmZpZ3VyYXRpb24gPT4ge1xuICBjb25zdCBjb21tb24gPSB7XG4gICAgVGl0bGU6IG1lc3NhZ2UudGl0bGUsXG4gICAgQm9keTogbWVzc2FnZS5ib2R5LFxuICAgIC4uLihtZXNzYWdlLmRhdGEgPyB7IERhdGE6IG1lc3NhZ2UuZGF0YSB9IDoge30pLFxuICB9O1xuXG4gIGlmIChjaGFubmVsVHlwZSA9PT0gJ0dDTScpIHtcbiAgICByZXR1cm4geyBHQ01NZXNzYWdlOiB7IC4uLmNvbW1vbiwgUHJpb3JpdHk6ICdoaWdoJyB9IH07XG4gIH1cbiAgLy8gQVBOUyBhbmQgQVBOU19TQU5EQk9YIGJvdGggdXNlIEFQTlNNZXNzYWdlOyB0aGUgY2hhbm5lbCBpcyBzZWxlY3RlZCBwZXJcbiAgLy8gYWRkcmVzcyB2aWEgQWRkcmVzc0NvbmZpZ3VyYXRpb24uQ2hhbm5lbFR5cGUuXG4gIHJldHVybiB7IEFQTlNNZXNzYWdlOiBjb21tb24gfTtcbn07XG4iXX0=
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Frozen contract for the push-delivery Lambda.
3
+ *
4
+ * Amazon Connect has no native mobile-push channel. Delivery is a workaround:
5
+ * a Connect Journey Custom-action (Invoke Lambda) block calls THIS Lambda,
6
+ * which resolves each targeted profile's registered devices from Customer
7
+ * Profiles and pushes to them via AWS End User Messaging (the Pinpoint
8
+ * `SendMessages` API).
9
+ *
10
+ * These types mirror the JSON shapes the Lambda accepts / returns so the
11
+ * handler, the parsing / payload / delivery layers, and the tests share one
12
+ * source of truth.
13
+ */
14
+ /** The push channels this backend can deliver to (post-normalization). */
15
+ export type PushChannelType = 'GCM' | 'APNS' | 'APNS_SANDBOX';
16
+ /** A single push notification's content. */
17
+ export type PushMessage = {
18
+ /** Title shown above the notification. */
19
+ title: string;
20
+ /** Notification body text. */
21
+ body: string;
22
+ /**
23
+ * Optional opaque data payload delivered alongside the notification (added to
24
+ * the platform message's `Data` map, all values coerced to strings).
25
+ */
26
+ data?: Record<string, string>;
27
+ };
28
+ /**
29
+ * A single profile the Journey targeted, as surfaced to this Lambda. Mirrors a
30
+ * Connect Journey Custom-action `CustomerProfiles` entry: the resolved
31
+ * `ProfileId` plus a bag of profile fields / attributes (`CustomerData`).
32
+ */
33
+ export type ProfileTarget = {
34
+ /** The Customer Profiles ProfileId to deliver to. */
35
+ profileId: string;
36
+ /**
37
+ * The profile's standard fields + Attributes as delivered by Connect
38
+ * (camelCase: `firstName`, `attributes.*`, ...). Passed as flat
39
+ * `customAttributes` to personalize the rendered Q Connect PUSH template (see
40
+ * `renderProfileChannelMessages`); real journeys carry NO message copy here.
41
+ * Device tokens are always resolved authoritatively via ListProfileObjects,
42
+ * never from here.
43
+ */
44
+ customerData?: Record<string, unknown>;
45
+ };
46
+ /**
47
+ * Which envelope shape {@link parsePushEvent} matched, for observability.
48
+ * `canonical` — the real Connect Outbound Campaigns v2 journey envelope
49
+ * (`Items.CustomerProfiles[]`); `none` — no targets were resolvable.
50
+ */
51
+ export type PushEventParsePath = 'canonical' | 'none';
52
+ /**
53
+ * The Outbound Campaigns v2 journey context carried on the real invocation
54
+ * envelope under `InvocationMetadata.CampaignContext`. Extracted for
55
+ * observability and for the upcoming message-copy-by-campaign feature (message
56
+ * sourcing is NOT implemented off this yet). All fields optional/defensive
57
+ * since direct-invoke test payloads omit them.
58
+ */
59
+ export type CampaignContext = {
60
+ /** The Connect campaign / journey id. */
61
+ campaignId?: string;
62
+ /** The human-readable campaign / journey name (e.g. `journey-2`). */
63
+ campaignName?: string;
64
+ /** The journey action id (e.g. the Custom-action block name). */
65
+ actionId?: string;
66
+ /** The specific campaign run id for this invocation. */
67
+ runId?: string;
68
+ };
69
+ /** The normalized result of parsing a raw Journey Custom-action event. */
70
+ export type ParsedPushEvent = {
71
+ /** Every profile the event targeted (batches are flattened). */
72
+ targets: ProfileTarget[];
73
+ /**
74
+ * The safe DEFAULT push copy ({@link DEFAULT_PUSH_TITLE} /
75
+ * {@link DEFAULT_PUSH_BODY}) used as the fallback when no Q Connect template
76
+ * copy applies for a channel. Real journeys carry no event-level copy.
77
+ */
78
+ message: PushMessage;
79
+ /**
80
+ * The envelope shape that produced the targets (`canonical`), or `none` when
81
+ * no targets were resolvable. Logged by the handler for observability.
82
+ */
83
+ parsePath: PushEventParsePath;
84
+ /**
85
+ * The journey/campaign context from `InvocationMetadata.CampaignContext`,
86
+ * when present on the envelope (real Outbound Campaigns v2 journeys), else
87
+ * `undefined` (direct-invoke test payloads).
88
+ */
89
+ campaign?: CampaignContext;
90
+ };
91
+ /** Delivery outcome for a single device (one `SendMessages` call). */
92
+ export type DeviceDeliveryResult = {
93
+ /** The push token the message was addressed to. */
94
+ deviceToken: string;
95
+ /** The (normalized) channel the message was sent on. */
96
+ channelType: PushChannelType;
97
+ /**
98
+ * The Customer Profiles ProfileObjectUniqueKey of the AmplifyDevice object
99
+ * this token came from — carried so a stale token can be deleted.
100
+ */
101
+ objectUniqueKey?: string;
102
+ /**
103
+ * Pinpoint `DeliveryStatus` (`SUCCESSFUL`, `PERMANENT_FAILURE`, ...), or
104
+ * `ERROR` when the `SendMessages` call itself threw, or `SKIPPED` when the
105
+ * device could not be delivered to (e.g. unsupported / missing channel).
106
+ */
107
+ status: string;
108
+ /** Whether delivery succeeded. */
109
+ delivered: boolean;
110
+ /**
111
+ * Whether this represents a permanently-invalid TOKEN whose backing
112
+ * AmplifyDevice object should be deleted (stale-token cleanup). Set ONLY for
113
+ * a token-invalidity signal (see `isInvalidTokenFailure`); channel / app
114
+ * misconfiguration and transient failures are `false` (token kept).
115
+ */
116
+ stale: boolean;
117
+ /** Pinpoint numeric status code, when available. */
118
+ statusCode?: number;
119
+ /** Human-readable status / error detail. */
120
+ statusMessage?: string;
121
+ };
122
+ /** Aggregated delivery outcome for a single profile. */
123
+ export type ProfileDeliveryResult = {
124
+ profileId: string;
125
+ /** Number of devices delivered to successfully. */
126
+ delivered: number;
127
+ /** Number of devices that failed delivery. */
128
+ failed: number;
129
+ /** Number of stale device objects deleted during cleanup. */
130
+ cleaned: number;
131
+ /** Per-device breakdown. */
132
+ devices: DeviceDeliveryResult[];
133
+ };
134
+ /**
135
+ * The response returned to the Connect Journey Custom-action invocation.
136
+ *
137
+ * NOTE: Connect's exact expected custom-action response envelope for the
138
+ * outbound-campaigns Journey batch is not publicly documented; this structured
139
+ * per-profile summary is a best-effort shape and is flagged for review.
140
+ */
141
+ export type PushDeliveryResponse = {
142
+ /** Total profiles processed. */
143
+ profilesProcessed: number;
144
+ /** Total devices delivered to across all profiles. */
145
+ totalDelivered: number;
146
+ /** Total device deliveries that failed across all profiles. */
147
+ totalFailed: number;
148
+ /** Total stale device objects deleted across all profiles. */
149
+ totalCleaned: number;
150
+ /** Per-profile results. */
151
+ results: ProfileDeliveryResult[];
152
+ };
153
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,4 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export {};
4
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhL3B1c2gvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEscUVBQXFFO0FBQ3JFLHNDQUFzQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjBcblxuLyoqXG4gKiBGcm96ZW4gY29udHJhY3QgZm9yIHRoZSBwdXNoLWRlbGl2ZXJ5IExhbWJkYS5cbiAqXG4gKiBBbWF6b24gQ29ubmVjdCBoYXMgbm8gbmF0aXZlIG1vYmlsZS1wdXNoIGNoYW5uZWwuIERlbGl2ZXJ5IGlzIGEgd29ya2Fyb3VuZDpcbiAqIGEgQ29ubmVjdCBKb3VybmV5IEN1c3RvbS1hY3Rpb24gKEludm9rZSBMYW1iZGEpIGJsb2NrIGNhbGxzIFRISVMgTGFtYmRhLFxuICogd2hpY2ggcmVzb2x2ZXMgZWFjaCB0YXJnZXRlZCBwcm9maWxlJ3MgcmVnaXN0ZXJlZCBkZXZpY2VzIGZyb20gQ3VzdG9tZXJcbiAqIFByb2ZpbGVzIGFuZCBwdXNoZXMgdG8gdGhlbSB2aWEgQVdTIEVuZCBVc2VyIE1lc3NhZ2luZyAodGhlIFBpbnBvaW50XG4gKiBgU2VuZE1lc3NhZ2VzYCBBUEkpLlxuICpcbiAqIFRoZXNlIHR5cGVzIG1pcnJvciB0aGUgSlNPTiBzaGFwZXMgdGhlIExhbWJkYSBhY2NlcHRzIC8gcmV0dXJucyBzbyB0aGVcbiAqIGhhbmRsZXIsIHRoZSBwYXJzaW5nIC8gcGF5bG9hZCAvIGRlbGl2ZXJ5IGxheWVycywgYW5kIHRoZSB0ZXN0cyBzaGFyZSBvbmVcbiAqIHNvdXJjZSBvZiB0cnV0aC5cbiAqL1xuXG4vKiogVGhlIHB1c2ggY2hhbm5lbHMgdGhpcyBiYWNrZW5kIGNhbiBkZWxpdmVyIHRvIChwb3N0LW5vcm1hbGl6YXRpb24pLiAqL1xuZXhwb3J0IHR5cGUgUHVzaENoYW5uZWxUeXBlID0gJ0dDTScgfCAnQVBOUycgfCAnQVBOU19TQU5EQk9YJztcblxuLyoqIEEgc2luZ2xlIHB1c2ggbm90aWZpY2F0aW9uJ3MgY29udGVudC4gKi9cbmV4cG9ydCB0eXBlIFB1c2hNZXNzYWdlID0ge1xuICAvKiogVGl0bGUgc2hvd24gYWJvdmUgdGhlIG5vdGlmaWNhdGlvbi4gKi9cbiAgdGl0bGU6IHN0cmluZztcbiAgLyoqIE5vdGlmaWNhdGlvbiBib2R5IHRleHQuICovXG4gIGJvZHk6IHN0cmluZztcbiAgLyoqXG4gICAqIE9wdGlvbmFsIG9wYXF1ZSBkYXRhIHBheWxvYWQgZGVsaXZlcmVkIGFsb25nc2lkZSB0aGUgbm90aWZpY2F0aW9uIChhZGRlZCB0b1xuICAgKiB0aGUgcGxhdGZvcm0gbWVzc2FnZSdzIGBEYXRhYCBtYXAsIGFsbCB2YWx1ZXMgY29lcmNlZCB0byBzdHJpbmdzKS5cbiAgICovXG4gIGRhdGE/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xufTtcblxuLyoqXG4gKiBBIHNpbmdsZSBwcm9maWxlIHRoZSBKb3VybmV5IHRhcmdldGVkLCBhcyBzdXJmYWNlZCB0byB0aGlzIExhbWJkYS4gTWlycm9ycyBhXG4gKiBDb25uZWN0IEpvdXJuZXkgQ3VzdG9tLWFjdGlvbiBgQ3VzdG9tZXJQcm9maWxlc2AgZW50cnk6IHRoZSByZXNvbHZlZFxuICogYFByb2ZpbGVJZGAgcGx1cyBhIGJhZyBvZiBwcm9maWxlIGZpZWxkcyAvIGF0dHJpYnV0ZXMgKGBDdXN0b21lckRhdGFgKS5cbiAqL1xuZXhwb3J0IHR5cGUgUHJvZmlsZVRhcmdldCA9IHtcbiAgLyoqIFRoZSBDdXN0b21lciBQcm9maWxlcyBQcm9maWxlSWQgdG8gZGVsaXZlciB0by4gKi9cbiAgcHJvZmlsZUlkOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgcHJvZmlsZSdzIHN0YW5kYXJkIGZpZWxkcyArIEF0dHJpYnV0ZXMgYXMgZGVsaXZlcmVkIGJ5IENvbm5lY3RcbiAgICogKGNhbWVsQ2FzZTogYGZpcnN0TmFtZWAsIGBhdHRyaWJ1dGVzLipgLCAuLi4pLiBQYXNzZWQgYXMgZmxhdFxuICAgKiBgY3VzdG9tQXR0cmlidXRlc2AgdG8gcGVyc29uYWxpemUgdGhlIHJlbmRlcmVkIFEgQ29ubmVjdCBQVVNIIHRlbXBsYXRlIChzZWVcbiAgICogYHJlbmRlclByb2ZpbGVDaGFubmVsTWVzc2FnZXNgKTsgcmVhbCBqb3VybmV5cyBjYXJyeSBOTyBtZXNzYWdlIGNvcHkgaGVyZS5cbiAgICogRGV2aWNlIHRva2VucyBhcmUgYWx3YXlzIHJlc29sdmVkIGF1dGhvcml0YXRpdmVseSB2aWEgTGlzdFByb2ZpbGVPYmplY3RzLFxuICAgKiBuZXZlciBmcm9tIGhlcmUuXG4gICAqL1xuICBjdXN0b21lckRhdGE/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn07XG5cbi8qKlxuICogV2hpY2ggZW52ZWxvcGUgc2hhcGUge0BsaW5rIHBhcnNlUHVzaEV2ZW50fSBtYXRjaGVkLCBmb3Igb2JzZXJ2YWJpbGl0eS5cbiAqIGBjYW5vbmljYWxgIOKAlCB0aGUgcmVhbCBDb25uZWN0IE91dGJvdW5kIENhbXBhaWducyB2MiBqb3VybmV5IGVudmVsb3BlXG4gKiAoYEl0ZW1zLkN1c3RvbWVyUHJvZmlsZXNbXWApOyBgbm9uZWAg4oCUIG5vIHRhcmdldHMgd2VyZSByZXNvbHZhYmxlLlxuICovXG5leHBvcnQgdHlwZSBQdXNoRXZlbnRQYXJzZVBhdGggPSAnY2Fub25pY2FsJyB8ICdub25lJztcblxuLyoqXG4gKiBUaGUgT3V0Ym91bmQgQ2FtcGFpZ25zIHYyIGpvdXJuZXkgY29udGV4dCBjYXJyaWVkIG9uIHRoZSByZWFsIGludm9jYXRpb25cbiAqIGVudmVsb3BlIHVuZGVyIGBJbnZvY2F0aW9uTWV0YWRhdGEuQ2FtcGFpZ25Db250ZXh0YC4gRXh0cmFjdGVkIGZvclxuICogb2JzZXJ2YWJpbGl0eSBhbmQgZm9yIHRoZSB1cGNvbWluZyBtZXNzYWdlLWNvcHktYnktY2FtcGFpZ24gZmVhdHVyZSAobWVzc2FnZVxuICogc291cmNpbmcgaXMgTk9UIGltcGxlbWVudGVkIG9mZiB0aGlzIHlldCkuIEFsbCBmaWVsZHMgb3B0aW9uYWwvZGVmZW5zaXZlXG4gKiBzaW5jZSBkaXJlY3QtaW52b2tlIHRlc3QgcGF5bG9hZHMgb21pdCB0aGVtLlxuICovXG5leHBvcnQgdHlwZSBDYW1wYWlnbkNvbnRleHQgPSB7XG4gIC8qKiBUaGUgQ29ubmVjdCBjYW1wYWlnbiAvIGpvdXJuZXkgaWQuICovXG4gIGNhbXBhaWduSWQ/OiBzdHJpbmc7XG4gIC8qKiBUaGUgaHVtYW4tcmVhZGFibGUgY2FtcGFpZ24gLyBqb3VybmV5IG5hbWUgKGUuZy4gYGpvdXJuZXktMmApLiAqL1xuICBjYW1wYWlnbk5hbWU/OiBzdHJpbmc7XG4gIC8qKiBUaGUgam91cm5leSBhY3Rpb24gaWQgKGUuZy4gdGhlIEN1c3RvbS1hY3Rpb24gYmxvY2sgbmFtZSkuICovXG4gIGFjdGlvbklkPzogc3RyaW5nO1xuICAvKiogVGhlIHNwZWNpZmljIGNhbXBhaWduIHJ1biBpZCBmb3IgdGhpcyBpbnZvY2F0aW9uLiAqL1xuICBydW5JZD86IHN0cmluZztcbn07XG5cbi8qKiBUaGUgbm9ybWFsaXplZCByZXN1bHQgb2YgcGFyc2luZyBhIHJhdyBKb3VybmV5IEN1c3RvbS1hY3Rpb24gZXZlbnQuICovXG5leHBvcnQgdHlwZSBQYXJzZWRQdXNoRXZlbnQgPSB7XG4gIC8qKiBFdmVyeSBwcm9maWxlIHRoZSBldmVudCB0YXJnZXRlZCAoYmF0Y2hlcyBhcmUgZmxhdHRlbmVkKS4gKi9cbiAgdGFyZ2V0czogUHJvZmlsZVRhcmdldFtdO1xuICAvKipcbiAgICogVGhlIHNhZmUgREVGQVVMVCBwdXNoIGNvcHkgKHtAbGluayBERUZBVUxUX1BVU0hfVElUTEV9IC9cbiAgICoge0BsaW5rIERFRkFVTFRfUFVTSF9CT0RZfSkgdXNlZCBhcyB0aGUgZmFsbGJhY2sgd2hlbiBubyBRIENvbm5lY3QgdGVtcGxhdGVcbiAgICogY29weSBhcHBsaWVzIGZvciBhIGNoYW5uZWwuIFJlYWwgam91cm5leXMgY2Fycnkgbm8gZXZlbnQtbGV2ZWwgY29weS5cbiAgICovXG4gIG1lc3NhZ2U6IFB1c2hNZXNzYWdlO1xuICAvKipcbiAgICogVGhlIGVudmVsb3BlIHNoYXBlIHRoYXQgcHJvZHVjZWQgdGhlIHRhcmdldHMgKGBjYW5vbmljYWxgKSwgb3IgYG5vbmVgIHdoZW5cbiAgICogbm8gdGFyZ2V0cyB3ZXJlIHJlc29sdmFibGUuIExvZ2dlZCBieSB0aGUgaGFuZGxlciBmb3Igb2JzZXJ2YWJpbGl0eS5cbiAgICovXG4gIHBhcnNlUGF0aDogUHVzaEV2ZW50UGFyc2VQYXRoO1xuICAvKipcbiAgICogVGhlIGpvdXJuZXkvY2FtcGFpZ24gY29udGV4dCBmcm9tIGBJbnZvY2F0aW9uTWV0YWRhdGEuQ2FtcGFpZ25Db250ZXh0YCxcbiAgICogd2hlbiBwcmVzZW50IG9uIHRoZSBlbnZlbG9wZSAocmVhbCBPdXRib3VuZCBDYW1wYWlnbnMgdjIgam91cm5leXMpLCBlbHNlXG4gICAqIGB1bmRlZmluZWRgIChkaXJlY3QtaW52b2tlIHRlc3QgcGF5bG9hZHMpLlxuICAgKi9cbiAgY2FtcGFpZ24/OiBDYW1wYWlnbkNvbnRleHQ7XG59O1xuXG4vKiogRGVsaXZlcnkgb3V0Y29tZSBmb3IgYSBzaW5nbGUgZGV2aWNlIChvbmUgYFNlbmRNZXNzYWdlc2AgY2FsbCkuICovXG5leHBvcnQgdHlwZSBEZXZpY2VEZWxpdmVyeVJlc3VsdCA9IHtcbiAgLyoqIFRoZSBwdXNoIHRva2VuIHRoZSBtZXNzYWdlIHdhcyBhZGRyZXNzZWQgdG8uICovXG4gIGRldmljZVRva2VuOiBzdHJpbmc7XG4gIC8qKiBUaGUgKG5vcm1hbGl6ZWQpIGNoYW5uZWwgdGhlIG1lc3NhZ2Ugd2FzIHNlbnQgb24uICovXG4gIGNoYW5uZWxUeXBlOiBQdXNoQ2hhbm5lbFR5cGU7XG4gIC8qKlxuICAgKiBUaGUgQ3VzdG9tZXIgUHJvZmlsZXMgUHJvZmlsZU9iamVjdFVuaXF1ZUtleSBvZiB0aGUgQW1wbGlmeURldmljZSBvYmplY3RcbiAgICogdGhpcyB0b2tlbiBjYW1lIGZyb20g4oCUIGNhcnJpZWQgc28gYSBzdGFsZSB0b2tlbiBjYW4gYmUgZGVsZXRlZC5cbiAgICovXG4gIG9iamVjdFVuaXF1ZUtleT86IHN0cmluZztcbiAgLyoqXG4gICAqIFBpbnBvaW50IGBEZWxpdmVyeVN0YXR1c2AgKGBTVUNDRVNTRlVMYCwgYFBFUk1BTkVOVF9GQUlMVVJFYCwgLi4uKSwgb3JcbiAgICogYEVSUk9SYCB3aGVuIHRoZSBgU2VuZE1lc3NhZ2VzYCBjYWxsIGl0c2VsZiB0aHJldywgb3IgYFNLSVBQRURgIHdoZW4gdGhlXG4gICAqIGRldmljZSBjb3VsZCBub3QgYmUgZGVsaXZlcmVkIHRvIChlLmcuIHVuc3VwcG9ydGVkIC8gbWlzc2luZyBjaGFubmVsKS5cbiAgICovXG4gIHN0YXR1czogc3RyaW5nO1xuICAvKiogV2hldGhlciBkZWxpdmVyeSBzdWNjZWVkZWQuICovXG4gIGRlbGl2ZXJlZDogYm9vbGVhbjtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhpcyByZXByZXNlbnRzIGEgcGVybWFuZW50bHktaW52YWxpZCBUT0tFTiB3aG9zZSBiYWNraW5nXG4gICAqIEFtcGxpZnlEZXZpY2Ugb2JqZWN0IHNob3VsZCBiZSBkZWxldGVkIChzdGFsZS10b2tlbiBjbGVhbnVwKS4gU2V0IE9OTFkgZm9yXG4gICAqIGEgdG9rZW4taW52YWxpZGl0eSBzaWduYWwgKHNlZSBgaXNJbnZhbGlkVG9rZW5GYWlsdXJlYCk7IGNoYW5uZWwgLyBhcHBcbiAgICogbWlzY29uZmlndXJhdGlvbiBhbmQgdHJhbnNpZW50IGZhaWx1cmVzIGFyZSBgZmFsc2VgICh0b2tlbiBrZXB0KS5cbiAgICovXG4gIHN0YWxlOiBib29sZWFuO1xuICAvKiogUGlucG9pbnQgbnVtZXJpYyBzdGF0dXMgY29kZSwgd2hlbiBhdmFpbGFibGUuICovXG4gIHN0YXR1c0NvZGU/OiBudW1iZXI7XG4gIC8qKiBIdW1hbi1yZWFkYWJsZSBzdGF0dXMgLyBlcnJvciBkZXRhaWwuICovXG4gIHN0YXR1c01lc3NhZ2U/OiBzdHJpbmc7XG59O1xuXG4vKiogQWdncmVnYXRlZCBkZWxpdmVyeSBvdXRjb21lIGZvciBhIHNpbmdsZSBwcm9maWxlLiAqL1xuZXhwb3J0IHR5cGUgUHJvZmlsZURlbGl2ZXJ5UmVzdWx0ID0ge1xuICBwcm9maWxlSWQ6IHN0cmluZztcbiAgLyoqIE51bWJlciBvZiBkZXZpY2VzIGRlbGl2ZXJlZCB0byBzdWNjZXNzZnVsbHkuICovXG4gIGRlbGl2ZXJlZDogbnVtYmVyO1xuICAvKiogTnVtYmVyIG9mIGRldmljZXMgdGhhdCBmYWlsZWQgZGVsaXZlcnkuICovXG4gIGZhaWxlZDogbnVtYmVyO1xuICAvKiogTnVtYmVyIG9mIHN0YWxlIGRldmljZSBvYmplY3RzIGRlbGV0ZWQgZHVyaW5nIGNsZWFudXAuICovXG4gIGNsZWFuZWQ6IG51bWJlcjtcbiAgLyoqIFBlci1kZXZpY2UgYnJlYWtkb3duLiAqL1xuICBkZXZpY2VzOiBEZXZpY2VEZWxpdmVyeVJlc3VsdFtdO1xufTtcblxuLyoqXG4gKiBUaGUgcmVzcG9uc2UgcmV0dXJuZWQgdG8gdGhlIENvbm5lY3QgSm91cm5leSBDdXN0b20tYWN0aW9uIGludm9jYXRpb24uXG4gKlxuICogTk9URTogQ29ubmVjdCdzIGV4YWN0IGV4cGVjdGVkIGN1c3RvbS1hY3Rpb24gcmVzcG9uc2UgZW52ZWxvcGUgZm9yIHRoZVxuICogb3V0Ym91bmQtY2FtcGFpZ25zIEpvdXJuZXkgYmF0Y2ggaXMgbm90IHB1YmxpY2x5IGRvY3VtZW50ZWQ7IHRoaXMgc3RydWN0dXJlZFxuICogcGVyLXByb2ZpbGUgc3VtbWFyeSBpcyBhIGJlc3QtZWZmb3J0IHNoYXBlIGFuZCBpcyBmbGFnZ2VkIGZvciByZXZpZXcuXG4gKi9cbmV4cG9ydCB0eXBlIFB1c2hEZWxpdmVyeVJlc3BvbnNlID0ge1xuICAvKiogVG90YWwgcHJvZmlsZXMgcHJvY2Vzc2VkLiAqL1xuICBwcm9maWxlc1Byb2Nlc3NlZDogbnVtYmVyO1xuICAvKiogVG90YWwgZGV2aWNlcyBkZWxpdmVyZWQgdG8gYWNyb3NzIGFsbCBwcm9maWxlcy4gKi9cbiAgdG90YWxEZWxpdmVyZWQ6IG51bWJlcjtcbiAgLyoqIFRvdGFsIGRldmljZSBkZWxpdmVyaWVzIHRoYXQgZmFpbGVkIGFjcm9zcyBhbGwgcHJvZmlsZXMuICovXG4gIHRvdGFsRmFpbGVkOiBudW1iZXI7XG4gIC8qKiBUb3RhbCBzdGFsZSBkZXZpY2Ugb2JqZWN0cyBkZWxldGVkIGFjcm9zcyBhbGwgcHJvZmlsZXMuICovXG4gIHRvdGFsQ2xlYW5lZDogbnVtYmVyO1xuICAvKiogUGVyLXByb2ZpbGUgcmVzdWx0cy4gKi9cbiAgcmVzdWx0czogUHJvZmlsZURlbGl2ZXJ5UmVzdWx0W107XG59O1xuIl19
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Customer Profiles serializes writes to a single profile: concurrent
3
+ * UpdateProfile / PutProfileObject calls against the same profile fail with a
4
+ * `BadRequestException: Failed to update profile due to concurrent update
5
+ * in-progress.` This is a TRANSIENT, idempotent condition (the write is safe to
6
+ * repeat), so the correct handling is a short bounded retry with jittered
7
+ * backoff rather than surfacing a 5xx to the caller.
8
+ */
9
+ export declare const isTransientConcurrentUpdate: (err: unknown) => boolean;
10
+ /**
11
+ * Run `fn`, retrying on transient concurrent-update / throttling errors with
12
+ * exponential backoff + full jitter. Non-transient errors propagate immediately.
13
+ */
14
+ export declare const withTransientRetry: <T>(fn: () => Promise<T>, opts?: {
15
+ attempts?: number;
16
+ baseDelayMs?: number;
17
+ }) => Promise<T>;
18
+ //# sourceMappingURL=retry.d.ts.map