@adtrackify/at-service-common 4.0.5 → 4.0.6

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 (79) hide show
  1. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.d.ts +1 -0
  2. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js +646 -0
  3. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js.map +1 -0
  4. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.d.ts +1 -0
  5. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js +327 -0
  6. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js.map +1 -0
  7. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js +250 -108
  8. package/dist/cjs/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js.map +1 -1
  9. package/dist/cjs/__tests__/identity-cache/identity-cache-tier-routing.spec.js +37 -36
  10. package/dist/cjs/__tests__/identity-cache/identity-cache-tier-routing.spec.js.map +1 -1
  11. package/dist/cjs/__tests__/identity-cache/identity-gateway-service.spec.d.ts +1 -0
  12. package/dist/cjs/__tests__/identity-cache/identity-gateway-service.spec.js +567 -0
  13. package/dist/cjs/__tests__/identity-cache/identity-gateway-service.spec.js.map +1 -0
  14. package/dist/cjs/services/db/identity-cache-dynamodb-service/constants.d.ts +3 -0
  15. package/dist/cjs/services/db/identity-cache-dynamodb-service/constants.js +7 -0
  16. package/dist/cjs/services/db/identity-cache-dynamodb-service/constants.js.map +1 -0
  17. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.d.ts +14 -0
  18. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.js +251 -0
  19. package/dist/cjs/services/db/identity-cache-dynamodb-service/helpers.js.map +1 -0
  20. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.d.ts +24 -0
  21. package/dist/cjs/services/db/{identity-cache-dynamodb-service.js → identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js} +221 -343
  22. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js.map +1 -0
  23. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.d.ts +22 -0
  24. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.js +375 -0
  25. package/dist/cjs/services/db/identity-cache-dynamodb-service/identity-gateway-service.js.map +1 -0
  26. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.d.ts +4 -0
  27. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.js +21 -0
  28. package/dist/cjs/services/db/identity-cache-dynamodb-service/index.js.map +1 -0
  29. package/dist/cjs/services/db/identity-cache-dynamodb-service/key-builders.d.ts +12 -0
  30. package/dist/cjs/services/db/identity-cache-dynamodb-service/key-builders.js +32 -0
  31. package/dist/cjs/services/db/identity-cache-dynamodb-service/key-builders.js.map +1 -0
  32. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.d.ts +205 -0
  33. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.js +35 -0
  34. package/dist/cjs/services/db/identity-cache-dynamodb-service/types.js.map +1 -0
  35. package/dist/cjs/services/db/index.d.ts +4 -1
  36. package/dist/cjs/services/db/index.js +4 -1
  37. package/dist/cjs/services/db/index.js.map +1 -1
  38. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.d.ts +1 -0
  39. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js +644 -0
  40. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-db-service-v2-comparison.spec.js.map +1 -0
  41. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.d.ts +1 -0
  42. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js +325 -0
  43. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service-v2-comparison.spec.js.map +1 -0
  44. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js +250 -108
  45. package/dist/esm/__tests__/identity-cache/identity-cache-dynamodb-service.spec.js.map +1 -1
  46. package/dist/esm/__tests__/identity-cache/identity-cache-tier-routing.spec.js +37 -36
  47. package/dist/esm/__tests__/identity-cache/identity-cache-tier-routing.spec.js.map +1 -1
  48. package/dist/esm/__tests__/identity-cache/identity-gateway-service.spec.d.ts +1 -0
  49. package/dist/esm/__tests__/identity-cache/identity-gateway-service.spec.js +565 -0
  50. package/dist/esm/__tests__/identity-cache/identity-gateway-service.spec.js.map +1 -0
  51. package/dist/esm/services/db/identity-cache-dynamodb-service/constants.d.ts +3 -0
  52. package/dist/esm/services/db/identity-cache-dynamodb-service/constants.js +4 -0
  53. package/dist/esm/services/db/identity-cache-dynamodb-service/constants.js.map +1 -0
  54. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.d.ts +14 -0
  55. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.js +234 -0
  56. package/dist/esm/services/db/identity-cache-dynamodb-service/helpers.js.map +1 -0
  57. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.d.ts +24 -0
  58. package/dist/esm/services/db/{identity-cache-dynamodb-service.js → identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js} +199 -321
  59. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js.map +1 -0
  60. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.d.ts +22 -0
  61. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.js +368 -0
  62. package/dist/esm/services/db/identity-cache-dynamodb-service/identity-gateway-service.js.map +1 -0
  63. package/dist/esm/services/db/identity-cache-dynamodb-service/index.d.ts +4 -0
  64. package/dist/esm/services/db/identity-cache-dynamodb-service/index.js +5 -0
  65. package/dist/esm/services/db/identity-cache-dynamodb-service/index.js.map +1 -0
  66. package/dist/esm/services/db/identity-cache-dynamodb-service/key-builders.d.ts +12 -0
  67. package/dist/esm/services/db/identity-cache-dynamodb-service/key-builders.js +24 -0
  68. package/dist/esm/services/db/identity-cache-dynamodb-service/key-builders.js.map +1 -0
  69. package/dist/esm/services/db/identity-cache-dynamodb-service/types.d.ts +205 -0
  70. package/dist/esm/services/db/identity-cache-dynamodb-service/types.js +32 -0
  71. package/dist/esm/services/db/identity-cache-dynamodb-service/types.js.map +1 -0
  72. package/dist/esm/services/db/index.d.ts +4 -1
  73. package/dist/esm/services/db/index.js +4 -1
  74. package/dist/esm/services/db/index.js.map +1 -1
  75. package/package.json +2 -1
  76. package/dist/cjs/services/db/identity-cache-dynamodb-service.d.ts +0 -44
  77. package/dist/cjs/services/db/identity-cache-dynamodb-service.js.map +0 -1
  78. package/dist/esm/services/db/identity-cache-dynamodb-service.d.ts +0 -44
  79. package/dist/esm/services/db/identity-cache-dynamodb-service.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const at_tracking_event_types_1 = require("@adtrackify/at-tracking-event-types");
3
4
  const mockInvokeFunction = jest.fn();
