@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,171 @@
1
+ import { MAX_ATTRIBUTE_LENGTH } from '../../constants.js';
2
+ /**
3
+ * Flatten a multi-value attribute into a single string that fits within the
4
+ * Customer Profiles attribute-value limit.
5
+ *
6
+ * - Zero values -> empty string.
7
+ * - Exactly one value -> that element verbatim.
8
+ * - More than one value -> JSON.stringify of the array (preserves all values).
9
+ * The result is truncated to {@link MAX_ATTRIBUTE_LENGTH} characters.
10
+ */
11
+ export const flatten = (values) => {
12
+ let out;
13
+ if (!values || values.length === 0) {
14
+ out = '';
15
+ }
16
+ else if (values.length === 1) {
17
+ out = values[0] ?? '';
18
+ }
19
+ else {
20
+ out = JSON.stringify(values);
21
+ }
22
+ return out.length > MAX_ATTRIBUTE_LENGTH
23
+ ? out.slice(0, MAX_ATTRIBUTE_LENGTH)
24
+ : out;
25
+ };
26
+ /**
27
+ * Serialize a map of multi-value attributes into a single JSON string.
28
+ *
29
+ * Customer Profiles requires statically declared field mappings, so dynamic key
30
+ * spaces (customProperties / userAttributes) are collapsed into one JSON
31
+ * attribute. Each value is flattened per the single-string rule first.
32
+ */
33
+ const serializeMultiValueMap = (map) => {
34
+ if (!map) {
35
+ return undefined;
36
+ }
37
+ const keys = Object.keys(map);
38
+ if (keys.length === 0) {
39
+ return undefined;
40
+ }
41
+ const flattened = {};
42
+ for (const key of keys) {
43
+ flattened[key] = flatten(map[key]);
44
+ }
45
+ const out = JSON.stringify(flattened);
46
+ return out.length > MAX_ATTRIBUTE_LENGTH
47
+ ? out.slice(0, MAX_ATTRIBUTE_LENGTH)
48
+ : out;
49
+ };
50
+ const splitName = (name) => {
51
+ const trimmed = name.trim();
52
+ const idx = trimmed.indexOf(' ');
53
+ if (idx === -1) {
54
+ return { firstName: trimmed };
55
+ }
56
+ return {
57
+ firstName: trimmed.slice(0, idx),
58
+ lastName: trimmed.slice(idx + 1).trim() || undefined,
59
+ };
60
+ };
61
+ /** Drop keys whose value is undefined/null/empty. */
62
+ const compact = (obj) => {
63
+ const out = {};
64
+ for (const [k, v] of Object.entries(obj)) {
65
+ if (v !== undefined && v !== null && v !== '') {
66
+ out[k] = v;
67
+ }
68
+ }
69
+ return out;
70
+ };
71
+ /** Which promoted targeting attribute a channel type activates. */
72
+ export const targetingFlagsForChannel = (channelType) => {
73
+ switch (channelType) {
74
+ case 'GCM':
75
+ return { hasGCM: 'true' };
76
+ case 'APNS':
77
+ case 'APNS_SANDBOX':
78
+ return { hasAPNS: 'true' };
79
+ default:
80
+ return {};
81
+ }
82
+ };
83
+ /** True when the request carries enough data to register/update a device. */
84
+ export const hasDeviceData = (req) => !!req.options?.deviceId;
85
+ /**
86
+ * Build the UpdateProfile payload (standard fields + Attributes map) for the
87
+ * profile identified by the verified {@link Principal} (authed `sub` or guest
88
+ * `cognitoIdentityId`).
89
+ *
90
+ * SECURITY: `principal.value` comes from an authorizer-verified source (JWT
91
+ * claims or the IAM/Cognito identity). The client-supplied `userId` is stored
92
+ * only as the `appUserId` attribute — never the identity.
93
+ */
94
+ export const buildProfileUpdate = (principal, req) => {
95
+ const profile = req.userProfile ?? {};
96
+ const demographic = profile.demographic;
97
+ const location = profile.location;
98
+ const name = profile.name ? splitName(profile.name) : undefined;
99
+ const flags = targetingFlagsForChannel(req.options?.channelType);
100
+ const attributes = compact({
101
+ // Identity trail (searchable key is separate; this is for reference only).
102
+ [principal.keyName]: principal.value,
103
+ appUserId: req.userId,
104
+ // Targeting / custom attributes for Connect segmentation.
105
+ plan: profile.plan,
106
+ locale: demographic?.locale,
107
+ platform: demographic?.platform,
108
+ appVersion: demographic?.appVersion,
109
+ make: demographic?.make,
110
+ model: demographic?.model,
111
+ modelVersion: demographic?.modelVersion,
112
+ platformVersion: demographic?.platformVersion,
113
+ timezone: demographic?.timezone,
114
+ latitude: location?.latitude !== undefined ? String(location.latitude) : undefined,
115
+ longitude: location?.longitude !== undefined
116
+ ? String(location.longitude)
117
+ : undefined,
118
+ customProperties: serializeMultiValueMap(profile.customProperties),
119
+ userAttributes: serializeMultiValueMap(req.options?.userAttributes),
120
+ metrics: profile.metrics ? JSON.stringify(profile.metrics) : undefined,
121
+ // Promoted push-capability flags.
122
+ hasGCM: flags.hasGCM,
123
+ hasAPNS: flags.hasAPNS,
124
+ });
125
+ const address = compact({
126
+ city: location?.city,
127
+ country: location?.country,
128
+ postalCode: location?.postalCode,
129
+ province: location?.region,
130
+ });
131
+ return {
132
+ emailAddress: profile.email,
133
+ firstName: name?.firstName,
134
+ lastName: name?.lastName,
135
+ address: Object.keys(address).length > 0 ? address : undefined,
136
+ attributes,
137
+ };
138
+ };
139
+ /**
140
+ * Build the `_source.*` payload for the AmplifyDevice object type.
141
+ *
142
+ * Keyed UNIQUELY by the stable `deviceId`; `deviceToken` (options.address) is a
143
+ * mutable field so token refreshes upsert the same object in place. Carries the
144
+ * verified identity field (`cognitoSub` for authed, `cognitoIdentityId` for
145
+ * guest) as the PROFILE-resolution key so the device merges into the profile
146
+ * bound to that {@link Principal}.
147
+ *
148
+ * `platform` / `appVersion` come from the options, falling back to the
149
+ * `userProfile.demographic` equivalents. `updatedAt` is server-set on every
150
+ * write; `createdAt` is the IMMUTABLE first-registration time — the caller
151
+ * passes the value read back from the existing device object (if any) so it is
152
+ * preserved across PutProfileObject replacements, otherwise it defaults to now.
153
+ */
154
+ export const buildDeviceObject = (principal, req, existingCreatedAt) => {
155
+ const options = req.options ?? {};
156
+ const demographic = req.userProfile?.demographic;
157
+ const platform = options.platform ?? demographic?.platform;
158
+ const appVersion = options.appVersion ?? demographic?.appVersion;
159
+ const now = new Date().toISOString();
160
+ return compact({
161
+ [principal.objectField]: principal.value,
162
+ deviceId: options.deviceId,
163
+ deviceToken: options.address,
164
+ channelType: options.channelType,
165
+ platform,
166
+ appVersion,
167
+ createdAt: existingCreatedAt ?? now,
168
+ updatedAt: now,
169
+ });
170
+ };
171
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFwcGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvaWRlbnRpZnkvbWFwcGluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQW9CMUQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxNQUFnQixFQUFVLEVBQUU7SUFDbEQsSUFBSSxHQUFXLENBQUM7SUFDaEIsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ25DLEdBQUcsR0FBRyxFQUFFLENBQUM7SUFDWCxDQUFDO1NBQU0sSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQy9CLEdBQUcsR0FBRyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ3hCLENBQUM7U0FBTSxDQUFDO1FBQ04sR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFDLE1BQU0sR0FBRyxvQkFBb0I7UUFDdEMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLG9CQUFvQixDQUFDO1FBQ3BDLENBQUMsQ0FBQyxHQUFHLENBQUM7QUFDVixDQUFDLENBQUM7QUFFRjs7Ozs7O0dBTUc7QUFDSCxNQUFNLHNCQUFzQixHQUFHLENBQzdCLEdBQXlDLEVBQ3JCLEVBQUU7SUFDdEIsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ1QsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDOUIsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3RC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RyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsV0FBVyxFQUFFLENBQUM7SUFFckMsT0FBTyxPQUFPLENBQUM7UUFDYixDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsRUFBRSxTQUFTLENBQUMsS0FBSztRQUN4QyxRQUFRLEVBQUUsT0FBTyxDQUFDLFFBQVE7UUFDMUIsV0FBVyxFQUFFLE9BQU8sQ0FBQyxPQUFPO1FBQzVCLFdBQVcsRUFBRSxPQUFPLENBQUMsV0FBVztRQUNoQyxRQUFRO1FBQ1IsVUFBVTtRQUNWLFNBQVMsRUFBRSxpQkFBaUIsSUFBSSxHQUFHO1FBQ25DLFNBQVMsRUFBRSxHQUFHO0tBQ2YsQ0FBMkIsQ0FBQztBQUMvQixDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDaGFubmVsVHlwZSwgSWRlbnRpZnlVc2VyUmVxdWVzdCB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IHsgTUFYX0FUVFJJQlVURV9MRU5HVEggfSBmcm9tICcuLi8uLi9jb25zdGFudHMuanMnO1xuaW1wb3J0IHsgUHJpbmNpcGFsIH0gZnJvbSAnLi9wcmluY2lwYWwuanMnO1xuXG4vKiogQSBzdGFuZGFyZCBDdXN0b21lciBQcm9maWxlcyBhZGRyZXNzIChzdWJzZXQgdXNlZCBieSB0aGlzIGJhY2tlbmQpLiAqL1xuZXhwb3J0IHR5cGUgUHJvZmlsZUFkZHJlc3MgPSB7XG4gIGNpdHk/OiBzdHJpbmc7XG4gIGNvdW50cnk/OiBzdHJpbmc7XG4gIHBvc3RhbENvZGU/OiBzdHJpbmc7XG4gIHByb3ZpbmNlPzogc3RyaW5nO1xufTtcblxuLyoqIFBlcnNvbiBkYXRhIG1hcHBlZCB0byBVcGRhdGVQcm9maWxlIHN0YW5kYXJkIGZpZWxkcyArIEF0dHJpYnV0ZXMgbWFwLiAqL1xuZXhwb3J0IHR5cGUgUHJvZmlsZVVwZGF0ZSA9IHtcbiAgZW1haWxBZGRyZXNzPzogc3RyaW5nO1xuICBmaXJzdE5hbWU/OiBzdHJpbmc7XG4gIGxhc3ROYW1lPzogc3RyaW5nO1xuICBhZGRyZXNzPzogUHJvZmlsZUFkZHJlc3M7XG4gIGF0dHJpYnV0ZXM6IFJlY29yZDxzdHJpbmcsIHN0cmluZz47XG59O1xuXG4vKipcbiAqIEZsYXR0ZW4gYSBtdWx0aS12YWx1ZSBhdHRyaWJ1dGUgaW50byBhIHNpbmdsZSBzdHJpbmcgdGhhdCBmaXRzIHdpdGhpbiB0aGVcbiAqIEN1c3RvbWVyIFByb2ZpbGVzIGF0dHJpYnV0ZS12YWx1ZSBsaW1pdC5cbiAqXG4gKiAtIFplcm8gdmFsdWVzIC0+IGVtcHR5IHN0cmluZy5cbiAqIC0gRXhhY3RseSBvbmUgdmFsdWUgLT4gdGhhdCBlbGVtZW50IHZlcmJhdGltLlxuICogLSBNb3JlIHRoYW4gb25lIHZhbHVlIC0+IEpTT04uc3RyaW5naWZ5IG9mIHRoZSBhcnJheSAocHJlc2VydmVzIGFsbCB2YWx1ZXMpLlxuICogVGhlIHJlc3VsdCBpcyB0cnVuY2F0ZWQgdG8ge0BsaW5rIE1BWF9BVFRSSUJVVEVfTEVOR1RIfSBjaGFyYWN0ZXJzLlxuICovXG5leHBvcnQgY29uc3QgZmxhdHRlbiA9ICh2YWx1ZXM6IHN0cmluZ1tdKTogc3RyaW5nID0+IHtcbiAgbGV0IG91dDogc3RyaW5nO1xuICBpZiAoIXZhbHVlcyB8fCB2YWx1ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgb3V0ID0gJyc7XG4gIH0gZWxzZSBpZiAodmFsdWVzLmxlbmd0aCA9PT0gMSkge1xuICAgIG91dCA9IHZhbHVlc1swXSA/PyAnJztcbiAgfSBlbHNlIHtcbiAgICBvdXQgPSBKU09OLnN0cmluZ2lmeSh2YWx1ZXMpO1xuICB9XG4gIHJldHVybiBvdXQubGVuZ3RoID4gTUFYX0FUVFJJQlVURV9MRU5HVEhcbiAgICA/IG91dC5zbGljZSgwLCBNQVhfQVRUUklCVVRFX0xFTkdUSClcbiAgICA6IG91dDtcbn07XG5cbi8qKlxuICogU2VyaWFsaXplIGEgbWFwIG9mIG11bHRpLXZhbHVlIGF0dHJpYnV0ZXMgaW50byBhIHNpbmdsZSBKU09OIHN0cmluZy5cbiAqXG4gKiBDdXN0b21lciBQcm9maWxlcyByZXF1aXJlcyBzdGF0aWNhbGx5IGRlY2xhcmVkIGZpZWxkIG1hcHBpbmdzLCBzbyBkeW5hbWljIGtleVxuICogc3BhY2VzIChjdXN0b21Qcm9wZXJ0aWVzIC8gdXNlckF0dHJpYnV0ZXMpIGFyZSBjb2xsYXBzZWQgaW50byBvbmUgSlNPTlxuICogYXR0cmlidXRlLiBFYWNoIHZhbHVlIGlzIGZsYXR0ZW5lZCBwZXIgdGhlIHNpbmdsZS1zdHJpbmcgcnVsZSBmaXJzdC5cbiAqL1xuY29uc3Qgc2VyaWFsaXplTXVsdGlWYWx1ZU1hcCA9IChcbiAgbWFwOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT4gfCB1bmRlZmluZWQsXG4pOiBzdHJpbmcgfCB1bmRlZmluZWQgPT4ge1xuICBpZiAoIW1hcCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKG1hcCk7XG4gIGlmIChrZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgZmxhdHRlbmVkOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG4gIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICBmbGF0dGVuZWRba2V5XSA9IGZsYXR0ZW4obWFwW2tleV0pO1xuICB9XG4gIGNvbnN0IG91dCA9IEpTT04uc3RyaW5naWZ5KGZsYXR0ZW5lZCk7XG4gIHJldHVybiBvdXQubGVuZ3RoID4gTUFYX0FUVFJJQlVURV9MRU5HVEhcbiAgICA/IG91dC5zbGljZSgwLCBNQVhfQVRUUklCVVRFX0xFTkdUSClcbiAgICA6IG91dDtcbn07XG5cbmNvbnN0IHNwbGl0TmFtZSA9IChuYW1lOiBzdHJpbmcpOiB7IGZpcnN0TmFtZTogc3RyaW5nOyBsYXN0TmFtZT86IHN0cmluZyB9ID0+IHtcbiAgY29uc3QgdHJpbW1lZCA9IG5hbWUudHJpbSgpO1xuICBjb25zdCBpZHggPSB0cmltbWVkLmluZGV4T2YoJyAnKTtcbiAgaWYgKGlkeCA9PT0gLTEpIHtcbiAgICByZXR1cm4geyBmaXJzdE5hbWU6IHRyaW1tZWQgfTtcbiAgfVxuICByZXR1cm4ge1xuICAgIGZpcnN0TmFtZTogdHJpbW1lZC5zbGljZSgwLCBpZHgpLFxuICAgIGxhc3ROYW1lOiB0cmltbWVkLnNsaWNlKGlkeCArIDEpLnRyaW0oKSB8fCB1bmRlZmluZWQsXG4gIH07XG59O1xuXG4vKiogRHJvcCBrZXlzIHdob3NlIHZhbHVlIGlzIHVuZGVmaW5lZC9udWxsL2VtcHR5LiAqL1xuY29uc3QgY29tcGFjdCA9IDxUIGV4dGVuZHMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4+KG9iajogVCk6IFBhcnRpYWw8VD4gPT4ge1xuICBjb25zdCBvdXQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICBpZiAodiAhPT0gdW5kZWZpbmVkICYmIHYgIT09IG51bGwgJiYgdiAhPT0gJycpIHtcbiAgICAgIG91dFtrXSA9IHY7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXQgYXMgUGFydGlhbDxUPjtcbn07XG5cbi8qKiBXaGljaCBwcm9tb3RlZCB0YXJnZXRpbmcgYXR0cmlidXRlIGEgY2hhbm5lbCB0eXBlIGFjdGl2YXRlcy4gKi9cbmV4cG9ydCBjb25zdCB0YXJnZXRpbmdGbGFnc0ZvckNoYW5uZWwgPSAoXG4gIGNoYW5uZWxUeXBlOiBDaGFubmVsVHlwZSB8IHVuZGVmaW5lZCxcbik6IHsgaGFzR0NNPzogc3RyaW5nOyBoYXNBUE5TPzogc3RyaW5nIH0gPT4ge1xuICBzd2l0Y2ggKGNoYW5uZWxUeXBlKSB7XG4gICAgY2FzZSAnR0NNJzpcbiAgICAgIHJldHVybiB7IGhhc0dDTTogJ3RydWUnIH07XG4gICAgY2FzZSAnQVBOUyc6XG4gICAgY2FzZSAnQVBOU19TQU5EQk9YJzpcbiAgICAgIHJldHVybiB7IGhhc0FQTlM6ICd0cnVlJyB9O1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4ge307XG4gIH1cbn07XG5cbi8qKiBUcnVlIHdoZW4gdGhlIHJlcXVlc3QgY2FycmllcyBlbm91Z2ggZGF0YSB0byByZWdpc3Rlci91cGRhdGUgYSBkZXZpY2UuICovXG5leHBvcnQgY29uc3QgaGFzRGV2aWNlRGF0YSA9IChyZXE6IElkZW50aWZ5VXNlclJlcXVlc3QpOiBib29sZWFuID0+XG4gICEhcmVxLm9wdGlvbnM/LmRldmljZUlkO1xuXG4vKipcbiAqIEJ1aWxkIHRoZSBVcGRhdGVQcm9maWxlIHBheWxvYWQgKHN0YW5kYXJkIGZpZWxkcyArIEF0dHJpYnV0ZXMgbWFwKSBmb3IgdGhlXG4gKiBwcm9maWxlIGlkZW50aWZpZWQgYnkgdGhlIHZlcmlmaWVkIHtAbGluayBQcmluY2lwYWx9IChhdXRoZWQgYHN1YmAgb3IgZ3Vlc3RcbiAqIGBjb2duaXRvSWRlbnRpdHlJZGApLlxuICpcbiAqIFNFQ1VSSVRZOiBgcHJpbmNpcGFsLnZhbHVlYCBjb21lcyBmcm9tIGFuIGF1dGhvcml6ZXItdmVyaWZpZWQgc291cmNlIChKV1RcbiAqIGNsYWltcyBvciB0aGUgSUFNL0NvZ25pdG8gaWRlbnRpdHkpLiBUaGUgY2xpZW50LXN1cHBsaWVkIGB1c2VySWRgIGlzIHN0b3JlZFxuICogb25seSBhcyB0aGUgYGFwcFVzZXJJZGAgYXR0cmlidXRlIOKAlCBuZXZlciB0aGUgaWRlbnRpdHkuXG4gKi9cbmV4cG9ydCBjb25zdCBidWlsZFByb2ZpbGVVcGRhdGUgPSAoXG4gIHByaW5jaXBhbDogUHJpbmNpcGFsLFxuICByZXE6IElkZW50aWZ5VXNlclJlcXVlc3QsXG4pOiBQcm9maWxlVXBkYXRlID0+IHtcbiAgY29uc3QgcHJvZmlsZSA9IHJlcS51c2VyUHJvZmlsZSA/PyB7fTtcbiAgY29uc3QgZGVtb2dyYXBoaWMgPSBwcm9maWxlLmRlbW9ncmFwaGljO1xuICBjb25zdCBsb2NhdGlvbiA9IHByb2ZpbGUubG9jYXRpb247XG4gIGNvbnN0IG5hbWUgPSBwcm9maWxlLm5hbWUgPyBzcGxpdE5hbWUocHJvZmlsZS5uYW1lKSA6IHVuZGVmaW5lZDtcbiAgY29uc3QgZmxhZ3MgPSB0YXJnZXRpbmdGbGFnc0ZvckNoYW5uZWwocmVxLm9wdGlvbnM/LmNoYW5uZWxUeXBlKTtcblxuICBjb25zdCBhdHRyaWJ1dGVzID0gY29tcGFjdCh7XG4gICAgLy8gSWRlbnRpdHkgdHJhaWwgKHNlYXJjaGFibGUga2V5IGlzIHNlcGFyYXRlOyB0aGlzIGlzIGZvciByZWZlcmVuY2Ugb25seSkuXG4gICAgW3ByaW5jaXBhbC5rZXlOYW1lXTogcHJpbmNpcGFsLnZhbHVlLFxuICAgIGFwcFVzZXJJZDogcmVxLnVzZXJJZCxcblxuICAgIC8vIFRhcmdldGluZyAvIGN1c3RvbSBhdHRyaWJ1dGVzIGZvciBDb25uZWN0IHNlZ21lbnRhdGlvbi5cbiAgICBwbGFuOiBwcm9maWxlLnBsYW4sXG4gICAgbG9jYWxlOiBkZW1vZ3JhcGhpYz8ubG9jYWxlLFxuICAgIHBsYXRmb3JtOiBkZW1vZ3JhcGhpYz8ucGxhdGZvcm0sXG4gICAgYXBwVmVyc2lvbjogZGVtb2dyYXBoaWM/LmFwcFZlcnNpb24sXG4gICAgbWFrZTogZGVtb2dyYXBoaWM/Lm1ha2UsXG4gICAgbW9kZWw6IGRlbW9ncmFwaGljPy5tb2RlbCxcbiAgICBtb2RlbFZlcnNpb246IGRlbW9ncmFwaGljPy5tb2RlbFZlcnNpb24sXG4gICAgcGxhdGZvcm1WZXJzaW9uOiBkZW1vZ3JhcGhpYz8ucGxhdGZvcm1WZXJzaW9uLFxuICAgIHRpbWV6b25lOiBkZW1vZ3JhcGhpYz8udGltZXpvbmUsXG4gICAgbGF0aXR1ZGU6XG4gICAgICBsb2NhdGlvbj8ubGF0aXR1ZGUgIT09IHVuZGVmaW5lZCA/IFN0cmluZyhsb2NhdGlvbi5sYXRpdHVkZSkgOiB1bmRlZmluZWQsXG4gICAgbG9uZ2l0dWRlOlxuICAgICAgbG9jYXRpb24/LmxvbmdpdHVkZSAhPT0gdW5kZWZpbmVkXG4gICAgICAgID8gU3RyaW5nKGxvY2F0aW9uLmxvbmdpdHVkZSlcbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgY3VzdG9tUHJvcGVydGllczogc2VyaWFsaXplTXVsdGlWYWx1ZU1hcChwcm9maWxlLmN1c3RvbVByb3BlcnRpZXMpLFxuICAgIHVzZXJBdHRyaWJ1dGVzOiBzZXJpYWxpemVNdWx0aVZhbHVlTWFwKHJlcS5vcHRpb25zPy51c2VyQXR0cmlidXRlcyksXG4gICAgbWV0cmljczogcHJvZmlsZS5tZXRyaWNzID8gSlNPTi5zdHJpbmdpZnkocHJvZmlsZS5tZXRyaWNzKSA6IHVuZGVmaW5lZCxcblxuICAgIC8vIFByb21vdGVkIHB1c2gtY2FwYWJpbGl0eSBmbGFncy5cbiAgICBoYXNHQ006IGZsYWdzLmhhc0dDTSxcbiAgICBoYXNBUE5TOiBmbGFncy5oYXNBUE5TLFxuICB9KSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuXG4gIGNvbnN0IGFkZHJlc3MgPSBjb21wYWN0KHtcbiAgICBjaXR5OiBsb2NhdGlvbj8uY2l0eSxcbiAgICBjb3VudHJ5OiBsb2NhdGlvbj8uY291bnRyeSxcbiAgICBwb3N0YWxDb2RlOiBsb2NhdGlvbj8ucG9zdGFsQ29kZSxcbiAgICBwcm92aW5jZTogbG9jYXRpb24/LnJlZ2lvbixcbiAgfSkgYXMgUHJvZmlsZUFkZHJlc3M7XG5cbiAgcmV0dXJuIHtcbiAgICBlbWFpbEFkZHJlc3M6IHByb2ZpbGUuZW1haWwsXG4gICAgZmlyc3ROYW1lOiBuYW1lPy5maXJzdE5hbWUsXG4gICAgbGFzdE5hbWU6IG5hbWU/Lmxhc3ROYW1lLFxuICAgIGFkZHJlc3M6IE9iamVjdC5rZXlzKGFkZHJlc3MpLmxlbmd0aCA+IDAgPyBhZGRyZXNzIDogdW5kZWZpbmVkLFxuICAgIGF0dHJpYnV0ZXMsXG4gIH07XG59O1xuXG4vKipcbiAqIEJ1aWxkIHRoZSBgX3NvdXJjZS4qYCBwYXlsb2FkIGZvciB0aGUgQW1wbGlmeURldmljZSBvYmplY3QgdHlwZS5cbiAqXG4gKiBLZXllZCBVTklRVUVMWSBieSB0aGUgc3RhYmxlIGBkZXZpY2VJZGA7IGBkZXZpY2VUb2tlbmAgKG9wdGlvbnMuYWRkcmVzcykgaXMgYVxuICogbXV0YWJsZSBmaWVsZCBzbyB0b2tlbiByZWZyZXNoZXMgdXBzZXJ0IHRoZSBzYW1lIG9iamVjdCBpbiBwbGFjZS4gQ2FycmllcyB0aGVcbiAqIHZlcmlmaWVkIGlkZW50aXR5IGZpZWxkIChgY29nbml0b1N1YmAgZm9yIGF1dGhlZCwgYGNvZ25pdG9JZGVudGl0eUlkYCBmb3JcbiAqIGd1ZXN0KSBhcyB0aGUgUFJPRklMRS1yZXNvbHV0aW9uIGtleSBzbyB0aGUgZGV2aWNlIG1lcmdlcyBpbnRvIHRoZSBwcm9maWxlXG4gKiBib3VuZCB0byB0aGF0IHtAbGluayBQcmluY2lwYWx9LlxuICpcbiAqIGBwbGF0Zm9ybWAgLyBgYXBwVmVyc2lvbmAgY29tZSBmcm9tIHRoZSBvcHRpb25zLCBmYWxsaW5nIGJhY2sgdG8gdGhlXG4gKiBgdXNlclByb2ZpbGUuZGVtb2dyYXBoaWNgIGVxdWl2YWxlbnRzLiBgdXBkYXRlZEF0YCBpcyBzZXJ2ZXItc2V0IG9uIGV2ZXJ5XG4gKiB3cml0ZTsgYGNyZWF0ZWRBdGAgaXMgdGhlIElNTVVUQUJMRSBmaXJzdC1yZWdpc3RyYXRpb24gdGltZSDigJQgdGhlIGNhbGxlclxuICogcGFzc2VzIHRoZSB2YWx1ZSByZWFkIGJhY2sgZnJvbSB0aGUgZXhpc3RpbmcgZGV2aWNlIG9iamVjdCAoaWYgYW55KSBzbyBpdCBpc1xuICogcHJlc2VydmVkIGFjcm9zcyBQdXRQcm9maWxlT2JqZWN0IHJlcGxhY2VtZW50cywgb3RoZXJ3aXNlIGl0IGRlZmF1bHRzIHRvIG5vdy5cbiAqL1xuZXhwb3J0IGNvbnN0IGJ1aWxkRGV2aWNlT2JqZWN0ID0gKFxuICBwcmluY2lwYWw6IFByaW5jaXBhbCxcbiAgcmVxOiBJZGVudGlmeVVzZXJSZXF1ZXN0LFxuICBleGlzdGluZ0NyZWF0ZWRBdD86IHN0cmluZyxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gPT4ge1xuICBjb25zdCBvcHRpb25zID0gcmVxLm9wdGlvbnMgPz8ge307XG4gIGNvbnN0IGRlbW9ncmFwaGljID0gcmVxLnVzZXJQcm9maWxlPy5kZW1vZ3JhcGhpYztcbiAgY29uc3QgcGxhdGZvcm0gPSBvcHRpb25zLnBsYXRmb3JtID8/IGRlbW9ncmFwaGljPy5wbGF0Zm9ybTtcbiAgY29uc3QgYXBwVmVyc2lvbiA9IG9wdGlvbnMuYXBwVmVyc2lvbiA/PyBkZW1vZ3JhcGhpYz8uYXBwVmVyc2lvbjtcbiAgY29uc3Qgbm93ID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpO1xuXG4gIHJldHVybiBjb21wYWN0KHtcbiAgICBbcHJpbmNpcGFsLm9iamVjdEZpZWxkXTogcHJpbmNpcGFsLnZhbHVlLFxuICAgIGRldmljZUlkOiBvcHRpb25zLmRldmljZUlkLFxuICAgIGRldmljZVRva2VuOiBvcHRpb25zLmFkZHJlc3MsXG4gICAgY2hhbm5lbFR5cGU6IG9wdGlvbnMuY2hhbm5lbFR5cGUsXG4gICAgcGxhdGZvcm0sXG4gICAgYXBwVmVyc2lvbixcbiAgICBjcmVhdGVkQXQ6IGV4aXN0aW5nQ3JlYXRlZEF0ID8/IG5vdyxcbiAgICB1cGRhdGVkQXQ6IG5vdyxcbiAgfSkgYXMgUmVjb3JkPHN0cmluZywgc3RyaW5nPjtcbn07XG4iXX0=
@@ -0,0 +1,26 @@
1
+ import { CustomerProfilesClient } from '@aws-sdk/client-customer-profiles';
2
+ export type MergeOutcome = {
3
+ /** `true` when a distinct guest profile was found and merged. */
4
+ merged: boolean;
5
+ };
6
+ /**
7
+ * Merge-on-sign-in: fold a prior GUEST profile (keyed by `cognitoIdentityKey =
8
+ * guestIdentityId`) into the resolved AUTHENTICATED profile.
9
+ *
10
+ * Uses {@link MergeProfilesCommand}, which atomically (server-side Lambda job):
11
+ * 1. moves all profileKeys from the guest profile to the authed profile,
12
+ * 2. moves all OBJECTS (the guest's AmplifyDevice objects) to the authed
13
+ * profile,
14
+ * 3. deletes the now-empty guest profile.
15
+ *
16
+ * This is the deterministic mechanic (vs AddProfileKey, which only adds a lookup
17
+ * key, does not carry device objects, and risks an ambiguous-match rejection
18
+ * when the guest key already resolves to a distinct profile).
19
+ *
20
+ * No-ops (returns `{merged:false}`) when there is no prior guest profile, or the
21
+ * guest identity already resolves to the SAME profile (idempotent re-runs).
22
+ * Best-effort: a merge failure is surfaced to the caller to log, but never
23
+ * corrupts the primary identify result.
24
+ */
25
+ export declare const mergeGuestIntoAuthed: (profiles: CustomerProfilesClient, domainName: string, guestIdentityId: string, authedProfileId: string) => Promise<MergeOutcome>;
26
+ //# sourceMappingURL=merge_resolver.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { MergeProfilesCommand, } from '@aws-sdk/client-customer-profiles';
2
+ import { withTransientRetry } from '../shared/retry.js';
3
+ import { findProfileId } from './profile_resolver.js';
4
+ import { guestPrincipal } from './principal.js';
5
+ /**
6
+ * Merge-on-sign-in: fold a prior GUEST profile (keyed by `cognitoIdentityKey =
7
+ * guestIdentityId`) into the resolved AUTHENTICATED profile.
8
+ *
9
+ * Uses {@link MergeProfilesCommand}, which atomically (server-side Lambda job):
10
+ * 1. moves all profileKeys from the guest profile to the authed profile,
11
+ * 2. moves all OBJECTS (the guest's AmplifyDevice objects) to the authed
12
+ * profile,
13
+ * 3. deletes the now-empty guest profile.
14
+ *
15
+ * This is the deterministic mechanic (vs AddProfileKey, which only adds a lookup
16
+ * key, does not carry device objects, and risks an ambiguous-match rejection
17
+ * when the guest key already resolves to a distinct profile).
18
+ *
19
+ * No-ops (returns `{merged:false}`) when there is no prior guest profile, or the
20
+ * guest identity already resolves to the SAME profile (idempotent re-runs).
21
+ * Best-effort: a merge failure is surfaced to the caller to log, but never
22
+ * corrupts the primary identify result.
23
+ */
24
+ export const mergeGuestIntoAuthed = async (profiles, domainName, guestIdentityId, authedProfileId) => {
25
+ const guestProfileId = await findProfileId(profiles, domainName, guestPrincipal(guestIdentityId));
26
+ if (!guestProfileId || guestProfileId === authedProfileId) {
27
+ return { merged: false };
28
+ }
29
+ await withTransientRetry(() => profiles.send(new MergeProfilesCommand({
30
+ DomainName: domainName,
31
+ MainProfileId: authedProfileId,
32
+ ProfileIdsToBeMerged: [guestProfileId],
33
+ })));
34
+ return { merged: true };
35
+ };
36
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVyZ2VfcmVzb2x2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhL2lkZW50aWZ5L21lcmdlX3Jlc29sdmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFFTCxvQkFBb0IsR0FDckIsTUFBTSxtQ0FBbUMsQ0FBQztBQUUzQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RCxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBT2hEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxvQkFBb0IsR0FBRyxLQUFLLEVBQ3ZDLFFBQWdDLEVBQ2hDLFVBQWtCLEVBQ2xCLGVBQXVCLEVBQ3ZCLGVBQXVCLEVBQ0EsRUFBRTtJQUN6QixNQUFNLGNBQWMsR0FBRyxNQUFNLGFBQWEsQ0FDeEMsUUFBUSxFQUNSLFVBQVUsRUFDVixjQUFjLENBQUMsZUFBZSxDQUFDLENBQ2hDLENBQUM7SUFFRixJQUFJLENBQUMsY0FBYyxJQUFJLGNBQWMsS0FBSyxlQUFlLEVBQUUsQ0FBQztRQUMxRCxPQUFPLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRCxNQUFNLGtCQUFrQixDQUFDLEdBQUcsRUFBRSxDQUM1QixRQUFRLENBQUMsSUFBSSxDQUNYLElBQUksb0JBQW9CLENBQUM7UUFDdkIsVUFBVSxFQUFFLFVBQVU7UUFDdEIsYUFBYSxFQUFFLGVBQWU7UUFDOUIsb0JBQW9CLEVBQUUsQ0FBQyxjQUFjLENBQUM7S0FDdkMsQ0FBQyxDQUNILENBQ0YsQ0FBQztJQUVGLE9BQU8sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUM7QUFDMUIsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ3VzdG9tZXJQcm9maWxlc0NsaWVudCxcbiAgTWVyZ2VQcm9maWxlc0NvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jdXN0b21lci1wcm9maWxlcyc7XG5cbmltcG9ydCB7IHdpdGhUcmFuc2llbnRSZXRyeSB9IGZyb20gJy4uL3NoYXJlZC9yZXRyeS5qcyc7XG5pbXBvcnQgeyBmaW5kUHJvZmlsZUlkIH0gZnJvbSAnLi9wcm9maWxlX3Jlc29sdmVyLmpzJztcbmltcG9ydCB7IGd1ZXN0UHJpbmNpcGFsIH0gZnJvbSAnLi9wcmluY2lwYWwuanMnO1xuXG5leHBvcnQgdHlwZSBNZXJnZU91dGNvbWUgPSB7XG4gIC8qKiBgdHJ1ZWAgd2hlbiBhIGRpc3RpbmN0IGd1ZXN0IHByb2ZpbGUgd2FzIGZvdW5kIGFuZCBtZXJnZWQuICovXG4gIG1lcmdlZDogYm9vbGVhbjtcbn07XG5cbi8qKlxuICogTWVyZ2Utb24tc2lnbi1pbjogZm9sZCBhIHByaW9yIEdVRVNUIHByb2ZpbGUgKGtleWVkIGJ5IGBjb2duaXRvSWRlbnRpdHlLZXkgPVxuICogZ3Vlc3RJZGVudGl0eUlkYCkgaW50byB0aGUgcmVzb2x2ZWQgQVVUSEVOVElDQVRFRCBwcm9maWxlLlxuICpcbiAqIFVzZXMge0BsaW5rIE1lcmdlUHJvZmlsZXNDb21tYW5kfSwgd2hpY2ggYXRvbWljYWxseSAoc2VydmVyLXNpZGUgTGFtYmRhIGpvYik6XG4gKiAgIDEuIG1vdmVzIGFsbCBwcm9maWxlS2V5cyBmcm9tIHRoZSBndWVzdCBwcm9maWxlIHRvIHRoZSBhdXRoZWQgcHJvZmlsZSxcbiAqICAgMi4gbW92ZXMgYWxsIE9CSkVDVFMgKHRoZSBndWVzdCdzIEFtcGxpZnlEZXZpY2Ugb2JqZWN0cykgdG8gdGhlIGF1dGhlZFxuICogICAgICBwcm9maWxlLFxuICogICAzLiBkZWxldGVzIHRoZSBub3ctZW1wdHkgZ3Vlc3QgcHJvZmlsZS5cbiAqXG4gKiBUaGlzIGlzIHRoZSBkZXRlcm1pbmlzdGljIG1lY2hhbmljICh2cyBBZGRQcm9maWxlS2V5LCB3aGljaCBvbmx5IGFkZHMgYSBsb29rdXBcbiAqIGtleSwgZG9lcyBub3QgY2FycnkgZGV2aWNlIG9iamVjdHMsIGFuZCByaXNrcyBhbiBhbWJpZ3VvdXMtbWF0Y2ggcmVqZWN0aW9uXG4gKiB3aGVuIHRoZSBndWVzdCBrZXkgYWxyZWFkeSByZXNvbHZlcyB0byBhIGRpc3RpbmN0IHByb2ZpbGUpLlxuICpcbiAqIE5vLW9wcyAocmV0dXJucyBge21lcmdlZDpmYWxzZX1gKSB3aGVuIHRoZXJlIGlzIG5vIHByaW9yIGd1ZXN0IHByb2ZpbGUsIG9yIHRoZVxuICogZ3Vlc3QgaWRlbnRpdHkgYWxyZWFkeSByZXNvbHZlcyB0byB0aGUgU0FNRSBwcm9maWxlIChpZGVtcG90ZW50IHJlLXJ1bnMpLlxuICogQmVzdC1lZmZvcnQ6IGEgbWVyZ2UgZmFpbHVyZSBpcyBzdXJmYWNlZCB0byB0aGUgY2FsbGVyIHRvIGxvZywgYnV0IG5ldmVyXG4gKiBjb3JydXB0cyB0aGUgcHJpbWFyeSBpZGVudGlmeSByZXN1bHQuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUd1ZXN0SW50b0F1dGhlZCA9IGFzeW5jIChcbiAgcHJvZmlsZXM6IEN1c3RvbWVyUHJvZmlsZXNDbGllbnQsXG4gIGRvbWFpbk5hbWU6IHN0cmluZyxcbiAgZ3Vlc3RJZGVudGl0eUlkOiBzdHJpbmcsXG4gIGF1dGhlZFByb2ZpbGVJZDogc3RyaW5nLFxuKTogUHJvbWlzZTxNZXJnZU91dGNvbWU+ID0+IHtcbiAgY29uc3QgZ3Vlc3RQcm9maWxlSWQgPSBhd2FpdCBmaW5kUHJvZmlsZUlkKFxuICAgIHByb2ZpbGVzLFxuICAgIGRvbWFpbk5hbWUsXG4gICAgZ3Vlc3RQcmluY2lwYWwoZ3Vlc3RJZGVudGl0eUlkKSxcbiAgKTtcblxuICBpZiAoIWd1ZXN0UHJvZmlsZUlkIHx8IGd1ZXN0UHJvZmlsZUlkID09PSBhdXRoZWRQcm9maWxlSWQpIHtcbiAgICByZXR1cm4geyBtZXJnZWQ6IGZhbHNlIH07XG4gIH1cblxuICBhd2FpdCB3aXRoVHJhbnNpZW50UmV0cnkoKCkgPT5cbiAgICBwcm9maWxlcy5zZW5kKFxuICAgICAgbmV3IE1lcmdlUHJvZmlsZXNDb21tYW5kKHtcbiAgICAgICAgRG9tYWluTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgTWFpblByb2ZpbGVJZDogYXV0aGVkUHJvZmlsZUlkLFxuICAgICAgICBQcm9maWxlSWRzVG9CZU1lcmdlZDogW2d1ZXN0UHJvZmlsZUlkXSxcbiAgICAgIH0pLFxuICAgICksXG4gICk7XG5cbiAgcmV0dXJuIHsgbWVyZ2VkOiB0cnVlIH07XG59O1xuIl19
@@ -0,0 +1,68 @@
1
+ /**
2
+ * The resolved caller identity, abstracted over the two auth modes so the rest
3
+ * of the identify pipeline (profile find-or-create, device upsert, attribute
4
+ * write) is identity-agnostic:
5
+ *
6
+ * - `authed`: a verified Cognito user-pool `sub` (JWT authorizer). Keyed by
7
+ * `cognitoUserKey` (field `cognitoSub`) on the `AmplifyProfile` object type.
8
+ * - `guest`: a verified Cognito Identity Pool `cognitoIdentityId` for an
9
+ * UNAUTHENTICATED identity (IAM/SigV4 authorizer). Keyed by
10
+ * `cognitoIdentityKey` (field `cognitoIdentityId`) on the
11
+ * `AmplifyGuestProfile` object type.
12
+ *
13
+ * `keyName` is the searchable/resolution key on the object types; `objectField`
14
+ * is the field name the Lambda ingests via PutProfileObject (sourced into that
15
+ * key); `profileObjectType` is the object type the find-or-create ingests into
16
+ * (each mode has its OWN type because Customer Profiles requires exactly one
17
+ * UNIQUE key per object type, carried by every ingested object); `value` is the
18
+ * verified identity value. `value` is ALWAYS derived from an authorizer-verified
19
+ * source — never from the request body.
20
+ */
21
+ export type Principal = {
22
+ readonly kind: 'authed' | 'guest';
23
+ readonly keyName: string;
24
+ readonly objectField: string;
25
+ readonly profileObjectType: string;
26
+ readonly value: string;
27
+ };
28
+ /** Build the authenticated principal from a verified Cognito user-pool `sub`. */
29
+ export declare const authedPrincipal: (sub: string) => Principal;
30
+ /** Build the guest principal from a verified Cognito Identity Pool identityId. */
31
+ export declare const guestPrincipal: (identityId: string) => Principal;
32
+ /**
33
+ * The minimal structural shape shared by the two Lambda-proxy event formats
34
+ * this handler serves:
35
+ * - HTTP API payload format 2.0 + JWT authorizer (authed route): the verified
36
+ * `sub` is at `requestContext.authorizer.jwt.claims.sub`.
37
+ * - HTTP API payload format 1.0 + IAM/SigV4 authorization (guest route): the
38
+ * verified Cognito Identity Pool identity is at `requestContext.identity`
39
+ * (`cognitoIdentityId` + `cognitoAuthenticationType`). NOTE: format 2.0 has
40
+ * NO `identity` block at all, which is exactly why the guest route MUST use
41
+ * payload format 1.0.
42
+ */
43
+ export type IdentifyEvent = {
44
+ body?: string | null;
45
+ requestContext?: {
46
+ authorizer?: {
47
+ jwt?: {
48
+ claims?: Record<string, unknown>;
49
+ };
50
+ };
51
+ identity?: {
52
+ cognitoIdentityId?: string | null;
53
+ cognitoAuthenticationType?: string | null;
54
+ };
55
+ };
56
+ };
57
+ /**
58
+ * Resolve the verified caller {@link Principal} from either event shape.
59
+ *
60
+ * SECURITY: identity is derived ONLY from authorizer-verified fields — the JWT
61
+ * `sub` claim (which API Gateway populates only after cryptographically
62
+ * verifying the Cognito token) or the SigV4/IAM-verified Cognito
63
+ * `cognitoIdentityId`. The request body can never influence it. A guest is
64
+ * accepted only when `cognitoAuthenticationType === 'unauthenticated'` AND a
65
+ * `cognitoIdentityId` is present. Returns `undefined` when neither is present.
66
+ */
67
+ export declare const resolvePrincipal: (event: IdentifyEvent) => Principal | undefined;
68
+ //# sourceMappingURL=principal.d.ts.map
@@ -0,0 +1,48 @@
1
+ import { COGNITO_IDENTITY_FIELD, COGNITO_IDENTITY_KEY, COGNITO_SUB_FIELD, COGNITO_USER_KEY, OBJECT_TYPE_GUEST_PROFILE, OBJECT_TYPE_PROFILE, } from '../../constants.js';
2
+ /** Build the authenticated principal from a verified Cognito user-pool `sub`. */
3
+ export const authedPrincipal = (sub) => ({
4
+ kind: 'authed',
5
+ keyName: COGNITO_USER_KEY,
6
+ objectField: COGNITO_SUB_FIELD,
7
+ profileObjectType: OBJECT_TYPE_PROFILE,
8
+ value: sub,
9
+ });
10
+ /** Build the guest principal from a verified Cognito Identity Pool identityId. */
11
+ export const guestPrincipal = (identityId) => ({
12
+ kind: 'guest',
13
+ keyName: COGNITO_IDENTITY_KEY,
14
+ objectField: COGNITO_IDENTITY_FIELD,
15
+ profileObjectType: OBJECT_TYPE_GUEST_PROFILE,
16
+ value: identityId,
17
+ });
18
+ /**
19
+ * Resolve the verified caller {@link Principal} from either event shape.
20
+ *
21
+ * SECURITY: identity is derived ONLY from authorizer-verified fields — the JWT
22
+ * `sub` claim (which API Gateway populates only after cryptographically
23
+ * verifying the Cognito token) or the SigV4/IAM-verified Cognito
24
+ * `cognitoIdentityId`. The request body can never influence it. A guest is
25
+ * accepted only when `cognitoAuthenticationType === 'unauthenticated'` AND a
26
+ * `cognitoIdentityId` is present. Returns `undefined` when neither is present.
27
+ */
28
+ export const resolvePrincipal = (event) => {
29
+ const claims = event.requestContext?.authorizer?.jwt?.claims;
30
+ const sub = claims?.sub;
31
+ // SECURITY: the authed (JWT) principal takes unconditional precedence. In
32
+ // practice the two blocks are mutually exclusive by route/payload format (JWT
33
+ // claims on format 2.0, identity on format 1.0), so this ordering is a
34
+ // defense-in-depth guard against any future misconfiguration that surfaced
35
+ // both — a verified user is never downgraded to a guest.
36
+ if (typeof sub === 'string' && sub.length > 0) {
37
+ return authedPrincipal(sub);
38
+ }
39
+ const identity = event.requestContext?.identity;
40
+ const identityId = identity?.cognitoIdentityId;
41
+ if (identity?.cognitoAuthenticationType === 'unauthenticated' &&
42
+ typeof identityId === 'string' &&
43
+ identityId.length > 0) {
44
+ return guestPrincipal(identityId);
45
+ }
46
+ return undefined;
47
+ };
48
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJpbmNpcGFsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xhbWJkYS9pZGVudGlmeS9wcmluY2lwYWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixvQkFBb0IsRUFDcEIsaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNoQix5QkFBeUIsRUFDekIsbUJBQW1CLEdBQ3BCLE1BQU0sb0JBQW9CLENBQUM7QUE4QjVCLGlGQUFpRjtBQUNqRixNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsQ0FBQyxHQUFXLEVBQWEsRUFBRSxDQUFDLENBQUM7SUFDMUQsSUFBSSxFQUFFLFFBQVE7SUFDZCxPQUFPLEVBQUUsZ0JBQWdCO0lBQ3pCLFdBQVcsRUFBRSxpQkFBaUI7SUFDOUIsaUJBQWlCLEVBQUUsbUJBQW1CO0lBQ3RDLEtBQUssRUFBRSxHQUFHO0NBQ1gsQ0FBQyxDQUFDO0FBRUgsa0ZBQWtGO0FBQ2xGLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLFVBQWtCLEVBQWEsRUFBRSxDQUFDLENBQUM7SUFDaEUsSUFBSSxFQUFFLE9BQU87SUFDYixPQUFPLEVBQUUsb0JBQW9CO0lBQzdCLFdBQVcsRUFBRSxzQkFBc0I7SUFDbkMsaUJBQWlCLEVBQUUseUJBQXlCO0lBQzVDLEtBQUssRUFBRSxVQUFVO0NBQ2xCLENBQUMsQ0FBQztBQXdCSDs7Ozs7Ozs7O0dBU0c7QUFDSCxNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUM5QixLQUFvQixFQUNHLEVBQUU7SUFDekIsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLGNBQWMsRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQztJQUM3RCxNQUFNLEdBQUcsR0FBRyxNQUFNLEVBQUUsR0FBRyxDQUFDO0lBQ3hCLDBFQUEwRTtJQUMxRSw4RUFBOEU7SUFDOUUsdUVBQXVFO0lBQ3ZFLDJFQUEyRTtJQUMzRSx5REFBeUQ7SUFDekQsSUFBSSxPQUFPLEdBQUcsS0FBSyxRQUFRLElBQUksR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxPQUFPLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM5QixDQUFDO0lBRUQsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLGNBQWMsRUFBRSxRQUFRLENBQUM7SUFDaEQsTUFBTSxVQUFVLEdBQUcsUUFBUSxFQUFFLGlCQUFpQixDQUFDO0lBQy9DLElBQ0UsUUFBUSxFQUFFLHlCQUF5QixLQUFLLGlCQUFpQjtRQUN6RCxPQUFPLFVBQVUsS0FBSyxRQUFRO1FBQzlCLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUNyQixDQUFDO1FBQ0QsT0FBTyxjQUFjLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDcEMsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENPR05JVE9fSURFTlRJVFlfRklFTEQsXG4gIENPR05JVE9fSURFTlRJVFlfS0VZLFxuICBDT0dOSVRPX1NVQl9GSUVMRCxcbiAgQ09HTklUT19VU0VSX0tFWSxcbiAgT0JKRUNUX1RZUEVfR1VFU1RfUFJPRklMRSxcbiAgT0JKRUNUX1RZUEVfUFJPRklMRSxcbn0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcblxuLyoqXG4gKiBUaGUgcmVzb2x2ZWQgY2FsbGVyIGlkZW50aXR5LCBhYnN0cmFjdGVkIG92ZXIgdGhlIHR3byBhdXRoIG1vZGVzIHNvIHRoZSByZXN0XG4gKiBvZiB0aGUgaWRlbnRpZnkgcGlwZWxpbmUgKHByb2ZpbGUgZmluZC1vci1jcmVhdGUsIGRldmljZSB1cHNlcnQsIGF0dHJpYnV0ZVxuICogd3JpdGUpIGlzIGlkZW50aXR5LWFnbm9zdGljOlxuICpcbiAqICAgLSBgYXV0aGVkYDogYSB2ZXJpZmllZCBDb2duaXRvIHVzZXItcG9vbCBgc3ViYCAoSldUIGF1dGhvcml6ZXIpLiBLZXllZCBieVxuICogICAgIGBjb2duaXRvVXNlcktleWAgKGZpZWxkIGBjb2duaXRvU3ViYCkgb24gdGhlIGBBbXBsaWZ5UHJvZmlsZWAgb2JqZWN0IHR5cGUuXG4gKiAgIC0gYGd1ZXN0YDogYSB2ZXJpZmllZCBDb2duaXRvIElkZW50aXR5IFBvb2wgYGNvZ25pdG9JZGVudGl0eUlkYCBmb3IgYW5cbiAqICAgICBVTkFVVEhFTlRJQ0FURUQgaWRlbnRpdHkgKElBTS9TaWdWNCBhdXRob3JpemVyKS4gS2V5ZWQgYnlcbiAqICAgICBgY29nbml0b0lkZW50aXR5S2V5YCAoZmllbGQgYGNvZ25pdG9JZGVudGl0eUlkYCkgb24gdGhlXG4gKiAgICAgYEFtcGxpZnlHdWVzdFByb2ZpbGVgIG9iamVjdCB0eXBlLlxuICpcbiAqIGBrZXlOYW1lYCBpcyB0aGUgc2VhcmNoYWJsZS9yZXNvbHV0aW9uIGtleSBvbiB0aGUgb2JqZWN0IHR5cGVzOyBgb2JqZWN0RmllbGRgXG4gKiBpcyB0aGUgZmllbGQgbmFtZSB0aGUgTGFtYmRhIGluZ2VzdHMgdmlhIFB1dFByb2ZpbGVPYmplY3QgKHNvdXJjZWQgaW50byB0aGF0XG4gKiBrZXkpOyBgcHJvZmlsZU9iamVjdFR5cGVgIGlzIHRoZSBvYmplY3QgdHlwZSB0aGUgZmluZC1vci1jcmVhdGUgaW5nZXN0cyBpbnRvXG4gKiAoZWFjaCBtb2RlIGhhcyBpdHMgT1dOIHR5cGUgYmVjYXVzZSBDdXN0b21lciBQcm9maWxlcyByZXF1aXJlcyBleGFjdGx5IG9uZVxuICogVU5JUVVFIGtleSBwZXIgb2JqZWN0IHR5cGUsIGNhcnJpZWQgYnkgZXZlcnkgaW5nZXN0ZWQgb2JqZWN0KTsgYHZhbHVlYCBpcyB0aGVcbiAqIHZlcmlmaWVkIGlkZW50aXR5IHZhbHVlLiBgdmFsdWVgIGlzIEFMV0FZUyBkZXJpdmVkIGZyb20gYW4gYXV0aG9yaXplci12ZXJpZmllZFxuICogc291cmNlIOKAlCBuZXZlciBmcm9tIHRoZSByZXF1ZXN0IGJvZHkuXG4gKi9cbmV4cG9ydCB0eXBlIFByaW5jaXBhbCA9IHtcbiAgcmVhZG9ubHkga2luZDogJ2F1dGhlZCcgfCAnZ3Vlc3QnO1xuICByZWFkb25seSBrZXlOYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG9iamVjdEZpZWxkOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHByb2ZpbGVPYmplY3RUeXBlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHZhbHVlOiBzdHJpbmc7XG59O1xuXG4vKiogQnVpbGQgdGhlIGF1dGhlbnRpY2F0ZWQgcHJpbmNpcGFsIGZyb20gYSB2ZXJpZmllZCBDb2duaXRvIHVzZXItcG9vbCBgc3ViYC4gKi9cbmV4cG9ydCBjb25zdCBhdXRoZWRQcmluY2lwYWwgPSAoc3ViOiBzdHJpbmcpOiBQcmluY2lwYWwgPT4gKHtcbiAga2luZDogJ2F1dGhlZCcsXG4gIGtleU5hbWU6IENPR05JVE9fVVNFUl9LRVksXG4gIG9iamVjdEZpZWxkOiBDT0dOSVRPX1NVQl9GSUVMRCxcbiAgcHJvZmlsZU9iamVjdFR5cGU6IE9CSkVDVF9UWVBFX1BST0ZJTEUsXG4gIHZhbHVlOiBzdWIsXG59KTtcblxuLyoqIEJ1aWxkIHRoZSBndWVzdCBwcmluY2lwYWwgZnJvbSBhIHZlcmlmaWVkIENvZ25pdG8gSWRlbnRpdHkgUG9vbCBpZGVudGl0eUlkLiAqL1xuZXhwb3J0IGNvbnN0IGd1ZXN0UHJpbmNpcGFsID0gKGlkZW50aXR5SWQ6IHN0cmluZyk6IFByaW5jaXBhbCA9PiAoe1xuICBraW5kOiAnZ3Vlc3QnLFxuICBrZXlOYW1lOiBDT0dOSVRPX0lERU5USVRZX0tFWSxcbiAgb2JqZWN0RmllbGQ6IENPR05JVE9fSURFTlRJVFlfRklFTEQsXG4gIHByb2ZpbGVPYmplY3RUeXBlOiBPQkpFQ1RfVFlQRV9HVUVTVF9QUk9GSUxFLFxuICB2YWx1ZTogaWRlbnRpdHlJZCxcbn0pO1xuXG4vKipcbiAqIFRoZSBtaW5pbWFsIHN0cnVjdHVyYWwgc2hhcGUgc2hhcmVkIGJ5IHRoZSB0d28gTGFtYmRhLXByb3h5IGV2ZW50IGZvcm1hdHNcbiAqIHRoaXMgaGFuZGxlciBzZXJ2ZXM6XG4gKiAgIC0gSFRUUCBBUEkgcGF5bG9hZCBmb3JtYXQgMi4wICsgSldUIGF1dGhvcml6ZXIgKGF1dGhlZCByb3V0ZSk6IHRoZSB2ZXJpZmllZFxuICogICAgIGBzdWJgIGlzIGF0IGByZXF1ZXN0Q29udGV4dC5hdXRob3JpemVyLmp3dC5jbGFpbXMuc3ViYC5cbiAqICAgLSBIVFRQIEFQSSBwYXlsb2FkIGZvcm1hdCAxLjAgKyBJQU0vU2lnVjQgYXV0aG9yaXphdGlvbiAoZ3Vlc3Qgcm91dGUpOiB0aGVcbiAqICAgICB2ZXJpZmllZCBDb2duaXRvIElkZW50aXR5IFBvb2wgaWRlbnRpdHkgaXMgYXQgYHJlcXVlc3RDb250ZXh0LmlkZW50aXR5YFxuICogICAgIChgY29nbml0b0lkZW50aXR5SWRgICsgYGNvZ25pdG9BdXRoZW50aWNhdGlvblR5cGVgKS4gTk9URTogZm9ybWF0IDIuMCBoYXNcbiAqICAgICBOTyBgaWRlbnRpdHlgIGJsb2NrIGF0IGFsbCwgd2hpY2ggaXMgZXhhY3RseSB3aHkgdGhlIGd1ZXN0IHJvdXRlIE1VU1QgdXNlXG4gKiAgICAgcGF5bG9hZCBmb3JtYXQgMS4wLlxuICovXG5leHBvcnQgdHlwZSBJZGVudGlmeUV2ZW50ID0ge1xuICBib2R5Pzogc3RyaW5nIHwgbnVsbDtcbiAgcmVxdWVzdENvbnRleHQ/OiB7XG4gICAgYXV0aG9yaXplcj86IHsgand0PzogeyBjbGFpbXM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9IH07XG4gICAgaWRlbnRpdHk/OiB7XG4gICAgICBjb2duaXRvSWRlbnRpdHlJZD86IHN0cmluZyB8IG51bGw7XG4gICAgICBjb2duaXRvQXV0aGVudGljYXRpb25UeXBlPzogc3RyaW5nIHwgbnVsbDtcbiAgICB9O1xuICB9O1xufTtcblxuLyoqXG4gKiBSZXNvbHZlIHRoZSB2ZXJpZmllZCBjYWxsZXIge0BsaW5rIFByaW5jaXBhbH0gZnJvbSBlaXRoZXIgZXZlbnQgc2hhcGUuXG4gKlxuICogU0VDVVJJVFk6IGlkZW50aXR5IGlzIGRlcml2ZWQgT05MWSBmcm9tIGF1dGhvcml6ZXItdmVyaWZpZWQgZmllbGRzIOKAlCB0aGUgSldUXG4gKiBgc3ViYCBjbGFpbSAod2hpY2ggQVBJIEdhdGV3YXkgcG9wdWxhdGVzIG9ubHkgYWZ0ZXIgY3J5cHRvZ3JhcGhpY2FsbHlcbiAqIHZlcmlmeWluZyB0aGUgQ29nbml0byB0b2tlbikgb3IgdGhlIFNpZ1Y0L0lBTS12ZXJpZmllZCBDb2duaXRvXG4gKiBgY29nbml0b0lkZW50aXR5SWRgLiBUaGUgcmVxdWVzdCBib2R5IGNhbiBuZXZlciBpbmZsdWVuY2UgaXQuIEEgZ3Vlc3QgaXNcbiAqIGFjY2VwdGVkIG9ubHkgd2hlbiBgY29nbml0b0F1dGhlbnRpY2F0aW9uVHlwZSA9PT0gJ3VuYXV0aGVudGljYXRlZCdgIEFORCBhXG4gKiBgY29nbml0b0lkZW50aXR5SWRgIGlzIHByZXNlbnQuIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiBuZWl0aGVyIGlzIHByZXNlbnQuXG4gKi9cbmV4cG9ydCBjb25zdCByZXNvbHZlUHJpbmNpcGFsID0gKFxuICBldmVudDogSWRlbnRpZnlFdmVudCxcbik6IFByaW5jaXBhbCB8IHVuZGVmaW5lZCA9PiB7XG4gIGNvbnN0IGNsYWltcyA9IGV2ZW50LnJlcXVlc3RDb250ZXh0Py5hdXRob3JpemVyPy5qd3Q/LmNsYWltcztcbiAgY29uc3Qgc3ViID0gY2xhaW1zPy5zdWI7XG4gIC8vIFNFQ1VSSVRZOiB0aGUgYXV0aGVkIChKV1QpIHByaW5jaXBhbCB0YWtlcyB1bmNvbmRpdGlvbmFsIHByZWNlZGVuY2UuIEluXG4gIC8vIHByYWN0aWNlIHRoZSB0d28gYmxvY2tzIGFyZSBtdXR1YWxseSBleGNsdXNpdmUgYnkgcm91dGUvcGF5bG9hZCBmb3JtYXQgKEpXVFxuICAvLyBjbGFpbXMgb24gZm9ybWF0IDIuMCwgaWRlbnRpdHkgb24gZm9ybWF0IDEuMCksIHNvIHRoaXMgb3JkZXJpbmcgaXMgYVxuICAvLyBkZWZlbnNlLWluLWRlcHRoIGd1YXJkIGFnYWluc3QgYW55IGZ1dHVyZSBtaXNjb25maWd1cmF0aW9uIHRoYXQgc3VyZmFjZWRcbiAgLy8gYm90aCDigJQgYSB2ZXJpZmllZCB1c2VyIGlzIG5ldmVyIGRvd25ncmFkZWQgdG8gYSBndWVzdC5cbiAgaWYgKHR5cGVvZiBzdWIgPT09ICdzdHJpbmcnICYmIHN1Yi5sZW5ndGggPiAwKSB7XG4gICAgcmV0dXJuIGF1dGhlZFByaW5jaXBhbChzdWIpO1xuICB9XG5cbiAgY29uc3QgaWRlbnRpdHkgPSBldmVudC5yZXF1ZXN0Q29udGV4dD8uaWRlbnRpdHk7XG4gIGNvbnN0IGlkZW50aXR5SWQgPSBpZGVudGl0eT8uY29nbml0b0lkZW50aXR5SWQ7XG4gIGlmIChcbiAgICBpZGVudGl0eT8uY29nbml0b0F1dGhlbnRpY2F0aW9uVHlwZSA9PT0gJ3VuYXV0aGVudGljYXRlZCcgJiZcbiAgICB0eXBlb2YgaWRlbnRpdHlJZCA9PT0gJ3N0cmluZycgJiZcbiAgICBpZGVudGl0eUlkLmxlbmd0aCA+IDBcbiAgKSB7XG4gICAgcmV0dXJuIGd1ZXN0UHJpbmNpcGFsKGlkZW50aXR5SWQpO1xuICB9XG5cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn07XG4iXX0=
@@ -0,0 +1,35 @@
1
+ import { CustomerProfilesClient } from '@aws-sdk/client-customer-profiles';
2
+ import { Principal } from './principal.js';
3
+ export type ResolvedProfile = {
4
+ profileId: string;
5
+ };
6
+ /**
7
+ * Resolve (or create) the Customer Profiles profile bound to a verified caller
8
+ * ({@link Principal} — an authed `sub` or a guest `cognitoIdentityId`) via a
9
+ * single idempotent PutProfileObject find-or-create against the AmplifyProfile
10
+ * object type (keyed PROFILE+UNIQUE by the principal's key), then read back the
11
+ * profileId via SearchProfiles (bounded poll for eventual consistency). The
12
+ * PutProfileObject is wrapped in {@link withTransientRetry} so transient
13
+ * throttling / concurrent-update errors are retried with backoff.
14
+ *
15
+ * Because Customer Profiles enforces find-or-create atomically server-side on
16
+ * the PROFILE+UNIQUE key, concurrent first-logins for the same identity
17
+ * converge on a single profile — no duplicates, no create race.
18
+ *
19
+ * This is the DELIBERATELY ISOLATED identity-resolution seam: callers depend
20
+ * only on the returned `profileId`, regardless of auth mode.
21
+ * @throws if a profileId cannot be resolved after the bounded poll.
22
+ */
23
+ export declare const resolveOrCreateProfile: (profiles: CustomerProfilesClient, domainName: string, principal: Principal) => Promise<ResolvedProfile>;
24
+ /**
25
+ * Find the profileId bound to a principal WITHOUT creating one (single
26
+ * SearchProfiles, no poll). Returns `undefined` when no profile exists yet.
27
+ * Used by merge-on-sign-in to locate a prior guest profile.
28
+ *
29
+ * A single attempt (no retry poll, unlike {@link resolveOrCreateProfile}) is
30
+ * correct here: the guest profile, if any, was created on a PRIOR invocation —
31
+ * not in this request — so there is no just-written object to wait for eventual
32
+ * consistency on. A miss means "no guest profile", not "not yet visible".
33
+ */
34
+ export declare const findProfileId: (profiles: CustomerProfilesClient, domainName: string, principal: Principal) => Promise<string | undefined>;
35
+ //# sourceMappingURL=profile_resolver.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { PutProfileObjectCommand, SearchProfilesCommand, } from '@aws-sdk/client-customer-profiles';
2
+ import { withTransientRetry } from '../shared/retry.js';
3
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
4
+ /**
5
+ * Look up the profile bound to `value` via the searchable `keyName`, polling
6
+ * briefly to absorb SearchProfiles' eventual consistency.
7
+ */
8
+ const searchProfileId = async (profiles, domainName, keyName, value, attempts, baseDelayMs) => {
9
+ for (let i = 0; i < attempts; i++) {
10
+ const search = await profiles.send(new SearchProfilesCommand({
11
+ DomainName: domainName,
12
+ KeyName: keyName,
13
+ Values: [value],
14
+ }));
15
+ const found = search.Items?.find((item) => !!item.ProfileId)?.ProfileId;
16
+ if (found) {
17
+ return found;
18
+ }
19
+ if (i < attempts - 1) {
20
+ await sleep(baseDelayMs * (i + 1));
21
+ }
22
+ }
23
+ return undefined;
24
+ };
25
+ /**
26
+ * Resolve (or create) the Customer Profiles profile bound to a verified caller
27
+ * ({@link Principal} — an authed `sub` or a guest `cognitoIdentityId`) via a
28
+ * single idempotent PutProfileObject find-or-create against the AmplifyProfile
29
+ * object type (keyed PROFILE+UNIQUE by the principal's key), then read back the
30
+ * profileId via SearchProfiles (bounded poll for eventual consistency). The
31
+ * PutProfileObject is wrapped in {@link withTransientRetry} so transient
32
+ * throttling / concurrent-update errors are retried with backoff.
33
+ *
34
+ * Because Customer Profiles enforces find-or-create atomically server-side on
35
+ * the PROFILE+UNIQUE key, concurrent first-logins for the same identity
36
+ * converge on a single profile — no duplicates, no create race.
37
+ *
38
+ * This is the DELIBERATELY ISOLATED identity-resolution seam: callers depend
39
+ * only on the returned `profileId`, regardless of auth mode.
40
+ * @throws if a profileId cannot be resolved after the bounded poll.
41
+ */
42
+ export const resolveOrCreateProfile = async (profiles, domainName, principal) => {
43
+ await withTransientRetry(() => profiles.send(new PutProfileObjectCommand({
44
+ DomainName: domainName,
45
+ ObjectTypeName: principal.profileObjectType,
46
+ Object: JSON.stringify({ [principal.objectField]: principal.value }),
47
+ })));
48
+ const profileId = await searchProfileId(profiles, domainName, principal.keyName, principal.value, 8, 150);
49
+ if (!profileId) {
50
+ throw new Error('PutProfileObject find-or-create did not resolve a ProfileId');
51
+ }
52
+ return { profileId };
53
+ };
54
+ /**
55
+ * Find the profileId bound to a principal WITHOUT creating one (single
56
+ * SearchProfiles, no poll). Returns `undefined` when no profile exists yet.
57
+ * Used by merge-on-sign-in to locate a prior guest profile.
58
+ *
59
+ * A single attempt (no retry poll, unlike {@link resolveOrCreateProfile}) is
60
+ * correct here: the guest profile, if any, was created on a PRIOR invocation —
61
+ * not in this request — so there is no just-written object to wait for eventual
62
+ * consistency on. A miss means "no guest profile", not "not yet visible".
63
+ */
64
+ export const findProfileId = async (profiles, domainName, principal) => searchProfileId(profiles, domainName, principal.keyName, principal.value, 1, 0);
65
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvZmlsZV9yZXNvbHZlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvaWRlbnRpZnkvcHJvZmlsZV9yZXNvbHZlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBRUwsdUJBQXVCLEVBQ3ZCLHFCQUFxQixHQUN0QixNQUFNLG1DQUFtQyxDQUFDO0FBRTNDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBT3hELE1BQU0sS0FBSyxHQUFHLENBQUMsRUFBVSxFQUFpQixFQUFFLENBQzFDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFFcEQ7OztHQUdHO0FBQ0gsTUFBTSxlQUFlLEdBQUcsS0FBSyxFQUMzQixRQUFnQyxFQUNoQyxVQUFrQixFQUNsQixPQUFlLEVBQ2YsS0FBYSxFQUNiLFFBQWdCLEVBQ2hCLFdBQW1CLEVBQ1UsRUFBRTtJQUMvQixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsUUFBUSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDbEMsTUFBTSxNQUFNLEdBQUcsTUFBTSxRQUFRLENBQUMsSUFBSSxDQUNoQyxJQUFJLHFCQUFxQixDQUFDO1lBQ3hCLFVBQVUsRUFBRSxVQUFVO1lBQ3RCLE9BQU8sRUFBRSxPQUFPO1lBQ2hCLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQztTQUNoQixDQUFDLENBQ0gsQ0FBQztRQUNGLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLFNBQVMsQ0FBQztRQUN4RSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1YsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBQ0QsSUFBSSxDQUFDLEdBQUcsUUFBUSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3JCLE1BQU0sS0FBSyxDQUFDLFdBQVcsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyxDQUFDO0FBRUY7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxLQUFLLEVBQ3pDLFFBQWdDLEVBQ2hDLFVBQWtCLEVBQ2xCLFNBQW9CLEVBQ00sRUFBRTtJQUM1QixNQUFNLGtCQUFrQixDQUFDLEdBQUcsRUFBRSxDQUM1QixRQUFRLENBQUMsSUFBSSxDQUNYLElBQUksdUJBQXVCLENBQUM7UUFDMUIsVUFBVSxFQUFFLFVBQVU7UUFDdEIsY0FBYyxFQUFFLFNBQVMsQ0FBQyxpQkFBaUI7UUFDM0MsTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsRUFBRSxTQUFTLENBQUMsS0FBSyxFQUFFLENBQUM7S0FDckUsQ0FBQyxDQUNILENBQ0YsQ0FBQztJQUVGLE1BQU0sU0FBUyxHQUFHLE1BQU0sZUFBZSxDQUNyQyxRQUFRLEVBQ1IsVUFBVSxFQUNWLFNBQVMsQ0FBQyxPQUFPLEVBQ2pCLFNBQVMsQ0FBQyxLQUFLLEVBQ2YsQ0FBQyxFQUNELEdBQUcsQ0FDSixDQUFDO0lBQ0YsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2YsTUFBTSxJQUFJLEtBQUssQ0FDYiw2REFBNkQsQ0FDOUQsQ0FBQztJQUNKLENBQUM7SUFDRCxPQUFPLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDdkIsQ0FBQyxDQUFDO0FBRUY7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLEtBQUssRUFDaEMsUUFBZ0MsRUFDaEMsVUFBa0IsRUFDbEIsU0FBb0IsRUFDUyxFQUFFLENBQy9CLGVBQWUsQ0FDYixRQUFRLEVBQ1IsVUFBVSxFQUNWLFNBQVMsQ0FBQyxPQUFPLEVBQ2pCLFNBQVMsQ0FBQyxLQUFLLEVBQ2YsQ0FBQyxFQUNELENBQUMsQ0FDRixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ3VzdG9tZXJQcm9maWxlc0NsaWVudCxcbiAgUHV0UHJvZmlsZU9iamVjdENvbW1hbmQsXG4gIFNlYXJjaFByb2ZpbGVzQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWN1c3RvbWVyLXByb2ZpbGVzJztcblxuaW1wb3J0IHsgd2l0aFRyYW5zaWVudFJldHJ5IH0gZnJvbSAnLi4vc2hhcmVkL3JldHJ5LmpzJztcbmltcG9ydCB7IFByaW5jaXBhbCB9IGZyb20gJy4vcHJpbmNpcGFsLmpzJztcblxuZXhwb3J0IHR5cGUgUmVzb2x2ZWRQcm9maWxlID0ge1xuICBwcm9maWxlSWQ6IHN0cmluZztcbn07XG5cbmNvbnN0IHNsZWVwID0gKG1zOiBudW1iZXIpOiBQcm9taXNlPHZvaWQ+ID0+XG4gIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIG1zKSk7XG5cbi8qKlxuICogTG9vayB1cCB0aGUgcHJvZmlsZSBib3VuZCB0byBgdmFsdWVgIHZpYSB0aGUgc2VhcmNoYWJsZSBga2V5TmFtZWAsIHBvbGxpbmdcbiAqIGJyaWVmbHkgdG8gYWJzb3JiIFNlYXJjaFByb2ZpbGVzJyBldmVudHVhbCBjb25zaXN0ZW5jeS5cbiAqL1xuY29uc3Qgc2VhcmNoUHJvZmlsZUlkID0gYXN5bmMgKFxuICBwcm9maWxlczogQ3VzdG9tZXJQcm9maWxlc0NsaWVudCxcbiAgZG9tYWluTmFtZTogc3RyaW5nLFxuICBrZXlOYW1lOiBzdHJpbmcsXG4gIHZhbHVlOiBzdHJpbmcsXG4gIGF0dGVtcHRzOiBudW1iZXIsXG4gIGJhc2VEZWxheU1zOiBudW1iZXIsXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4gPT4ge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGF0dGVtcHRzOyBpKyspIHtcbiAgICBjb25zdCBzZWFyY2ggPSBhd2FpdCBwcm9maWxlcy5zZW5kKFxuICAgICAgbmV3IFNlYXJjaFByb2ZpbGVzQ29tbWFuZCh7XG4gICAgICAgIERvbWFpbk5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICAgIEtleU5hbWU6IGtleU5hbWUsXG4gICAgICAgIFZhbHVlczogW3ZhbHVlXSxcbiAgICAgIH0pLFxuICAgICk7XG4gICAgY29uc3QgZm91bmQgPSBzZWFyY2guSXRlbXM/LmZpbmQoKGl0ZW0pID0+ICEhaXRlbS5Qcm9maWxlSWQpPy5Qcm9maWxlSWQ7XG4gICAgaWYgKGZvdW5kKSB7XG4gICAgICByZXR1cm4gZm91bmQ7XG4gICAgfVxuICAgIGlmIChpIDwgYXR0ZW1wdHMgLSAxKSB7XG4gICAgICBhd2FpdCBzbGVlcChiYXNlRGVsYXlNcyAqIChpICsgMSkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufTtcblxuLyoqXG4gKiBSZXNvbHZlIChvciBjcmVhdGUpIHRoZSBDdXN0b21lciBQcm9maWxlcyBwcm9maWxlIGJvdW5kIHRvIGEgdmVyaWZpZWQgY2FsbGVyXG4gKiAoe0BsaW5rIFByaW5jaXBhbH0g4oCUIGFuIGF1dGhlZCBgc3ViYCBvciBhIGd1ZXN0IGBjb2duaXRvSWRlbnRpdHlJZGApIHZpYSBhXG4gKiBzaW5nbGUgaWRlbXBvdGVudCBQdXRQcm9maWxlT2JqZWN0IGZpbmQtb3ItY3JlYXRlIGFnYWluc3QgdGhlIEFtcGxpZnlQcm9maWxlXG4gKiBvYmplY3QgdHlwZSAoa2V5ZWQgUFJPRklMRStVTklRVUUgYnkgdGhlIHByaW5jaXBhbCdzIGtleSksIHRoZW4gcmVhZCBiYWNrIHRoZVxuICogcHJvZmlsZUlkIHZpYSBTZWFyY2hQcm9maWxlcyAoYm91bmRlZCBwb2xsIGZvciBldmVudHVhbCBjb25zaXN0ZW5jeSkuIFRoZVxuICogUHV0UHJvZmlsZU9iamVjdCBpcyB3cmFwcGVkIGluIHtAbGluayB3aXRoVHJhbnNpZW50UmV0cnl9IHNvIHRyYW5zaWVudFxuICogdGhyb3R0bGluZyAvIGNvbmN1cnJlbnQtdXBkYXRlIGVycm9ycyBhcmUgcmV0cmllZCB3aXRoIGJhY2tvZmYuXG4gKlxuICogQmVjYXVzZSBDdXN0b21lciBQcm9maWxlcyBlbmZvcmNlcyBmaW5kLW9yLWNyZWF0ZSBhdG9taWNhbGx5IHNlcnZlci1zaWRlIG9uXG4gKiB0aGUgUFJPRklMRStVTklRVUUga2V5LCBjb25jdXJyZW50IGZpcnN0LWxvZ2lucyBmb3IgdGhlIHNhbWUgaWRlbnRpdHlcbiAqIGNvbnZlcmdlIG9uIGEgc2luZ2xlIHByb2ZpbGUg4oCUIG5vIGR1cGxpY2F0ZXMsIG5vIGNyZWF0ZSByYWNlLlxuICpcbiAqIFRoaXMgaXMgdGhlIERFTElCRVJBVEVMWSBJU09MQVRFRCBpZGVudGl0eS1yZXNvbHV0aW9uIHNlYW06IGNhbGxlcnMgZGVwZW5kXG4gKiBvbmx5IG9uIHRoZSByZXR1cm5lZCBgcHJvZmlsZUlkYCwgcmVnYXJkbGVzcyBvZiBhdXRoIG1vZGUuXG4gKiBAdGhyb3dzIGlmIGEgcHJvZmlsZUlkIGNhbm5vdCBiZSByZXNvbHZlZCBhZnRlciB0aGUgYm91bmRlZCBwb2xsLlxuICovXG5leHBvcnQgY29uc3QgcmVzb2x2ZU9yQ3JlYXRlUHJvZmlsZSA9IGFzeW5jIChcbiAgcHJvZmlsZXM6IEN1c3RvbWVyUHJvZmlsZXNDbGllbnQsXG4gIGRvbWFpbk5hbWU6IHN0cmluZyxcbiAgcHJpbmNpcGFsOiBQcmluY2lwYWwsXG4pOiBQcm9taXNlPFJlc29sdmVkUHJvZmlsZT4gPT4ge1xuICBhd2FpdCB3aXRoVHJhbnNpZW50UmV0cnkoKCkgPT5cbiAgICBwcm9maWxlcy5zZW5kKFxuICAgICAgbmV3IFB1dFByb2ZpbGVPYmplY3RDb21tYW5kKHtcbiAgICAgICAgRG9tYWluTmFtZTogZG9tYWluTmFtZSxcbiAgICAgICAgT2JqZWN0VHlwZU5hbWU6IHByaW5jaXBhbC5wcm9maWxlT2JqZWN0VHlwZSxcbiAgICAgICAgT2JqZWN0OiBKU09OLnN0cmluZ2lmeSh7IFtwcmluY2lwYWwub2JqZWN0RmllbGRdOiBwcmluY2lwYWwudmFsdWUgfSksXG4gICAgICB9KSxcbiAgICApLFxuICApO1xuXG4gIGNvbnN0IHByb2ZpbGVJZCA9IGF3YWl0IHNlYXJjaFByb2ZpbGVJZChcbiAgICBwcm9maWxlcyxcbiAgICBkb21haW5OYW1lLFxuICAgIHByaW5jaXBhbC5rZXlOYW1lLFxuICAgIHByaW5jaXBhbC52YWx1ZSxcbiAgICA4LFxuICAgIDE1MCxcbiAgKTtcbiAgaWYgKCFwcm9maWxlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnUHV0UHJvZmlsZU9iamVjdCBmaW5kLW9yLWNyZWF0ZSBkaWQgbm90IHJlc29sdmUgYSBQcm9maWxlSWQnLFxuICAgICk7XG4gIH1cbiAgcmV0dXJuIHsgcHJvZmlsZUlkIH07XG59O1xuXG4vKipcbiAqIEZpbmQgdGhlIHByb2ZpbGVJZCBib3VuZCB0byBhIHByaW5jaXBhbCBXSVRIT1VUIGNyZWF0aW5nIG9uZSAoc2luZ2xlXG4gKiBTZWFyY2hQcm9maWxlcywgbm8gcG9sbCkuIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiBubyBwcm9maWxlIGV4aXN0cyB5ZXQuXG4gKiBVc2VkIGJ5IG1lcmdlLW9uLXNpZ24taW4gdG8gbG9jYXRlIGEgcHJpb3IgZ3Vlc3QgcHJvZmlsZS5cbiAqXG4gKiBBIHNpbmdsZSBhdHRlbXB0IChubyByZXRyeSBwb2xsLCB1bmxpa2Uge0BsaW5rIHJlc29sdmVPckNyZWF0ZVByb2ZpbGV9KSBpc1xuICogY29ycmVjdCBoZXJlOiB0aGUgZ3Vlc3QgcHJvZmlsZSwgaWYgYW55LCB3YXMgY3JlYXRlZCBvbiBhIFBSSU9SIGludm9jYXRpb24g4oCUXG4gKiBub3QgaW4gdGhpcyByZXF1ZXN0IOKAlCBzbyB0aGVyZSBpcyBubyBqdXN0LXdyaXR0ZW4gb2JqZWN0IHRvIHdhaXQgZm9yIGV2ZW50dWFsXG4gKiBjb25zaXN0ZW5jeSBvbi4gQSBtaXNzIG1lYW5zIFwibm8gZ3Vlc3QgcHJvZmlsZVwiLCBub3QgXCJub3QgeWV0IHZpc2libGVcIi5cbiAqL1xuZXhwb3J0IGNvbnN0IGZpbmRQcm9maWxlSWQgPSBhc3luYyAoXG4gIHByb2ZpbGVzOiBDdXN0b21lclByb2ZpbGVzQ2xpZW50LFxuICBkb21haW5OYW1lOiBzdHJpbmcsXG4gIHByaW5jaXBhbDogUHJpbmNpcGFsLFxuKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+ID0+XG4gIHNlYXJjaFByb2ZpbGVJZChcbiAgICBwcm9maWxlcyxcbiAgICBkb21haW5OYW1lLFxuICAgIHByaW5jaXBhbC5rZXlOYW1lLFxuICAgIHByaW5jaXBhbC52YWx1ZSxcbiAgICAxLFxuICAgIDAsXG4gICk7XG4iXX0=
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Frozen request/response contract for the identify-user backend.
3
+ *
4
+ * These types mirror exactly the JSON shape accepted by
5
+ * `POST {apiEndpoint}/identify-user`. They intentionally live in a single
6
+ * module so the handler, the mapping layer, and the tests share one source of
7
+ * truth.
8
+ */
9
+ export type ChannelType = 'GCM' | 'APNS' | 'APNS_SANDBOX' | 'IN_APP';
10
+ export type OptOut = 'ALL' | 'NONE';
11
+ export type Demographic = {
12
+ appVersion?: string;
13
+ locale?: string;
14
+ make?: string;
15
+ model?: string;
16
+ modelVersion?: string;
17
+ platform?: string;
18
+ platformVersion?: string;
19
+ timezone?: string;
20
+ };
21
+ export type Location = {
22
+ city?: string;
23
+ country?: string;
24
+ latitude?: number;
25
+ longitude?: number;
26
+ postalCode?: string;
27
+ region?: string;
28
+ };
29
+ export type UserProfile = {
30
+ name?: string;
31
+ email?: string;
32
+ plan?: string;
33
+ customProperties?: Record<string, string[]>;
34
+ demographic?: Demographic;
35
+ location?: Location;
36
+ metrics?: Record<string, number>;
37
+ };
38
+ export type IdentifyUserOptions = {
39
+ userAttributes?: Record<string, string[]>;
40
+ /** Mutable push token / endpoint address. Stored as a FIELD, not the key. */
41
+ address?: string;
42
+ /**
43
+ * Stable device identifier (e.g. the client-persisted endpointId). This is
44
+ * the UNIQUE key of the AmplifyDevice object, so a token refresh for the same
45
+ * device upserts in place instead of creating a new device object.
46
+ */
47
+ deviceId?: string;
48
+ channelType?: ChannelType;
49
+ /**
50
+ * Client OS platform (e.g. `Android` / `iOS`) recorded on the device object.
51
+ * Falls back to `userProfile.demographic.platform` when omitted.
52
+ */
53
+ platform?: string;
54
+ /**
55
+ * App version at device registration, recorded on the device object. Falls
56
+ * back to `userProfile.demographic.appVersion` when omitted.
57
+ */
58
+ appVersion?: string;
59
+ /**
60
+ * Accepted for API compatibility with the shared Pinpoint-style options, but
61
+ * has NO effect: it is not written to the device object nor the profile.
62
+ */
63
+ optOut?: OptOut;
64
+ /**
65
+ * The AUTHENTICATED caller's prior GUEST
66
+ * `cognitoIdentityId`. When present on an authed call, the handler folds the
67
+ * guest profile (keyed by `cognitoIdentityKey = this value`) — and its device
68
+ * objects — into the resolved authed profile via MergeProfiles. Ignored on
69
+ * guest calls. The value is only a merge HINT: it can only trigger merging a
70
+ * guest profile into the caller's OWN verified authed profile.
71
+ */
72
+ previousGuestIdentityId?: string;
73
+ };
74
+ export type IdentifyUserRequest = {
75
+ /**
76
+ * Client-supplied identifier. Stored ONLY as the `appUserId` attribute.
77
+ * It is NEVER used as the profile identity key — the authoritative identity
78
+ * is the verified Cognito `sub` from the JWT authorizer claims.
79
+ */
80
+ userId?: string;
81
+ userProfile: UserProfile;
82
+ options?: IdentifyUserOptions;
83
+ };
84
+ export type SuccessResponse = {
85
+ status: 'ok';
86
+ };
87
+ export type ErrorResponse = {
88
+ error: string;
89
+ };
90
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Frozen request/response contract for the identify-user backend.
3
+ *
4
+ * These types mirror exactly the JSON shape accepted by
5
+ * `POST {apiEndpoint}/identify-user`. They intentionally live in a single
6
+ * module so the handler, the mapping layer, and the tests share one source of
7
+ * truth.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhL2lkZW50aWZ5L3R5cGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O0dBT0ciLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZyb3plbiByZXF1ZXN0L3Jlc3BvbnNlIGNvbnRyYWN0IGZvciB0aGUgaWRlbnRpZnktdXNlciBiYWNrZW5kLlxuICpcbiAqIFRoZXNlIHR5cGVzIG1pcnJvciBleGFjdGx5IHRoZSBKU09OIHNoYXBlIGFjY2VwdGVkIGJ5XG4gKiBgUE9TVCB7YXBpRW5kcG9pbnR9L2lkZW50aWZ5LXVzZXJgLiBUaGV5IGludGVudGlvbmFsbHkgbGl2ZSBpbiBhIHNpbmdsZVxuICogbW9kdWxlIHNvIHRoZSBoYW5kbGVyLCB0aGUgbWFwcGluZyBsYXllciwgYW5kIHRoZSB0ZXN0cyBzaGFyZSBvbmUgc291cmNlIG9mXG4gKiB0cnV0aC5cbiAqL1xuXG5leHBvcnQgdHlwZSBDaGFubmVsVHlwZSA9ICdHQ00nIHwgJ0FQTlMnIHwgJ0FQTlNfU0FOREJPWCcgfCAnSU5fQVBQJztcbmV4cG9ydCB0eXBlIE9wdE91dCA9ICdBTEwnIHwgJ05PTkUnO1xuXG5leHBvcnQgdHlwZSBEZW1vZ3JhcGhpYyA9IHtcbiAgYXBwVmVyc2lvbj86IHN0cmluZztcbiAgbG9jYWxlPzogc3RyaW5nO1xuICBtYWtlPzogc3RyaW5nO1xuICBtb2RlbD86IHN0cmluZztcbiAgbW9kZWxWZXJzaW9uPzogc3RyaW5nO1xuICBwbGF0Zm9ybT86IHN0cmluZztcbiAgcGxhdGZvcm1WZXJzaW9uPzogc3RyaW5nO1xuICB0aW1lem9uZT86IHN0cmluZztcbn07XG5cbmV4cG9ydCB0eXBlIExvY2F0aW9uID0ge1xuICBjaXR5Pzogc3RyaW5nO1xuICBjb3VudHJ5Pzogc3RyaW5nO1xuICBsYXRpdHVkZT86IG51bWJlcjtcbiAgbG9uZ2l0dWRlPzogbnVtYmVyO1xuICBwb3N0YWxDb2RlPzogc3RyaW5nO1xuICByZWdpb24/OiBzdHJpbmc7XG59O1xuXG5leHBvcnQgdHlwZSBVc2VyUHJvZmlsZSA9IHtcbiAgbmFtZT86IHN0cmluZztcbiAgZW1haWw/OiBzdHJpbmc7XG4gIHBsYW4/OiBzdHJpbmc7XG4gIGN1c3RvbVByb3BlcnRpZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT47XG4gIGRlbW9ncmFwaGljPzogRGVtb2dyYXBoaWM7XG4gIGxvY2F0aW9uPzogTG9jYXRpb247XG4gIG1ldHJpY3M/OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xufTtcblxuZXhwb3J0IHR5cGUgSWRlbnRpZnlVc2VyT3B0aW9ucyA9IHtcbiAgdXNlckF0dHJpYnV0ZXM/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmdbXT47XG4gIC8qKiBNdXRhYmxlIHB1c2ggdG9rZW4gLyBlbmRwb2ludCBhZGRyZXNzLiBTdG9yZWQgYXMgYSBGSUVMRCwgbm90IHRoZSBrZXkuICovXG4gIGFkZHJlc3M/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBTdGFibGUgZGV2aWNlIGlkZW50aWZpZXIgKGUuZy4gdGhlIGNsaWVudC1wZXJzaXN0ZWQgZW5kcG9pbnRJZCkuIFRoaXMgaXNcbiAgICogdGhlIFVOSVFVRSBrZXkgb2YgdGhlIEFtcGxpZnlEZXZpY2Ugb2JqZWN0LCBzbyBhIHRva2VuIHJlZnJlc2ggZm9yIHRoZSBzYW1lXG4gICAqIGRldmljZSB1cHNlcnRzIGluIHBsYWNlIGluc3RlYWQgb2YgY3JlYXRpbmcgYSBuZXcgZGV2aWNlIG9iamVjdC5cbiAgICovXG4gIGRldmljZUlkPzogc3RyaW5nO1xuICBjaGFubmVsVHlwZT86IENoYW5uZWxUeXBlO1xuICAvKipcbiAgICogQ2xpZW50IE9TIHBsYXRmb3JtIChlLmcuIGBBbmRyb2lkYCAvIGBpT1NgKSByZWNvcmRlZCBvbiB0aGUgZGV2aWNlIG9iamVjdC5cbiAgICogRmFsbHMgYmFjayB0byBgdXNlclByb2ZpbGUuZGVtb2dyYXBoaWMucGxhdGZvcm1gIHdoZW4gb21pdHRlZC5cbiAgICovXG4gIHBsYXRmb3JtPzogc3RyaW5nO1xuICAvKipcbiAgICogQXBwIHZlcnNpb24gYXQgZGV2aWNlIHJlZ2lzdHJhdGlvbiwgcmVjb3JkZWQgb24gdGhlIGRldmljZSBvYmplY3QuIEZhbGxzXG4gICAqIGJhY2sgdG8gYHVzZXJQcm9maWxlLmRlbW9ncmFwaGljLmFwcFZlcnNpb25gIHdoZW4gb21pdHRlZC5cbiAgICovXG4gIGFwcFZlcnNpb24/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBBY2NlcHRlZCBmb3IgQVBJIGNvbXBhdGliaWxpdHkgd2l0aCB0aGUgc2hhcmVkIFBpbnBvaW50LXN0eWxlIG9wdGlvbnMsIGJ1dFxuICAgKiBoYXMgTk8gZWZmZWN0OiBpdCBpcyBub3Qgd3JpdHRlbiB0byB0aGUgZGV2aWNlIG9iamVjdCBub3IgdGhlIHByb2ZpbGUuXG4gICAqL1xuICBvcHRPdXQ/OiBPcHRPdXQ7XG4gIC8qKlxuICAgKiBUaGUgQVVUSEVOVElDQVRFRCBjYWxsZXIncyBwcmlvciBHVUVTVFxuICAgKiBgY29nbml0b0lkZW50aXR5SWRgLiBXaGVuIHByZXNlbnQgb24gYW4gYXV0aGVkIGNhbGwsIHRoZSBoYW5kbGVyIGZvbGRzIHRoZVxuICAgKiBndWVzdCBwcm9maWxlIChrZXllZCBieSBgY29nbml0b0lkZW50aXR5S2V5ID0gdGhpcyB2YWx1ZWApIOKAlCBhbmQgaXRzIGRldmljZVxuICAgKiBvYmplY3RzIOKAlCBpbnRvIHRoZSByZXNvbHZlZCBhdXRoZWQgcHJvZmlsZSB2aWEgTWVyZ2VQcm9maWxlcy4gSWdub3JlZCBvblxuICAgKiBndWVzdCBjYWxscy4gVGhlIHZhbHVlIGlzIG9ubHkgYSBtZXJnZSBISU5UOiBpdCBjYW4gb25seSB0cmlnZ2VyIG1lcmdpbmcgYVxuICAgKiBndWVzdCBwcm9maWxlIGludG8gdGhlIGNhbGxlcidzIE9XTiB2ZXJpZmllZCBhdXRoZWQgcHJvZmlsZS5cbiAgICovXG4gIHByZXZpb3VzR3Vlc3RJZGVudGl0eUlkPzogc3RyaW5nO1xufTtcblxuZXhwb3J0IHR5cGUgSWRlbnRpZnlVc2VyUmVxdWVzdCA9IHtcbiAgLyoqXG4gICAqIENsaWVudC1zdXBwbGllZCBpZGVudGlmaWVyLiBTdG9yZWQgT05MWSBhcyB0aGUgYGFwcFVzZXJJZGAgYXR0cmlidXRlLlxuICAgKiBJdCBpcyBORVZFUiB1c2VkIGFzIHRoZSBwcm9maWxlIGlkZW50aXR5IGtleSDigJQgdGhlIGF1dGhvcml0YXRpdmUgaWRlbnRpdHlcbiAgICogaXMgdGhlIHZlcmlmaWVkIENvZ25pdG8gYHN1YmAgZnJvbSB0aGUgSldUIGF1dGhvcml6ZXIgY2xhaW1zLlxuICAgKi9cbiAgdXNlcklkPzogc3RyaW5nO1xuICB1c2VyUHJvZmlsZTogVXNlclByb2ZpbGU7XG4gIG9wdGlvbnM/OiBJZGVudGlmeVVzZXJPcHRpb25zO1xufTtcblxuZXhwb3J0IHR5cGUgU3VjY2Vzc1Jlc3BvbnNlID0ge1xuICBzdGF0dXM6ICdvayc7XG59O1xuXG5leHBvcnQgdHlwZSBFcnJvclJlc3BvbnNlID0ge1xuICBlcnJvcjogc3RyaW5nO1xufTtcbiJdfQ==
@@ -0,0 +1,15 @@
1
+ import { IdentifyUserRequest } from './types.js';
2
+ export type ValidationResult = {
3
+ ok: boolean;
4
+ error?: string;
5
+ value?: IdentifyUserRequest;
6
+ };
7
+ /**
8
+ * Validate the frozen identify-user request contract.
9
+ *
10
+ * Returns `{ ok: false, error }` on the first violation so the handler can map
11
+ * it to a 400. Identity is NOT validated here — the verified `sub` is supplied
12
+ * separately by the authorizer.
13
+ */
14
+ export declare const validateBody: (body: unknown) => ValidationResult;
15
+ //# sourceMappingURL=validation.d.ts.map