@adtrackify/at-service-common 4.0.13 → 4.0.15

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 (109) hide show
  1. package/dist/cjs/__tests__/identity-cache/helpers.spec.js +37 -38
  2. package/dist/cjs/__tests__/identity-cache/helpers.spec.js.map +1 -1
  3. package/dist/cjs/__tests__/identity-cache/identity-cache-tier-routing.spec.js +92 -349
  4. package/dist/cjs/__tests__/identity-cache/identity-cache-tier-routing.spec.js.map +1 -1
  5. package/dist/cjs/__tests__/identity-cache/identity-client.spec.js +360 -0
  6. package/dist/cjs/__tests__/identity-cache/identity-client.spec.js.map +1 -0
  7. package/dist/cjs/__tests__/identity-cache/identity-gateway-cache-hit.spec.js +138 -0
  8. package/dist/cjs/__tests__/identity-cache/identity-gateway-cache-hit.spec.js.map +1 -0
  9. package/dist/cjs/__tests__/identity-cache/identity-gateway-cache-miss.spec.js +153 -0
  10. package/dist/cjs/__tests__/identity-cache/identity-gateway-cache-miss.spec.js.map +1 -0
  11. package/dist/cjs/__tests__/identity-cache/identity-gateway-constructor.spec.js +72 -0
  12. package/dist/cjs/__tests__/identity-cache/identity-gateway-constructor.spec.js.map +1 -0
  13. package/dist/cjs/__tests__/identity-cache/identity-gateway-edge-cases.spec.js +89 -0
  14. package/dist/cjs/__tests__/identity-cache/identity-gateway-edge-cases.spec.js.map +1 -0
  15. package/dist/cjs/__tests__/identity-cache/identity-gateway-enqueue-async.spec.js +136 -0
  16. package/dist/cjs/__tests__/identity-cache/identity-gateway-enqueue-async.spec.js.map +1 -0
  17. package/dist/cjs/__tests__/identity-cache/identity-gateway-stale-cache.spec.js +224 -0
  18. package/dist/cjs/__tests__/identity-cache/identity-gateway-stale-cache.spec.js.map +1 -0
  19. package/dist/cjs/__tests__/identity-cache/identity-gateway-test-setup.d.ts +28 -0
  20. package/dist/cjs/__tests__/identity-cache/identity-gateway-test-setup.js +90 -0
  21. package/dist/cjs/__tests__/identity-cache/identity-gateway-test-setup.js.map +1 -0
  22. package/dist/cjs/clients/internal-api/identity-client.d.ts +12 -2
  23. package/dist/cjs/clients/internal-api/identity-client.js +59 -13
  24. package/dist/cjs/clients/internal-api/identity-client.js.map +1 -1
  25. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.d.ts +1 -7
  26. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js +0 -305
  27. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js.map +1 -1
  28. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.d.ts +14 -14
  29. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.js +122 -330
  30. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.js.map +1 -1
  31. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.d.ts +0 -1
  32. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.js +0 -1
  33. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.js.map +1 -1
  34. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.d.ts +8 -158
  35. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.js +1 -15
  36. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.js.map +1 -1
  37. package/dist/esm/__tests__/identity-cache/helpers.spec.js +26 -27
  38. package/dist/esm/__tests__/identity-cache/helpers.spec.js.map +1 -1
  39. package/dist/esm/__tests__/identity-cache/identity-cache-tier-routing.spec.js +92 -349
  40. package/dist/esm/__tests__/identity-cache/identity-cache-tier-routing.spec.js.map +1 -1
  41. package/dist/esm/__tests__/identity-cache/identity-client.spec.js +358 -0
  42. package/dist/esm/__tests__/identity-cache/identity-client.spec.js.map +1 -0
  43. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-hit.spec.d.ts +1 -0
  44. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-hit.spec.js +136 -0
  45. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-hit.spec.js.map +1 -0
  46. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-miss.spec.d.ts +1 -0
  47. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-miss.spec.js +151 -0
  48. package/dist/esm/__tests__/identity-cache/identity-gateway-cache-miss.spec.js.map +1 -0
  49. package/dist/esm/__tests__/identity-cache/identity-gateway-constructor.spec.d.ts +1 -0
  50. package/dist/esm/__tests__/identity-cache/identity-gateway-constructor.spec.js +70 -0
  51. package/dist/esm/__tests__/identity-cache/identity-gateway-constructor.spec.js.map +1 -0
  52. package/dist/esm/__tests__/identity-cache/identity-gateway-edge-cases.spec.d.ts +1 -0
  53. package/dist/esm/__tests__/identity-cache/identity-gateway-edge-cases.spec.js +87 -0
  54. package/dist/esm/__tests__/identity-cache/identity-gateway-edge-cases.spec.js.map +1 -0
  55. package/dist/esm/__tests__/identity-cache/identity-gateway-enqueue-async.spec.d.ts +1 -0
  56. package/dist/esm/__tests__/identity-cache/identity-gateway-enqueue-async.spec.js +134 -0
  57. package/dist/esm/__tests__/identity-cache/identity-gateway-enqueue-async.spec.js.map +1 -0
  58. package/dist/esm/__tests__/identity-cache/identity-gateway-stale-cache.spec.d.ts +1 -0
  59. package/dist/esm/__tests__/identity-cache/identity-gateway-stale-cache.spec.js +222 -0
  60. package/dist/esm/__tests__/identity-cache/identity-gateway-stale-cache.spec.js.map +1 -0
  61. package/dist/esm/__tests__/identity-cache/identity-gateway-test-setup.d.ts +28 -0
  62. package/dist/esm/__tests__/identity-cache/identity-gateway-test-setup.js +83 -0
  63. package/dist/esm/__tests__/identity-cache/identity-gateway-test-setup.js.map +1 -0
  64. package/dist/esm/clients/internal-api/identity-client.d.ts +12 -2
  65. package/dist/esm/clients/internal-api/identity-client.js +60 -14
  66. package/dist/esm/clients/internal-api/identity-client.js.map +1 -1
  67. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.d.ts +1 -7
  68. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js +1 -303
  69. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js.map +1 -1
  70. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.d.ts +14 -14
  71. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.js +125 -330
  72. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.js.map +1 -1
  73. package/dist/esm/services/db/identity-cache-dynamodb-service/index.d.ts +0 -1
  74. package/dist/esm/services/db/identity-cache-dynamodb-service/index.js +0 -1
  75. package/dist/esm/services/db/identity-cache-dynamodb-service/index.js.map +1 -1
  76. package/dist/esm/services/db/identity-cache-dynamodb-service/types.d.ts +8 -158
  77. package/dist/esm/services/db/identity-cache-dynamodb-service/types.js +0 -14
  78. package/dist/esm/services/db/identity-cache-dynamodb-service/types.js.map +1 -1
  79. package/package.json +2 -2
  80. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js +0 -646
  81. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js.map +0 -1
  82. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js +0 -325
  83. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js.map +0 -1
  84. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js +0 -1286
  85. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js.map +0 -1
  86. package/dist/cjs/__tests__/identity-cache/identity-gateway-service.spec.js +0 -2170
  87. package/dist/cjs/__tests__/identity-cache/identity-gateway-service.spec.js.map +0 -1
  88. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.d.ts +0 -26
  89. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.js +0 -252
  90. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.js.map +0 -1
  91. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js +0 -644
  92. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js.map +0 -1
  93. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js +0 -323
  94. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js.map +0 -1
  95. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js +0 -1284
  96. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js.map +0 -1
  97. package/dist/esm/__tests__/identity-cache/identity-gateway-service.spec.js +0 -2168
  98. package/dist/esm/__tests__/identity-cache/identity-gateway-service.spec.js.map +0 -1
  99. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.d.ts +0 -26
  100. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.js +0 -235
  101. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.js.map +0 -1
  102. /package/dist/cjs/__tests__/identity-cache/{identity-cache-dynamodb-db-service-v2-comparison.spec.d.ts → identity-client.spec.d.ts} +0 -0
  103. /package/dist/cjs/__tests__/identity-cache/{identity-cache-dynamodb-service-v2-comparison.spec.d.ts → identity-gateway-cache-hit.spec.d.ts} +0 -0
  104. /package/dist/cjs/__tests__/identity-cache/{identity-cache-dynamodb-service.spec.d.ts → identity-gateway-cache-miss.spec.d.ts} +0 -0
  105. /package/dist/cjs/__tests__/identity-cache/{identity-gateway-service.spec.d.ts → identity-gateway-constructor.spec.d.ts} +0 -0
  106. /package/dist/{esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.d.ts → cjs/__tests__/identity-cache/identity-gateway-edge-cases.spec.d.ts} +0 -0
  107. /package/dist/{esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.d.ts → cjs/__tests__/identity-cache/identity-gateway-enqueue-async.spec.d.ts} +0 -0
  108. /package/dist/{esm/__tests__/identity-cache/identity-cache-dynamodb-service.spec.d.ts → cjs/__tests__/identity-cache/identity-gateway-stale-cache.spec.d.ts} +0 -0
  109. /package/dist/esm/__tests__/identity-cache/{identity-gateway-service.spec.d.ts → identity-client.spec.d.ts} +0 -0