4
5
  jest.mock('../../clients/index.js', () => ({
5
6
  DynamoDbClient: {
@@ -23,10 +24,13 @@ jest.mock('../../helpers/index.js', () => ({
23
24
  error: jest.fn(),
24
25
  },
25
26
  }));
26
- const identity_cache_dynamodb_service_js_1 = require("../../services/db/identity-cache-dynamodb-service.js");
27
+ const key_builders_js_1 = require("../../services/db/identity-cache-dynamodb-service/key-builders.js");
28
+ const identity_gateway_service_js_1 = require("../../services/db/identity-cache-dynamodb-service/identity-gateway-service.js");
29
+ const types_js_1 = require("../../services/db/identity-cache-dynamodb-service/types.js");
30
+ const identity_cache_dynamodb_db_service_js_1 = require("../../services/db/identity-cache-dynamodb-service/identity-cache-dynamodb-db-service.js");
27
31
  const index_js_1 = require("../../clients/index.js");
28
32
  const mockedDynamoDbClient = index_js_1.DynamoDbClient;
29
- describe('IdentityCacheDynamoDbService', () => {
33
+ describe('IdentityGatewayService', () => {
30
34
  beforeEach(() => {
31
35
  jest.clearAllMocks();
32
36
  mockedDynamoDbClient.safeGet.mockReset();
@@ -37,7 +41,31 @@ describe('IdentityCacheDynamoDbService', () => {
37
41
  mockedDynamoDbClient.safeQueryByGSI.mockReset();
38
42
  mockedDynamoDbClient.batchWrite.mockReset();
39
43
  mockInvokeFunction.mockReset();
40
- identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.lambdaInvokeClient = undefined;
44
+ identity_gateway_service_js_1.IdentityGatewayService.lambdaInvokeClient = undefined;
45
+ });
46
+ describe('identity cache key builders', () => {
47
+ it('should build primary identity cache keys', () => {
48
+ expect((0, key_builders_js_1.buildIdentityPk)('pixel123', 'identity456')).toBe('identity#pixel123#identity456');
49
+ });
50
+ it('should build lowercase email pointer keys', () => {
51
+ expect((0, key_builders_js_1.buildEmailPk)('pixel123', 'Test@Email.COM')).toBe('email#pixel123#test@email.com');
52
+ });
53
+ it('should build trimmed user id pointer keys', () => {
54
+ expect((0, key_builders_js_1.buildUserIdPk)('pixel123', ' user-1 ')).toBe('user_id#pixel123#user-1');
55
+ });
56
+ it('should build identity map keys', () => {
57
+ expect((0, key_builders_js_1.buildIdentityMapPk)('pixel123', 'identity456')).toBe('identity_map#pixel123#identity456');
58
+ });
59
+ it('should build force purge keys', () => {
60
+ expect((0, key_builders_js_1.buildForcePurgePk)('pixel123', 'identity456')).toBe('force_purge#pixel123#identity456');
61
+ });
62
+ it('should match the installed tracking-event-types key builder behavior during migration', () => {
63
+ expect((0, key_builders_js_1.buildIdentityPk)('pixel123', 'identity456')).toBe((0, at_tracking_event_types_1.buildIdentityPk)('pixel123', 'identity456'));
64
+ expect((0, key_builders_js_1.buildEmailPk)('pixel123', 'Test@Email.COM')).toBe((0, at_tracking_event_types_1.buildEmailPk)('pixel123', 'Test@Email.COM'));
65
+ expect((0, key_builders_js_1.buildUserIdPk)('pixel123', ' user-1 ')).toBe((0, at_tracking_event_types_1.buildUserIdPk)('pixel123', ' user-1 '));
66
+ expect((0, key_builders_js_1.buildIdentityMapPk)('pixel123', 'identity456')).toBe((0, at_tracking_event_types_1.buildIdentityMapPk)('pixel123', 'identity456'));
67
+ expect((0, key_builders_js_1.buildForcePurgePk)('pixel123', 'identity456')).toBe((0, at_tracking_event_types_1.buildForcePurgePk)('pixel123', 'identity456'));
68
+ });
41
69
  });
42
70
  describe('getIdentityWithCaching', () => {
43
71
  const pixelId = 'pixel123';
@@ -59,7 +87,7 @@ describe('IdentityCacheDynamoDbService', () => {
59
87
  updatedAt: new Date().toISOString(),
60
88
  };
61
89
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
62
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
90
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
63
91
  expect(result).toBeDefined();
64
92
  expect(result?.identityId).toBe('identity456');
65
93
  expect(mockInvokeFunction).not.toHaveBeenCalled();
@@ -81,7 +109,7 @@ describe('IdentityCacheDynamoDbService', () => {
81
109
  },
82
110
  }),
83
111
  });
84
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
112
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
85
113
  expect(mockInvokeFunction).toHaveBeenCalledWith(lambdaArn, {
86
114
  pixelId,
87
115
  context: { identity: incomingIdentity },
@@ -99,7 +127,7 @@ describe('IdentityCacheDynamoDbService', () => {
99
127
  statusCode: 200,
100
128
  body: JSON.stringify({ identity: undefined }),
101
129
  });
102
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
130
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
103
131
  expect(result).toEqual(incomingIdentity);
104
132
  });
105
133
  });
@@ -129,7 +157,7 @@ describe('IdentityCacheDynamoDbService', () => {
129
157
  },
130
158
  }),
131
159
  });
132
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
160
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
133
161
  expect(mockInvokeFunction).toHaveBeenCalled();
134
162
  expect(result?.identityId).toBe('identity456');
135
163
  expect(result?.traits?.emails).toContain('new@email.com');
@@ -154,7 +182,7 @@ describe('IdentityCacheDynamoDbService', () => {
154
182
  statusCode: 500,
155
183
  body: 'Internal Server Error',
156
184
  });
157
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
185
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
158
186
  expect(result).toBeDefined();
159
187
  expect(result?.identityId).toBe('identity456');
160
188
  });
@@ -174,7 +202,7 @@ describe('IdentityCacheDynamoDbService', () => {
174
202
  },
175
203
  }),
176
204
  });
177
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
205
+ await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
178
206
  expect(mockedDynamoDbClient.safeBatchWrite).toHaveBeenCalled();
179
207
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
180
208
  const identityPks = writtenItems.map((item) => item.pk);
@@ -189,18 +217,18 @@ describe('IdentityCacheDynamoDbService', () => {
189
217
  statusCode: 200,
190
218
  body: JSON.stringify({ identity: undefined }),
191
219
  });
192
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
220
+ await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
193
221
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
194
222
  });
195
223
  });
196
224
  describe('error handling (fail-open)', () => {
197
225
  it('should return undefined when pixelId is missing', async () => {
198
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(null, { identityId: 'test-id' }, lambdaArn);
226
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(null, { identityId: 'test-id' }, lambdaArn);
199
227
  expect(result).toBeUndefined();
200
228
  expect(mockInvokeFunction).not.toHaveBeenCalled();
201
229
  });
202
230
  it('should return undefined when incomingIdentity is missing', async () => {
203
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, null, lambdaArn);
231
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, null, lambdaArn);
204
232
  expect(result).toBeUndefined();
205
233
  expect(mockInvokeFunction).not.toHaveBeenCalled();
206
234
  });
@@ -211,7 +239,7 @@ describe('IdentityCacheDynamoDbService', () => {
211
239
  };
212
240
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
213
241
  mockInvokeFunction.mockRejectedValueOnce(new Error('Lambda invocation failed'));
214
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
242
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
215
243
  expect(result).toEqual(incomingIdentity);
216
244
  });
217
245
  it('should not throw when cache write fails after Neptune success', async () => {
@@ -229,7 +257,7 @@ describe('IdentityCacheDynamoDbService', () => {
229
257
  }),
230
258
  });
