@monorise/core 1.0.4-7 → 3.0.0

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 (198) hide show
  1. package/dist/constants/table.d.ts +0 -1
  2. package/dist/constants/table.d.ts.map +1 -1
  3. package/dist/constants/table.js +0 -1
  4. package/dist/constants/table.js.map +1 -1
  5. package/dist/controllers/entity/create-entity.controller.d.ts +1 -2
  6. package/dist/controllers/entity/create-entity.controller.d.ts.map +1 -1
  7. package/dist/controllers/entity/create-entity.controller.js +54 -34
  8. package/dist/controllers/entity/create-entity.controller.js.map +1 -1
  9. package/dist/controllers/entity/delete-entity.controller.d.ts +1 -2
  10. package/dist/controllers/entity/delete-entity.controller.d.ts.map +1 -1
  11. package/dist/controllers/entity/delete-entity.controller.js +30 -21
  12. package/dist/controllers/entity/delete-entity.controller.js.map +1 -1
  13. package/dist/controllers/entity/get-entity-by-unique-field-value.controller.d.ts +7 -0
  14. package/dist/controllers/entity/get-entity-by-unique-field-value.controller.d.ts.map +1 -0
  15. package/dist/controllers/entity/get-entity-by-unique-field-value.controller.js +36 -0
  16. package/dist/controllers/entity/get-entity-by-unique-field-value.controller.js.map +1 -0
  17. package/dist/controllers/entity/get-entity.controller.d.ts +1 -2
  18. package/dist/controllers/entity/get-entity.controller.d.ts.map +1 -1
  19. package/dist/controllers/entity/get-entity.controller.js +30 -17
  20. package/dist/controllers/entity/get-entity.controller.js.map +1 -1
  21. package/dist/controllers/entity/list-entities.controller.d.ts +1 -2
  22. package/dist/controllers/entity/list-entities.controller.d.ts.map +1 -1
  23. package/dist/controllers/entity/list-entities.controller.js +44 -39
  24. package/dist/controllers/entity/list-entities.controller.js.map +1 -1
  25. package/dist/controllers/entity/update-entity.controller.d.ts +1 -2
  26. package/dist/controllers/entity/update-entity.controller.d.ts.map +1 -1
  27. package/dist/controllers/entity/update-entity.controller.js +52 -35
  28. package/dist/controllers/entity/update-entity.controller.js.map +1 -1
  29. package/dist/controllers/entity/upsert-entity.controller.d.ts +3 -3
  30. package/dist/controllers/entity/upsert-entity.controller.d.ts.map +1 -1
  31. package/dist/controllers/entity/upsert-entity.controller.js +70 -60
  32. package/dist/controllers/entity/upsert-entity.controller.js.map +1 -1
  33. package/dist/controllers/mutual/create-mutual.controller.d.ts +2 -4
  34. package/dist/controllers/mutual/create-mutual.controller.d.ts.map +1 -1
  35. package/dist/controllers/mutual/create-mutual.controller.js +51 -45
  36. package/dist/controllers/mutual/create-mutual.controller.js.map +1 -1
  37. package/dist/controllers/mutual/delete-mutual.controller.d.ts +1 -2
  38. package/dist/controllers/mutual/delete-mutual.controller.d.ts.map +1 -1
  39. package/dist/controllers/mutual/delete-mutual.controller.js +32 -23
  40. package/dist/controllers/mutual/delete-mutual.controller.js.map +1 -1
  41. package/dist/controllers/mutual/get-mutual.controller.d.ts +1 -2
  42. package/dist/controllers/mutual/get-mutual.controller.d.ts.map +1 -1
  43. package/dist/controllers/mutual/get-mutual.controller.js +29 -17
  44. package/dist/controllers/mutual/get-mutual.controller.js.map +1 -1
  45. package/dist/controllers/mutual/list-entities-by-entity.controller.d.ts +1 -2
  46. package/dist/controllers/mutual/list-entities-by-entity.controller.d.ts.map +1 -1
  47. package/dist/controllers/mutual/list-entities-by-entity.controller.js +60 -44
  48. package/dist/controllers/mutual/list-entities-by-entity.controller.js.map +1 -1
  49. package/dist/controllers/mutual/update-mutual.controller.d.ts +1 -2
  50. package/dist/controllers/mutual/update-mutual.controller.d.ts.map +1 -1
  51. package/dist/controllers/mutual/update-mutual.controller.js +44 -30
  52. package/dist/controllers/mutual/update-mutual.controller.js.map +1 -1
  53. package/dist/controllers/setupRoutes.d.ts +2 -3
  54. package/dist/controllers/setupRoutes.d.ts.map +1 -1
  55. package/dist/controllers/setupRoutes.js +19 -17
  56. package/dist/controllers/setupRoutes.js.map +1 -1
  57. package/dist/controllers/tag/list-tags.controller.d.ts +1 -2
  58. package/dist/controllers/tag/list-tags.controller.d.ts.map +1 -1
  59. package/dist/controllers/tag/list-tags.controller.js +42 -33
  60. package/dist/controllers/tag/list-tags.controller.js.map +1 -1
  61. package/dist/data/DbUtils.js +24 -13
  62. package/dist/data/DbUtils.js.map +1 -1
  63. package/dist/data/Entity.d.ts +14 -10
  64. package/dist/data/Entity.d.ts.map +1 -1
  65. package/dist/data/Entity.js +370 -227
  66. package/dist/data/Entity.js.map +1 -1
  67. package/dist/data/EventUtils.d.ts +3 -3
  68. package/dist/data/EventUtils.d.ts.map +1 -1
  69. package/dist/data/EventUtils.js +35 -27
  70. package/dist/data/EventUtils.js.map +1 -1
  71. package/dist/data/Mutual.d.ts +7 -8
  72. package/dist/data/Mutual.d.ts.map +1 -1
  73. package/dist/data/Mutual.js +288 -341
  74. package/dist/data/Mutual.js.map +1 -1
  75. package/dist/data/Tag.d.ts +2 -2
  76. package/dist/data/Tag.d.ts.map +1 -1
  77. package/dist/data/Tag.js +229 -230
  78. package/dist/data/Tag.js.map +1 -1
  79. package/dist/data/abstract/Repository.base.js +4 -7
  80. package/dist/data/abstract/Repository.base.js.map +1 -1
  81. package/dist/errors/extendable-error.js +0 -7
  82. package/dist/errors/extendable-error.js.map +1 -1
  83. package/dist/errors/standard-error.d.ts +22 -0
  84. package/dist/errors/standard-error.d.ts.map +1 -1
  85. package/dist/errors/standard-error.js +21 -3
  86. package/dist/errors/standard-error.js.map +1 -1
  87. package/dist/handles/app.d.ts +16 -0
  88. package/dist/handles/app.d.ts.map +1 -0
  89. package/dist/handles/app.js +31 -0
  90. package/dist/handles/app.js.map +1 -0
  91. package/dist/helpers/event.d.ts.map +1 -1
  92. package/dist/helpers/event.js +35 -34
  93. package/dist/helpers/event.js.map +1 -1
  94. package/dist/index.d.ts +24 -16
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +12 -21
  97. package/dist/index.js.map +1 -1
  98. package/dist/middlewares/api-key-auth.d.ts +3 -0
  99. package/dist/middlewares/api-key-auth.d.ts.map +1 -0
  100. package/dist/middlewares/api-key-auth.js +32 -0
  101. package/dist/middlewares/api-key-auth.js.map +1 -0
  102. package/dist/middlewares/entity-type-check.d.ts +1 -1
  103. package/dist/middlewares/entity-type-check.d.ts.map +1 -1
  104. package/dist/middlewares/entity-type-check.js +17 -7
  105. package/dist/middlewares/entity-type-check.js.map +1 -1
  106. package/dist/middlewares/general-error-handler.d.ts +7 -0
  107. package/dist/middlewares/general-error-handler.d.ts.map +1 -0
  108. package/dist/middlewares/general-error-handler.js +40 -0
  109. package/dist/middlewares/general-error-handler.js.map +1 -0
  110. package/dist/middlewares/mutual-type-check.d.ts +1 -1
  111. package/dist/middlewares/mutual-type-check.d.ts.map +1 -1
  112. package/dist/middlewares/mutual-type-check.js +18 -8
  113. package/dist/middlewares/mutual-type-check.js.map +1 -1
  114. package/dist/processors/create-entity-processor.d.ts.map +1 -1
  115. package/dist/processors/create-entity-processor.js +17 -5
  116. package/dist/processors/create-entity-processor.js.map +1 -1
  117. package/dist/processors/mutual-processor.d.ts.map +1 -1
  118. package/dist/processors/mutual-processor.js +39 -29
  119. package/dist/processors/mutual-processor.js.map +1 -1
  120. package/dist/processors/prejoin-processor.d.ts.map +1 -1
  121. package/dist/processors/prejoin-processor.js +117 -104
  122. package/dist/processors/prejoin-processor.js.map +1 -1
  123. package/dist/processors/replication-processor.d.ts.map +1 -1
  124. package/dist/processors/replication-processor.js +31 -31
  125. package/dist/processors/replication-processor.js.map +1 -1
  126. package/dist/processors/tag-processor.js +48 -35
  127. package/dist/processors/tag-processor.js.map +1 -1
  128. package/dist/services/DependencyContainer.d.ts +16 -7
  129. package/dist/services/DependencyContainer.d.ts.map +1 -1
  130. package/dist/services/DependencyContainer.js +13 -24
  131. package/dist/services/DependencyContainer.js.map +1 -1
  132. package/dist/services/entity-service-lifecycle.js +29 -20
  133. package/dist/services/entity-service-lifecycle.js.map +1 -1
  134. package/dist/services/entity.service.d.ts +6 -6
  135. package/dist/services/entity.service.d.ts.map +1 -1
  136. package/dist/services/entity.service.js +96 -93
  137. package/dist/services/entity.service.js.map +1 -1
  138. package/dist/services/mutual.service.js +117 -113
  139. package/dist/services/mutual.service.js.map +1 -1
  140. package/dist/tsconfig.tsbuildinfo +1 -0
  141. package/dist/types/entity.type.d.ts.map +1 -1
  142. package/dist/types/event.d.ts +4 -3
  143. package/dist/types/event.d.ts.map +1 -1
  144. package/dist/types/event.js +9 -9
  145. package/dist/types/event.js.map +1 -1
  146. package/dist/vitest.config.d.ts +3 -0
  147. package/dist/vitest.config.d.ts.map +1 -0
  148. package/dist/vitest.config.js +10 -0
  149. package/dist/vitest.config.js.map +1 -0
  150. package/package.json +8 -6
  151. package/dist/mock/entity.d.ts +0 -13
  152. package/dist/mock/entity.d.ts.map +0 -1
  153. package/dist/mock/entity.js +0 -14
  154. package/dist/mock/entity.js.map +0 -1
  155. package/dist/mock/monorise/admin.d.ts +0 -127
  156. package/dist/mock/monorise/admin.d.ts.map +0 -1
  157. package/dist/mock/monorise/admin.js +0 -29
  158. package/dist/mock/monorise/admin.js.map +0 -1
  159. package/dist/mock/monorise/chapter.d.ts +0 -457
  160. package/dist/mock/monorise/chapter.d.ts.map +0 -1
  161. package/dist/mock/monorise/chapter.js +0 -81
  162. package/dist/mock/monorise/chapter.js.map +0 -1
  163. package/dist/mock/monorise/course.d.ts +0 -311
  164. package/dist/mock/monorise/course.d.ts.map +0 -1
  165. package/dist/mock/monorise/course.js +0 -128
  166. package/dist/mock/monorise/course.js.map +0 -1
  167. package/dist/mock/monorise/index.d.ts +0 -3599
  168. package/dist/mock/monorise/index.d.ts.map +0 -1
  169. package/dist/mock/monorise/index.js +0 -62
  170. package/dist/mock/monorise/index.js.map +0 -1
  171. package/dist/mock/monorise/learner.d.ts +0 -390
  172. package/dist/mock/monorise/learner.d.ts.map +0 -1
  173. package/dist/mock/monorise/learner.js +0 -59
  174. package/dist/mock/monorise/learner.js.map +0 -1
  175. package/dist/mock/monorise/learning-activity.d.ts +0 -266
  176. package/dist/mock/monorise/learning-activity.d.ts.map +0 -1
  177. package/dist/mock/monorise/learning-activity.js +0 -50
  178. package/dist/mock/monorise/learning-activity.js.map +0 -1
  179. package/dist/mock/monorise/learning-journey-config.d.ts +0 -84
  180. package/dist/mock/monorise/learning-journey-config.d.ts.map +0 -1
  181. package/dist/mock/monorise/learning-journey-config.js +0 -27
  182. package/dist/mock/monorise/learning-journey-config.js.map +0 -1
  183. package/dist/mock/monorise/module.d.ts +0 -211
  184. package/dist/mock/monorise/module.d.ts.map +0 -1
  185. package/dist/mock/monorise/module.js +0 -91
  186. package/dist/mock/monorise/module.js.map +0 -1
  187. package/dist/mock/monorise/organization.d.ts +0 -346
  188. package/dist/mock/monorise/organization.d.ts.map +0 -1
  189. package/dist/mock/monorise/organization.js +0 -54
  190. package/dist/mock/monorise/organization.js.map +0 -1
  191. package/dist/mock/monorise/reference.d.ts +0 -171
  192. package/dist/mock/monorise/reference.d.ts.map +0 -1
  193. package/dist/mock/monorise/reference.js +0 -25
  194. package/dist/mock/monorise/reference.js.map +0 -1
  195. package/dist/mock/monorise/video.d.ts +0 -346
  196. package/dist/mock/monorise/video.d.ts.map +0 -1
  197. package/dist/mock/monorise/video.js +0 -33
  198. package/dist/mock/monorise/video.js.map +0 -1
