@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.
- package/README.md +235 -0
- package/lib/campaign-association-asset/index.js +48413 -0
- package/lib/constants.d.ts +122 -0
- package/lib/constants.js +125 -0
- package/lib/construct.d.ts +283 -0
- package/lib/construct.js +824 -0
- package/lib/factory.d.ts +53 -0
- package/lib/factory.js +158 -0
- package/lib/handler-asset/index.js +530 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +5 -0
- package/lib/lambda/campaign-association/handler.d.ts +29 -0
- package/lib/lambda/campaign-association/handler.js +80 -0
- package/lib/lambda/campaign-association/integration.d.ts +59 -0
- package/lib/lambda/campaign-association/integration.js +108 -0
- package/lib/lambda/campaign-association/onboarding.d.ts +25 -0
- package/lib/lambda/campaign-association/onboarding.js +74 -0
- package/lib/lambda/identify/device_resolver.d.ts +18 -0
- package/lib/lambda/identify/device_resolver.js +56 -0
- package/lib/lambda/identify/handler.d.ts +17 -0
- package/lib/lambda/identify/handler.js +124 -0
- package/lib/lambda/identify/mapping.d.ts +61 -0
- package/lib/lambda/identify/mapping.js +171 -0
- package/lib/lambda/identify/merge_resolver.d.ts +26 -0
- package/lib/lambda/identify/merge_resolver.js +36 -0
- package/lib/lambda/identify/principal.d.ts +68 -0
- package/lib/lambda/identify/principal.js +48 -0
- package/lib/lambda/identify/profile_resolver.d.ts +35 -0
- package/lib/lambda/identify/profile_resolver.js +65 -0
- package/lib/lambda/identify/types.d.ts +90 -0
- package/lib/lambda/identify/types.js +10 -0
- package/lib/lambda/identify/validation.d.ts +15 -0
- package/lib/lambda/identify/validation.js +99 -0
- package/lib/lambda/push/delivery.d.ts +49 -0
- package/lib/lambda/push/delivery.js +120 -0
- package/lib/lambda/push/device_lookup.d.ts +35 -0
- package/lib/lambda/push/device_lookup.js +88 -0
- package/lib/lambda/push/eum_client.d.ts +31 -0
- package/lib/lambda/push/eum_client.js +140 -0
- package/lib/lambda/push/event.d.ts +32 -0
- package/lib/lambda/push/event.js +122 -0
- package/lib/lambda/push/fixtures/real_journey_event.d.ts +19 -0
- package/lib/lambda/push/fixtures/real_journey_event.js +22 -0
- package/lib/lambda/push/handler.d.ts +15 -0
- package/lib/lambda/push/handler.js +86 -0
- package/lib/lambda/push/message_template.d.ts +72 -0
- package/lib/lambda/push/message_template.js +270 -0
- package/lib/lambda/push/payload.d.ts +25 -0
- package/lib/lambda/push/payload.js +53 -0
- package/lib/lambda/push/types.d.ts +153 -0
- package/lib/lambda/push/types.js +4 -0
- package/lib/lambda/shared/retry.d.ts +18 -0
- package/lib/lambda/shared/retry.js +45 -0
- package/lib/object_types.d.ts +63 -0
- package/lib/object_types.js +131 -0
- package/lib/push-handler-asset/index.js +75517 -0
- package/lib/types.d.ts +125 -0
- package/lib/types.js +2 -0
- package/package.json +49 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { IAMClient } from '@aws-sdk/client-iam';
|
|
2
|
+
import { ConnectCampaignsV2Client } from '@aws-sdk/client-connectcampaignsv2';
|
|
3
|
+
import { CustomerProfilesClient } from '@aws-sdk/client-customer-profiles';
|
|
4
|
+
/** Customer Profiles domain ARN for a domain name in the deploy account/region. */
|
|
5
|
+
export declare const domainArnOf: (account: string, region: string, domainName: string) => string;
|
|
6
|
+
/** connect-campaigns instance ARN used as the Customer Profiles integration Uri. */
|
|
7
|
+
export declare const campaignsInstanceArnOf: (account: string, region: string, connectInstanceId: string) => string;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the Outbound Campaigns service-linked role ARN
|
|
10
|
+
* (`AWSServiceRoleForConnectCampaigns_*`), which StartInstanceOnboardingJob
|
|
11
|
+
* auto-creates under `/aws-service-role/connect-campaigns.amazonaws.com/`. The
|
|
12
|
+
* newest role (last in the returned list) is used, matching the empirically
|
|
13
|
+
* verified recipe.
|
|
14
|
+
*/
|
|
15
|
+
export declare const resolveCampaignsServiceLinkedRoleArn: (iam: IAMClient) => Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Associate the (created) Customer Profiles domain with the Connect instance's
|
|
18
|
+
* Outbound Campaigns v2 so Connect Journeys can target the domain's profiles:
|
|
19
|
+
* 1. connectcampaignsv2:PutConnectInstanceIntegration — binds the domain ARN.
|
|
20
|
+
* 2. customer-profiles:PutIntegration — the reciprocal binding, using the
|
|
21
|
+
* campaigns service-linked role.
|
|
22
|
+
* Succeeds on an EMPTY domain: `objectTypeNames` is a label/routing map to
|
|
23
|
+
* BUILT-IN templates, so no object types need pre-creating.
|
|
24
|
+
*/
|
|
25
|
+
export declare const associateDomain: (clients: {
|
|
26
|
+
campaigns: ConnectCampaignsV2Client;
|
|
27
|
+
profiles: CustomerProfilesClient;
|
|
28
|
+
iam: IAMClient;
|
|
29
|
+
}, args: {
|
|
30
|
+
connectInstanceId: string;
|
|
31
|
+
domainName: string;
|
|
32
|
+
roleArn: string;
|
|
33
|
+
account: string;
|
|
34
|
+
region: string;
|
|
35
|
+
}) => Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Best-effort reverse of {@link associateDomain} on stack teardown. Each step is
|
|
38
|
+
* idempotent and swallows errors (logged) so a missing / already-removed
|
|
39
|
+
* integration — e.g. when CloudFormation deleted the parent instance / domain
|
|
40
|
+
* FIRST — NEVER fails teardown. Reverses everything onCreate did:
|
|
41
|
+
* 1. connectcampaignsv2:DeleteConnectInstanceIntegration (campaigns -> domain)
|
|
42
|
+
* 2. customer-profiles:DeleteIntegration (domain -> campaigns)
|
|
43
|
+
* 3. connectcampaignsv2:DeleteInstanceOnboardingJob (offboard from Campaigns v2)
|
|
44
|
+
*
|
|
45
|
+
* The `AWSServiceRoleForConnectCampaigns_*` service-linked role is deliberately
|
|
46
|
+
* NOT deleted: it is account-wide, shared across ALL Connect instances /
|
|
47
|
+
* campaigns in the account, free, and harmless — deleting it could break other
|
|
48
|
+
* instances still onboarded to Outbound Campaigns.
|
|
49
|
+
*/
|
|
50
|
+
export declare const disassociateDomain: (clients: {
|
|
51
|
+
campaigns: ConnectCampaignsV2Client;
|
|
52
|
+
profiles: CustomerProfilesClient;
|
|
53
|
+
}, args: {
|
|
54
|
+
connectInstanceId: string;
|
|
55
|
+
domainName: string;
|
|
56
|
+
account: string;
|
|
57
|
+
region: string;
|
|
58
|
+
}) => Promise<void>;
|
|
59
|
+
//# sourceMappingURL=integration.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { ListRolesCommand } from '@aws-sdk/client-iam';
|
|
4
|
+
import { DeleteConnectInstanceIntegrationCommand, DeleteInstanceOnboardingJobCommand, PutConnectInstanceIntegrationCommand, } from '@aws-sdk/client-connectcampaignsv2';
|
|
5
|
+
import { DeleteIntegrationCommand, PutIntegrationCommand, } from '@aws-sdk/client-customer-profiles';
|
|
6
|
+
import { CAMPAIGN_OBJECT_TYPE_NAMES, CONNECT_CAMPAIGNS_SLR_PATH_PREFIX, } from '../../constants.js';
|
|
7
|
+
/** Object-type routing map supplied to both integration calls. */
|
|
8
|
+
const objectTypeNames = { ...CAMPAIGN_OBJECT_TYPE_NAMES };
|
|
9
|
+
/** Customer Profiles domain ARN for a domain name in the deploy account/region. */
|
|
10
|
+
export const domainArnOf = (account, region, domainName) => `arn:aws:profile:${region}:${account}:domains/${domainName}`;
|
|
11
|
+
/** connect-campaigns instance ARN used as the Customer Profiles integration Uri. */
|
|
12
|
+
export const campaignsInstanceArnOf = (account, region, connectInstanceId) => `arn:aws:connect-campaigns:${region}:${account}:instance/${connectInstanceId}`;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the Outbound Campaigns service-linked role ARN
|
|
15
|
+
* (`AWSServiceRoleForConnectCampaigns_*`), which StartInstanceOnboardingJob
|
|
16
|
+
* auto-creates under `/aws-service-role/connect-campaigns.amazonaws.com/`. The
|
|
17
|
+
* newest role (last in the returned list) is used, matching the empirically
|
|
18
|
+
* verified recipe.
|
|
19
|
+
*/
|
|
20
|
+
export const resolveCampaignsServiceLinkedRoleArn = async (iam) => {
|
|
21
|
+
const { Roles: roles } = await iam.send(new ListRolesCommand({ PathPrefix: CONNECT_CAMPAIGNS_SLR_PATH_PREFIX }));
|
|
22
|
+
const arn = roles?.[roles.length - 1]?.Arn;
|
|
23
|
+
if (!arn) {
|
|
24
|
+
throw new Error('Outbound Campaigns service-linked role not found after onboarding');
|
|
25
|
+
}
|
|
26
|
+
return arn;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Associate the (created) Customer Profiles domain with the Connect instance's
|
|
30
|
+
* Outbound Campaigns v2 so Connect Journeys can target the domain's profiles:
|
|
31
|
+
* 1. connectcampaignsv2:PutConnectInstanceIntegration — binds the domain ARN.
|
|
32
|
+
* 2. customer-profiles:PutIntegration — the reciprocal binding, using the
|
|
33
|
+
* campaigns service-linked role.
|
|
34
|
+
* Succeeds on an EMPTY domain: `objectTypeNames` is a label/routing map to
|
|
35
|
+
* BUILT-IN templates, so no object types need pre-creating.
|
|
36
|
+
*/
|
|
37
|
+
export const associateDomain = async (clients, args) => {
|
|
38
|
+
const { campaigns, profiles } = clients;
|
|
39
|
+
const { connectInstanceId, domainName, roleArn, account, region } = args;
|
|
40
|
+
const domainArn = domainArnOf(account, region, domainName);
|
|
41
|
+
await campaigns.send(new PutConnectInstanceIntegrationCommand({
|
|
42
|
+
connectInstanceId,
|
|
43
|
+
integrationConfig: {
|
|
44
|
+
customerProfiles: { domainArn, objectTypeNames },
|
|
45
|
+
},
|
|
46
|
+
}));
|
|
47
|
+
console.log('[campaign-assoc] connect instance integration created', {
|
|
48
|
+
connectInstanceId,
|
|
49
|
+
domainArn,
|
|
50
|
+
});
|
|
51
|
+
await profiles.send(new PutIntegrationCommand({
|
|
52
|
+
DomainName: domainName,
|
|
53
|
+
Uri: campaignsInstanceArnOf(account, region, connectInstanceId),
|
|
54
|
+
ObjectTypeNames: objectTypeNames,
|
|
55
|
+
RoleArn: roleArn,
|
|
56
|
+
}));
|
|
57
|
+
console.log('[campaign-assoc] customer profiles integration created', {
|
|
58
|
+
domainName,
|
|
59
|
+
connectInstanceId,
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Best-effort reverse of {@link associateDomain} on stack teardown. Each step is
|
|
64
|
+
* idempotent and swallows errors (logged) so a missing / already-removed
|
|
65
|
+
* integration — e.g. when CloudFormation deleted the parent instance / domain
|
|
66
|
+
* FIRST — NEVER fails teardown. Reverses everything onCreate did:
|
|
67
|
+
* 1. connectcampaignsv2:DeleteConnectInstanceIntegration (campaigns -> domain)
|
|
68
|
+
* 2. customer-profiles:DeleteIntegration (domain -> campaigns)
|
|
69
|
+
* 3. connectcampaignsv2:DeleteInstanceOnboardingJob (offboard from Campaigns v2)
|
|
70
|
+
*
|
|
71
|
+
* The `AWSServiceRoleForConnectCampaigns_*` service-linked role is deliberately
|
|
72
|
+
* NOT deleted: it is account-wide, shared across ALL Connect instances /
|
|
73
|
+
* campaigns in the account, free, and harmless — deleting it could break other
|
|
74
|
+
* instances still onboarded to Outbound Campaigns.
|
|
75
|
+
*/
|
|
76
|
+
export const disassociateDomain = async (clients, args) => {
|
|
77
|
+
const { campaigns, profiles } = clients;
|
|
78
|
+
const { connectInstanceId, domainName, account, region } = args;
|
|
79
|
+
await bestEffort('connect instance integration delete', () => campaigns.send(new DeleteConnectInstanceIntegrationCommand({
|
|
80
|
+
connectInstanceId,
|
|
81
|
+
integrationIdentifier: {
|
|
82
|
+
customerProfiles: {
|
|
83
|
+
domainArn: domainArnOf(account, region, domainName),
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
})));
|
|
87
|
+
await bestEffort('customer profiles integration delete', () => profiles.send(new DeleteIntegrationCommand({
|
|
88
|
+
DomainName: domainName,
|
|
89
|
+
Uri: campaignsInstanceArnOf(account, region, connectInstanceId),
|
|
90
|
+
})));
|
|
91
|
+
await bestEffort('instance offboarding', () => campaigns.send(new DeleteInstanceOnboardingJobCommand({ connectInstanceId })));
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Run a teardown step, swallowing (and logging) any error so a partial /
|
|
95
|
+
* already-removed resource never fails CloudFormation teardown.
|
|
96
|
+
*/
|
|
97
|
+
const bestEffort = async (label, fn) => {
|
|
98
|
+
try {
|
|
99
|
+
await fn();
|
|
100
|
+
console.log(`[campaign-assoc] ${label} ok`);
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
console.warn(`[campaign-assoc] ${label} skipped`, {
|
|
104
|
+
error: err?.name ?? 'unknown',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZWdyYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGFtYmRhL2NhbXBhaWduLWFzc29jaWF0aW9uL2ludGVncmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHFFQUFxRTtBQUNyRSxzQ0FBc0M7QUFFdEMsT0FBTyxFQUFhLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDbEUsT0FBTyxFQUVMLHVDQUF1QyxFQUN2QyxrQ0FBa0MsRUFDbEMsb0NBQW9DLEdBQ3JDLE1BQU0sb0NBQW9DLENBQUM7QUFDNUMsT0FBTyxFQUVMLHdCQUF3QixFQUN4QixxQkFBcUIsR0FDdEIsTUFBTSxtQ0FBbUMsQ0FBQztBQUUzQyxPQUFPLEVBQ0wsMEJBQTBCLEVBQzFCLGlDQUFpQyxHQUNsQyxNQUFNLG9CQUFvQixDQUFDO0FBRTVCLGtFQUFrRTtBQUNsRSxNQUFNLGVBQWUsR0FBRyxFQUFFLEdBQUcsMEJBQTBCLEVBQUUsQ0FBQztBQUUxRCxtRkFBbUY7QUFDbkYsTUFBTSxDQUFDLE1BQU0sV0FBVyxHQUFHLENBQ3pCLE9BQWUsRUFDZixNQUFjLEVBQ2QsVUFBa0IsRUFDVixFQUFFLENBQUMsbUJBQW1CLE1BQU0sSUFBSSxPQUFPLFlBQVksVUFBVSxFQUFFLENBQUM7QUFFMUUsb0ZBQW9GO0FBQ3BGLE1BQU0sQ0FBQyxNQUFNLHNCQUFzQixHQUFHLENBQ3BDLE9BQWUsRUFDZixNQUFjLEVBQ2QsaUJBQXlCLEVBQ2pCLEVBQUUsQ0FDViw2QkFBNkIsTUFBTSxJQUFJLE9BQU8sYUFBYSxpQkFBaUIsRUFBRSxDQUFDO0FBRWpGOzs7Ozs7R0FNRztBQUNILE1BQU0sQ0FBQyxNQUFNLG9DQUFvQyxHQUFHLEtBQUssRUFDdkQsR0FBYyxFQUNHLEVBQUU7SUFDbkIsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsR0FBRyxNQUFNLEdBQUcsQ0FBQyxJQUFJLENBQ3JDLElBQUksZ0JBQWdCLENBQUMsRUFB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QztBQUVGOzs7R0FHRztBQUNILE1BQU0sVUFBVSxHQUFHLEtBQUssRUFDdEIsS0FBYSxFQUNiLEVBQTBCLEVBQ1gsRUFBRTtJQUNqQixJQUFJLENBQUM7UUFDSCxNQUFNLEVBQUUsRUFBRSxDQUFDO1FBQ1gsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsS0FBSyxLQUFLLENBQUMsQ0FBQztJQUM5QyxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLEtBQUssVUFBVSxFQUFFO1lBQ2hELEtBQUssRUFBRyxHQUF5QixFQUFFLElBQUksSUFBSSxTQUFTO1NBQ3JELENBQUMsQ0FBQztJQUNMLENBQUM7QUFDSCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCB7IElBTUNsaWVudCwgTGlzdFJvbGVzQ29tbWFuZCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1pYW0nO1xuaW1wb3J0IHtcbiAgQ29ubmVjdENhbXBhaWduc1YyQ2xpZW50LFxuICBEZWxldGVDb25uZWN0SW5zdGFuY2VJbnRlZ3JhdGlvbkNvbW1hbmQsXG4gIERlbGV0ZUluc3RhbmNlT25ib2FyZGluZ0pvYkNvbW1hbmQsXG4gIFB1dENvbm5lY3RJbnN0YW5jZUludGVncmF0aW9uQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNvbm5lY3RjYW1wYWlnbnN2Mic7XG5pbXBvcnQge1xuICBDdXN0b21lclByb2ZpbGVzQ2xpZW50LFxuICBEZWxldGVJbnRlZ3JhdGlvbkNvbW1hbmQsXG4gIFB1dEludGVncmF0aW9uQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWN1c3RvbWVyLXByb2ZpbGVzJztcblxuaW1wb3J0IHtcbiAgQ0FNUEFJR05fT0JKRUNUX1RZUEVfTkFNRVMsXG4gIENPTk5FQ1RfQ0FNUEFJR05TX1NMUl9QQVRIX1BSRUZJWCxcbn0gZnJvbSAnLi4vLi4vY29uc3RhbnRzLmpzJztcblxuLyoqIE9iamVjdC10eXBlIHJvdXRpbmcgbWFwIHN1cHBsaWVkIHRvIGJvdGggaW50ZWdyYXRpb24gY2FsbHMuICovXG5jb25zdCBvYmplY3RUeXBlTmFtZXMgPSB7IC4uLkNBTVBBSUdOX09CSkVDVF9UWVBFX05BTUVTIH07XG5cbi8qKiBDdXN0b21lciBQcm9maWxlcyBkb21haW4gQVJOIGZvciBhIGRvbWFpbiBuYW1lIGluIHRoZSBkZXBsb3kgYWNjb3VudC9yZWdpb24uICovXG5leHBvcnQgY29uc3QgZG9tYWluQXJuT2YgPSAoXG4gIGFjY291bnQ6IHN0cmluZyxcbiAgcmVnaW9uOiBzdHJpbmcsXG4gIGRvbWFpbk5hbWU6IHN0cmluZyxcbik6IHN0cmluZyA9PiBgYXJuOmF3czpwcm9maWxlOiR7cmVnaW9ufToke2FjY291bnR9OmRvbWFpbnMvJHtkb21haW5OYW1lfWA7XG5cbi8qKiBjb25uZWN0LWNhbXBhaWducyBpbnN0YW5jZSBBUk4gdXNlZCBhcyB0aGUgQ3VzdG9tZXIgUHJvZmlsZXMgaW50ZWdyYXRpb24gVXJpLiAqL1xuZXhwb3J0IGNvbnN0IGNhbXBhaWduc0luc3RhbmNlQXJuT2YgPSAoXG4gIGFjY291bnQ6IHN0cmluZyxcbiAgcmVnaW9uOiBzdHJpbmcsXG4gIGNvbm5lY3RJbnN0YW5jZUlkOiBzdHJpbmcsXG4pOiBzdHJpbmcgPT5cbiAgYGFybjphd3M6Y29ubmVjdC1jYW1wYWlnbnM6JHtyZWdpb259OiR7YWNjb3VudH06aW5zdGFuY2UvJHtjb25uZWN0SW5zdGFuY2VJZH1gO1xuXG4vKipcbiAqIFJlc29sdmUgdGhlIE91dGJvdW5kIENhbXBhaWducyBzZXJ2aWNlLWxpbmtlZCByb2xlIEFSTlxuICogKGBBV1NTZXJ2aWNlUm9sZUZvckNvbm5lY3RDYW1wYWlnbnNfKmApLCB3aGljaCBTdGFydEluc3RhbmNlT25ib2FyZGluZ0pvYlxuICogYXV0by1jcmVhdGVzIHVuZGVyIGAvYXdzLXNlcnZpY2Utcm9sZS9jb25uZWN0LWNhbXBhaWducy5hbWF6b25hd3MuY29tL2AuIFRoZVxuICogbmV3ZXN0IHJvbGUgKGxhc3QgaW4gdGhlIHJldHVybmVkIGxpc3QpIGlzIHVzZWQsIG1hdGNoaW5nIHRoZSBlbXBpcmljYWxseVxuICogdmVyaWZpZWQgcmVjaXBlLlxuICovXG5leHBvcnQgY29uc3QgcmVzb2x2ZUNhbXBhaWduc1NlcnZpY2VMaW5rZWRSb2xlQXJuID0gYXN5bmMgKFxuICBpYW06IElBTUNsaWVudCxcbik6IFByb21pc2U8c3RyaW5nPiA9PiB7XG4gIGNvbnN0IHsgUm9sZXM6IHJvbGVzIH0gPSBhd2FpdCBpYW0uc2VuZChcbiAgICBuZXcgTGlzdFJvbGVzQ29tbWFuZCh7IFBhdGhQcmVmaXg6IENPTk5FQ1RfQ0FNUEFJR05TX1NMUl9QQVRIX1BSRUZJWCB9KSxcbiAgKTtcbiAgY29uc3QgYXJuID0gcm9sZXM/Lltyb2xlcy5sZW5ndGggLSAxXT8uQXJuO1xuICBpZiAoIWFybikge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdPdXRib3VuZCBDYW1wYWlnbnMgc2VydmljZS1saW5rZWQgcm9sZSBub3QgZm91bmQgYWZ0ZXIgb25ib2FyZGluZycsXG4gICAgKTtcbiAgfVxuICByZXR1cm4gYXJuO1xufTtcblxuLyoqXG4gKiBBc3NvY2lhdGUgdGhlIChjcmVhdGVkKSBDdXN0b21lciBQcm9maWxlcyBkb21haW4gd2l0aCB0aGUgQ29ubmVjdCBpbnN0YW5jZSdzXG4gKiBPdXRib3VuZCBDYW1wYWlnbnMgdjIgc28gQ29ubmVjdCBKb3VybmV5cyBjYW4gdGFyZ2V0IHRoZSBkb21haW4ncyBwcm9maWxlczpcbiAqICAgMS4gY29ubmVjdGNhbXBhaWduc3YyOlB1dENvbm5lY3RJbnN0YW5jZUludGVncmF0aW9uIOKAlCBiaW5kcyB0aGUgZG9tYWluIEFSTi5cbiAqICAgMi4gY3VzdG9tZXItcHJvZmlsZXM6UHV0SW50ZWdyYXRpb24g4oCUIHRoZSByZWNpcHJvY2FsIGJpbmRpbmcsIHVzaW5nIHRoZVxuICogICAgICBjYW1wYWlnbnMgc2VydmljZS1saW5rZWQgcm9sZS5cbiAqIFN1Y2NlZWRzIG9uIGFuIEVNUFRZIGRvbWFpbjogYG9iamVjdFR5cGVOYW1lc2AgaXMgYSBsYWJlbC9yb3V0aW5nIG1hcCB0b1xuICogQlVJTFQtSU4gdGVtcGxhdGVzLCBzbyBubyBvYmplY3QgdHlwZXMgbmVlZCBwcmUtY3JlYXRpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBhc3NvY2lhdGVEb21haW4gPSBhc3luYyAoXG4gIGNsaWVudHM6IHtcbiAgICBjYW1wYWlnbnM6IENvbm5lY3RDYW1wYWlnbnNWMkNsaWVudDtcbiAgICBwcm9maWxlczogQ3VzdG9tZXJQcm9maWxlc0NsaWVudDtcbiAgICBpYW06IElBTUNsaWVudDtcbiAgfSxcbiAgYXJnczoge1xuICAgIGNvbm5lY3RJbnN0YW5jZUlkOiBzdHJpbmc7XG4gICAgZG9tYWluTmFtZTogc3RyaW5nO1xuICAgIHJvbGVBcm46IHN0cmluZztcbiAgICBhY2NvdW50OiBzdHJpbmc7XG4gICAgcmVnaW9uOiBzdHJpbmc7XG4gIH0sXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcbiAgY29uc3QgeyBjYW1wYWlnbnMsIHByb2ZpbGVzIH0gPSBjbGllbnRzO1xuICBjb25zdCB7IGNvbm5lY3RJbnN0YW5jZUlkLCBkb21haW5OYW1lLCByb2xlQXJuLCBhY2NvdW50LCByZWdpb24gfSA9IGFyZ3M7XG4gIGNvbnN0IGRvbWFpbkFybiA9IGRvbWFpbkFybk9mKGFjY291bnQsIHJlZ2lvbiwgZG9tYWluTmFtZSk7XG5cbiAgYXdhaXQgY2FtcGFpZ25zLnNlbmQoXG4gICAgbmV3IFB1dENvbm5lY3RJbnN0YW5jZUludGVncmF0aW9uQ29tbWFuZCh7XG4gICAgICBjb25uZWN0SW5zdGFuY2VJZCxcbiAgICAgIGludGVncmF0aW9uQ29uZmlnOiB7XG4gICAgICAgIGN1c3RvbWVyUHJvZmlsZXM6IHsgZG9tYWluQXJuLCBvYmplY3RUeXBlTmFtZXMgfSxcbiAgICAgIH0sXG4gICAgfSksXG4gICk7XG4gIGNvbnNvbGUubG9nKCdbY2FtcGFpZ24tYXNzb2NdIGNvbm5lY3QgaW5zdGFuY2UgaW50ZWdyYXRpb24gY3JlYXRlZCcsIHtcbiAgICBjb25uZWN0SW5zdGFuY2VJZCxcbiAgICBkb21haW5Bcm4sXG4gIH0pO1xuXG4gIGF3YWl0IHByb2ZpbGVzLnNlbmQoXG4gICAgbmV3IFB1dEludGVncmF0aW9uQ29tbWFuZCh7XG4gICAgICBEb21haW5OYW1lOiBkb21haW5OYW1lLFxuICAgICAgVXJpOiBjYW1wYWlnbnNJbnN0YW5jZUFybk9mKGFjY291bnQsIHJlZ2lvbiwgY29ubmVjdEluc3RhbmNlSWQpLFxuICAgICAgT2JqZWN0VHlwZU5hbWVzOiBvYmplY3RUeXBlTmFtZXMsXG4gICAgICBSb2xlQXJuOiByb2xlQXJuLFxuICAgIH0pLFxuICApO1xuICBjb25zb2xlLmxvZygnW2NhbXBhaWduLWFzc29jXSBjdXN0b21lciBwcm9maWxlcyBpbnRlZ3JhdGlvbiBjcmVhdGVkJywge1xuICAgIGRvbWFpbk5hbWUsXG4gICAgY29ubmVjdEluc3RhbmNlSWQsXG4gIH0pO1xufTtcblxuLyoqXG4gKiBCZXN0LWVmZm9ydCByZXZlcnNlIG9mIHtAbGluayBhc3NvY2lhdGVEb21haW59IG9uIHN0YWNrIHRlYXJkb3duLiBFYWNoIHN0ZXAgaXNcbiAqIGlkZW1wb3RlbnQgYW5kIHN3YWxsb3dzIGVycm9ycyAobG9nZ2VkKSBzbyBhIG1pc3NpbmcgLyBhbHJlYWR5LXJlbW92ZWRcbiAqIGludGVncmF0aW9uIOKAlCBlLmcuIHdoZW4gQ2xvdWRGb3JtYXRpb24gZGVsZXRlZCB0aGUgcGFyZW50IGluc3RhbmNlIC8gZG9tYWluXG4gKiBGSVJTVCDigJQgTkVWRVIgZmFpbHMgdGVhcmRvd24uIFJldmVyc2VzIGV2ZXJ5dGhpbmcgb25DcmVhdGUgZGlkOlxuICogICAxLiBjb25uZWN0Y2FtcGFpZ25zdjI6RGVsZXRlQ29ubmVjdEluc3RhbmNlSW50ZWdyYXRpb24gKGNhbXBhaWducyAtPiBkb21haW4pXG4gKiAgIDIuIGN1c3RvbWVyLXByb2ZpbGVzOkRlbGV0ZUludGVncmF0aW9uIChkb21haW4gLT4gY2FtcGFpZ25zKVxuICogICAzLiBjb25uZWN0Y2FtcGFpZ25zdjI6RGVsZXRlSW5zdGFuY2VPbmJvYXJkaW5nSm9iIChvZmZib2FyZCBmcm9tIENhbXBhaWducyB2MilcbiAqXG4gKiBUaGUgYEFXU1NlcnZpY2VSb2xlRm9yQ29ubmVjdENhbXBhaWduc18qYCBzZXJ2aWNlLWxpbmtlZCByb2xlIGlzIGRlbGliZXJhdGVseVxuICogTk9UIGRlbGV0ZWQ6IGl0IGlzIGFjY291bnQtd2lkZSwgc2hhcmVkIGFjcm9zcyBBTEwgQ29ubmVjdCBpbnN0YW5jZXMgL1xuICogY2FtcGFpZ25zIGluIHRoZSBhY2NvdW50LCBmcmVlLCBhbmQgaGFybWxlc3Mg4oCUIGRlbGV0aW5nIGl0IGNvdWxkIGJyZWFrIG90aGVyXG4gKiBpbnN0YW5jZXMgc3RpbGwgb25ib2FyZGVkIHRvIE91dGJvdW5kIENhbXBhaWducy5cbiAqL1xuZXhwb3J0IGNvbnN0IGRpc2Fzc29jaWF0ZURvbWFpbiA9IGFzeW5jIChcbiAgY2xpZW50czoge1xuICAgIGNhbXBhaWduczogQ29ubmVjdENhbXBhaWduc1YyQ2xpZW50O1xuICAgIHByb2ZpbGVzOiBDdXN0b21lclByb2ZpbGVzQ2xpZW50O1xuICB9LFxuICBhcmdzOiB7XG4gICAgY29ubmVjdEluc3RhbmNlSWQ6IHN0cmluZztcbiAgICBkb21haW5OYW1lOiBzdHJpbmc7XG4gICAgYWNjb3VudDogc3RyaW5nO1xuICAgIHJlZ2lvbjogc3RyaW5nO1xuICB9LFxuKTogUHJvbWlzZTx2b2lkPiA9PiB7XG4gIGNvbnN0IHsgY2FtcGFpZ25zLCBwcm9maWxlcyB9ID0gY2xpZW50cztcbiAgY29uc3QgeyBjb25uZWN0SW5zdGFuY2VJZCwgZG9tYWluTmFtZSwgYWNjb3VudCwgcmVnaW9uIH0gPSBhcmdzO1xuXG4gIGF3YWl0IGJlc3RFZmZvcnQoJ2Nvbm5lY3QgaW5zdGFuY2UgaW50ZWdyYXRpb24gZGVsZXRlJywgKCkgPT5cbiAgICBjYW1wYWlnbnMuc2VuZChcbiAgICAgIG5ldyBEZWxldGVDb25uZWN0SW5zdGFuY2VJbnRlZ3JhdGlvbkNvbW1hbmQoe1xuICAgICAgICBjb25uZWN0SW5zdGFuY2VJZCxcbiAgICAgICAgaW50ZWdyYXRpb25JZGVudGlmaWVyOiB7XG4gICAgICAgICAgY3VzdG9tZXJQcm9maWxlczoge1xuICAgICAgICAgICAgZG9tYWluQXJuOiBkb21haW5Bcm5PZihhY2NvdW50LCByZWdpb24sIGRvbWFpbk5hbWUpLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICApLFxuICApO1xuXG4gIGF3YWl0IGJlc3RFZmZvcnQoJ2N1c3RvbWVyIHByb2ZpbGVzIGludGVncmF0aW9uIGRlbGV0ZScsICgpID0+XG4gICAgcHJvZmlsZXMuc2VuZChcbiAgICAgIG5ldyBEZWxldGVJbnRlZ3JhdGlvbkNvbW1hbmQoe1xuICAgICAgICBEb21haW5OYW1lOiBkb21haW5OYW1lLFxuICAgICAgICBVcmk6IGNhbXBhaWduc0luc3RhbmNlQXJuT2YoYWNjb3VudCwgcmVnaW9uLCBjb25uZWN0SW5zdGFuY2VJZCksXG4gICAgICB9KSxcbiAgICApLFxuICApO1xuXG4gIGF3YWl0IGJlc3RFZmZvcnQoJ2luc3RhbmNlIG9mZmJvYXJkaW5nJywgKCkgPT5cbiAgICBjYW1wYWlnbnMuc2VuZChcbiAgICAgIG5ldyBEZWxldGVJbnN0YW5jZU9uYm9hcmRpbmdKb2JDb21tYW5kKHsgY29ubmVjdEluc3RhbmNlSWQgfSksXG4gICAgKSxcbiAgKTtcbn07XG5cbi8qKlxuICogUnVuIGEgdGVhcmRvd24gc3RlcCwgc3dhbGxvd2luZyAoYW5kIGxvZ2dpbmcpIGFueSBlcnJvciBzbyBhIHBhcnRpYWwgL1xuICogYWxyZWFkeS1yZW1vdmVkIHJlc291cmNlIG5ldmVyIGZhaWxzIENsb3VkRm9ybWF0aW9uIHRlYXJkb3duLlxuICovXG5jb25zdCBiZXN0RWZmb3J0ID0gYXN5bmMgKFxuICBsYWJlbDogc3RyaW5nLFxuICBmbjogKCkgPT4gUHJvbWlzZTx1bmtub3duPixcbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICB0cnkge1xuICAgIGF3YWl0IGZuKCk7XG4gICAgY29uc29sZS5sb2coYFtjYW1wYWlnbi1hc3NvY10gJHtsYWJlbH0gb2tgKTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS53YXJuKGBbY2FtcGFpZ24tYXNzb2NdICR7bGFiZWx9IHNraXBwZWRgLCB7XG4gICAgICBlcnJvcjogKGVyciBhcyB7IG5hbWU/OiBzdHJpbmcgfSk/Lm5hbWUgPz8gJ3Vua25vd24nLFxuICAgIH0pO1xuICB9XG59O1xuIl19
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ConnectCampaignsV2Client } from '@aws-sdk/client-connectcampaignsv2';
|
|
2
|
+
/**
|
|
3
|
+
* Onboard an Amazon Connect instance to Outbound Campaigns v2 and wait until the
|
|
4
|
+
* onboarding job reaches SUCCEEDED.
|
|
5
|
+
*
|
|
6
|
+
* StartInstanceOnboardingJob (with encryption disabled) auto-creates the
|
|
7
|
+
* `AWSServiceRoleForConnectCampaigns_*` service-linked role, then the job runs
|
|
8
|
+
* asynchronously (~20s). We poll GetInstanceOnboardingJobStatus with bounded,
|
|
9
|
+
* exponentially-backed-off retries (capped ~2min) until it SUCCEEDS.
|
|
10
|
+
*
|
|
11
|
+
* Idempotent: if the instance is already onboarded (StartInstanceOnboardingJob
|
|
12
|
+
* conflicts or the status is already SUCCEEDED / absent), this resolves without
|
|
13
|
+
* error. Throws only on an explicit FAILED status or if the job never succeeds
|
|
14
|
+
* within the polling budget.
|
|
15
|
+
*/
|
|
16
|
+
export declare const ensureInstanceOnboarded: (client: ConnectCampaignsV2Client, opts: {
|
|
17
|
+
connectInstanceId: string;
|
|
18
|
+
/** Injected in tests to avoid real delays. Defaults to real setTimeout. */
|
|
19
|
+
sleepFn?: (ms: number) => Promise<void>;
|
|
20
|
+
/** Max polling attempts. Default 24 (~2min with capped backoff). */
|
|
21
|
+
maxAttempts?: number;
|
|
22
|
+
/** Base backoff in ms. Default 2000. */
|
|
23
|
+
baseDelayMs?: number;
|
|
24
|
+
}) => Promise<void>;
|
|
25
|
+
//# sourceMappingURL=onboarding.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { GetInstanceOnboardingJobStatusCommand, StartInstanceOnboardingJobCommand, } from '@aws-sdk/client-connectcampaignsv2';
|
|
4
|
+
/** Terminal + in-flight onboarding job statuses reported by the service. */
|
|
5
|
+
const STATUS_SUCCEEDED = 'SUCCEEDED';
|
|
6
|
+
const STATUS_FAILED = 'FAILED';
|
|
7
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8
|
+
/**
|
|
9
|
+
* Names that, when thrown by StartInstanceOnboardingJob, indicate the instance
|
|
10
|
+
* is ALREADY onboarded to Outbound Campaigns v2. Treated as success so the
|
|
11
|
+
* custom resource is idempotent across stack updates / retried deployments.
|
|
12
|
+
*/
|
|
13
|
+
const isAlreadyOnboardedError = (err) => {
|
|
14
|
+
const name = err?.name ?? '';
|
|
15
|
+
return name === 'ConflictException' || name === 'ResourceConflictException';
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Onboard an Amazon Connect instance to Outbound Campaigns v2 and wait until the
|
|
19
|
+
* onboarding job reaches SUCCEEDED.
|
|
20
|
+
*
|
|
21
|
+
* StartInstanceOnboardingJob (with encryption disabled) auto-creates the
|
|
22
|
+
* `AWSServiceRoleForConnectCampaigns_*` service-linked role, then the job runs
|
|
23
|
+
* asynchronously (~20s). We poll GetInstanceOnboardingJobStatus with bounded,
|
|
24
|
+
* exponentially-backed-off retries (capped ~2min) until it SUCCEEDS.
|
|
25
|
+
*
|
|
26
|
+
* Idempotent: if the instance is already onboarded (StartInstanceOnboardingJob
|
|
27
|
+
* conflicts or the status is already SUCCEEDED / absent), this resolves without
|
|
28
|
+
* error. Throws only on an explicit FAILED status or if the job never succeeds
|
|
29
|
+
* within the polling budget.
|
|
30
|
+
*/
|
|
31
|
+
export const ensureInstanceOnboarded = async (client, opts) => {
|
|
32
|
+
const { connectInstanceId, sleepFn = sleep, maxAttempts = 24, baseDelayMs = 2000, } = opts;
|
|
33
|
+
try {
|
|
34
|
+
await client.send(new StartInstanceOnboardingJobCommand({
|
|
35
|
+
connectInstanceId,
|
|
36
|
+
encryptionConfig: { enabled: false },
|
|
37
|
+
}));
|
|
38
|
+
console.log('[campaign-assoc] onboarding job started', {
|
|
39
|
+
connectInstanceId,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
if (isAlreadyOnboardedError(err)) {
|
|
44
|
+
console.log('[campaign-assoc] instance already onboarded (start conflict)', {
|
|
45
|
+
connectInstanceId,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
52
|
+
const { connectInstanceOnboardingJobStatus } = await client.send(new GetInstanceOnboardingJobStatusCommand({ connectInstanceId }));
|
|
53
|
+
const status = connectInstanceOnboardingJobStatus?.status;
|
|
54
|
+
const failureCode = connectInstanceOnboardingJobStatus?.failureCode;
|
|
55
|
+
console.log('[campaign-assoc] onboarding status', {
|
|
56
|
+
connectInstanceId,
|
|
57
|
+
status: status ?? 'NONE',
|
|
58
|
+
failureCode: failureCode ?? 'NONE',
|
|
59
|
+
attempt,
|
|
60
|
+
});
|
|
61
|
+
if (status === STATUS_SUCCEEDED || status === undefined) {
|
|
62
|
+
// SUCCEEDED, or no job present (already-onboarded steady state).
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (status === STATUS_FAILED) {
|
|
66
|
+
throw new Error(`Instance onboarding to Outbound Campaigns FAILED for ${connectInstanceId}` +
|
|
67
|
+
(failureCode ? ` (failureCode: ${failureCode})` : ''));
|
|
68
|
+
}
|
|
69
|
+
const delay = Math.min(baseDelayMs * 2 ** attempt, 10000);
|
|
70
|
+
await sleepFn(delay);
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Instance onboarding did not reach SUCCEEDED within the polling budget for ${connectInstanceId}`);
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib25ib2FyZGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvY2FtcGFpZ24tYXNzb2NpYXRpb24vb25ib2FyZGluZy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxxRUFBcUU7QUFDckUsc0NBQXNDO0FBRXRDLE9BQU8sRUFFTCxxQ0FBcUMsRUFDckMsaUNBQWlDLEdBQ2xDLE1BQU0sb0NBQW9DLENBQUM7QUFFNUMsNEVBQTRFO0FBQzVFLE1BQU0sZ0JBQWdCLEdBQUcsV0FBVyxDQUFDO0FBQ3JDLE1BQU0sYUFBYSxHQUFHLFFBQVEsQ0FBQztBQUUvQixNQUFNLEtBQUssR0FBRyxDQUFDLEVBQVUsRUFBaUIsRUFBRSxDQUMxQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBRXBEOzs7O0dBSUc7QUFDSCxNQUFNLHVCQUF1QixHQUFHLENBQUMsR0FBWSxFQUFXLEVBQUU7SUFDeEQsTUFBTSxJQUFJLEdBQUksR0FBeUIsRUFBRSxJQUFJLElBQUksRUFBRSxDQUFDO0lBQ3BELE9BQU8sSUFBSSxLQUFLLG1CQUFtQixJQUFJLElBQUksS0FBSywyQkFBMkIsQ0FBQztBQUM5RSxDQUFDLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7OztHQWFHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsS0FBSyxFQUMxQyxNQUFnQyxFQUNoQyxJQVFDLEVBQ2MsRUFBRTtJQUNqQixNQUFNLEVBQ0osaUJBQWlCLEVBQ2pCLE9BQU8sR0FBRyxLQUFLLEVBQ2YsV0FBVyxHQUFHLEVBQUUsRUFDaEIsV0FBVyxHQUFHLElBQUksR0FDbkIsR0FBRyxJQUFJLENBQUM7SUFFVCxJQUFJLENBQUM7UUFDSCxNQUFNLE1BQU0sQ0FBQyxJQUFJLENBQ2YsSUFBSSxpQ0FBaUMsQ0FBQztZQUNwQyxpQkFBaUI7WUFDakIsZ0JBQWdCLEVBQUUsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFO1NBQ3JDLENBQUMsQ0FDSCxDQUFDO1FBQ0YsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5Q0FBeUMsRUFBRTtZQUNyRCxpQkFBaUI7U0FDbEIsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDYixJQUFJLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDakMsT0FBTyxDQUFDLEdBQUcsQ0FDVCw4REFBOEQsRUFDOUQ7Z0JBQ0UsaUJBQWlCO2FBQ2xCLENBQ0YsQ0FBQztZQUNGLE9BQU87UUFDVCxDQUFDO1FBQ0QsTUFBTSxHQUFHLENBQUM7SUFDWixDQUFDO0lBRUQsS0FBSyxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUUsT0FBTyxHQUFHLFdBQVcsRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDO1FBQ3ZELE1BQU0sRUFBRSxrQ0FBa0MsRUFBRSxHQUFHLE1BQU0sTUFBTSxDQUFDLElBQUksQ0FDOUQsSUFBSSxxQ0FBcUMsQ0FBQyxFQUFFLGlCQUFpQixFQUFFLENBQUMsQ0FDakUsQ0FBQztRQUNGLE1BQU0sTUFBTSxHQUFHLGtDQUFrQyxFQUFFLE1BQU0sQ0FBQztRQUMxRCxNQUFNLFdBQVcsR0FBRyxrQ0FBa0MsRUFBRSxXQUFXLENBQUM7UUFDcEUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQ0FBb0MsRUFBRTtZQUNoRCxpQkFBaUI7WUFDakIsTUFBTSxFQUFFLE1BQU0sSUFBSSxNQUFNO1lBQ3hCLFdBQVcsRUFBRSxXQUFXLElBQUksTUFBTTtZQUNsQyxPQUFPO1NBQ1IsQ0FBQyxDQUFDO1FBRUgsSUFBSSxNQUFNLEtBQUssZ0JBQWdCLElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1lBQ3hELGlFQUFpRTtZQUNqRSxPQUFPO1FBQ1QsQ0FBQztRQUNELElBQUksTUFBTSxLQUFLLGFBQWEsRUFBRSxDQUFDO1lBQzdCLE1BQU0sSUFBSSxLQUFLLENBQ2Isd0RBQXdELGlCQUFpQixFQUFFO2dCQUN6RSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsa0JBQWtCLFdBQVcsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FDeEQsQ0FBQztRQUNKLENBQUM7UUFFRCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLFdBQVcsR0FBRyxDQUFDLElBQUksT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQzFELE1BQU0sT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxNQUFNLElBQUksS0FBSyxDQUNiLDZFQUE2RSxpQkFBaUIsRUFBRSxDQUNqRyxDQUFDO0FBQ0osQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IEFtYXpvbi5jb20sIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4vLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMFxuXG5pbXBvcnQge1xuICBDb25uZWN0Q2FtcGFpZ25zVjJDbGllbnQsXG4gIEdldEluc3RhbmNlT25ib2FyZGluZ0pvYlN0YXR1c0NvbW1hbmQsXG4gIFN0YXJ0SW5zdGFuY2VPbmJvYXJkaW5nSm9iQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNvbm5lY3RjYW1wYWlnbnN2Mic7XG5cbi8qKiBUZXJtaW5hbCArIGluLWZsaWdodCBvbmJvYXJkaW5nIGpvYiBzdGF0dXNlcyByZXBvcnRlZCBieSB0aGUgc2VydmljZS4gKi9cbmNvbnN0IFNUQVRVU19TVUNDRUVERUQgPSAnU1VDQ0VFREVEJztcbmNvbnN0IFNUQVRVU19GQUlMRUQgPSAnRkFJTEVEJztcblxuY29uc3Qgc2xlZXAgPSAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4gPT5cbiAgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcblxuLyoqXG4gKiBOYW1lcyB0aGF0LCB3aGVuIHRocm93biBieSBTdGFydEluc3RhbmNlT25ib2FyZGluZ0pvYiwgaW5kaWNhdGUgdGhlIGluc3RhbmNlXG4gKiBpcyBBTFJFQURZIG9uYm9hcmRlZCB0byBPdXRib3VuZCBDYW1wYWlnbnMgdjIuIFRyZWF0ZWQgYXMgc3VjY2VzcyBzbyB0aGVcbiAqIGN1c3RvbSByZXNvdXJjZSBpcyBpZGVtcG90ZW50IGFjcm9zcyBzdGFjayB1cGRhdGVzIC8gcmV0cmllZCBkZXBsb3ltZW50cy5cbiAqL1xuY29uc3QgaXNBbHJlYWR5T25ib2FyZGVkRXJyb3IgPSAoZXJyOiB1bmtub3duKTogYm9vbGVhbiA9PiB7XG4gIGNvbnN0IG5hbWUgPSAoZXJyIGFzIHsgbmFtZT86IHN0cmluZyB9KT8ubmFtZSA/PyAnJztcbiAgcmV0dXJuIG5hbWUgPT09ICdDb25mbGljdEV4Y2VwdGlvbicgfHwgbmFtZSA9PT0gJ1Jlc291cmNlQ29uZmxpY3RFeGNlcHRpb24nO1xufTtcblxuLyoqXG4gKiBPbmJvYXJkIGFuIEFtYXpvbiBDb25uZWN0IGluc3RhbmNlIHRvIE91dGJvdW5kIENhbXBhaWducyB2MiBhbmQgd2FpdCB1bnRpbCB0aGVcbiAqIG9uYm9hcmRpbmcgam9iIHJlYWNoZXMgU1VDQ0VFREVELlxuICpcbiAqIFN0YXJ0SW5zdGFuY2VPbmJvYXJkaW5nSm9iICh3aXRoIGVuY3J5cHRpb24gZGlzYWJsZWQpIGF1dG8tY3JlYXRlcyB0aGVcbiAqIGBBV1NTZXJ2aWNlUm9sZUZvckNvbm5lY3RDYW1wYWlnbnNfKmAgc2VydmljZS1saW5rZWQgcm9sZSwgdGhlbiB0aGUgam9iIHJ1bnNcbiAqIGFzeW5jaHJvbm91c2x5ICh+MjBzKS4gV2UgcG9sbCBHZXRJbnN0YW5jZU9uYm9hcmRpbmdKb2JTdGF0dXMgd2l0aCBib3VuZGVkLFxuICogZXhwb25lbnRpYWxseS1iYWNrZWQtb2ZmIHJldHJpZXMgKGNhcHBlZCB+Mm1pbikgdW50aWwgaXQgU1VDQ0VFRFMuXG4gKlxuICogSWRlbXBvdGVudDogaWYgdGhlIGluc3RhbmNlIGlzIGFscmVhZHkgb25ib2FyZGVkIChTdGFydEluc3RhbmNlT25ib2FyZGluZ0pvYlxuICogY29uZmxpY3RzIG9yIHRoZSBzdGF0dXMgaXMgYWxyZWFkeSBTVUNDRUVERUQgLyBhYnNlbnQpLCB0aGlzIHJlc29sdmVzIHdpdGhvdXRcbiAqIGVycm9yLiBUaHJvd3Mgb25seSBvbiBhbiBleHBsaWNpdCBGQUlMRUQgc3RhdHVzIG9yIGlmIHRoZSBqb2IgbmV2ZXIgc3VjY2VlZHNcbiAqIHdpdGhpbiB0aGUgcG9sbGluZyBidWRnZXQuXG4gKi9cbmV4cG9ydCBjb25zdCBlbnN1cmVJbnN0YW5jZU9uYm9hcmRlZCA9IGFzeW5jIChcbiAgY2xpZW50OiBDb25uZWN0Q2FtcGFpZ25zVjJDbGllbnQsXG4gIG9wdHM6IHtcbiAgICBjb25uZWN0SW5zdGFuY2VJZDogc3RyaW5nO1xuICAgIC8qKiBJbmplY3RlZCBpbiB0ZXN0cyB0byBhdm9pZCByZWFsIGRlbGF5cy4gRGVmYXVsdHMgdG8gcmVhbCBzZXRUaW1lb3V0LiAqL1xuICAgIHNsZWVwRm4/OiAobXM6IG51bWJlcikgPT4gUHJvbWlzZTx2b2lkPjtcbiAgICAvKiogTWF4IHBvbGxpbmcgYXR0ZW1wdHMuIERlZmF1bHQgMjQgKH4ybWluIHdpdGggY2FwcGVkIGJhY2tvZmYpLiAqL1xuICAgIG1heEF0dGVtcHRzPzogbnVtYmVyO1xuICAgIC8qKiBCYXNlIGJhY2tvZmYgaW4gbXMuIERlZmF1bHQgMjAwMC4gKi9cbiAgICBiYXNlRGVsYXlNcz86IG51bWJlcjtcbiAgfSxcbik6IFByb21pc2U8dm9pZD4gPT4ge1xuICBjb25zdCB7XG4gICAgY29ubmVjdEluc3RhbmNlSWQsXG4gICAgc2xlZXBGbiA9IHNsZWVwLFxuICAgIG1heEF0dGVtcHRzID0gMjQsXG4gICAgYmFzZURlbGF5TXMgPSAyMDAwLFxuICB9ID0gb3B0cztcblxuICB0cnkge1xuICAgIGF3YWl0IGNsaWVudC5zZW5kKFxuICAgICAgbmV3IFN0YXJ0SW5zdGFuY2VPbmJvYXJkaW5nSm9iQ29tbWFuZCh7XG4gICAgICAgIGNvbm5lY3RJbnN0YW5jZUlkLFxuICAgICAgICBlbmNyeXB0aW9uQ29uZmlnOiB7IGVuYWJsZWQ6IGZhbHNlIH0sXG4gICAgICB9KSxcbiAgICApO1xuICAgIGNvbnNvbGUubG9nKCdbY2FtcGFpZ24tYXNzb2NdIG9uYm9hcmRpbmcgam9iIHN0YXJ0ZWQnLCB7XG4gICAgICBjb25uZWN0SW5zdGFuY2VJZCxcbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgaWYgKGlzQWxyZWFkeU9uYm9hcmRlZEVycm9yKGVycikpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAnW2NhbXBhaWduLWFzc29jXSBpbnN0YW5jZSBhbHJlYWR5IG9uYm9hcmRlZCAoc3RhcnQgY29uZmxpY3QpJyxcbiAgICAgICAge1xuICAgICAgICAgIGNvbm5lY3RJbnN0YW5jZUlkLFxuICAgICAgICB9LFxuICAgICAgKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhyb3cgZXJyO1xuICB9XG5cbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IGF0dGVtcHQgPCBtYXhBdHRlbXB0czsgYXR0ZW1wdCsrKSB7XG4gICAgY29uc3QgeyBjb25uZWN0SW5zdGFuY2VPbmJvYXJkaW5nSm9iU3RhdHVzIH0gPSBhd2FpdCBjbGllbnQuc2VuZChcbiAgICAgIG5ldyBHZXRJbnN0YW5jZU9uYm9hcmRpbmdKb2JTdGF0dXNDb21tYW5kKHsgY29ubmVjdEluc3RhbmNlSWQgfSksXG4gICAgKTtcbiAgICBjb25zdCBzdGF0dXMgPSBjb25uZWN0SW5zdGFuY2VPbmJvYXJkaW5nSm9iU3RhdHVzPy5zdGF0dXM7XG4gICAgY29uc3QgZmFpbHVyZUNvZGUgPSBjb25uZWN0SW5zdGFuY2VPbmJvYXJkaW5nSm9iU3RhdHVzPy5mYWlsdXJlQ29kZTtcbiAgICBjb25zb2xlLmxvZygnW2NhbXBhaWduLWFzc29jXSBvbmJvYXJkaW5nIHN0YXR1cycsIHtcbiAgICAgIGNvbm5lY3RJbnN0YW5jZUlkLFxuICAgICAgc3RhdHVzOiBzdGF0dXMgPz8gJ05PTkUnLFxuICAgICAgZmFpbHVyZUNvZGU6IGZhaWx1cmVDb2RlID8/ICdOT05FJyxcbiAgICAgIGF0dGVtcHQsXG4gICAgfSk7XG5cbiAgICBpZiAoc3RhdHVzID09PSBTVEFUVVNfU1VDQ0VFREVEIHx8IHN0YXR1cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBTVUNDRUVERUQsIG9yIG5vIGpvYiBwcmVzZW50IChhbHJlYWR5LW9uYm9hcmRlZCBzdGVhZHkgc3RhdGUpLlxuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoc3RhdHVzID09PSBTVEFUVVNfRkFJTEVEKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBJbnN0YW5jZSBvbmJvYXJkaW5nIHRvIE91dGJvdW5kIENhbXBhaWducyBGQUlMRUQgZm9yICR7Y29ubmVjdEluc3RhbmNlSWR9YCArXG4gICAgICAgICAgKGZhaWx1cmVDb2RlID8gYCAoZmFpbHVyZUNvZGU6ICR7ZmFpbHVyZUNvZGV9KWAgOiAnJyksXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IGRlbGF5ID0gTWF0aC5taW4oYmFzZURlbGF5TXMgKiAyICoqIGF0dGVtcHQsIDEwMDAwKTtcbiAgICBhd2FpdCBzbGVlcEZuKGRlbGF5KTtcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihcbiAgICBgSW5zdGFuY2Ugb25ib2FyZGluZyBkaWQgbm90IHJlYWNoIFNVQ0NFRURFRCB3aXRoaW4gdGhlIHBvbGxpbmcgYnVkZ2V0IGZvciAke2Nvbm5lY3RJbnN0YW5jZUlkfWAsXG4gICk7XG59O1xuIl19
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { CustomerProfilesClient } from '@aws-sdk/client-customer-profiles';
|
|
2
|
+
/**
|
|
3
|
+
* Read back the IMMUTABLE `createdAt` of the existing AmplifyDevice object for
|
|
4
|
+
* `deviceId` under the resolved profile, so a subsequent PutProfileObject (which
|
|
5
|
+
* REPLACES the object for that key) can preserve the original first-registration
|
|
6
|
+
* time while refreshing `updatedAt`.
|
|
7
|
+
*
|
|
8
|
+
* Pages through the profile's device objects and matches by `deviceId` (the
|
|
9
|
+
* UNIQUE object key). Returns the stored `createdAt` when a prior object exists,
|
|
10
|
+
* otherwise `undefined` so the caller sets a fresh `createdAt = now`.
|
|
11
|
+
*
|
|
12
|
+
* Best-effort and NEVER throws: any failure — a not-yet-propagated profile
|
|
13
|
+
* (SearchProfiles / ListProfileObjects are eventually consistent), a transient
|
|
14
|
+
* service error, or a permissions gap — simply yields `undefined` so the caller
|
|
15
|
+
* re-seeds `createdAt` and device registration stays resilient.
|
|
16
|
+
*/
|
|
17
|
+
export declare const findExistingDeviceCreatedAt: (profiles: CustomerProfilesClient, domainName: string, profileId: string, deviceId: string) => Promise<string | undefined>;
|
|
18
|
+
//# sourceMappingURL=device_resolver.d.ts.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ListProfileObjectsCommand, } from '@aws-sdk/client-customer-profiles';
|
|
2
|
+
import { OBJECT_TYPE_DEVICE } from '../../constants.js';
|
|
3
|
+
import { withTransientRetry } from '../shared/retry.js';
|
|
4
|
+
/**
|
|
5
|
+
* Read back the IMMUTABLE `createdAt` of the existing AmplifyDevice object for
|
|
6
|
+
* `deviceId` under the resolved profile, so a subsequent PutProfileObject (which
|
|
7
|
+
* REPLACES the object for that key) can preserve the original first-registration
|
|
8
|
+
* time while refreshing `updatedAt`.
|
|
9
|
+
*
|
|
10
|
+
* Pages through the profile's device objects and matches by `deviceId` (the
|
|
11
|
+
* UNIQUE object key). Returns the stored `createdAt` when a prior object exists,
|
|
12
|
+
* otherwise `undefined` so the caller sets a fresh `createdAt = now`.
|
|
13
|
+
*
|
|
14
|
+
* Best-effort and NEVER throws: any failure — a not-yet-propagated profile
|
|
15
|
+
* (SearchProfiles / ListProfileObjects are eventually consistent), a transient
|
|
16
|
+
* service error, or a permissions gap — simply yields `undefined` so the caller
|
|
17
|
+
* re-seeds `createdAt` and device registration stays resilient.
|
|
18
|
+
*/
|
|
19
|
+
export const findExistingDeviceCreatedAt = async (profiles, domainName, profileId, deviceId) => {
|
|
20
|
+
try {
|
|
21
|
+
let nextToken;
|
|
22
|
+
do {
|
|
23
|
+
const res = await withTransientRetry(() => profiles.send(new ListProfileObjectsCommand({
|
|
24
|
+
DomainName: domainName,
|
|
25
|
+
ObjectTypeName: OBJECT_TYPE_DEVICE,
|
|
26
|
+
ProfileId: profileId,
|
|
27
|
+
NextToken: nextToken,
|
|
28
|
+
})));
|
|
29
|
+
for (const item of res.Items ?? []) {
|
|
30
|
+
if (!item.Object) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const parsed = JSON.parse(item.Object);
|
|
35
|
+
if (parsed.deviceId === deviceId &&
|
|
36
|
+
typeof parsed.createdAt === 'string' &&
|
|
37
|
+
parsed.createdAt.length > 0) {
|
|
38
|
+
return parsed.createdAt;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Ignore a malformed stored object; treat as no prior createdAt.
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
nextToken = res.NextToken;
|
|
47
|
+
} while (nextToken);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// Best-effort: ListProfileObjects unavailable / errored; the caller
|
|
51
|
+
// re-seeds createdAt = now rather than failing device registration.
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlX3Jlc29sdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2xhbWJkYS9pZGVudGlmeS9kZXZpY2VfcmVzb2x2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLHlCQUF5QixHQUMxQixNQUFNLG1DQUFtQyxDQUFDO0FBRTNDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBRXhEOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsS0FBSyxFQUM5QyxRQUFnQyxFQUNoQyxVQUFrQixFQUNsQixTQUFpQixFQUNqQixRQUFnQixFQUNhLEVBQUU7SUFDL0IsSUFBSSxDQUFDO1FBQ0gsSUFBSSxTQUE2QixDQUFDO1FBQ2xDLEdBQUcsQ0FBQztZQUNGLE1BQU0sR0FBRyxHQUFHLE1BQU0sa0JBQWtCLENBQUMsR0FBRyxFQUFFLENBQ3hDLFFBQVEsQ0FBQyxJQUFJLENBQ1gsSUFBSSx5QkFBeUIsQ0FBQztnQkFDNUIsVUFBVSxFQUFFLFVBQVU7Z0JBQ3RCLGNBQWMsRUFBRSxrQkFBa0I7Z0JBQ2xDLFNBQVMsRUFBRSxTQUFTO2dCQUNwQixTQUFTLEVBQUUsU0FBUzthQUNyQixDQUFDLENBQ0gsQ0FDRixDQUFDO1lBRUYsS0FBSyxNQUFNLElBQUksSUFBSSxHQUFHLENBQUMsS0FBSyxJQUFJLEVBQUUsRUFBRSxDQUFDO2dCQUNuQyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO29CQUNqQixTQUFTO2dCQUNYLENBQUM7Z0JBQ0QsSUFBSSxDQUFDO29CQUNILE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBNEIsQ0FBQztvQkFDbEUsSUFDRSxNQUFNLENBQUMsUUFBUSxLQUFLLFFBQVE7d0JBQzVCLE9BQU8sTUFBTSxDQUFDLFNBQVMsS0FBSyxRQUFRO3dCQUNwQyxNQUFNLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQzNCLENBQUM7d0JBQ0QsT0FBTyxNQUFNLENBQUMsU0FBUyxDQUFDO29CQUMxQixDQUFDO2dCQUNILENBQUM7Z0JBQUMsTUFBTSxDQUFDO29CQUNQLGlFQUFpRTtvQkFDakUsU0FBUztnQkFDWCxDQUFDO1lBQ0gsQ0FBQztZQUNELFNBQVMsR0FBRyxHQUFHLENBQUMsU0FBUyxDQUFDO1FBQzVCLENBQUMsUUFBUSxTQUFTLEVBQUU7SUFDdEIsQ0FBQztJQUFDLE1BQU0sQ0FBQztRQUNQLG9FQUFvRTtRQUNwRSxvRUFBb0U7UUFDcEUsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEN1c3RvbWVyUHJvZmlsZXNDbGllbnQsXG4gIExpc3RQcm9maWxlT2JqZWN0c0NvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jdXN0b21lci1wcm9maWxlcyc7XG5cbmltcG9ydCB7IE9CSkVDVF9UWVBFX0RFVklDRSB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgeyB3aXRoVHJhbnNpZW50UmV0cnkgfSBmcm9tICcuLi9zaGFyZWQvcmV0cnkuanMnO1xuXG4vKipcbiAqIFJlYWQgYmFjayB0aGUgSU1NVVRBQkxFIGBjcmVhdGVkQXRgIG9mIHRoZSBleGlzdGluZyBBbXBsaWZ5RGV2aWNlIG9iamVjdCBmb3JcbiAqIGBkZXZpY2VJZGAgdW5kZXIgdGhlIHJlc29sdmVkIHByb2ZpbGUsIHNvIGEgc3Vic2VxdWVudCBQdXRQcm9maWxlT2JqZWN0ICh3aGljaFxuICogUkVQTEFDRVMgdGhlIG9iamVjdCBmb3IgdGhhdCBrZXkpIGNhbiBwcmVzZXJ2ZSB0aGUgb3JpZ2luYWwgZmlyc3QtcmVnaXN0cmF0aW9uXG4gKiB0aW1lIHdoaWxlIHJlZnJlc2hpbmcgYHVwZGF0ZWRBdGAuXG4gKlxuICogUGFnZXMgdGhyb3VnaCB0aGUgcHJvZmlsZSdzIGRldmljZSBvYmplY3RzIGFuZCBtYXRjaGVzIGJ5IGBkZXZpY2VJZGAgKHRoZVxuICogVU5JUVVFIG9iamVjdCBrZXkpLiBSZXR1cm5zIHRoZSBzdG9yZWQgYGNyZWF0ZWRBdGAgd2hlbiBhIHByaW9yIG9iamVjdCBleGlzdHMsXG4gKiBvdGhlcndpc2UgYHVuZGVmaW5lZGAgc28gdGhlIGNhbGxlciBzZXRzIGEgZnJlc2ggYGNyZWF0ZWRBdCA9IG5vd2AuXG4gKlxuICogQmVzdC1lZmZvcnQgYW5kIE5FVkVSIHRocm93czogYW55IGZhaWx1cmUg4oCUIGEgbm90LXlldC1wcm9wYWdhdGVkIHByb2ZpbGVcbiAqIChTZWFyY2hQcm9maWxlcyAvIExpc3RQcm9maWxlT2JqZWN0cyBhcmUgZXZlbnR1YWxseSBjb25zaXN0ZW50KSwgYSB0cmFuc2llbnRcbiAqIHNlcnZpY2UgZXJyb3IsIG9yIGEgcGVybWlzc2lvbnMgZ2FwIOKAlCBzaW1wbHkgeWllbGRzIGB1bmRlZmluZWRgIHNvIHRoZSBjYWxsZXJcbiAqIHJlLXNlZWRzIGBjcmVhdGVkQXRgIGFuZCBkZXZpY2UgcmVnaXN0cmF0aW9uIHN0YXlzIHJlc2lsaWVudC5cbiAqL1xuZXhwb3J0IGNvbnN0IGZpbmRFeGlzdGluZ0RldmljZUNyZWF0ZWRBdCA9IGFzeW5jIChcbiAgcHJvZmlsZXM6IEN1c3RvbWVyUHJvZmlsZXNDbGllbnQsXG4gIGRvbWFpbk5hbWU6IHN0cmluZyxcbiAgcHJvZmlsZUlkOiBzdHJpbmcsXG4gIGRldmljZUlkOiBzdHJpbmcsXG4pOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4gPT4ge1xuICB0cnkge1xuICAgIGxldCBuZXh0VG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgICBkbyB7XG4gICAgICBjb25zdCByZXMgPSBhd2FpdCB3aXRoVHJhbnNpZW50UmV0cnkoKCkgPT5cbiAgICAgICAgcHJvZmlsZXMuc2VuZChcbiAgICAgICAgICBuZXcgTGlzdFByb2ZpbGVPYmplY3RzQ29tbWFuZCh7XG4gICAgICAgICAgICBEb21haW5OYW1lOiBkb21haW5OYW1lLFxuICAgICAgICAgICAgT2JqZWN0VHlwZU5hbWU6IE9CSkVDVF9UWVBFX0RFVklDRSxcbiAgICAgICAgICAgIFByb2ZpbGVJZDogcHJvZmlsZUlkLFxuICAgICAgICAgICAgTmV4dFRva2VuOiBuZXh0VG9rZW4sXG4gICAgICAgICAgfSksXG4gICAgICAgICksXG4gICAgICApO1xuXG4gICAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgcmVzLkl0ZW1zID8/IFtdKSB7XG4gICAgICAgIGlmICghaXRlbS5PYmplY3QpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IEpTT04ucGFyc2UoaXRlbS5PYmplY3QpIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICAgICAgICAgIGlmIChcbiAgICAgICAgICAgIHBhcnNlZC5kZXZpY2VJZCA9PT0gZGV2aWNlSWQgJiZcbiAgICAgICAgICAgIHR5cGVvZiBwYXJzZWQuY3JlYXRlZEF0ID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgICAgcGFyc2VkLmNyZWF0ZWRBdC5sZW5ndGggPiAwXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICByZXR1cm4gcGFyc2VkLmNyZWF0ZWRBdDtcbiAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIC8vIElnbm9yZSBhIG1hbGZvcm1lZCBzdG9yZWQgb2JqZWN0OyB0cmVhdCBhcyBubyBwcmlvciBjcmVhdGVkQXQuXG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIG5leHRUb2tlbiA9IHJlcy5OZXh0VG9rZW47XG4gICAgfSB3aGlsZSAobmV4dFRva2VuKTtcbiAgfSBjYXRjaCB7XG4gICAgLy8gQmVzdC1lZmZvcnQ6IExpc3RQcm9maWxlT2JqZWN0cyB1bmF2YWlsYWJsZSAvIGVycm9yZWQ7IHRoZSBjYWxsZXJcbiAgICAvLyByZS1zZWVkcyBjcmVhdGVkQXQgPSBub3cgcmF0aGVyIHRoYW4gZmFpbGluZyBkZXZpY2UgcmVnaXN0cmF0aW9uLlxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn07XG4iXX0=
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { APIGatewayProxyStructuredResultV2 } from 'aws-lambda';
|
|
2
|
+
import { IdentifyEvent } from './principal.js';
|
|
3
|
+
/**
|
|
4
|
+
* HTTP API handler for the identify-user routes. Serves BOTH:
|
|
5
|
+
* - `POST /identify-user` — authed (Cognito user-pool JWT authorizer,
|
|
6
|
+
* payload format 2.0). Identity = verified `sub`.
|
|
7
|
+
* - `POST /identify-user-guest` — guest (IAM/SigV4 authorization, payload
|
|
8
|
+
* format 1.0). Identity = verified Cognito Identity Pool `cognitoIdentityId`
|
|
9
|
+
* of an UNAUTHENTICATED identity.
|
|
10
|
+
*
|
|
11
|
+
* The verified {@link Principal} abstracts the two modes; the profile
|
|
12
|
+
* find-or-create + device upsert + attribute write are identity-agnostic. On an
|
|
13
|
+
* authed call carrying `options.previousGuestIdentityId`, the prior guest
|
|
14
|
+
* profile (and its devices) is folded into the authed profile via MergeProfiles.
|
|
15
|
+
*/
|
|
16
|
+
export declare const handler: (event: IdentifyEvent) => Promise<APIGatewayProxyStructuredResultV2>;
|
|
17
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { CustomerProfilesClient, PutProfileObjectCommand, UpdateProfileCommand, } from '@aws-sdk/client-customer-profiles';
|
|
2
|
+
import { validateBody } from './validation.js';
|
|
3
|
+
import { buildDeviceObject, buildProfileUpdate, hasDeviceData, } from './mapping.js';
|
|
4
|
+
import { resolveOrCreateProfile } from './profile_resolver.js';
|
|
5
|
+
import { findExistingDeviceCreatedAt } from './device_resolver.js';
|
|
6
|
+
import { mergeGuestIntoAuthed } from './merge_resolver.js';
|
|
7
|
+
import { resolvePrincipal } from './principal.js';
|
|
8
|
+
import { withTransientRetry } from '../shared/retry.js';
|
|
9
|
+
import { ENV_DOMAIN_NAME, OBJECT_TYPE_DEVICE } from '../../constants.js';
|
|
10
|
+
/**
|
|
11
|
+
* Module-level client so warm invocations reuse the connection pool. Region is
|
|
12
|
+
* resolved from the standard AWS_REGION Lambda environment variable.
|
|
13
|
+
*/
|
|
14
|
+
const profiles = new CustomerProfilesClient({});
|
|
15
|
+
const response = (statusCode, body) => ({
|
|
16
|
+
statusCode,
|
|
17
|
+
headers: { 'content-type': 'application/json' },
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* HTTP API handler for the identify-user routes. Serves BOTH:
|
|
22
|
+
* - `POST /identify-user` — authed (Cognito user-pool JWT authorizer,
|
|
23
|
+
* payload format 2.0). Identity = verified `sub`.
|
|
24
|
+
* - `POST /identify-user-guest` — guest (IAM/SigV4 authorization, payload
|
|
25
|
+
* format 1.0). Identity = verified Cognito Identity Pool `cognitoIdentityId`
|
|
26
|
+
* of an UNAUTHENTICATED identity.
|
|
27
|
+
*
|
|
28
|
+
* The verified {@link Principal} abstracts the two modes; the profile
|
|
29
|
+
* find-or-create + device upsert + attribute write are identity-agnostic. On an
|
|
30
|
+
* authed call carrying `options.previousGuestIdentityId`, the prior guest
|
|
31
|
+
* profile (and its devices) is folded into the authed profile via MergeProfiles.
|
|
32
|
+
*/
|
|
33
|
+
export const handler = async (event) => {
|
|
34
|
+
const domainName = process.env[ENV_DOMAIN_NAME];
|
|
35
|
+
if (!domainName) {
|
|
36
|
+
console.error(`Missing required env var ${ENV_DOMAIN_NAME}`);
|
|
37
|
+
return response(500, { error: 'Server misconfiguration' });
|
|
38
|
+
}
|
|
39
|
+
const principal = resolvePrincipal(event);
|
|
40
|
+
if (!principal) {
|
|
41
|
+
return response(401, {
|
|
42
|
+
error: 'Unauthorized: missing or invalid verified caller identity',
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = event.body ? JSON.parse(event.body) : undefined;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return response(400, { error: 'Invalid JSON request body' });
|
|
51
|
+
}
|
|
52
|
+
const validation = validateBody(parsed);
|
|
53
|
+
if (!validation.ok || !validation.value) {
|
|
54
|
+
return response(400, { error: validation.error ?? 'Invalid request' });
|
|
55
|
+
}
|
|
56
|
+
const request = validation.value;
|
|
57
|
+
try {
|
|
58
|
+
// 1) Resolve (or create + key) the profile bound to the verified caller.
|
|
59
|
+
// Isolated behind resolveOrCreateProfile so the identity-resolution
|
|
60
|
+
// strategy (authed sub vs guest identityId) is a single seam.
|
|
61
|
+
const { profileId } = await resolveOrCreateProfile(profiles, domainName, principal);
|
|
62
|
+
// 2) Register / update the device object (keyed by stable deviceId) only
|
|
63
|
+
// when device data is present. Token refreshes upsert in place: because
|
|
64
|
+
// PutProfileObject REPLACES the object for a deviceId, read back the
|
|
65
|
+
// prior object first to preserve its immutable `createdAt`.
|
|
66
|
+
if (hasDeviceData(request)) {
|
|
67
|
+
const deviceId = request.options.deviceId;
|
|
68
|
+
const existingCreatedAt = await findExistingDeviceCreatedAt(profiles, domainName, profileId, deviceId);
|
|
69
|
+
const deviceObject = buildDeviceObject(principal, request, existingCreatedAt);
|
|
70
|
+
await withTransientRetry(() => profiles.send(new PutProfileObjectCommand({
|
|
71
|
+
DomainName: domainName,
|
|
72
|
+
ObjectTypeName: OBJECT_TYPE_DEVICE,
|
|
73
|
+
Object: JSON.stringify(deviceObject),
|
|
74
|
+
})));
|
|
75
|
+
}
|
|
76
|
+
// 3) Set user-level / targeting attributes (incl. promoted hasGCM/hasAPNS)
|
|
77
|
+
// on the resolved profile.
|
|
78
|
+
const update = buildProfileUpdate(principal, request);
|
|
79
|
+
await withTransientRetry(() => profiles.send(new UpdateProfileCommand({
|
|
80
|
+
DomainName: domainName,
|
|
81
|
+
ProfileId: profileId,
|
|
82
|
+
EmailAddress: update.emailAddress,
|
|
83
|
+
FirstName: update.firstName,
|
|
84
|
+
LastName: update.lastName,
|
|
85
|
+
Address: update.address
|
|
86
|
+
? {
|
|
87
|
+
City: update.address.city,
|
|
88
|
+
Country: update.address.country,
|
|
89
|
+
PostalCode: update.address.postalCode,
|
|
90
|
+
Province: update.address.province,
|
|
91
|
+
}
|
|
92
|
+
: undefined,
|
|
93
|
+
Attributes: update.attributes,
|
|
94
|
+
})));
|
|
95
|
+
// 4) Merge-on-sign-in: an AUTHENTICATED caller that carries its prior guest
|
|
96
|
+
// identityId folds the guest profile (+ its devices) into this authed
|
|
97
|
+
// profile via MergeProfiles. Guests never trigger a merge. Best-effort:
|
|
98
|
+
// a merge failure is logged but does not fail the identify result, which
|
|
99
|
+
// already succeeded above.
|
|
100
|
+
const guestIdentityId = request.options?.previousGuestIdentityId;
|
|
101
|
+
if (principal.kind === 'authed' && guestIdentityId) {
|
|
102
|
+
try {
|
|
103
|
+
const outcome = await mergeGuestIntoAuthed(profiles, domainName, guestIdentityId, profileId);
|
|
104
|
+
console.log('[identify] guestMerge', JSON.stringify({ merged: outcome.merged }));
|
|
105
|
+
}
|
|
106
|
+
catch (mergeErr) {
|
|
107
|
+
const name = mergeErr instanceof Error ? mergeErr.name : 'UnknownError';
|
|
108
|
+
console.error('[identify] guestMergeError', JSON.stringify({ name }));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return response(200, { status: 'ok' });
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
const message = err instanceof Error ? err.message : 'unknown error';
|
|
115
|
+
// Log only the error name (and HTTP status when present) — never the full
|
|
116
|
+
// error object, whose stack / request input can carry customer content.
|
|
117
|
+
const name = err instanceof Error ? err.name : 'UnknownError';
|
|
118
|
+
const statusCode = err
|
|
119
|
+
?.$metadata?.httpStatusCode;
|
|
120
|
+
console.error('[identify] customerProfilesError', JSON.stringify({ name, statusCode }));
|
|
121
|
+
return response(500, { error: `Customer Profiles error: ${message}` });
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYW1iZGEvaWRlbnRpZnkvaGFuZGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQ0wsc0JBQXNCLEVBQ3RCLHVCQUF1QixFQUN2QixvQkFBb0IsR0FDckIsTUFBTSxtQ0FBbUMsQ0FBQztBQUUzQyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixrQkFBa0IsRUFDbEIsYUFBYSxHQUNkLE1BQU0sY0FBYyxDQUFDO0FBQ3RCLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQy9ELE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzNELE9BQU8sRUFBaUIsZ0JBQWdCLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RCxPQUFPLEVBQUUsZUFBZSxFQUFFLGtCQUFrQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFHekU7OztHQUdHO0FBQ0gsTUFBTSxRQUFRLEdBQUcsSUFBSSxzQkFBc0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUVoRCxNQUFNLFFBQVEsR0FBRyxDQUNmLFVBQWtCLEVBQ2xCLElBQXFDLEVBQ0YsRUFBRSxDQUFDLENBQUM7SUFDdkMsVUFBVTtJQUNWLE9BQU8sRUFBRSxFQUFFLGNBQWMsRUFBRSxrQkFBa0IsRUFBRTtJQUMvQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUM7Q0FDM0IsQ0FBQyxDQUFDO0FBRUg7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sT0FBTyxHQUFHLEtBQUssRUFDMUIsS0FBb0Is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LEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDeEUsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLFFBQVEsQ0FBQyxHQUFHLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN6QyxDQUFDO0lBQUMsT0FBTyxHQUFHLEVBQUUsQ0FBQztRQUNiLE1BQU0sT0FBTyxHQUFHLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQztRQUNyRSwwRUFBMEU7UUFDMUUsd0VBQXdFO1FBQ3hFLE1BQU0sSUFBSSxHQUFHLEdBQUcsWUFBWSxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGNBQWMsQ0FBQztRQUM5RCxNQUFNLFVBQVUsR0FBSSxHQUFtRDtZQUNyRSxFQUFFLFNBQVMsRUFBRSxjQUFjLENBQUM7UUFDOUIsT0FBTyxDQUFDLEtBQUssQ0FDWCxrQ0FBa0MsRUFDbEMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsQ0FBQyxDQUNyQyxDQUFDO1FBQ0YsT0FBTyxRQUFRLENBQUMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLDRCQUE0QixPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDekUsQ0FBQztBQUNILENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgQVBJR2F0ZXdheVByb3h5U3RydWN0dXJlZFJlc3VsdFYyIH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQge1xuICBDdXN0b21lclByb2ZpbGVzQ2xpZW50LFxuICBQdXRQcm9maWxlT2JqZWN0Q29tbWFuZCxcbiAgVXBkYXRlUHJvZmlsZUNvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jdXN0b21lci1wcm9maWxlcyc7XG5cbmltcG9ydCB7IHZhbGlkYXRlQm9keSB9IGZyb20gJy4vdmFsaWRhdGlvbi5qcyc7XG5pbXBvcnQge1xuICBidWlsZERldmljZU9iamVjdCxcbiAgYnVpbGRQcm9maWxlVXBkYXRlLFxuICBoYXNEZXZpY2VEYXRhLFxufSBmcm9tICcuL21hcHBpbmcuanMnO1xuaW1wb3J0IHsgcmVzb2x2ZU9yQ3JlYXRlUHJvZmlsZSB9IGZyb20gJy4vcHJvZmlsZV9yZXNvbHZlci5qcyc7XG5pbXBvcnQgeyBmaW5kRXhpc3RpbmdEZXZpY2VDcmVhdGVkQXQgfSBmcm9tICcuL2RldmljZV9yZXNvbHZlci5qcyc7XG5pbXBvcnQgeyBtZXJnZUd1ZXN0SW50b0F1dGhlZCB9IGZyb20gJy4vbWVyZ2VfcmVzb2x2ZXIuanMnO1xuaW1wb3J0IHsgSWRlbnRpZnlFdmVudCwgcmVzb2x2ZVByaW5jaXBhbCB9IGZyb20gJy4vcHJpbmNpcGFsLmpzJztcbmltcG9ydCB7IHdpdGhUcmFuc2llbnRSZXRyeSB9IGZyb20gJy4uL3NoYXJlZC9yZXRyeS5qcyc7XG5pbXBvcnQgeyBFTlZfRE9NQUlOX05BTUUsIE9CSkVDVF9UWVBFX0RFVklDRSB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy5qcyc7XG5pbXBvcnQgeyBFcnJvclJlc3BvbnNlLCBTdWNjZXNzUmVzcG9uc2UgfSBmcm9tICcuL3R5cGVzLmpzJztcblxuLyoqXG4gKiBNb2R1bGUtbGV2ZWwgY2xpZW50IHNvIHdhcm0gaW52b2NhdGlvbnMgcmV1c2UgdGhlIGNvbm5lY3Rpb24gcG9vbC4gUmVnaW9uIGlzXG4gKiByZXNvbHZlZCBmcm9tIHRoZSBzdGFuZGFyZCBBV1NfUkVHSU9OIExhbWJkYSBlbnZpcm9ubWVudCB2YXJpYWJsZS5cbiAqL1xuY29uc3QgcHJvZmlsZXMgPSBuZXcgQ3VzdG9tZXJQcm9maWxlc0NsaWVudCh7fSk7XG5cbmNvbnN0IHJlc3BvbnNlID0gKFxuICBzdGF0dXNDb2RlOiBudW1iZXIsXG4gIGJvZHk6IFN1Y2Nlc3NSZXNwb25zZSB8IEVycm9yUmVzcG9uc2UsXG4pOiBBUElHYXRld2F5UHJveHlTdHJ1Y3R1cmVkUmVzdWx0VjIgPT4gKHtcbiAgc3RhdHVzQ29kZSxcbiAgaGVhZGVyczogeyAnY29udGVudC10eXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nIH0sXG4gIGJvZHk6IEpTT04uc3RyaW5naWZ5KGJvZHkpLFxufSk7XG5cbi8qKlxuICogSFRUUCBBUEkgaGFuZGxlciBmb3IgdGhlIGlkZW50aWZ5LXVzZXIgcm91dGVzLiBTZXJ2ZXMgQk9USDpcbiAqICAgLSBgUE9TVCAvaWRlbnRpZnktdXNlcmAgICAgICAgIOKAlCBhdXRoZWQgKENvZ25pdG8gdXNlci1wb29sIEpXVCBhdXRob3JpemVyLFxuICogICAgIHBheWxvYWQgZm9ybWF0IDIuMCkuIElkZW50aXR5ID0gdmVyaWZpZWQgYHN1YmAuXG4gKiAgIC0gYFBPU1QgL2lkZW50aWZ5LXVzZXItZ3Vlc3RgICDigJQgZ3Vlc3QgKElBTS9TaWdWNCBhdXRob3JpemF0aW9uLCBwYXlsb2FkXG4gKiAgICAgZm9ybWF0IDEuMCkuIElkZW50aXR5ID0gdmVyaWZpZWQgQ29nbml0byBJZGVudGl0eSBQb29sIGBjb2duaXRvSWRlbnRpdHlJZGBcbiAqICAgICBvZiBhbiBVTkFVVEhFTlRJQ0FURUQgaWRlbnRpdHkuXG4gKlxuICogVGhlIHZlcmlmaWVkIHtAbGluayBQcmluY2lwYWx9IGFic3RyYWN0cyB0aGUgdHdvIG1vZGVzOyB0aGUgcHJvZmlsZVxuICogZmluZC1vci1jcmVhdGUgKyBkZXZpY2UgdXBzZXJ0ICsgYXR0cmlidXRlIHdyaXRlIGFyZSBpZGVudGl0eS1hZ25vc3RpYy4gT24gYW5cbiAqIGF1dGhlZCBjYWxsIGNhcnJ5aW5nIGBvcHRpb25zLnByZXZpb3VzR3Vlc3RJZGVudGl0eUlkYCwgdGhlIHByaW9yIGd1ZXN0XG4gKiBwcm9maWxlIChhbmQgaXRzIGRldmljZXMpIGlzIGZvbGRlZCBpbnRvIHRoZSBhdXRoZWQgcHJvZmlsZSB2aWEgTWVyZ2VQcm9maWxlcy5cbiAqL1xuZXhwb3J0IGNvbnN0IGhhbmRsZXIgPSBhc3luYyAoXG4gIGV2ZW50OiBJZGVudGlmeUV2ZW50LFxuKTogUHJvbWlzZTxBUElHYXRld2F5UHJveHlTdHJ1Y3R1cmVkUmVzdWx0VjI+ID0+IHtcbiAgY29uc3QgZG9tYWluTmFtZSA9IHByb2Nlc3MuZW52W0VOVl9ET01BSU5fTkFNRV07XG4gIGlmICghZG9tYWluTmFtZSkge1xuICAgIGNvbnNvbGUuZXJyb3IoYE1pc3NpbmcgcmVxdWlyZWQgZW52IHZhciAke0VOVl9ET01BSU5fTkFNRX1gKTtcbiAgICByZXR1cm4gcmVzcG9uc2UoNTAwLCB7IGVycm9yOiAnU2VydmVyIG1pc2NvbmZpZ3VyYXRpb24nIH0pO1xuICB9XG5cbiAgY29uc3QgcHJpbmNpcGFsID0gcmVzb2x2ZVByaW5jaXBhbChldmVudCk7XG4gIGlmICghcHJpbmNpcGFsKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMSwge1xuICAgICAgZXJyb3I6ICdVbmF1dGhvcml6ZWQ6IG1pc3Npbmcgb3IgaW52YWxpZCB2ZXJpZmllZCBjYWxsZXIgaWRlbnRpdHknLFxuICAgIH0pO1xuICB9XG5cbiAgbGV0IHBhcnNlZDogdW5rbm93bjtcbiAgdHJ5IHtcbiAgICBwYXJzZWQgPSBldmVudC5ib2R5ID8gSlNPTi5wYXJzZShldmVudC5ib2R5KSA6IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHJlc3BvbnNlKDQwMCwgeyBlcnJvcjogJ0ludmFsaWQgSlNPTiByZXF1ZXN0IGJvZHknIH0pO1xuICB9XG5cbiAgY29uc3QgdmFsaWRhdGlvbiA9IHZhbGlkYXRlQm9keShwYXJzZWQpO1xuICBpZiAoIXZhbGlkYXRpb24ub2sgfHwgIXZhbGlkYXRpb24udmFsdWUpIHtcbiAgICByZXR1cm4gcmVzcG9uc2UoNDAwLCB7IGVycm9yOiB2YWxpZGF0aW9uLmVycm9yID8/ICdJbnZhbGlkIHJlcXVlc3QnIH0pO1xuICB9XG4gIGNvbnN0IHJlcXVlc3QgPSB2YWxpZGF0aW9uLnZhbHVlO1xuXG4gIHRyeSB7XG4gICAgLy8gMSkgUmVzb2x2ZSAob3IgY3JlYXRlICsga2V5KSB0aGUgcHJvZmlsZSBib3VuZCB0byB0aGUgdmVyaWZpZWQgY2FsbGVyLlxuICAgIC8vICAgIElzb2xhdGVkIGJlaGluZCByZXNvbHZlT3JDcmVhdGVQcm9maWxlIHNvIHRoZSBpZGVudGl0eS1yZXNvbHV0aW9uXG4gICAgLy8gICAgc3RyYXRlZ3kgKGF1dGhlZCBzdWIgdnMgZ3Vlc3QgaWRlbnRpdHlJZCkgaXMgYSBzaW5nbGUgc2VhbS5cbiAgICBjb25zdCB7IHByb2ZpbGVJZCB9ID0gYXdhaXQgcmVzb2x2ZU9yQ3JlYXRlUHJvZmlsZShcbiAgICAgIHByb2ZpbGVzLFxuICAgICAgZG9tYWluTmFtZSxcbiAgICAgIHByaW5jaXBhbCxcbiAgICApO1xuXG4gICAgLy8gMikgUmVnaXN0ZXIgLyB1cGRhdGUgdGhlIGRldmljZSBvYmplY3QgKGtleWVkIGJ5IHN0YWJsZSBkZXZpY2VJZCkgb25seVxuICAgIC8vICAgIHdoZW4gZGV2aWNlIGRhdGEgaXMgcHJlc2VudC4gVG9rZW4gcmVmcmVzaGVzIHVwc2VydCBpbiBwbGFjZTogYmVjYXVzZVxuICAgIC8vICAgIFB1dFByb2ZpbGVPYmplY3QgUkVQTEFDRVMgdGhlIG9iamVjdCBmb3IgYSBkZXZpY2VJZCwgcmVhZCBiYWNrIHRoZVxuICAgIC8vICAgIHByaW9yIG9iamVjdCBmaXJzdCB0byBwcmVzZXJ2ZSBpdHMgaW1tdXRhYmxlIGBjcmVhdGVkQXRgLlxuICAgIGlmIChoYXNEZXZpY2VEYXRhKHJlcXVlc3QpKSB7XG4gICAgICBjb25zdCBkZXZpY2VJZCA9IHJlcXVlc3Qub3B0aW9ucyEuZGV2aWNlSWQhO1xuICAgICAgY29uc3QgZXhpc3RpbmdDcmVhdGVkQXQgPSBhd2FpdCBmaW5kRXhpc3RpbmdEZXZpY2VDcmVhdGVkQXQoXG4gICAgICAgIHByb2ZpbGVzLFxuICAgICAgICBkb21haW5OYW1lLFxuICAgICAgICBwcm9maWxlSWQsXG4gICAgICAgIGRldmljZUlkLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IGRldmljZU9iamVjdCA9IGJ1aWxkRGV2aWNlT2JqZWN0KFxuICAgICAgICBwcmluY2lwYWwsXG4gICAgICAgIHJlcXVlc3QsXG4gICAgICAgIGV4aXN0aW5nQ3JlYXRlZEF0LFxuICAgICAgKTtcbiAgICAgIGF3YWl0IHdpdGhUcmFuc2llbnRSZXRyeSgoKSA9PlxuICAgICAgICBwcm9maWxlcy5zZW5kKFxuICAgICAgICAgIG5ldyBQdXRQcm9maWxlT2JqZWN0Q29tbWFuZCh7XG4gICAgICAgICAgICBEb21haW5OYW1lOiBkb21haW5OYW1lLFxuICAgICAgICAgICAgT2JqZWN0VHlwZU5hbWU6IE9CSkVDVF9UWVBFX0RFVklDRSxcbiAgICAgICAgICAgIE9iamVjdDogSlNPTi5zdHJpbmdpZnkoZGV2aWNlT2JqZWN0KSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gMykgU2V0IHVzZXItbGV2ZWwgLyB0YXJnZXRpbmcgYXR0cmlidXRlcyAoaW5jbC4gcHJvbW90ZWQgaGFzR0NNL2hhc0FQTlMpXG4gICAgLy8gICAgb24gdGhlIHJlc29sdmVkIHByb2ZpbGUuXG4gICAgY29uc3QgdXBkYXRlID0gYnVpbGRQcm9maWxlVXBkYXRlKHByaW5jaXBhbCwgcmVxdWVzdCk7XG4gICAgYXdhaXQgd2l0aFRyYW5zaWVudFJldHJ5KCgpID0+XG4gICAgICBwcm9maWxlcy5zZW5kKFxuICAgICAgICBuZXcgVXBkYXRlUHJvZmlsZUNvbW1hbmQoe1xuICAgICAgICAgIERvbWFpbk5hbWU6IGRvbWFpbk5hbWUsXG4gICAgICAgICAgUHJvZmlsZUlkOiBwcm9maWxlSWQsXG4gICAgICAgICAgRW1haWxBZGRyZXNzOiB1cGRhdGUuZW1haWxBZGRyZXNzLFxuICAgICAgICAgIEZpcnN0TmFtZTogdXBkYXRlLmZpcnN0TmFtZSxcbiAgICAgICAgICBMYXN0TmFtZTogdXBkYXRlLmxhc3ROYW1lLFxuICAgICAgICAgIEFkZHJlc3M6IHVwZGF0ZS5hZGRyZXNzXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBDaXR5OiB1cGRhdGUuYWRkcmVzcy5jaXR5LFxuICAgICAgICAgICAgICAgIENvdW50cnk6IHVwZGF0ZS5hZGRyZXNzLmNvdW50cnksXG4gICAgICAgICAgICAgICAgUG9zdGFsQ29kZTogdXBkYXRlLmFkZHJlc3MucG9zdGFsQ29kZSxcbiAgICAgICAgICAgICAgICBQcm92aW5jZTogdXBkYXRlLmFkZHJlc3MucHJvdmluY2UsXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICAgIEF0dHJpYnV0ZXM6IHVwZGF0ZS5hdHRyaWJ1dGVzLFxuICAgICAgICB9KSxcbiAgICAgICksXG4gICAgKTtcblxuICAgIC8vIDQpIE1lcmdlLW9uLXNpZ24taW46IGFuIEFVVEhFTlRJQ0FURUQgY2FsbGVyIHRoYXQgY2FycmllcyBpdHMgcHJpb3IgZ3Vlc3RcbiAgICAvLyAgICBpZGVudGl0eUlkIGZvbGRzIHRoZSBndWVzdCBwcm9maWxlICgrIGl0cyBkZXZpY2VzKSBpbnRvIHRoaXMgYXV0aGVkXG4gICAgLy8gICAgcHJvZmlsZSB2aWEgTWVyZ2VQcm9maWxlcy4gR3Vlc3RzIG5ldmVyIHRyaWdnZXIgYSBtZXJnZS4gQmVzdC1lZmZvcnQ6XG4gICAgLy8gICAgYSBtZXJnZSBmYWlsdXJlIGlzIGxvZ2dlZCBidXQgZG9lcyBub3QgZmFpbCB0aGUgaWRlbnRpZnkgcmVzdWx0LCB3aGljaFxuICAgIC8vICAgIGFscmVhZHkgc3VjY2VlZGVkIGFib3ZlLlxuICAgIGNvbnN0IGd1ZXN0SWRlbnRpdHlJZCA9IHJlcXVlc3Qub3B0aW9ucz8ucHJldmlvdXNHdWVzdElkZW50aXR5SWQ7XG4gICAgaWYgKHByaW5jaXBhbC5raW5kID09PSAnYXV0aGVkJyAmJiBndWVzdElkZW50aXR5SWQpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IG91dGNvbWUgPSBhd2FpdCBtZXJnZUd1ZXN0SW50b0F1dGhlZChcbiAgICAgICAgICBwcm9maWxlcyxcbiAgICAgICAgICBkb21haW5OYW1lLFxuICAgICAgICAgIGd1ZXN0SWRlbnRpdHlJZCxcbiAgICAgICAgICBwcm9maWxlSWQsXG4gICAgICAgICk7XG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICdbaWRlbnRpZnldIGd1ZXN0TWVyZ2UnLFxuICAgICAgICAgIEpTT04uc3RyaW5naWZ5KHsgbWVyZ2VkOiBvdXRjb21lLm1lcmdlZCB9KSxcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKG1lcmdlRXJyKSB7XG4gICAgICAgIGNvbnN0IG5hbWUgPSBtZXJnZUVyciBpbnN0YW5jZW9mIEVycm9yID8gbWVyZ2VFcnIubmFtZSA6ICdVbmtub3duRXJyb3InO1xuICAgICAgICBjb25zb2xlLmVycm9yKCdbaWRlbnRpZnldIGd1ZXN0TWVyZ2VFcnJvcicsIEpTT04uc3RyaW5naWZ5KHsgbmFtZSB9KSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlKDIwMCwgeyBzdGF0dXM6ICdvaycgfSk7XG4gIH0gY2F0Y2ggKGVycikge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnIgaW5zdGFuY2VvZiBFcnJvciA/IGVyci5tZXNzYWdlIDogJ3Vua25vd24gZXJyb3InO1xuICAgIC8vIExvZyBvbmx5IHRoZSBlcnJvciBuYW1lIChhbmQgSFRUUCBzdGF0dXMgd2hlbiBwcmVzZW50KSDigJQgbmV2ZXIgdGhlIGZ1bGxcbiAgICAvLyBlcnJvciBvYmplY3QsIHdob3NlIHN0YWNrIC8gcmVxdWVzdCBpbnB1dCBjYW4gY2FycnkgY3VzdG9tZXIgY29udGVudC5cbiAgICBjb25zdCBuYW1lID0gZXJyIGluc3RhbmNlb2YgRXJyb3IgPyBlcnIubmFtZSA6ICdVbmtub3duRXJyb3InO1xuICAgIGNvbnN0IHN0YXR1c0NvZGUgPSAoZXJyIGFzIHsgJG1ldGFkYXRhPzogeyBodHRwU3RhdHVzQ29kZT86IG51bWJlciB9IH0pXG4gICAgICA/LiRtZXRhZGF0YT8uaHR0cFN0YXR1c0NvZGU7XG4gICAgY29uc29sZS5lcnJvcihcbiAgICAgICdbaWRlbnRpZnldIGN1c3RvbWVyUHJvZmlsZXNFcnJvcicsXG4gICAgICBKU09OLnN0cmluZ2lmeSh7IG5hbWUsIHN0YXR1c0NvZGUgfSksXG4gICAgKTtcbiAgICByZXR1cm4gcmVzcG9uc2UoNTAwLCB7IGVycm9yOiBgQ3VzdG9tZXIgUHJvZmlsZXMgZXJyb3I6ICR7bWVzc2FnZX1gIH0pO1xuICB9XG59O1xuIl19
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ChannelType, IdentifyUserRequest } from './types.js';
|
|
2
|
+
import { Principal } from './principal.js';
|
|
3
|
+
/** A standard Customer Profiles address (subset used by this backend). */
|
|
4
|
+
export type ProfileAddress = {
|
|
5
|
+
city?: string;
|
|
6
|
+
country?: string;
|
|
7
|
+
postalCode?: string;
|
|
8
|
+
province?: string;
|
|
9
|
+
};
|
|
10
|
+
/** Person data mapped to UpdateProfile standard fields + Attributes map. */
|
|
11
|
+
export type ProfileUpdate = {
|
|
12
|
+
emailAddress?: string;
|
|
13
|
+
firstName?: string;
|
|
14
|
+
lastName?: string;
|
|
15
|
+
address?: ProfileAddress;
|
|
16
|
+
attributes: Record<string, string>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Flatten a multi-value attribute into a single string that fits within the
|
|
20
|
+
* Customer Profiles attribute-value limit.
|
|
21
|
+
*
|
|
22
|
+
* - Zero values -> empty string.
|
|
23
|
+
* - Exactly one value -> that element verbatim.
|
|
24
|
+
* - More than one value -> JSON.stringify of the array (preserves all values).
|
|
25
|
+
* The result is truncated to {@link MAX_ATTRIBUTE_LENGTH} characters.
|
|
26
|
+
*/
|
|
27
|
+
export declare const flatten: (values: string[]) => string;
|
|
28
|
+
/** Which promoted targeting attribute a channel type activates. */
|
|
29
|
+
export declare const targetingFlagsForChannel: (channelType: ChannelType | undefined) => {
|
|
30
|
+
hasGCM?: string;
|
|
31
|
+
hasAPNS?: string;
|
|
32
|
+
};
|
|
33
|
+
/** True when the request carries enough data to register/update a device. */
|
|
34
|
+
export declare const hasDeviceData: (req: IdentifyUserRequest) => boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Build the UpdateProfile payload (standard fields + Attributes map) for the
|
|
37
|
+
* profile identified by the verified {@link Principal} (authed `sub` or guest
|
|
38
|
+
* `cognitoIdentityId`).
|
|
39
|
+
*
|
|
40
|
+
* SECURITY: `principal.value` comes from an authorizer-verified source (JWT
|
|
41
|
+
* claims or the IAM/Cognito identity). The client-supplied `userId` is stored
|
|
42
|
+
* only as the `appUserId` attribute — never the identity.
|
|
43
|
+
*/
|
|
44
|
+
export declare const buildProfileUpdate: (principal: Principal, req: IdentifyUserRequest) => ProfileUpdate;
|
|
45
|
+
/**
|
|
46
|
+
* Build the `_source.*` payload for the AmplifyDevice object type.
|
|
47
|
+
*
|
|
48
|
+
* Keyed UNIQUELY by the stable `deviceId`; `deviceToken` (options.address) is a
|
|
49
|
+
* mutable field so token refreshes upsert the same object in place. Carries the
|
|
50
|
+
* verified identity field (`cognitoSub` for authed, `cognitoIdentityId` for
|
|
51
|
+
* guest) as the PROFILE-resolution key so the device merges into the profile
|
|
52
|
+
* bound to that {@link Principal}.
|
|
53
|
+
*
|
|
54
|
+
* `platform` / `appVersion` come from the options, falling back to the
|
|
55
|
+
* `userProfile.demographic` equivalents. `updatedAt` is server-set on every
|
|
56
|
+
* write; `createdAt` is the IMMUTABLE first-registration time — the caller
|
|
57
|
+
* passes the value read back from the existing device object (if any) so it is
|
|
58
|
+
* preserved across PutProfileObject replacements, otherwise it defaults to now.
|
|
59
|
+
*/
|
|
60
|
+
export declare const buildDeviceObject: (principal: Principal, req: IdentifyUserRequest, existingCreatedAt?: string) => Record<string, string>;
|
|
61
|
+
//# sourceMappingURL=mapping.d.ts.map
|