231
259
  mockedDynamoDbClient.safeBatchWrite.mockRejectedValueOnce(new Error('DynamoDB write failed'));
232
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
260
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
233
261
  expect(result?.identityId).toBe('neptune-resolved-id');
234
262
  });
235
263
  });
@@ -240,7 +268,7 @@ describe('IdentityCacheDynamoDbService', () => {
240
268
  const pixelId = 'pixel123';
241
269
  const identityId = 'identity456';
242
270
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
243
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, { identityId });
271
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, { identityId });
244
272
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalledWith(expect.any(String), 'pk', `identity#${pixelId}#${identityId}`);
245
273
  });
246
274
  });
@@ -249,7 +277,7 @@ describe('IdentityCacheDynamoDbService', () => {
249
277
  const pixelId = 'pixel123';
250
278
  const email = 'Test@Email.COM';
251
279
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
252
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
280
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
253
281
  traits: { emails: [email] },
254
282
  });
255
283
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalledWith(expect.any(String), 'pk', `email#${pixelId}#test@email.com`);
@@ -260,7 +288,7 @@ describe('IdentityCacheDynamoDbService', () => {
260
288
  const pixelId = 'pixel123';
261
289
  const userId = ' user789 ';
262
290
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
263
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
291
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
264
292
  traits: { userIds: [userId] },
265
293
  });
266
294
  expect(mockedDynamoDbClient.safeBatchGet).not.toHaveBeenCalled();
@@ -283,7 +311,7 @@ describe('IdentityCacheDynamoDbService', () => {
283
311
  updatedAt: new Date().toISOString(),
284
312
  };
285
313
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
286
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
314
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
287
315
  identityId,
288
316
  traits: { emails: ['test@email.com'] },
289
317
  });
@@ -293,7 +321,7 @@ describe('IdentityCacheDynamoDbService', () => {
293
321
  });
294
322
  it('should return cache miss when identity not found', async () => {
295
323
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
296
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
324
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
297
325
  identityId: 'unknown-id',
298
326
  });
299
327
  expect(result.resolvedIdentity).toBeUndefined();
@@ -301,7 +329,7 @@ describe('IdentityCacheDynamoDbService', () => {
301
329
  });
302
330
  it('should NOT fallback to secondary keys when identityId lookup misses', async () => {
303
331
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
304
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
332
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
305
333
  identityId: 'unknown-id',
306
334
  traits: { emails: ['test@email.com'] },
307
335
  });
@@ -320,7 +348,7 @@ describe('IdentityCacheDynamoDbService', () => {
320
348
  updatedAt: new Date().toISOString(),
321
349
  };
322
350
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
323
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
351
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
324
352
  identityId,
325
353
  traits: { emails: ['old@email.com', 'new@email.com'] },
326
354
  });
@@ -338,7 +366,7 @@ describe('IdentityCacheDynamoDbService', () => {
338
366
  updatedAt: new Date().toISOString(),
339
367
  };
340
368
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(pointerRecord);
341
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
369
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
342
370
  traits: { emails: ['test@email.com'], userIds: ['user123'] },
343
371
  });
344
372
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalledWith(expect.any(String), 'pk', `email#${pixelId}#test@email.com`);
@@ -356,7 +384,7 @@ describe('IdentityCacheDynamoDbService', () => {
356
384
  updatedAt: new Date().toISOString(),
357
385
  };
358
386
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(pointerRecord);
359
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
387
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
360
388
  traits: { emails: ['test@email.com'], userIds: ['user123'] },
361
389
  });
362
390
  expect(result.resolvedIdentity).toBeDefined();
@@ -365,14 +393,14 @@ describe('IdentityCacheDynamoDbService', () => {
365
393
  });
366
394
  it('should return cache miss when no secondary keys match', async () => {
367
395
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
368
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
396
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
369
397
  traits: { emails: ['unknown@email.com'] },
370
398
  });
371
399
  expect(result.resolvedIdentity).toBeUndefined();
372
400
  expect(result.isCacheStale).toBe(true);
373
401
  });
374
402
  it('should return cache miss when no emails to lookup', async () => {
375
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
403
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
376
404
  traits: { userIds: ['user123'] },
377
405
  });
378
406
  expect(result.resolvedIdentity).toBeUndefined();
@@ -380,7 +408,7 @@ describe('IdentityCacheDynamoDbService', () => {
380
408
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
381
409
  });
382
410
  it('should return cache miss when empty traits', async () => {
383
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
411
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
384
412
  traits: {},
385
413
  });
386
414
  expect(result.resolvedIdentity).toBeUndefined();
@@ -390,7 +418,7 @@ describe('IdentityCacheDynamoDbService', () => {
390
418
  describe('error handling (fail-open)', () => {
391
419
  it('should return cache miss on safeGet error', async () => {
392
420
  mockedDynamoDbClient.safeGet.mockRejectedValueOnce(new Error('DynamoDB error'));
393
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
421
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
394
422
  identityId: 'test-id',
395
423
  });
396
424
  expect(result.resolvedIdentity).toBeUndefined();
@@ -398,21 +426,21 @@ describe('IdentityCacheDynamoDbService', () => {
398
426
  });
399
427
  it('should return cache miss on safeGet error for email lookup', async () => {
400
428
  mockedDynamoDbClient.safeGet.mockRejectedValueOnce(new Error('DynamoDB error'));
401
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
429
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
402
430
  traits: { emails: ['test@email.com'] },
403
431
  });
404
432
  expect(result.resolvedIdentity).toBeUndefined();
405
433
  expect(result.isCacheStale).toBe(true);
406
434
  });
407
435
  it('should return cache miss for null pixelId', async () => {
408
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(null, {
436
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(null, {
409
437
  identityId: 'test-id',
410
438
  });
411
439
  expect(result.resolvedIdentity).toBeUndefined();
412
440
  expect(result.isCacheStale).toBe(true);
413
441
  });
414
442
  it('should return cache miss for null incomingIdentity', async () => {
415
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, null);
443
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, null);
416
444
  expect(result.resolvedIdentity).toBeUndefined();
417
445
  expect(result.isCacheStale).toBe(true);
418
446
  });
@@ -428,7 +456,7 @@ describe('IdentityCacheDynamoDbService', () => {
428
456
  userIds: ['user1', 'user2'],
429
457
  },
430
458
  };
431
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
459
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
432
460
  expect(mockedDynamoDbClient.safeBatchWrite).toHaveBeenCalledTimes(1);
433
461
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
434
462
  expect(writtenItems).toHaveLength(3);
@@ -440,12 +468,12 @@ describe('IdentityCacheDynamoDbService', () => {
440
468
  expect(pks).not.toContain(`user_id#${pixelId}#user2`);
441
469
  const identityItem = writtenItems.find((item) => item.pk.startsWith('identity#'));
442
470
  expect(identityItem).toBeDefined();
443
- expect(identityItem.response).toBeDefined();
444
- expect(identityItem.response.identityId).toBe('identity456');
471
+ expect(identityItem?.response).toBeDefined();
472
+ expect(identityItem?.response.identityId).toBe('identity456');
445
473
  const emailItem = writtenItems.find((item) => item.pk.startsWith('email#'));
446
474
  expect(emailItem).toBeDefined();
447
- expect(emailItem.response).toBeUndefined();
448
- expect(emailItem.identityId).toBe('identity456');
475
+ expect(emailItem?.response).toBeUndefined();
476
+ expect(emailItem?.identityId).toBe('identity456');
449
477
  });
450
478
  it('should not throw on safeBatchWrite error (fail-open)', async () => {
451
479
  mockedDynamoDbClient.safeBatchWrite.mockRejectedValueOnce(new Error('DynamoDB error'));
@@ -453,14 +481,14 @@ describe('IdentityCacheDynamoDbService', () => {
453
481
  identityId: 'identity456',
454
482
  traits: { emails: ['test@email.com'] },
455
483
  };
456
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity)).resolves.toBeUndefined();
484
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity)).resolves.toBeUndefined();
457
485
  });