@@ -1,23 +1,22 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
1
10
  import { BatchStatementErrorCodeEnum, TransactionCanceledException, } from '@aws-sdk/client-dynamodb';
2
11
  import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';
3
12
  import { ulid } from 'ulid';
4
- import { StandardError } from '../errors/standard-error';
13
+ import { StandardError, StandardErrorCode } from '../errors/standard-error';
14
+ import { fromLastKeyQuery } from '../helpers/fromLastKeyQuery';
5
15
  import { sleep } from '../helpers/sleep';
16
+ import { toLastKeyResponse } from '../helpers/toLastKeyResponse';
6
17
  import { PROJECTION_EXPRESSION, } from './ProjectionExpression';
7
18
  import { Repository } from './abstract/Repository.base';
8
19
  export class Mutual {
9
- byEntityType;
10
- byEntityId;
11
- byData;
12
- entityType;
13
- entityId;
14
- data;
15
- mutualData;
16
- mutualId;
17
- _createdAt;
18
- _updatedAt;
19
- _mutualUpdatedAt;
20
- _expiresAt;
21
20
  constructor(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, mutualId, _createdAt, _updatedAt, _mutualUpdatedAt, _expiresAt) {
22
21
  this.byEntityType = byEntityType;
23
22
  this.byEntityId = byEntityId;
@@ -34,7 +33,7 @@ export class Mutual {
34
33
  }
35
34
  static fromItem(item) {
36
35
  if (!item)
37
- throw new StandardError('MUTUAL_IS_UNDEFINED', 'Mutual item empty');
36
+ throw new StandardError(StandardErrorCode.MUTUAL_IS_UNDEFINED, 'Mutual item empty');
38
37
  const parsedItem = unmarshall(item);
39
38
  return new Mutual(parsedItem.byEntityType, parsedItem.byEntityId, parsedItem.byData, parsedItem.entityType, parsedItem.entityId, parsedItem.data, parsedItem.mutualData, parsedItem.mutualId, parsedItem.createdAt ? new Date(parsedItem.createdAt) : undefined, parsedItem.updatedAt ? new Date(parsedItem.updatedAt) : undefined, parsedItem.mutualUpdatedAt
40
39
  ? new Date(parsedItem.mutualUpdatedAt)
@@ -68,44 +67,28 @@ export class Mutual {
68
67
  return '#METADATA#';
69
68
  }
70
69
  get createdAt() {
71
- return this._createdAt?.toISOString();
70
+ var _a;
71
+ return (_a = this._createdAt) === null || _a === void 0 ? void 0 : _a.toISOString();
72
72
  }
73
73
  get updatedAt() {
74
- return this._updatedAt?.toISOString();
74
+ var _a;
75
+ return (_a = this._updatedAt) === null || _a === void 0 ? void 0 : _a.toISOString();
75
76
  }
76
77
  get mutualUpdatedAt() {
77
- return this._mutualUpdatedAt?.toISOString();
78
+ var _a;
79
+ return (_a = this._mutualUpdatedAt) === null || _a === void 0 ? void 0 : _a.toISOString();
78
80
  }
79
81
  get expiresAt() {
80
- return this._expiresAt?.toISOString();
81
- }
82
- toMutualItemOnly() {
83
- // Mutual #METADATA# has `mutualData` only
84
- return {
85
- ...marshall({ ...this.toJSON(), data: {} }, { removeUndefinedValues: true }),
86
- ...this.mainKeys(),
87
- };
82
+ var _a;
83
+ return (_a = this._expiresAt) === null || _a === void 0 ? void 0 : _a.toISOString();
88
84
  }
89
85
  toItem() {
90
- return {
91
- ...marshall(this.toJSON(), { removeUndefinedValues: true }),
92
- ...this.mainKeys(),
93
- };
86
+ return Object.assign(Object.assign({}, marshall(this.toJSON(), { removeUndefinedValues: true })), this.mainKeys());
94
87
  }
95
88
  toReversedItem() {
96
89
  const item = this.toJSON();
97
- const reversedMutual = {
98
- ...item,
99
- byEntityType: item.entityType,
100
- byEntityId: item.entityId,
101
- entityType: item.byEntityType,
102
- entityId: item.byEntityId,
103
- data: this.byData,
104
- };
105
- return {
106
- ...marshall(reversedMutual, { removeUndefinedValues: true }),
107
- ...this.mainKeys(),
108
- };
90
+ const reversedMutual = Object.assign(Object.assign({}, item), { byEntityType: item.entityType, byEntityId: item.entityId, entityType: item.byEntityType, entityId: item.byEntityId, data: this.byData });
91
+ return Object.assign(Object.assign({}, marshall(reversedMutual, { removeUndefinedValues: true })), this.mainKeys());
109
92
  }
110
93
  toJSON() {
111
94
  return {
@@ -124,369 +107,333 @@ export class Mutual {
124
107
  }
125
108
  }
126
109
  export class MutualRepository extends Repository {
127
- TABLE_NAME;
128
- dynamodbClient;
129
- ddbUtils;
130
110
  constructor(TABLE_NAME, dynamodbClient, ddbUtils) {
131
111
  super();
132
112
  this.TABLE_NAME = TABLE_NAME;
133
113
  this.dynamodbClient = dynamodbClient;
134
114
  this.ddbUtils = ddbUtils;
135
115
  }
136
- async listEntitiesByEntity(byEntityType, byEntityId, entityType, opts = {}) {
137
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, 'list_by_only', {}, {});
138
- const listAssociationsQuery = {
139
- TableName: this.TABLE_NAME,
140
- KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
141
- FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
142
- ExpressionAttributeNames: {
143
- '#PK': 'PK',
144
- '#SK': 'SK',
145
- '#expiresAt': 'expiresAt',
146
- },
147
- ExpressionAttributeValues: {
148
- ':PK': {
149
- S: mutual.byFullEntityId,
116
+ listEntitiesByEntity(byEntityType_1, byEntityId_1, entityType_1) {
117
+ return __awaiter(this, arguments, void 0, function* (byEntityType, byEntityId, entityType, opts = {}) {
118
+ var _a, _b, _c, _d;
119
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, 'list_by_only', {}, {});
120
+ const listAssociationsQuery = {
121
+ TableName: this.TABLE_NAME,
122
+ KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
123
+ FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
124
+ ExpressionAttributeNames: {
125
+ '#PK': 'PK',
126
+ '#SK': 'SK',
127
+ '#expiresAt': 'expiresAt',
150
128
  },
151
- ':SK': {
152
- S: mutual.listEntitySK,
129
+ ExpressionAttributeValues: {
130
+ ':PK': {
131
+ S: mutual.byFullEntityId,
132
+ },
133
+ ':SK': {
134
+ S: `${mutual.listEntitySK}#`,
135
+ },
136
+ ':nullType': { S: 'NULL' },
153
137
  },
154
- ':nullType': { S: 'NULL' },
155
- },
156
- ProjectionExpression: opts.ProjectionExpression,
157
- };
158
- let lastKey = opts.lastKey;
159
- let items = [];
160
- let remainingCount = opts.limit ?? 0;
161
- do {
162
- const resp = await this.dynamodbClient.query({
163
- ...listAssociationsQuery,
164
- ...(remainingCount && { Limit: remainingCount }),
165
- ...(lastKey && {
166
- ExclusiveStartKey: lastKey,
167
- }),
138
+ ProjectionExpression: opts.ProjectionExpression,
139
+ };
140
+ let lastKey = opts.lastKey;
141
+ let items = [];
142
+ let remainingCount = (_a = opts.limit) !== null && _a !== void 0 ? _a : 0;
143
+ do {
144
+ const resp = yield this.dynamodbClient.query(Object.assign(Object.assign(Object.assign({}, listAssociationsQuery), (remainingCount && { Limit: remainingCount })), (lastKey && {
145
+ ExclusiveStartKey: fromLastKeyQuery(lastKey),
146
+ })));
147
+ items = items.concat(((_b = resp.Items) === null || _b === void 0 ? void 0 : _b.map((item) => Mutual.fromItem(item))) || []);
148
+ lastKey = toLastKeyResponse(resp.LastEvaluatedKey);
149
+ if (opts.limit) {
150
+ remainingCount = remainingCount - ((_d = (_c = resp.Items) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0);
151
+ }
152
+ } while (
153
+ // limit is given, haven't reach limit, and there are still items to retrieve
154
+ (opts.limit && remainingCount && lastKey) ||
155
+ // no limit is given and there are still items to retrieve
156
+ (!opts.limit && lastKey));
157
+ return {
158
+ items,
159
+ lastKey,
160
+ };
161
+ });
162
+ }
163
+ getMutual(byEntityType, byEntityId, entityType, entityId, opts) {
164
+ return __awaiter(this, void 0, void 0, function* () {
165
+ var _a, _b;
166
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
167
+ const resp = yield this.dynamodbClient.query({
168
+ TableName: this.TABLE_NAME,
169
+ KeyConditionExpression: '#PK = :PK and begins_with(#SK, :SK)',
170
+ FilterExpression: 'attribute_not_exists(#expiresAt) or attribute_type(#expiresAt, :nullType)',
171
+ ExpressionAttributeNames: {
172
+ '#PK': 'PK',
173
+ '#SK': 'SK',
174
+ '#expiresAt': 'expiresAt',
175
+ },
176
+ ExpressionAttributeValues: {
177
+ ':PK': { S: mutual.byFullEntityId },
178
+ ':SK': { S: mutual.fullEntityId },
179
+ ':nullType': { S: 'NULL' },
180
+ },
181
+ Limit: 1,
168
182
  });
169
- items = items.concat(resp.Items?.map((item) => Mutual.fromItem(item)) || []);
170
- lastKey = resp.LastEvaluatedKey;
171
- if (opts.limit) {
172
- remainingCount = remainingCount - (resp.Items?.length ?? 0);
183
+ let mutualMetadata = null;
184
+ if (opts === null || opts === void 0 ? void 0 : opts.isFromMetadata) {
185
+ const tempMutual = Mutual.fromItem((_a = resp.Items) === null || _a === void 0 ? void 0 : _a[0]);
186
+ const respMetadataMutual = yield this.dynamodbClient.getItem({
187
+ TableName: this.TABLE_NAME,
188
+ Key: tempMutual.mainKeys(),
189
+ ProjectionExpression: opts === null || opts === void 0 ? void 0 : opts.ProjectionExpression,
190
+ });
191
+ mutualMetadata = Mutual.fromItem(respMetadataMutual.Item);
173
192
  }
174
- } while (
175
- // limit is given, haven't reach limit, and there are still items to retrieve
176
- (opts.limit && remainingCount && lastKey) ||
177
- // no limit is given and there are still items to retrieve
178
- (!opts.limit && lastKey));
179
- return {
180
- items,
181
- lastKey,
182
- };
183
- }
184
- async getMutual(byEntityType, byEntityId, entityType, entityId, opts) {
185
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
186
- const resp = await this.dynamodbClient.getItem({
187
- TableName: this.TABLE_NAME,
188
- Key: mutual.subKeys(),
189
- ProjectionExpression: opts?.ProjectionExpression,
193
+ return mutualMetadata || Mutual.fromItem((_b = resp.Items) === null || _b === void 0 ? void 0 : _b[0]);
190
194
  });
191
- let mutualMetadata = null;
192
- if (opts?.isFromMetadata) {
193
- const tempMutual = Mutual.fromItem(resp.Item);
194
- const respMetadataMutual = await this.dynamodbClient.getItem({
195
+ }
196
+ checkMutualExist(byEntityType, byEntityId, entityType, entityId) {
197
+ return __awaiter(this, void 0, void 0, function* () {
198
+ var _a;
199
+ const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
200
+ const resp = yield this.dynamodbClient.getItem({
195
201
  TableName: this.TABLE_NAME,
196
- Key: tempMutual.mainKeys(),
197
- ProjectionExpression: opts?.ProjectionExpression,
202
+ Key: mutual.subKeys(),
203
+ ProjectionExpression: 'PK, SK, expiresAt',
198
204
  });
199
- mutualMetadata = Mutual.fromItem(respMetadataMutual.Item);
200
- }
201
- return mutualMetadata || Mutual.fromItem(resp.Item);
202
- }
203
- async checkMutualExist(byEntityType, byEntityId, entityType, entityId) {
204
- const mutual = new Mutual(byEntityType, byEntityId, {}, entityType, entityId, {}, {});
205
- const resp = await this.dynamodbClient.getItem({
206
- TableName: this.TABLE_NAME,
207
- Key: mutual.subKeys(),
208
- ProjectionExpression: 'PK, SK, expiresAt',
205
+ if (resp.Item && !((_a = resp.Item) === null || _a === void 0 ? void 0 : _a.expiresAt)) {
206
+ throw new StandardError(StandardErrorCode.MUTUAL_EXISTS, 'Entities are already linked');
207
+ }
208
+ return;
209
209
  });
210
- if (resp.Item && !resp.Item?.expiresAt) {
211
- throw new StandardError('MUTUAL_EXISTS', 'Entities are already linked');
212
- }
213
- return;
214
210
  }
215
211
  createMutualTransactItems(mutual, opts) {
216
212
  const TransactItems = [
217
213
  {
218
214
  Put: {
219
215
  TableName: this.TABLE_NAME,
220
- ConditionExpression: opts?.ConditionExpression ||
216
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
221
217
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
222
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
223
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
218
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
219
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
224
220
  Item: mutual.toItem(),
225
221
  },
226
222
  },
227
223
  {
228
224
  Put: {
229
225
  TableName: this.TABLE_NAME,
230
- ConditionExpression: opts?.ConditionExpression ||
226
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
231
227
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
232
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
233
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
234
- Item: {
235
- ...mutual.toItem(),
236
- PK: { S: mutual.byFullEntityId },
237
- SK: { S: mutual.fullEntityId },
238
- R1PK: { S: mutual.fullEntityId },
239
- R1SK: { S: mutual.byFullEntityId },
240
- R2PK: { S: mutual.mainPk },
241
- R2SK: { S: mutual.byFullEntityId },
242
- },
228
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
229
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
230
+ Item: Object.assign(Object.assign({}, mutual.toItem()), { PK: { S: mutual.byFullEntityId }, SK: { S: mutual.fullEntityId }, R1PK: { S: mutual.fullEntityId }, R1SK: { S: mutual.byFullEntityId }, R2PK: { S: mutual.mainPk }, R2SK: { S: mutual.byFullEntityId } }),
243
231
  },
244
232
  },
245
233
  {
246
234
  Put: {
247
235
  TableName: this.TABLE_NAME,
248
- ConditionExpression: opts?.ConditionExpression ||
236
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
249
237
  'attribute_not_exists(PK) OR attribute_exists(expiresAt)',
250
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
251
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
252
- Item: {
253
- ...mutual.toReversedItem(),
254
- PK: { S: mutual.fullEntityId },
255
- SK: { S: mutual.byFullEntityId },
256
- R1PK: { S: mutual.byFullEntityId },
257
- R1SK: { S: mutual.fullEntityId },
258
- R2PK: { S: mutual.mainPk },
259
- R2SK: { S: mutual.fullEntityId },
260
- },
238
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
239
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
240
+ Item: Object.assign(Object.assign({}, mutual.toReversedItem()), { PK: { S: mutual.fullEntityId }, SK: { S: mutual.byFullEntityId }, R1PK: { S: mutual.byFullEntityId }, R1SK: { S: mutual.fullEntityId }, R2PK: { S: mutual.mainPk }, R2SK: { S: mutual.fullEntityId } }),
261
241
  },
262
242
  },
263
243
  ];
264
244
  return TransactItems;
265
245
  }
266
- async createMutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData = {}, opts) {
267
- const errorContext = {};
268
- const currentDatetime = opts?.createAndUpdateDatetime || new Date();
269
- const mutual = new Mutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, ulid(), currentDatetime, currentDatetime, currentDatetime);
270
- const TransactItems = this.createMutualTransactItems(mutual, {
271
- ConditionExpression: opts?.ConditionExpression,
272
- ExpressionAttributeNames: opts?.ExpressionAttributeNames,
273
- ExpressionAttributeValues: opts?.ExpressionAttributeValues,
246
+ createMutual(byEntityType_1, byEntityId_1, byData_1, entityType_1, entityId_1, data_1) {
247
+ return __awaiter(this, arguments, void 0, function* (byEntityType, byEntityId, byData, entityType, entityId, data, mutualData = {}, opts) {
248
+ const errorContext = {};
249
+ const currentDatetime = (opts === null || opts === void 0 ? void 0 : opts.createAndUpdateDatetime) || new Date();
250
+ const mutual = new Mutual(byEntityType, byEntityId, byData, entityType, entityId, data, mutualData, ulid(), currentDatetime, currentDatetime, currentDatetime);
251
+ const TransactItems = this.createMutualTransactItems(mutual, {
252
+ ConditionExpression: opts === null || opts === void 0 ? void 0 : opts.ConditionExpression,
253
+ ExpressionAttributeNames: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames,
254
+ ExpressionAttributeValues: opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues,
255
+ });
256
+ errorContext.TransactItems = TransactItems;
257
+ yield this.dynamodbClient.transactWriteItems({ TransactItems });
258
+ return mutual;
274
259
  });
275
- errorContext.TransactItems = TransactItems;
276
- await this.dynamodbClient.transactWriteItems({ TransactItems });
277
- return mutual;
278
260
  }
279
- async updateMutual(byEntityType, byEntityId, entityType, entityId, toUpdate, opts) {
280
- const returnUpdatedValue = opts?.returnUpdatedValue ?? false;
281
- const errorContext = {};
282
- try {
283
- const mutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
284
- const currentDatetime = new Date().toISOString();
285
- const toUpdateExpressions = this.toUpdate({
286
- mutualUpdatedAt: currentDatetime,
287
- ...toUpdate,
288
- }, { maxLevel: opts?.maxObjectUpdateLevel });
289
- const updateExpression = {
290
- ConditionExpression: opts?.ConditionExpression || 'attribute_exists(PK)',
291
- UpdateExpression: toUpdateExpressions.UpdateExpression,
292
- ExpressionAttributeNames: {
293
- ...toUpdateExpressions.ExpressionAttributeNames,
294
- ...opts?.ExpressionAttributeNames,
295
- },
296
- ExpressionAttributeValues: {
297
- ...toUpdateExpressions.ExpressionAttributeValues,
298
- ...opts?.ExpressionAttributeValues,
299
- },
300
- };
301
- const TransactItems = [
302
- {
303
- Update: {
304
- TableName: this.TABLE_NAME,
305
- Key: mutual.mainKeys(),
306
- ...updateExpression,
261
+ updateMutual(byEntityType, byEntityId, entityType, entityId, toUpdate, opts) {
262
+ return __awaiter(this, void 0, void 0, function* () {
263
+ var _a;
264
+ const returnUpdatedValue = (_a = opts === null || opts === void 0 ? void 0 : opts.returnUpdatedValue) !== null && _a !== void 0 ? _a : false;
265
+ const errorContext = {};
266
+ try {
267
+ const mutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
268
+ const currentDatetime = new Date().toISOString();
269
+ const toUpdateExpressions = this.toUpdate(Object.assign({ mutualUpdatedAt: currentDatetime }, toUpdate), { maxLevel: opts === null || opts === void 0 ? void 0 : opts.maxObjectUpdateLevel });
270
+ const updateExpression = {
271
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) || 'attribute_exists(PK)',
272
+ UpdateExpression: toUpdateExpressions.UpdateExpression,
273
+ ExpressionAttributeNames: Object.assign(Object.assign({}, toUpdateExpressions.ExpressionAttributeNames), opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames),
274
+ ExpressionAttributeValues: Object.assign(Object.assign({}, toUpdateExpressions.ExpressionAttributeValues), opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues),
275
+ };
276
+ const TransactItems = [
277
+ {
278
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: mutual.mainKeys() }, updateExpression),
307
279
  },
308
- },
309
- {
310
- Update: {
311
- TableName: this.TABLE_NAME,
312
- Key: {
313
- PK: { S: mutual.byFullEntityId },
314
- SK: { S: mutual.fullEntityId },
315
- },
316
- ...updateExpression,
280
+ {
281
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
282
+ PK: { S: mutual.byFullEntityId },
283
+ SK: { S: mutual.fullEntityId },
284
+ } }, updateExpression),
317
285
  },
318
- },
319
- {
320
- Update: {
321
- TableName: this.TABLE_NAME,
322
- Key: {
323
- PK: { S: mutual.fullEntityId },
324
- SK: { S: mutual.byFullEntityId },
325
- },
326
- ...updateExpression,
286
+ {
287
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
288
+ PK: { S: mutual.fullEntityId },
289
+ SK: { S: mutual.byFullEntityId },
290
+ } }, updateExpression),
327
291
  },
328
- },
329
- ];
330
- errorContext.TransactItems = TransactItems;
331
- await this.ddbUtils.executeTransactWrite({ TransactItems });
332
- if (!returnUpdatedValue) {
333
- return;
292
+ ];
293
+ errorContext.TransactItems = TransactItems;
294
+ yield this.ddbUtils.executeTransactWrite({ TransactItems });
295
+ if (!returnUpdatedValue) {
296
+ return;
297
+ }
298
+ const updatedMutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId);
299
+ return updatedMutual;
334
300
  }
335
- const updatedMutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId);
336
- return updatedMutual;
337
- }
338
- catch (err) {
339
- if (err instanceof StandardError &&
340
- err.code === 'CONDITIONAL_CHECK_FAILED') {
341
- throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
342
- errorContext,
343
- });
301
+ catch (err) {
302
+ if (err instanceof StandardError &&
303
+ err.code === StandardErrorCode.CONDITIONAL_CHECK_FAILED) {
304
+ throw new StandardError(StandardErrorCode.MUTUAL_NOT_FOUND, 'Mutual not found', err, {
305
+ errorContext,
306
+ });
307
+ }
308
+ throw err;
344
309
  }
345
- throw err;
346
- }
310
+ });
347
311
  }
348
- async deleteMutual(byEntityType, byEntityId, entityType, entityId, opts) {
349
- const errorContext = {
350
- byEntityType,
351
- byEntityId,
352
- entityType,
353
- entityId,
354
- };
355
- try {
356
- const mutual = await this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
357
- const tenMinsLater = Math.floor(new Date().getTime() / 1000 + 10 * 60);
358
- const expressions = {
359
- UpdateExpression: 'SET #expiresAt = :expiresAt, #mutualUpdatedAt = :mutualUpdatedAt, #updatedAt = :mutualUpdatedAt',
360
- ConditionExpression: opts?.ConditionExpression ||
361
- 'attribute_exists(PK) AND attribute_not_exists(#expiresAt)',
362
- ExpressionAttributeNames: {
363
- '#expiresAt': 'expiresAt',
364
- '#mutualUpdatedAt': 'mutualUpdatedAt',
365
- '#updatedAt': 'updatedAt',
366
- ...opts?.ExpressionAttributeNames,
367
- },
368
- ExpressionAttributeValues: {
369
- ':expiresAt': { N: String(tenMinsLater) },
370
- ':mutualUpdatedAt': { S: new Date().toISOString() },
371
- ...opts?.ExpressionAttributeValues,
372
- },
312
+ deleteMutual(byEntityType, byEntityId, entityType, entityId, opts) {
313
+ return __awaiter(this, void 0, void 0, function* () {
314
+ var _a;
315
+ const errorContext = {
316
+ byEntityType,
317
+ byEntityId,
318
+ entityType,
319
+ entityId,
373
320
  };
374
- const TransactItems = [
375
- {
376
- Update: {
377
- TableName: this.TABLE_NAME,
378
- Key: mutual.mainKeys(),
379
- ...expressions,
321
+ try {
322
+ const mutual = yield this.getMutual(byEntityType, byEntityId, entityType, entityId, { ProjectionExpression: PROJECTION_EXPRESSION.NO_DATA });
323
+ const tenMinsLater = Math.floor(new Date().getTime() / 1000 + 10 * 60);
324
+ const expressions = {
325
+ UpdateExpression: 'SET #expiresAt = :expiresAt, #mutualUpdatedAt = :mutualUpdatedAt, #updatedAt = :mutualUpdatedAt',
326
+ ConditionExpression: (opts === null || opts === void 0 ? void 0 : opts.ConditionExpression) ||
327
+ 'attribute_exists(PK) AND attribute_not_exists(#expiresAt)',
328
+ ExpressionAttributeNames: Object.assign({ '#expiresAt': 'expiresAt', '#mutualUpdatedAt': 'mutualUpdatedAt', '#updatedAt': 'updatedAt' }, opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeNames),
329
+ ExpressionAttributeValues: Object.assign({ ':expiresAt': { N: String(tenMinsLater) }, ':mutualUpdatedAt': { S: new Date().toISOString() } }, opts === null || opts === void 0 ? void 0 : opts.ExpressionAttributeValues),
330
+ };
331
+ const TransactItems = [
332
+ {
333
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: mutual.mainKeys() }, expressions),
380
334
  },
381
- },
382
- {
383
- Update: {
384
- TableName: this.TABLE_NAME,
385
- Key: {
386
- PK: { S: mutual.byFullEntityId },
387
- SK: { S: mutual.fullEntityId },
388
- },
389
- ...expressions,
335
+ {
336
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
337
+ PK: { S: mutual.byFullEntityId },
338
+ SK: { S: mutual.fullEntityId },
339
+ } }, expressions),
390
340
  },
341
+ {
342
+ Update: Object.assign({ TableName: this.TABLE_NAME, Key: {
343
+ PK: { S: mutual.fullEntityId },
344
+ SK: { S: mutual.byFullEntityId },
345
+ } }, expressions),
346
+ },
347
+ ];
348
+ errorContext.TransactItems = TransactItems;
349
+ yield this.dynamodbClient.transactWriteItems({ TransactItems });
350
+ return mutual;
351
+ }
352
+ catch (err) {
353
+ const isConditionalCheckFailed = err instanceof TransactionCanceledException &&
354
+ ((_a = err.CancellationReasons) === null || _a === void 0 ? void 0 : _a.some((reason) => reason.Code === BatchStatementErrorCodeEnum.ConditionalCheckFailed));
355
+ const isMutualIsUndefined = err instanceof StandardError &&
356
+ err.code === StandardErrorCode.MUTUAL_IS_UNDEFINED;
357
+ if (isConditionalCheckFailed || isMutualIsUndefined) {
358
+ throw new StandardError(StandardErrorCode.MUTUAL_NOT_FOUND, 'Mutual not found', err, {
359
+ errorContext,
360
+ });
361
+ }
362
+ throw err;
363
+ }
364
+ });
365
+ }
366
+ createMutualLock(_a) {
367
+ return __awaiter(this, arguments, void 0, function* ({ byEntityType, byEntityId, entityType, version, }) {
368
+ var _b, _c, _d;
369
+ let retryCount = 2;
370
+ const itemKey = {
371
+ PK: {
372
+ S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
391
373
  },
392
- {
393
- Update: {
374
+ SK: { S: '#LOCK#' },
375
+ };
376
+ do {
377
+ try {
378
+ const fiveMinsLater = Math.floor(new Date().getTime() / 1000 + 5 * 60);
379
+ yield this.dynamodbClient.putItem({
394
380
  TableName: this.TABLE_NAME,
395
- Key: {
396
- PK: { S: mutual.fullEntityId },
397
- SK: { S: mutual.byFullEntityId },
381
+ Item: Object.assign(Object.assign({}, itemKey), { version: { S: version }, status: { S: 'LOCK' }, expiresAt: {
382
+ // auto release lock in case the mutual logic gone wrong to prevent dead lock
383
+ N: `${fiveMinsLater}`,
384
+ } }),
385
+ ConditionExpression: 'attribute_not_exists(PK) OR version < :version AND #status <> :status',
386
+ ExpressionAttributeNames: { '#status': 'status' },
387
+ ExpressionAttributeValues: {
388
+ ':version': { S: version },
389
+ ':status': { S: 'LOCK' },
398
390
  },
399
- ...expressions,
400
- },
401
- },
402
- ];
403
- errorContext.TransactItems = TransactItems;
404
- await this.dynamodbClient.transactWriteItems({ TransactItems });
405
- return mutual;
406
- }
407
- catch (err) {
408
- const isConditionalCheckFailed = err instanceof TransactionCanceledException &&
409
- err.CancellationReasons?.some((reason) => reason.Code === BatchStatementErrorCodeEnum.ConditionalCheckFailed);
410
- const isMutualIsUndefined = err instanceof StandardError && err.code === 'MUTUAL_IS_UNDEFINED';
411
- if (isConditionalCheckFailed || isMutualIsUndefined) {
412
- throw new StandardError('MUTUAL_NOT_FOUND', 'Mutual not found', err, {
413
- errorContext,
414
- });
415
- }
416
- throw err;
417
- }
391
+ });
392
+ return;
393
+ }
394
+ catch (err) {
395
+ console.log('=====CATCHED_MUTUAL_LOCK_CONFLICT=====');
396
+ const lock = yield this.dynamodbClient.getItem({
397
+ TableName: this.TABLE_NAME,
398
+ Key: itemKey,
399
+ });
400
+ // if version is lower, throw not retryable error to skip
401
+ const existingVersion = (_d = (_c = (_b = lock.Item) === null || _b === void 0 ? void 0 : _b.version) === null || _c === void 0 ? void 0 : _c.S) !== null && _d !== void 0 ? _d : '';
402
+ const isExistingVersionGreaterThanNewVersion = existingVersion >= version;
403
+ if (isExistingVersionGreaterThanNewVersion) {
404
+ throw new StandardError(StandardErrorCode.MUTUAL_LOCK_CONFLICT, 'Lock conflict', err, { lock: lock.Item });
405
+ }
406
+ // default behaviour
407
+ // if version is higher, retry
408
+ // if lock not found, retry
409
+ yield sleep(2000);
410
+ console.log('=====RETRY_MUTUAL_LOCK=====');
411
+ }
412
+ } while (retryCount-- > 0);
413
+ // catch real unhandled error, so it can reach DLQ for inspection
414
+ throw new StandardError(StandardErrorCode.RETRYABLE_MUTUAL_LOCK_CONFLICT, 'Retryable lock conflict');
415
+ });
418
416
  }
419
- async createMutualLock({ byEntityType, byEntityId, entityType, version, }) {
420
- let retryCount = 2;
421
- const itemKey = {
422
- PK: {
423
- S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
424
- },
425
- SK: { S: '#LOCK#' },
426
- };
427
- do {
417
+ deleteMutualLock(_a) {
418
+ return __awaiter(this, arguments, void 0, function* ({ byEntityType, byEntityId, entityType, }) {
428
419
  try {
429
- const fiveMinsLater = Math.floor(new Date().getTime() / 1000 + 5 * 60);
430
- await this.dynamodbClient.putItem({
420
+ yield this.dynamodbClient.updateItem({
431
421
  TableName: this.TABLE_NAME,
432
- Item: {
433
- ...itemKey,
434
- version: { S: version },
435
- status: { S: 'LOCK' },
436
- expiresAt: {
437
- // auto release lock in case the mutual logic gone wrong to prevent dead lock
438
- N: `${fiveMinsLater}`,
422
+ Key: {
423
+ PK: {
424
+ S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
439
425
  },
426
+ SK: { S: '#LOCK#' },
440
427
  },
441
- ConditionExpression: 'attribute_not_exists(PK) OR version < :version AND #status <> :status',
428
+ UpdateExpression: 'REMOVE #status',
442
429
  ExpressionAttributeNames: { '#status': 'status' },
443
- ExpressionAttributeValues: {
444
- ':version': { S: version },
445
- ':status': { S: 'LOCK' },
446
- },
447
430
  });
448
431
  return;
449
432
  }
450
- catch (err) {
451
- console.log('=====CATCHED_MUTUAL_LOCK_CONFLICT=====');
452
- const lock = await this.dynamodbClient.getItem({
453
- TableName: this.TABLE_NAME,
454
- Key: itemKey,
455
- });
456
- // if version is lower, throw not retryable error to skip
457
- const existingVersion = lock.Item?.version?.S ?? '';
458
- const isExistingVersionGreaterThanNewVersion = existingVersion >= version;
459
- if (isExistingVersionGreaterThanNewVersion) {
460
- throw new StandardError('MUTUAL_LOCK_CONFLICT', 'Lock conflict', err, { lock: lock.Item });
461
- }
462
- // default behaviour
463
- // if version is higher, retry
464
- // if lock not found, retry
465
- await sleep(2000);
466
- console.log('=====RETRY_MUTUAL_LOCK=====');
433
+ catch (error) {
434
+ // if lock is not found, it's okay
467
435
  }
468
- } while (retryCount-- > 0);
469
- // catch real unhandled error, so it can reach DLQ for inspection
470
- throw new StandardError('RETRYABLE_MUTUAL_LOCK_CONFLICT', 'Retryable lock conflict');
471
- }
472
- async deleteMutualLock({ byEntityType, byEntityId, entityType, }) {
473
- try {
474
- await this.dynamodbClient.updateItem({
475
- TableName: this.TABLE_NAME,
476
- Key: {
477
- PK: {
478
- S: `MUTUAL#${byEntityType}#${byEntityId}#${entityType}`,
479
- },
480
- SK: { S: '#LOCK#' },
481
- },
482
- UpdateExpression: 'REMOVE #status',
483
- ExpressionAttributeNames: { '#status': 'status' },
484
- });
485
- return;
486
- }
487
- catch (error) {
488
- // if lock is not found, it's okay
489
- }
436
+ });
490
437
  }
491
438
  }
492
439
  //# sourceMappingURL=Mutual.js.map