@@ -1,7 +1,5 @@
1
1
  import { ADDRESS_INFO_SOURCE } from '@adtrackify/at-tracking-event-types';
2
- import { IDENTITY_CACHE_STALENESS_TIER } from '@adtrackify/at-shared-utils';
3
- import { CACHE_WRITE_REASON } from '../../services/db/identity-cache-dynamodb-service';
4
- const mockInvokeFunction = jest.fn();
2
+ const mockLambdaInvoke = jest.fn();
5
3
  const mockBuildAndSendMessage = jest.fn();
6
4
  const mockSQSClientConstructor = jest.fn();
7
5
  jest.mock('../../clients/index.js', () => ({
@@ -15,7 +13,7 @@ jest.mock('../../clients/index.js', () => ({
15
13
  batchWrite: jest.fn(),
16
14
  },
17
15
  LambdaInvokeClient: jest.fn().mockImplementation(() => ({
18
- invokeFunction: mockInvokeFunction,
16
+ invokeFunction: mockLambdaInvoke,
19
17
  })),
20
18
  SQSClient: jest.fn().mockImplementation((_region, _accountId, _queueName) => {
21
19
  mockSQSClientConstructor(_region, _accountId, _queueName);
@@ -33,15 +31,23 @@ jest.mock('../../helpers/index.js', () => ({
33
31
  error: jest.fn(),
34
32
  },
35
33
  }));
34
+ const mockGetIdentity = jest.fn();
35
+ jest.mock('../../clients/internal-api/identity-client.js', () => ({
36
+ IdentityClient: jest.fn().mockImplementation(() => ({
37
+ getIdentity: mockGetIdentity,
38
+ })),
39
+ }));
36
40
  import { IdentityGatewayService, } from '../../services/db/identity-cache-dynamodb-service/identity-gateway-service.js';
37
41
  import { IDENTITY_CACHE_WITH_CACHING_OUTCOME, } from '../../services/db/identity-cache-dynamodb-service/types.js';
38
- import { IdentityCacheDynamoDbDbService } from '../../services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js';
39
42
  import { DynamoDbClient, SQSClient } from '../../clients/index.js';
40
43
  const mockedDynamoDbClient = DynamoDbClient;
41
44
  const _mockedSQSClient = SQSClient;
45
+ const createService = (options = { identifyPrivateLambdaArn: 'arn:aws:lambda:us-east-1:123456789:function:identity-private' }) => {
46
+ return new IdentityGatewayService(options);
47
+ };
42
48
  describe('Identity Cache Three-Tier Routing', () => {
43
49
  const pixelId = 'pixel123';
44
- const lambdaArn = 'arn:aws:lambda:us-east-1:123456789:function:identity-private';
50
+ let service;
45
51
  beforeEach(() => {
46
52
  jest.clearAllMocks();
47
53
  mockedDynamoDbClient.safeGet.mockReset();
@@ -51,13 +57,11 @@ describe('Identity Cache Three-Tier Routing', () => {
51
57
  mockedDynamoDbClient.safeBatchWrite.mockReset();
52
58
  mockedDynamoDbClient.safeQueryByGSI.mockReset();
53
59
  mockedDynamoDbClient.batchWrite.mockReset();
54
- mockInvokeFunction.mockReset();
60
+ mockGetIdentity.mockReset();
55
61
  mockBuildAndSendMessage.mockReset();
56
62
  mockSQSClientConstructor.mockReset();
57
63
  _mockedSQSClient.mockClear();
58
- IdentityGatewayService.lambdaInvokeClient = undefined;
59
- IdentityGatewayService.sqsClient = undefined;
60
- IdentityGatewayService.sqsQueueUrl = undefined;
64
+ service = createService();
61
65
  });
62
66
  describe('TIER: VOLATILE_ONLY — Returns merged identity, NO Neptune, NO cache write', () => {
63
67
  it('should return merged identity without Neptune call when only ipAddress is stale', async () => {
@@ -82,10 +86,10 @@ describe('Identity Cache Three-Tier Routing', () => {
82
86
  updatedAt: new Date().toISOString(),
83
87
  };
84
88
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
85
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
89
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
86
90
  expect(result.identity).toBeDefined();
87
91
  expect(result.identity?.identityId).toBe('identity456');
88
- expect(mockInvokeFunction).not.toHaveBeenCalled();
92
+ expect(mockGetIdentity).not.toHaveBeenCalled();
89
93
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
90
94
  });
91
95
  it('should return merged identity without Neptune call when only userAgent is stale', async () => {
@@ -110,9 +114,9 @@ describe('Identity Cache Three-Tier Routing', () => {
110
114
  updatedAt: new Date().toISOString(),
111
115
  };
112
116
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
113
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
117
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
114
118
  expect(result.identity).toBeDefined();
115
- expect(mockInvokeFunction).not.toHaveBeenCalled();
119
+ expect(mockGetIdentity).not.toHaveBeenCalled();
116
120
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
117
121
  });
118
122
  it('should return merged identity without Neptune call when only IP-sourced addresses are stale', async () => {
@@ -137,115 +141,10 @@ describe('Identity Cache Three-Tier Routing', () => {
137
141
  updatedAt: new Date().toISOString(),
138
142
  };
139
143
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
140
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
141
- expect(result.identity).toBeDefined();
142
- expect(mockInvokeFunction).not.toHaveBeenCalled();
143
- expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
144
- });
145
- });
146
- describe('TIER: ADDRESS_UPDATE — Enqueues async update, NO Neptune call, NO sync cache write', () => {
147
- it('should enqueue async update but skip Neptune when new non-IP address is added', async () => {
148
- IdentityGatewayService.configure({
149
- awsRegion: 'us-east-1',
150
- awsAccountId: '123456789',
151
- asyncUpdateQueueName: 'test-queue',
152
- });
153
- mockBuildAndSendMessage.mockResolvedValueOnce({ MessageId: 'test-msg-id' });
154
- const incomingIdentity = {
155
- identityId: 'identity456',
156
- traits: {
157
- emails: ['test@email.com'],
158
- addresses: [{ city: 'Boston', firstName: 'John', s: ADDRESS_INFO_SOURCE.INPUT }],
159
- },
160
- };
161
- const cachedResponse = {
162
- pk: `identity#${pixelId}#identity456`,
163
- pixelId,
164
- identityId: 'identity456',
165
- response: {
166
- identityId: 'identity456',
167
- traits: {
168
- emails: ['test@email.com'],
169
- addresses: [],
170
- },
171
- },
172
- updatedAt: new Date().toISOString(),
173
- };
174
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
175
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
176
- expect(result.identity).toBeDefined();
177
- expect(result.identity?.traits?.addresses).toHaveLength(1);
178
- expect(mockInvokeFunction).not.toHaveBeenCalled();
179
- expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
180
- expect(mockBuildAndSendMessage).toHaveBeenCalled();
181
- });
182
- it('should enqueue async update and skip Neptune when address with PII but no source is added', async () => {
183
- IdentityGatewayService.configure({
184
- awsRegion: 'us-east-1',
185
- awsAccountId: '123456789',
186
- asyncUpdateQueueName: 'test-queue',
187
- });
188
- mockBuildAndSendMessage.mockResolvedValueOnce({ MessageId: 'test-msg-id' });
189
- const incomingIdentity = {
190
- identityId: 'identity456',
191
- traits: {
192
- emails: ['test@email.com'],
193
- addresses: [{ city: 'Miami', lastName: 'Smith' }],
194
- },
195
- };
196
- const cachedResponse = {
197
- pk: `identity#${pixelId}#identity456`,
198
- pixelId,
199
- identityId: 'identity456',
200
- response: {
201
- identityId: 'identity456',
202
- traits: {
203
- emails: ['test@email.com'],
204
- addresses: [],
205
- },
206
- },
207
- updatedAt: new Date().toISOString(),
208
- };
209
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
210
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
144
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
211
145
  expect(result.identity).toBeDefined();
212
- expect(mockInvokeFunction).not.toHaveBeenCalled();
146
+ expect(mockGetIdentity).not.toHaveBeenCalled();
213
147
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
214
- expect(mockBuildAndSendMessage).toHaveBeenCalled();
215
- });
216
- it('should return ADDRESS_UPDATE_ASYNC outcome in summary', async () => {
217
- IdentityGatewayService.configure({
218
- awsRegion: 'us-east-1',
219
- awsAccountId: '123456789',
220
- asyncUpdateQueueName: 'test-queue',
221
- });
222
- mockBuildAndSendMessage.mockResolvedValueOnce({ MessageId: 'test-msg-id' });
223
- const incomingIdentity = {
224
- identityId: 'identity456',
225
- traits: {
226
- emails: ['test@email.com'],
227
- addresses: [{ city: 'Seattle', s: ADDRESS_INFO_SOURCE.INPUT }],
228
- },
229
- };
230
- const cachedResponse = {
231
- pk: `identity#${pixelId}#identity456`,
232
- pixelId,
233
- identityId: 'identity456',
234
- response: {
235
- identityId: 'identity456',
236
- traits: {
237
- emails: ['test@email.com'],
238
- addresses: [],
239
- },
240
- },
241
- updatedAt: new Date().toISOString(),
242
- };
243
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
244
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
245
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.ADDRESS_UPDATE_ASYNC);
246
- expect(result.summary.didSkipNeptune).toBe(true);
247
- expect(result.summary.didWriteCache).toBe(false);
248
- expect(result.summary.didEnqueueAsync).toBe(true);
249
148
  });
250
149
  });
251
150
  describe('TIER: IDENTITY_STALE — Calls Neptune AND writes to cache', () => {
@@ -269,18 +168,13 @@ describe('Identity Cache Three-Tier Routing', () => {
269
168
  updatedAt: new Date().toISOString(),
270
169
  };
271
170
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
272
- mockInvokeFunction.mockResolvedValueOnce({
273
- statusCode: 200,
274
- body: JSON.stringify({
275
- identity: {
276
- identityId: 'identity456',
277
- traits: { emails: ['old@email.com', 'new@email.com', 'resolved@email.com'] },
278
- },
279
- }),
171
+ mockGetIdentity.mockResolvedValueOnce({
172
+ identityId: 'identity456',
173
+ traits: { emails: ['old@email.com', 'new@email.com', 'resolved@email.com'] },
280
174
  });
281
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
175
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
282
176
  expect(result.identity).toBeDefined();
283
- expect(mockInvokeFunction).toHaveBeenCalled();
177
+ expect(mockGetIdentity).toHaveBeenCalled();
284
178
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
285
179
  });
286
180
  it('should call Neptune and write to cache when phones are stale', async () => {
@@ -303,18 +197,13 @@ describe('Identity Cache Three-Tier Routing', () => {
303
197
  updatedAt: new Date().toISOString(),
304
198
  };
305
199
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
306
- mockInvokeFunction.mockResolvedValueOnce({
307
- statusCode: 200,
308
- body: JSON.stringify({
309
- identity: {
310
- identityId: 'identity456',
311
- traits: { phones: ['+1234567890', '+9876543210'] },
312
- },
313
- }),
200
+ mockGetIdentity.mockResolvedValueOnce({
201
+ identityId: 'identity456',
202
+ traits: { phones: ['+1234567890', '+9876543210'] },
314
203
  });
315
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
204
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
316
205
  expect(result.identity).toBeDefined();
317
- expect(mockInvokeFunction).toHaveBeenCalled();
206
+ expect(mockGetIdentity).toHaveBeenCalled();
318
207
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
319
208
  });
320
209
  it('should return NEPTUNE_WRITE_BACK outcome with staleTraits in summary', async () => {
@@ -335,20 +224,15 @@ describe('Identity Cache Three-Tier Routing', () => {
335
224
  updatedAt: new Date().toISOString(),
336
225
  };
337
226
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
338
- mockInvokeFunction.mockResolvedValueOnce({
339
- statusCode: 200,
340
- body: JSON.stringify({
341
- identity: {
342
- identityId: 'identity456',
343
- traits: { emails: ['old@email.com', 'new@email.com'] },
344
- },
345
- }),
227
+ mockGetIdentity.mockResolvedValueOnce({
228
+ identityId: 'identity456',
229
+ traits: { emails: ['old@email.com', 'new@email.com'] },
346
230
  });
347
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
348
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
349
- expect(result.summary.staleTraits).toContain('emails');
350
- expect(result.summary.didCallNeptune).toBe(true);
351
- expect(result.summary.didWriteCache).toBe(false);
231
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
232
+ expect(result.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
233
+ expect(result.stalenessResult?.staleTraits).toContain('emails');
234
+ expect(result.didCallNeptune).toBe(true);
235
+ expect(result.didWriteCache).toBe(false);
352
236
  });
353
237
  });
354
238
  describe('CACHE_MISS — Calls Neptune AND writes to cache', () => {
@@ -358,18 +242,13 @@ describe('Identity Cache Three-Tier Routing', () => {
358
242
  traits: { emails: ['test@email.com'] },
359
243
  };
360
244
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
361
- mockInvokeFunction.mockResolvedValueOnce({
362
- statusCode: 200,
363
- body: JSON.stringify({
364
- identity: {
365
- identityId: 'identity456',
366
- traits: { emails: ['test@email.com'] },
367
- },
368
- }),
245
+ mockGetIdentity.mockResolvedValueOnce({
246
+ identityId: 'identity456',
247
+ traits: { emails: ['test@email.com'] },
369
248
  });
370
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
249
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
371
250
  expect(result.identity).toBeDefined();
372
- expect(mockInvokeFunction).toHaveBeenCalled();
251
+ expect(mockGetIdentity).toHaveBeenCalled();
373
252
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
374
253
  });
375
254
  it('should return NEPTUNE_WRITE_BACK outcome for cache miss', async () => {
@@ -378,19 +257,14 @@ describe('Identity Cache Three-Tier Routing', () => {
378
257
  traits: { emails: ['test@email.com'] },
379
258
  };
380
259
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
381
- mockInvokeFunction.mockResolvedValueOnce({
382
- statusCode: 200,
383
- body: JSON.stringify({
384
- identity: {
385
- identityId: 'identity456',
386
- traits: { emails: ['test@email.com'] },
387
- },
388
- }),
260
+ mockGetIdentity.mockResolvedValueOnce({
261
+ identityId: 'identity456',
262
+ traits: { emails: ['test@email.com'] },
389
263
  });
390
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
391
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
392
- expect(result.summary.didCallNeptune).toBe(true);
393
- expect(result.summary.didWriteCache).toBe(false);
264
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
265
+ expect(result.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
266
+ expect(result.didCallNeptune).toBe(true);
267
+ expect(result.didWriteCache).toBe(false);
394
268
  });
395
269
  });
396
270
  describe('EMAIL_POINTER_DISCOVERY — Calls Neptune with discovered identityId', () => {
@@ -406,36 +280,30 @@ describe('Identity Cache Three-Tier Routing', () => {
406
280
  updatedAt: new Date().toISOString(),
407
281
  };
408
282
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(pointerRecord);
409
- mockInvokeFunction.mockResolvedValueOnce({
410
- statusCode: 200,
411
- body: JSON.stringify({
412
- identity: {
413
- identityId: 'discovered-id',
414
- traits: { emails: ['test@email.com', 'other@email.com'] },
415
- },
416
- }),
283
+ mockGetIdentity.mockResolvedValueOnce({
284
+ identityId: 'discovered-id',
285
+ traits: { emails: ['test@email.com', 'other@email.com'] },
417
286
  });
418
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
287
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
419
288
  expect(result.identity?.identityId).toBe('discovered-id');
420
- expect(mockInvokeFunction).toHaveBeenCalledWith(lambdaArn, expect.objectContaining({
421
- context: {
422
- identity: expect.objectContaining({
423
- traits: { emails: ['test@email.com'] },
424
- }),
425
- },
289
+ expect(mockGetIdentity).toHaveBeenCalledWith(pixelId, expect.objectContaining({
290
+ identity: expect.objectContaining({
291
+ identityId: 'discovered-id',
292
+ traits: expect.objectContaining({ emails: ['test@email.com'] }),
293
+ }),
426
294
  }));
427
295
  });
428
296
  });
429
297
  });
430
298
  describe('Identity Cache stripAddressTimestamps', () => {
431
299
  const pixelId = 'pixel123';
432
- const lambdaArn = 'arn:aws:lambda:us-east-1:123456789:function:identity-private';
300
+ let service;
433
301
  beforeEach(() => {
434
302
  jest.clearAllMocks();
435
303
  mockedDynamoDbClient.safeGet.mockReset();
436
304
  mockedDynamoDbClient.safeBatchWrite.mockReset();
437
- mockInvokeFunction.mockReset();
438
- IdentityGatewayService.lambdaInvokeClient = undefined;
305
+ mockGetIdentity.mockReset();
306
+ service = createService();
439
307
  });
440
308
  it('should strip cra and upa from addresses during comparison', async () => {
441
309
  const incomingIdentity = {
@@ -473,9 +341,9 @@ describe('Identity Cache stripAddressTimestamps', () => {
473
341
  updatedAt: new Date().toISOString(),
474
342
  };
475
343
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
476
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
344
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
477
345
  expect(result.identity).toBeDefined();
478
- expect(mockInvokeFunction).not.toHaveBeenCalled();
346
+ expect(mockGetIdentity).not.toHaveBeenCalled();
479
347
  });
480
348
  it('should NOT mutate the original object when stripping timestamps', async () => {
481
349
  const originalAddress = {
@@ -512,7 +380,7 @@ describe('Identity Cache stripAddressTimestamps', () => {
512
380
  updatedAt: new Date().toISOString(),
513
381
  };
514
382
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
515
- await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
383
+ await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
516
384
  expect(incomingIdentity.traits?.addresses?.[0]).toHaveProperty('cra');
517
385
  expect(incomingIdentity.traits?.addresses?.[0]).toHaveProperty('upa');
518
386
  expect(cachedResponse.response.traits?.addresses?.[0]).toHaveProperty('cra');
@@ -538,9 +406,9 @@ describe('Identity Cache stripAddressTimestamps', () => {
538
406
  updatedAt: new Date().toISOString(),
539
407
  };
540
408
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
541
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
409
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
542
410
  expect(result.identity).toBeDefined();
543
- expect(mockInvokeFunction).not.toHaveBeenCalled();
411
+ expect(mockGetIdentity).not.toHaveBeenCalled();
544
412
  });
545
413
  it('should handle identity with empty addresses array', async () => {
546
414
  const incomingIdentity = {
@@ -564,9 +432,9 @@ describe('Identity Cache stripAddressTimestamps', () => {
564
432
  updatedAt: new Date().toISOString(),
565
433
  };
566
434
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
567
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
435
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
568
436
  expect(result.identity).toBeDefined();
569
- expect(mockInvokeFunction).not.toHaveBeenCalled();
437
+ expect(mockGetIdentity).not.toHaveBeenCalled();
570
438
  });
571
439
  it('should handle addresses without cra/upa (no-op)', async () => {
572
440
  const incomingIdentity = {
@@ -590,20 +458,20 @@ describe('Identity Cache stripAddressTimestamps', () => {
590
458
  updatedAt: new Date().toISOString(),
591
459
  };
592
460
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
593
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
461
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
594
462
  expect(result.identity).toBeDefined();
595
- expect(mockInvokeFunction).not.toHaveBeenCalled();
463
+ expect(mockGetIdentity).not.toHaveBeenCalled();
596
464
  });
597
465
  });
598
466
  describe('Identity Cache fastDeepEqual with Timestamp Stripping', () => {
599
467
  const pixelId = 'pixel123';
600
- const lambdaArn = 'arn:aws:lambda:us-east-1:123456789:function:identity-private';
468
+ let service;
601
469
  beforeEach(() => {
602
470
  jest.clearAllMocks();
603
471
  mockedDynamoDbClient.safeGet.mockReset();
604
472
  mockedDynamoDbClient.safeBatchWrite.mockReset();
605
- mockInvokeFunction.mockReset();
606
- IdentityGatewayService.lambdaInvokeClient = undefined;
473
+ mockGetIdentity.mockReset();
474
+ service = createService();
607
475
  });
608
476
  it('should treat cached and merged as equal when they differ ONLY in cra/upa', async () => {
609
477
  const incomingIdentity = {
@@ -645,9 +513,9 @@ describe('Identity Cache fastDeepEqual with Timestamp Stripping', () => {
645
513
  updatedAt: new Date().toISOString(),
646
514
  };
647
515
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
648
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
516
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
649
517
  expect(result.identity).toBeDefined();
650
- expect(mockInvokeFunction).not.toHaveBeenCalled();
518
+ expect(mockGetIdentity).not.toHaveBeenCalled();
651
519
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
652
520
  });
653
521
  it('should treat cached and merged as NOT equal when address content differs (plus cra/upa)', async () => {
@@ -688,19 +556,19 @@ describe('Identity Cache fastDeepEqual with Timestamp Stripping', () => {
688
556
  updatedAt: new Date().toISOString(),
689
557
  };
690
558
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
691
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
559
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
692
560
  expect(result.identity).toBeDefined();
693
561
  });
694
562
  });
695
563
  describe('Identity Cache Logging Levels', () => {
696
564
  const pixelId = 'pixel123';
697
- const lambdaArn = 'arn:aws:lambda:us-east-1:123456789:function:identity-private';
565
+ let service;
698
566
  beforeEach(() => {
699
567
  jest.clearAllMocks();
700
568
  mockedDynamoDbClient.safeGet.mockReset();
701
569
  mockedDynamoDbClient.safeBatchWrite.mockReset();
702
- mockInvokeFunction.mockReset();
703
- IdentityGatewayService.lambdaInvokeClient = undefined;
570
+ mockGetIdentity.mockReset();
571
+ service = createService();
704
572
  });
705
573
  it('should return fresh cache hit without calling Neptune or writing cache', async () => {
706
574
  const incomingIdentity = {
@@ -722,45 +590,11 @@ describe('Identity Cache Logging Levels', () => {
722
590
  updatedAt: new Date().toISOString(),
723
591
  };
724
592
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
725
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
726
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.FRESH_CACHE_HIT);
727
- expect(mockInvokeFunction).not.toHaveBeenCalled();
593
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
594
+ expect(result.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.FRESH_CACHE_HIT);
595
+ expect(mockGetIdentity).not.toHaveBeenCalled();
728
596
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
729
597
  });
730
- it('should return ADDRESS_UPDATE_ASYNC outcome for address update path', async () => {
731
- IdentityGatewayService.configure({
732
- awsRegion: 'us-east-1',
733
- awsAccountId: '123456789',
734
- asyncUpdateQueueName: 'test-queue',
735
- });
736
- mockBuildAndSendMessage.mockResolvedValueOnce({ MessageId: 'test-msg-id' });
737
- const incomingIdentity = {
738
- identityId: 'identity456',
739
- traits: {
740
- emails: ['test@email.com'],
741
- addresses: [{ city: 'New City', s: ADDRESS_INFO_SOURCE.INPUT }],
742
- },
743
- };
744
- const cachedResponse = {
745
- pk: `identity#${pixelId}#identity456`,
746
- pixelId,
747
- identityId: 'identity456',
748
- response: {
749
- identityId: 'identity456',
750
- traits: {
751
- emails: ['test@email.com'],
752
- addresses: [],
753
- },
754
- },
755
- updatedAt: new Date().toISOString(),
756
- };
757
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
758
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
759
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.ADDRESS_UPDATE_ASYNC);
760
- expect(result.summary.didSkipNeptune).toBe(true);
761
- expect(result.summary.didWriteCache).toBe(false);
762
- expect(result.summary.didEnqueueAsync).toBe(true);
763
- });
764
598
  it('should return NEPTUNE_WRITE_BACK outcome with traitChanges for stale traits', async () => {
765
599
  const incomingIdentity = {
766
600
  identityId: 'identity456',
@@ -781,107 +615,16 @@ describe('Identity Cache Logging Levels', () => {
781
615
  updatedAt: new Date().toISOString(),
782
616
  };
783
617
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
784
- mockInvokeFunction.mockResolvedValueOnce({
785
- statusCode: 200,
786
- body: JSON.stringify({
787
- identity: {
788
- identityId: 'identity456',
789
- traits: { emails: ['old@email.com', 'new@email.com'] },
790
- },
791
- }),
792
- });
793
- const result = await IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
794
- expect(result.summary.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
795
- expect(result.summary.staleTraits).toContain('emails');
796
- expect(result.summary.traitChanges).toBeDefined();
797
- expect(result.summary.didCallNeptune).toBe(true);
798
- expect(result.summary.didWriteCache).toBe(false);
799
- });
800
- });
801
- describe('getIdentityFromCache staleness tier results', () => {
802
- const pixelId = 'pixel123';
803
- beforeEach(() => {
804
- jest.clearAllMocks();
805
- mockedDynamoDbClient.safeGet.mockReset();
806
- });
807
- it('should return staleTier NONE when cached and incoming are deep equal', async () => {
808
- const incomingIdentity = {
809
- identityId: 'identity456',
810
- traits: {
811
- emails: ['test@email.com'],
812
- },
813
- };
814
- const cachedResponse = {
815
- pk: `identity#${pixelId}#identity456`,
816
- pixelId,
817
- identityId: 'identity456',
818
- response: {
819
- identityId: 'identity456',
820
- traits: {
821
- emails: ['test@email.com'],
822
- },
823
- },
824
- updatedAt: new Date().toISOString(),
825
- };
826
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
827
- const result = await IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, incomingIdentity);
828
- expect(result.staleTier).toBe(IDENTITY_CACHE_STALENESS_TIER.NONE);
829
- expect(result.isCacheStale).toBe(false);
830
- expect(result.skipNeptune).toBeUndefined();
831
- });
832
- it('should return staleTier ADDRESS_UPDATE and skipNeptune=true for new non-IP address', async () => {
833
- const incomingIdentity = {
834
- identityId: 'identity456',
835
- traits: {
836
- emails: ['test@email.com'],
837
- addresses: [{ city: 'New City', s: ADDRESS_INFO_SOURCE.INPUT }],
838
- },
839
- };
840
- const cachedResponse = {
841
- pk: `identity#${pixelId}#identity456`,
842
- pixelId,
843
- identityId: 'identity456',
844
- response: {
845
- identityId: 'identity456',
846
- traits: {
847
- emails: ['test@email.com'],
848
- addresses: [],
849
- },
850
- },
851
- updatedAt: new Date().toISOString(),
852
- };
853
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
854
- const result = await IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, incomingIdentity);
855
- expect(result.staleTier).toBe(IDENTITY_CACHE_STALENESS_TIER.ADDRESS_UPDATE);
856
- expect(result.isCacheStale).toBe(true);
857
- expect(result.skipNeptune).toBe(true);
858
- expect(result.writeReason).toBe(CACHE_WRITE_REASON.ADDRESS_UPDATE);
859
- });
860
- it('should return staleTier IDENTITY_STALE and skipNeptune=false for new email', async () => {
861
- const incomingIdentity = {
618
+ mockGetIdentity.mockResolvedValueOnce({
862
619
  identityId: 'identity456',
863
- traits: {
864
- emails: ['old@email.com', 'new@email.com'],
865
- },
866
- };
867
- const cachedResponse = {
868
- pk: `identity#${pixelId}#identity456`,
869
- pixelId,
870
- identityId: 'identity456',
871
- response: {
872
- identityId: 'identity456',
873
- traits: {
874
- emails: ['old@email.com'],
875
- },
876
- },
877
- updatedAt: new Date().toISOString(),
878
- };
879
- mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
880
- const result = await IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, incomingIdentity);
881
- expect(result.staleTier).toBe(IDENTITY_CACHE_STALENESS_TIER.IDENTITY_STALE);
882
- expect(result.isCacheStale).toBe(true);
883
- expect(result.skipNeptune).toBe(false);
884
- expect(result.writeReason).toBe(CACHE_WRITE_REASON.STALE_TRAITS);
620
+ traits: { emails: ['old@email.com', 'new@email.com'] },
621
+ });
622
+ const result = await service.resolveIdentityWithCaching(pixelId, incomingIdentity);
623
+ expect(result.outcome).toBe(IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_RESOLVED);
624
+ expect(result.stalenessResult?.staleTraits).toContain('emails');
625
+ expect(result.traitChanges).toBeDefined();
626
+ expect(result.didCallNeptune).toBe(true);
627
+ expect(result.didWriteCache).toBe(false);
885
628
  });
886
629
  });
887
630
  //# sourceMappingURL=identity-cache-tier-routing.spec.js.map