458
486
  it('should return early for missing identityId', async () => {
459
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, {});
487
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, {});
460
488
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
461
489
  });
462
490
  it('should return early for missing pixelId', async () => {
463
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(null, {
491
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(null, {
464
492
  identityId: 'test-id',
465
493
  });
466
494
  expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
@@ -469,7 +497,7 @@ describe('IdentityCacheDynamoDbService', () => {
469
497
  const identity = {
470
498
  identityId: 'identity456',
471
499
  };
472
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
500
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
473
501
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
474
502
  expect(writtenItems).toHaveLength(1);
475
503
  });
@@ -478,7 +506,7 @@ describe('IdentityCacheDynamoDbService', () => {
478
506
  identityId: 'identity456',
479
507
  traits: { emails: ['test@email.com'] },
480
508
  };
481
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
509
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
482
510
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
483
511
  for (const item of writtenItems) {
484
512
  expect(item.gsi1pk).toBe('identity456');
@@ -495,33 +523,33 @@ describe('IdentityCacheDynamoDbService', () => {
495
523
  updatedAt: new Date().toISOString(),
496
524
  };
497
525
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(mockMap);
498
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('pixel123', 'identity456');
526
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('pixel123', 'identity456');
499
527
  expect(result).toEqual(mockMap);
500
528
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalledWith(expect.any(String), 'pk', 'identity_map#pixel123#identity456');
501
529
  });
502
530
  it('should return undefined when not found', async () => {
503
531
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
504
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('pixel123', 'identity456');
532
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('pixel123', 'identity456');
505
533
  expect(result).toBeUndefined();
506
534
  });
507
535
  it('should return undefined for missing params (fail-open)', async () => {
508
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('', '');
536
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('', '');
509
537
  expect(result).toBeUndefined();
510
538
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
511
539
  });
512
540
  it('should return undefined when only pixelId is missing', async () => {
513
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('', 'identity456');
541
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('', 'identity456');
514
542
  expect(result).toBeUndefined();
515
543
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
516
544
  });
517
545
  it('should return undefined when only identityId is missing', async () => {
518
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('pixel123', '');
546
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('pixel123', '');
519
547
  expect(result).toBeUndefined();
520
548
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
521
549
  });
522
550
  it('should return undefined on safeGet error (fail-open)', async () => {
523
551
  mockedDynamoDbClient.safeGet.mockRejectedValueOnce(new Error('DynamoDB error'));
524
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityMap('pixel123', 'identity456');
552
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityMap('pixel123', 'identity456');
525
553
  expect(result).toBeUndefined();
526
554
  });
527
555
  });
@@ -530,28 +558,28 @@ describe('IdentityCacheDynamoDbService', () => {
530
558
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce({
531
559
  pk: 'force_purge#pixel123#identity456',
532
560
  });
533
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getForcePurgeFlag('pixel123', 'identity456');
561
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getForcePurgeFlag('pixel123', 'identity456');
534
562
  expect(result).toBe(true);
535
563
  });
536
564
  it('should return false when flag not found', async () => {
537
565
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
538
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getForcePurgeFlag('pixel123', 'identity456');
566
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getForcePurgeFlag('pixel123', 'identity456');
539
567
  expect(result).toBe(false);
540
568
  });
541
569
  it('should return false on error (fail-open)', async () => {
542
570
  mockedDynamoDbClient.safeGet.mockRejectedValueOnce(new Error('DynamoDB error'));
543
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getForcePurgeFlag('pixel123', 'identity456');
571
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getForcePurgeFlag('pixel123', 'identity456');
544
572
  expect(result).toBe(false);
545
573
  });
546
574
  it('should return false for missing params', async () => {
547
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getForcePurgeFlag('', '');
575
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getForcePurgeFlag('', '');
548
576
  expect(result).toBe(false);
549
577
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
550
578
  });
551
579
  });
552
580
  describe('setForcePurgeFlag', () => {
553
581
  it('should set flag with TTL', async () => {
554
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('pixel123', 'identity456');
582
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('pixel123', 'identity456');
555
583
  expect(mockedDynamoDbClient.safePut).toHaveBeenCalledTimes(1);
556
584
  const putItem = mockedDynamoDbClient.safePut.mock.calls[0][1];
557
585
  expect(putItem.pk).toBe('force_purge#pixel123#identity456');
@@ -560,13 +588,13 @@ describe('IdentityCacheDynamoDbService', () => {
560
588
  expect(putItem.ttl).toBeGreaterThan(0);
561
589
  });
562
590
  it('should accept custom TTL', async () => {
563
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('pixel123', 'identity456', 3600);
591
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('pixel123', 'identity456', 3600);
564
592
  const putItem = mockedDynamoDbClient.safePut.mock.calls[0][1];
565
593
  expect(putItem.ttl).toBeGreaterThan(0);
566
594
  });
567
595
  it('should include createdAt timestamp', async () => {
568
596
  const before = new Date().toISOString();
569
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('pixel123', 'identity456');
597
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('pixel123', 'identity456');
570
598
  const after = new Date().toISOString();
571
599
  const putItem = mockedDynamoDbClient.safePut.mock.calls[0][1];
572
600
  expect(putItem.createdAt).toBeDefined();
@@ -574,41 +602,41 @@ describe('IdentityCacheDynamoDbService', () => {
574
602
  expect(putItem.createdAt <= after).toBe(true);
575
603
  });
576
604
  it('should return early when pixelId is missing', async () => {
577
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('', 'identity456');
605
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('', 'identity456');
578
606
  expect(mockedDynamoDbClient.safePut).not.toHaveBeenCalled();
579
607
  });
580
608
  it('should return early when identityId is missing', async () => {
581
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('pixel123', '');
609
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('pixel123', '');
582
610
  expect(mockedDynamoDbClient.safePut).not.toHaveBeenCalled();
583
611
  });
584
612
  it('should not throw on error (fail-open)', async () => {
585
613
  mockedDynamoDbClient.safePut.mockRejectedValueOnce(new Error('DynamoDB error'));
586
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.setForcePurgeFlag('pixel123', 'identity456')).resolves.toBeUndefined();
614
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.setForcePurgeFlag('pixel123', 'identity456')).resolves.toBeUndefined();
587
615
  });
588
616
  });
589
617
  describe('putIdentityMap', () => {
590
618
  it('should write identity map', async () => {
591
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('pixel123', 'identity456', ['linked1', 'linked2']);
619
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('pixel123', 'identity456', ['linked1', 'linked2']);
592
620
  expect(mockedDynamoDbClient.safePut).toHaveBeenCalledTimes(1);
593
621
  const putItem = mockedDynamoDbClient.safePut.mock.calls[0][1];
594
622
  expect(putItem.pk).toBe('identity_map#pixel123#identity456');
595
623
  expect(putItem.linkedIdentities).toEqual(['linked1', 'linked2']);
596
624
  });
597
625
  it('should return early for missing params', async () => {
598
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('', '', []);
626
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('', '', []);
599
627
  expect(mockedDynamoDbClient.safePut).not.toHaveBeenCalled();
600
628
  });
601
629
  it('should return early when only pixelId is missing', async () => {
602
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('', 'identity456', ['linked1']);
630
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('', 'identity456', ['linked1']);
603
631
  expect(mockedDynamoDbClient.safePut).not.toHaveBeenCalled();
604
632
  });
605
633
  it('should return early when only identityId is missing', async () => {
606
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('pixel123', '', ['linked1']);
634
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('pixel123', '', ['linked1']);
607
635
  expect(mockedDynamoDbClient.safePut).not.toHaveBeenCalled();
608
636
  });
609
637
  it('should include updatedAt timestamp', async () => {
610
638
  const before = new Date().toISOString();
611
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('pixel123', 'identity456', ['linked1']);
639
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('pixel123', 'identity456', ['linked1']);
612
640
  const after = new Date().toISOString();
613
641
  const putItem = mockedDynamoDbClient.safePut.mock.calls[0][1];
614
642
  expect(putItem.updatedAt).toBeDefined();
@@ -617,51 +645,51 @@ describe('IdentityCacheDynamoDbService', () => {
617
645
  });
618
646
  it('should not throw on safePut error (fail-open)', async () => {
619
647
  mockedDynamoDbClient.safePut.mockRejectedValueOnce(new Error('DynamoDB error'));
620
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.putIdentityMap('pixel123', 'identity456', ['linked1'])).resolves.toBeUndefined();
648
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.putIdentityMap('pixel123', 'identity456', ['linked1'])).resolves.toBeUndefined();
621
649
  });
622
650
  });
623
651
  describe('deleteIdentityMap', () => {
624
652
  it('should delete identity map', async () => {
625
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityMap('pixel123', 'identity456');
653
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityMap('pixel123', 'identity456');
626
654
  expect(mockedDynamoDbClient.safeDelete).toHaveBeenCalledWith(expect.any(String), 'pk', 'identity_map#pixel123#identity456');
627
655
  });
628
656
  it('should return early for missing params', async () => {
629
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityMap('', '');
657
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityMap('', '');
630
658
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
631
659
  });
632
660
  it('should return early when only pixelId is missing', async () => {
633
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityMap('', 'identity456');
661
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityMap('', 'identity456');
634
662
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
635
663
  });
636
664
  it('should return early when only identityId is missing', async () => {
637
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityMap('pixel123', '');
665
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityMap('pixel123', '');
638
666
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
639
667
  });
640
668
  it('should not throw on safeDelete error (fail-open)', async () => {
641
669
  mockedDynamoDbClient.safeDelete.mockRejectedValueOnce(new Error('DynamoDB error'));
642
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityMap('pixel123', 'identity456')).resolves.toBeUndefined();
670
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityMap('pixel123', 'identity456')).resolves.toBeUndefined();
643
671
  });
644
672
  });
645
673
  describe('deleteForcePurgeFlag', () => {
646
674
  it('should delete force purge flag', async () => {
647
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteForcePurgeFlag('pixel123', 'identity456');
675
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteForcePurgeFlag('pixel123', 'identity456');
648
676
  expect(mockedDynamoDbClient.safeDelete).toHaveBeenCalledWith(expect.any(String), 'pk', 'force_purge#pixel123#identity456');
649
677
  });
650
678
  it('should return early for missing params', async () => {
651
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteForcePurgeFlag('', '');
679
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteForcePurgeFlag('', '');
652
680
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
653
681
  });
654
682
  it('should return early when only pixelId is missing', async () => {
655
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteForcePurgeFlag('', 'identity456');
683
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteForcePurgeFlag('', 'identity456');
656
684
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
657
685
  });
658
686
  it('should return early when only identityId is missing', async () => {
659
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteForcePurgeFlag('pixel123', '');
687
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteForcePurgeFlag('pixel123', '');
660
688
  expect(mockedDynamoDbClient.safeDelete).not.toHaveBeenCalled();
661
689
  });
662
690
  it('should not throw on safeDelete error (fail-open)', async () => {
663
691
  mockedDynamoDbClient.safeDelete.mockRejectedValueOnce(new Error('DynamoDB error'));
664
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteForcePurgeFlag('pixel123', 'identity456')).resolves.toBeUndefined();
692
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteForcePurgeFlag('pixel123', 'identity456')).resolves.toBeUndefined();
665
693
  });
666
694
  });
667
695
  describe('deleteIdentityCache', () => {
@@ -680,12 +708,12 @@ describe('IdentityCacheDynamoDbService', () => {
680
708
  identityId: 'identity456',
681
709
  traits: { emails: ['test@email.com', 'other@email.com'] },
682
710
  };
683
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
711
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
684
712
  expect(mockedDynamoDbClient.safeQueryByGSI).toHaveBeenCalled();
685
713
  expect(mockedDynamoDbClient.batchWrite).toHaveBeenCalled();
686
714
  });
687
715
  it('should return early for missing pixelId', async () => {
688
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(null, {}, {});
716
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(null, {}, {});
689
717
  expect(mockedDynamoDbClient.safeQueryByGSI).not.toHaveBeenCalled();
690
718
  });
691
719
  it('should handle different identityIds in incoming vs resolved', async () => {
@@ -699,19 +727,19 @@ describe('IdentityCacheDynamoDbService', () => {
699
727
  identityId: 'resolved-id',
700
728
  traits: { emails: ['test@email.com'] },
701
729
  };
702
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
730
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
703
731
  expect(mockedDynamoDbClient.safeQueryByGSI).toHaveBeenCalledTimes(2);
704
732
  });
705
733
  it('should not throw on batchWrite error (fail-open)', async () => {
706
734
  mockedDynamoDbClient.safeQueryByGSI.mockResolvedValue([{ pk: `identity#${pixelId}#identity456`, pixelId }]);
707
735
  mockedDynamoDbClient.batchWrite.mockRejectedValueOnce(new Error('DynamoDB error'));
708
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' })).resolves.toBeUndefined();
736
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' })).resolves.toBeUndefined();
709
737
  });
710
738
  it('should deduplicate keys when same items returned from GSI query', async () => {
711
739
  const duplicateItem = { pk: `identity#${pixelId}#identity456`, pixelId };
712
740
  mockedDynamoDbClient.safeQueryByGSI.mockResolvedValue([duplicateItem, duplicateItem]);
713
741
  mockedDynamoDbClient.batchWrite.mockResolvedValue({ $metadata: {} });
714
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
742
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
715
743
  expect(mockedDynamoDbClient.batchWrite).toHaveBeenCalled();
716
744
  const batchWriteCall = mockedDynamoDbClient.batchWrite.mock.calls[0];
717
745
  expect(batchWriteCall).toBeDefined();
@@ -734,7 +762,7 @@ describe('IdentityCacheDynamoDbService', () => {
734
762
  updatedAt: new Date().toISOString(),
735
763
  };
736
764
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
737
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
765
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
738
766
  identityId: 'identity456',
739
767
  traits: {
740
768
  emails: ['incoming@email.com'],
@@ -758,7 +786,7 @@ describe('IdentityCacheDynamoDbService', () => {
758
786
  updatedAt: new Date().toISOString(),
759
787
  };
760
788
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
761
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
789
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
762
790
  identityId: 'identity456',
763
791
  traits: {
764
792
  emails: ['cached@email.com', 'new@email.com'],
@@ -781,7 +809,7 @@ describe('IdentityCacheDynamoDbService', () => {
781
809
  updatedAt: new Date().toISOString(),
782
810
  };
783
811
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
784
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
812
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
785
813
  identityId: 'identity456',
786
814
  traits: {
787
815
  emails: ['a@email.com'],
@@ -799,7 +827,7 @@ describe('IdentityCacheDynamoDbService', () => {
799
827
  emails: ['first@email.com', 'second@email.com', 'third@email.com', 'fourth@email.com'],
800
828
  },
801
829
  };
802
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
830
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
803
831
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
804
832
  expect(writtenItems).toHaveLength(5);
805
833
  const emailPks = writtenItems
@@ -817,7 +845,7 @@ describe('IdentityCacheDynamoDbService', () => {
817
845
  emails: ['valid@email.com', null, undefined, '', 'another@email.com'],
818
846
  },
819
847
  };
820
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
848
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
821
849
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
822
850
  const emailItems = writtenItems.filter((item) => item.pk.startsWith('email#'));
823
851
  expect(emailItems).toHaveLength(2);
@@ -829,7 +857,7 @@ describe('IdentityCacheDynamoDbService', () => {
829
857
  identityId: 'identity456',
830
858
  traits: { emails: [] },
831
859
  };
832
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
860
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
833
861
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
834
862
  expect(writtenItems).toHaveLength(1);
835
863
  expect(writtenItems[0].pk).toBe(`identity#${pixelId}#identity456`);
@@ -841,7 +869,7 @@ describe('IdentityCacheDynamoDbService', () => {
841
869
  emails: ['UPPERCASE@EMAIL.COM', 'MixedCase@Email.Com'],
842
870
  },
843
871
  };
844
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
872
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
845
873
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
846
874
  const emailPks = writtenItems
847
875
  .filter((item) => item.pk.startsWith('email#'))
@@ -857,7 +885,7 @@ describe('IdentityCacheDynamoDbService', () => {
857
885
  identityId: 'identity456',
858
886
  traits: null,
859
887
  };
860
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
888
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
861
889
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
862
890
  expect(writtenItems).toHaveLength(1);
863
891
  });
@@ -866,12 +894,12 @@ describe('IdentityCacheDynamoDbService', () => {
866
894
  identityId: 'identity456',
867
895
  traits: undefined,
868
896
  };
869
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
897
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
870
898
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
871
899
  expect(writtenItems).toHaveLength(1);
872
900
  });
873
901
  it('should return cache miss for identity with null traits in lookup', async () => {
874
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
902
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
875
903
  traits: null,
876
904
  });
877
905
  expect(result.resolvedIdentity).toBeUndefined();
@@ -879,7 +907,7 @@ describe('IdentityCacheDynamoDbService', () => {
879
907
  expect(mockedDynamoDbClient.safeGet).not.toHaveBeenCalled();
880
908
  });
881
909
  it('should handle identity with undefined emails in traits', async () => {
882
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
910
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
883
911
  traits: { userIds: ['user123'] },
884
912
  });
885
913
  expect(result.resolvedIdentity).toBeUndefined();
@@ -901,7 +929,7 @@ describe('IdentityCacheDynamoDbService', () => {
901
929
  updatedAt: new Date().toISOString(),
902
930
  };
903
931
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(oldFormatEmailRecord);
904
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
932
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
905
933
  traits: { emails: ['test@email.com'] },
906
934
  });
907
935
  expect(result.resolvedIdentity).toBeDefined();
@@ -917,7 +945,7 @@ describe('IdentityCacheDynamoDbService', () => {
917
945
  updatedAt: new Date().toISOString(),
918
946
  };
919
947
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(newFormatPointerRecord);
920
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
948
+ const result = await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
921
949
  traits: { emails: ['test@email.com'] },
922
950
  });
923
951
  expect(result.resolvedIdentity).toBeDefined();
@@ -943,7 +971,7 @@ describe('IdentityCacheDynamoDbService', () => {
943
971
  },
944
972
  }),
945
973
  });
946
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, { traits: { emails: ['test@email.com'] } }, lambdaArn);
974
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, { traits: { emails: ['test@email.com'] } }, lambdaArn);
947
975
  expect(mockInvokeFunction).toHaveBeenCalledWith(lambdaArn, expect.objectContaining({
948
976
  pixelId,
949
977
  context: {
@@ -970,7 +998,7 @@ describe('IdentityCacheDynamoDbService', () => {
970
998
  identityId: 'identity456',
971
999
  traits: { emails: ['resolved1@email.com', 'resolved2@email.com', 'resolved3@email.com'] },
972
1000
  };
973
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
1001
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, incomingIdentity, resolvedIdentity);
974
1002
  expect(mockedDynamoDbClient.batchWrite).toHaveBeenCalled();
975
1003
  const batchWriteCall = mockedDynamoDbClient.batchWrite.mock.calls[0][0];
976
1004
  const deleteRequests = batchWriteCall.RequestItems[Object.keys(batchWriteCall.RequestItems)[0]];
@@ -987,7 +1015,7 @@ describe('IdentityCacheDynamoDbService', () => {
987
1015
  { pk: `identity#${pixelId}#identity456`, pixelId },
988
1016
  ]);
989
1017
  mockedDynamoDbClient.batchWrite.mockResolvedValue({ $metadata: {} });
990
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456', traits: { emails: [] } }, { identityId: 'identity456' });
1018
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456', traits: { emails: [] } }, { identityId: 'identity456' });
991
1019
  expect(mockedDynamoDbClient.batchWrite).toHaveBeenCalled();
992
1020
  });
993
1021
  it('should handle missing traits in delete', async () => {
@@ -995,7 +1023,7 @@ describe('IdentityCacheDynamoDbService', () => {
995
1023
  { pk: `identity#${pixelId}#identity456`, pixelId },
996
1024
  ]);
997
1025
  mockedDynamoDbClient.batchWrite.mockResolvedValue({ $metadata: {} });
998
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
1026
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
999
1027
  expect(mockedDynamoDbClient.batchWrite).toHaveBeenCalled();
1000
1028
  });
1001
1029
  it('should not delete items from other pixelIds', async () => {
@@ -1005,7 +1033,7 @@ describe('IdentityCacheDynamoDbService', () => {
1005
1033
  { pk: `identity#${otherPixelId}#identity456`, pixelId: otherPixelId },
1006
1034
  ]);
1007
1035
  mockedDynamoDbClient.batchWrite.mockResolvedValue({ $metadata: {} });
1008
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
1036
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' });
1009
1037
  const batchWriteCall = mockedDynamoDbClient.batchWrite.mock.calls[0][0];
1010
1038
  const deleteRequests = batchWriteCall.RequestItems[Object.keys(batchWriteCall.RequestItems)[0]];
1011
1039
  const deletedPks = deleteRequests.map((req) => req.DeleteRequest.Key.pk);
@@ -1024,24 +1052,24 @@ describe('IdentityCacheDynamoDbService', () => {
1024
1052
  ];
1025
1053
  mockedDynamoDbClient.safeQueryByGSI.mockResolvedValue(mockResults);
1026
1054
  mockedDynamoDbClient.batchWrite.mockResolvedValue({ $metadata: {} });
1027
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId }, { identityId });
1055
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId }, { identityId });
1028
1056
  expect(mockedDynamoDbClient.safeQueryByGSI).toHaveBeenCalledWith(expect.any(String), expect.any(String), 'gsi1pk', identityId);
1029
1057
  });
1030
1058
  it('should handle GSI1 query returning empty results', async () => {
1031
1059
  mockedDynamoDbClient.safeQueryByGSI.mockResolvedValue([]);
1032
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'unknown-id' }, { identityId: 'unknown-id' });
1060
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'unknown-id' }, { identityId: 'unknown-id' });
1033
1061
  expect(mockedDynamoDbClient.batchWrite).not.toHaveBeenCalled();
1034
1062
  });
1035
1063
  it('should handle GSI1 query error gracefully (fail-open)', async () => {
1036
1064
  mockedDynamoDbClient.safeQueryByGSI.mockRejectedValueOnce(new Error('GSI query failed'));
1037
- await expect(identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' })).resolves.toBeUndefined();
1065
+ await expect(identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.deleteIdentityCache(pixelId, { identityId: 'identity456' }, { identityId: 'identity456' })).resolves.toBeUndefined();
1038
1066
  });
1039
1067
  });
1040
1068
  describe('email pointer lookups', () => {
1041
1069
  const pixelId = 'pixel123';
1042
1070
  it('should only lookup first email (optimization)', async () => {
1043
1071
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
1044
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
1072
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
1045
1073
  traits: { emails: ['first@email.com', 'second@email.com', 'third@email.com'] },
1046
1074
  });
1047
1075
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalledTimes(1);
@@ -1049,7 +1077,7 @@ describe('IdentityCacheDynamoDbService', () => {
1049
1077
  });
1050
1078
  it('should handle whitespace in email during lookup', async () => {
1051
1079
  mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
1052
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityFromCache(pixelId, {
1080
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.getIdentityFromCache(pixelId, {
1053
1081
  traits: { emails: [' test@email.com '] },
1054
1082
  });
1055
1083
  expect(mockedDynamoDbClient.safeGet).toHaveBeenCalled();
@@ -1065,7 +1093,7 @@ describe('IdentityCacheDynamoDbService', () => {
1065
1093
  };
1066
1094
  mockedDynamoDbClient.safeGet.mockRejectedValueOnce(new Error('DynamoDB down'));
1067
1095
  mockInvokeFunction.mockRejectedValueOnce(new Error('Lambda down'));
1068
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1096
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1069
1097
  expect(result).toEqual(incomingIdentity);
1070
1098
  });
1071
1099
  it('should continue when cache write fails after Neptune success', async () => {
@@ -1077,7 +1105,7 @@ describe('IdentityCacheDynamoDbService', () => {
1077
1105
  }),
1078
1106
  });
1079
1107
  mockedDynamoDbClient.safeBatchWrite.mockRejectedValueOnce(new Error('Write failed'));
1080
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, { traits: { emails: ['test@email.com'] } }, lambdaArn);
1108
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, { traits: { emails: ['test@email.com'] } }, lambdaArn);
1081
1109
  expect(result?.identityId).toBe('resolved-id');
1082
1110
  });
1083
1111
  it('should return incoming identity when Neptune returns non-200', async () => {
@@ -1090,7 +1118,7 @@ describe('IdentityCacheDynamoDbService', () => {
1090
1118
  statusCode: 500,
1091
1119
  body: 'Internal Server Error',
1092
1120
  });
1093
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1121
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1094
1122
  expect(result).toEqual(incomingIdentity);
1095
1123
  });
1096
1124
  it('should return incoming identity when Neptune returns malformed JSON (fail-open)', async () => {
@@ -1103,14 +1131,128 @@ describe('IdentityCacheDynamoDbService', () => {
1103
1131
  statusCode: 200,
1104
1132
  body: 'not valid json',
1105
1133
  });
1106
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1134
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(pixelId, incomingIdentity, lambdaArn);
1107
1135
  expect(result).toEqual(incomingIdentity);
1108
1136
  });
1109
1137
  it('should return undefined only when both inputs are invalid', async () => {
1110
- const result = await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.getIdentityWithCaching(null, null, lambdaArn);
1138
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCaching(null, null, lambdaArn);
1111
1139
  expect(result).toBeUndefined();
1112
1140
  });
1113
1141
  });
1142
+ describe('getIdentityWithCachingV2', () => {
1143
+ const pixelId = 'pixel123';
1144
+ const lambdaArn = 'arn:aws:lambda:us-east-1:123456789:function:identity-private';
1145
+ it('should return invalid input summary without resolving', async () => {
1146
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCachingV2('', { identityId: 'identity456' }, lambdaArn);
1147
+ expect(result.identity).toBeUndefined();
1148
+ expect(result.summary).toEqual(expect.objectContaining({
1149
+ outcome: types_js_1.IDENTITY_CACHE_WITH_CACHING_OUTCOME.INVALID_INPUT,
1150
+ didReadCache: false,
1151
+ didCallNeptune: false,
1152
+ didWriteCache: false,
1153
+ }));
1154
+ expect(mockInvokeFunction).not.toHaveBeenCalled();
1155
+ expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
1156
+ });
1157
+ it('should return fresh cache hit summary without invoking Neptune', async () => {
1158
+ const incomingIdentity = {
1159
+ identityId: 'identity456',
1160
+ traits: { emails: ['test@email.com'] },
1161
+ };
1162
+ const cachedResponse = {
1163
+ pk: `identity#${pixelId}#identity456`,
1164
+ pixelId,
1165
+ identityId: 'identity456',
1166
+ response: {
1167
+ identityId: 'identity456',
1168
+ traits: { emails: ['test@email.com'] },
1169
+ },
1170
+ updatedAt: new Date().toISOString(),
1171
+ };
1172
+ mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
1173
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
1174
+ expect(result.identity?.identityId).toBe('identity456');
1175
+ expect(result.summary).toEqual(expect.objectContaining({
1176
+ outcome: types_js_1.IDENTITY_CACHE_WITH_CACHING_OUTCOME.FRESH_CACHE_HIT,
1177
+ pixelId,
1178
+ identityId: 'identity456',
1179
+ didReadCache: true,
1180
+ didCallNeptune: false,
1181
+ didWriteCache: false,
1182
+ cachedIdentity: cachedResponse.response,
1183
+ incomingIdentity,
1184
+ resolvedIdentity: expect.objectContaining({ identityId: 'identity456' }),
1185
+ }));
1186
+ expect(mockInvokeFunction).not.toHaveBeenCalled();
1187
+ });
1188
+ it('should return Neptune write-back summary on cache miss', async () => {
1189
+ const incomingIdentity = {
1190
+ identityId: 'identity456',
1191
+ traits: { emails: ['test@email.com'] },
1192
+ };
1193
+ const neptuneIdentity = {
1194
+ identityId: 'resolved-identity',
1195
+ traits: { emails: ['test@email.com', 'resolved@email.com'] },
1196
+ };
1197
+ mockedDynamoDbClient.safeGet.mockResolvedValueOnce(null);
1198
+ mockInvokeFunction.mockResolvedValueOnce({
1199
+ statusCode: 200,
1200
+ body: JSON.stringify({ identity: neptuneIdentity }),
1201
+ });
1202
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
1203
+ expect(result.identity).toEqual(neptuneIdentity);
1204
+ expect(result.summary).toEqual(expect.objectContaining({
1205
+ outcome: types_js_1.IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_WRITE_BACK,
1206
+ pixelId,
1207
+ identityId: 'resolved-identity',
1208
+ didReadCache: true,
1209
+ didCallNeptune: true,
1210
+ didWriteCache: true,
1211
+ incomingIdentity,
1212
+ identityForNeptune: incomingIdentity,
1213
+ neptuneIdentity,
1214
+ traitChanges: { reason: { resolved: 'no cached identity' } },
1215
+ }));
1216
+ expect(mockedDynamoDbClient.safeBatchWrite).toHaveBeenCalled();
1217
+ });
1218
+ it('should return Neptune skip-write summary when Neptune matches cached identity', async () => {
1219
+ const incomingIdentity = {
1220
+ identityId: 'identity456',
1221
+ traits: { emails: ['old@email.com', 'new@email.com'] },
1222
+ };
1223
+ const cachedIdentity = {
1224
+ identityId: 'identity456',
1225
+ traits: { emails: ['old@email.com'] },
1226
+ };
1227
+ const cachedResponse = {
1228
+ pk: `identity#${pixelId}#identity456`,
1229
+ pixelId,
1230
+ identityId: 'identity456',
1231
+ response: cachedIdentity,
1232
+ updatedAt: new Date().toISOString(),
1233
+ };
1234
+ mockedDynamoDbClient.safeGet.mockResolvedValueOnce(cachedResponse);
1235
+ mockInvokeFunction.mockResolvedValueOnce({
1236
+ statusCode: 200,
1237
+ body: JSON.stringify({ identity: cachedIdentity }),
1238
+ });
1239
+ const result = await identity_gateway_service_js_1.IdentityGatewayService.getIdentityWithCachingV2(pixelId, incomingIdentity, lambdaArn);
1240
+ expect(result.identity).toEqual(cachedIdentity);
1241
+ expect(result.summary).toEqual(expect.objectContaining({
1242
+ outcome: types_js_1.IDENTITY_CACHE_WITH_CACHING_OUTCOME.NEPTUNE_SKIP_WRITE,
1243
+ pixelId,
1244
+ identityId: 'identity456',
1245
+ didReadCache: true,
1246
+ didCallNeptune: true,
1247
+ didWriteCache: false,
1248
+ cachedIdentity,
1249
+ incomingIdentity,
1250
+ identityForNeptune: expect.objectContaining({ identityId: 'identity456' }),
1251
+ neptuneIdentity: cachedIdentity,
1252
+ }));
1253
+ expect(mockedDynamoDbClient.safeBatchWrite).not.toHaveBeenCalled();
1254
+ });
1255
+ });
1114
1256
  describe('gsi1pk attribute on all records', () => {
1115
1257
  const pixelId = 'pixel123';
1116
1258
  it('should include gsi1pk on identity record', async () => {
@@ -1118,18 +1260,18 @@ describe('IdentityCacheDynamoDbService', () => {
1118
1260
  identityId: 'identity456',
1119
1261
  traits: { emails: ['test@email.com'] },
1120
1262
  };
1121
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
1263
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
1122
1264
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
1123
1265
  const identityItem = writtenItems.find((item) => item.pk.startsWith('identity#'));
1124
1266
  expect(identityItem).toBeDefined();
1125
- expect(identityItem.gsi1pk).toBe('identity456');
1267
+ expect(identityItem?.gsi1pk).toBe('identity456');
1126
1268
  });
1127
1269
  it('should include gsi1pk on all email pointer records', async () => {
1128
1270
  const identity = {
1129
1271
  identityId: 'identity456',
1130
1272
  traits: { emails: ['email1@test.com', 'email2@test.com'] },
1131
1273
  };
1132
- await identity_cache_dynamodb_service_js_1.IdentityCacheDynamoDbService.updateIdentityCache(pixelId, identity);
1274
+ await identity_cache_dynamodb_db_service_js_1.IdentityCacheDynamoDbDbService.updateIdentityCache(pixelId, identity);
1133
1275
  const writtenItems = mockedDynamoDbClient.safeBatchWrite.mock.calls[0][1];
1134
1276
  const emailItems = writtenItems.filter((item) => item.pk.startsWith('email#'));
1135
1277
  for (const emailItem of emailItems) {