@monorise/core 1.0.3 → 1.0.4-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 (156) hide show
  1. package/dist/controllers/entity/create-entity.controller.d.ts +1 -1
  2. package/dist/controllers/entity/create-entity.controller.d.ts.map +1 -1
  3. package/dist/controllers/entity/create-entity.controller.js +1 -1
  4. package/dist/controllers/entity/create-entity.controller.js.map +1 -1
  5. package/dist/controllers/entity/delete-entity.controller.d.ts +1 -1
  6. package/dist/controllers/entity/delete-entity.controller.d.ts.map +1 -1
  7. package/dist/controllers/entity/delete-entity.controller.js +1 -1
  8. package/dist/controllers/entity/delete-entity.controller.js.map +1 -1
  9. package/dist/controllers/entity/get-entity.controller.d.ts +1 -1
  10. package/dist/controllers/entity/get-entity.controller.d.ts.map +1 -1
  11. package/dist/controllers/entity/list-entities.controller.d.ts +1 -1
  12. package/dist/controllers/entity/list-entities.controller.d.ts.map +1 -1
  13. package/dist/controllers/entity/list-entities.controller.js +2 -2
  14. package/dist/controllers/entity/list-entities.controller.js.map +1 -1
  15. package/dist/controllers/entity/update-entity.controller.d.ts +1 -1
  16. package/dist/controllers/entity/update-entity.controller.d.ts.map +1 -1
  17. package/dist/controllers/entity/update-entity.controller.js +1 -1
  18. package/dist/controllers/entity/update-entity.controller.js.map +1 -1
  19. package/dist/controllers/entity/upsert-entity.controller.d.ts +2 -2
  20. package/dist/controllers/entity/upsert-entity.controller.d.ts.map +1 -1
  21. package/dist/controllers/entity/upsert-entity.controller.js +2 -2
  22. package/dist/controllers/entity/upsert-entity.controller.js.map +1 -1
  23. package/dist/controllers/mutual/create-mutual.controller.d.ts +2 -2
  24. package/dist/controllers/mutual/create-mutual.controller.d.ts.map +1 -1
  25. package/dist/controllers/mutual/create-mutual.controller.js +2 -2
  26. package/dist/controllers/mutual/create-mutual.controller.js.map +1 -1
  27. package/dist/controllers/mutual/delete-mutual.controller.d.ts +1 -1
  28. package/dist/controllers/mutual/delete-mutual.controller.d.ts.map +1 -1
  29. package/dist/controllers/mutual/delete-mutual.controller.js +1 -1
  30. package/dist/controllers/mutual/delete-mutual.controller.js.map +1 -1
  31. package/dist/controllers/mutual/get-mutual.controller.d.ts +1 -1
  32. package/dist/controllers/mutual/get-mutual.controller.d.ts.map +1 -1
  33. package/dist/controllers/mutual/list-entities-by-entity.controller.d.ts +1 -1
  34. package/dist/controllers/mutual/list-entities-by-entity.controller.d.ts.map +1 -1
  35. package/dist/controllers/mutual/update-mutual.controller.d.ts +1 -1
  36. package/dist/controllers/mutual/update-mutual.controller.d.ts.map +1 -1
  37. package/dist/controllers/mutual/update-mutual.controller.js +1 -1
  38. package/dist/controllers/mutual/update-mutual.controller.js.map +1 -1
  39. package/dist/controllers/setupRoutes.js +1 -1
  40. package/dist/controllers/setupRoutes.js.map +1 -1
  41. package/dist/controllers/tag/list-tags.controller.d.ts +1 -1
  42. package/dist/controllers/tag/list-tags.controller.d.ts.map +1 -1
  43. package/dist/controllers/tag/list-tags.controller.js +2 -2
  44. package/dist/controllers/tag/list-tags.controller.js.map +1 -1
  45. package/dist/data/DbUtils.js +1 -1
  46. package/dist/data/DbUtils.js.map +1 -1
  47. package/dist/data/Entity.js +1 -1
  48. package/dist/data/Entity.js.map +1 -1
  49. package/dist/data/EventUtils.d.ts +1 -1
  50. package/dist/data/EventUtils.d.ts.map +1 -1
  51. package/dist/data/EventUtils.js +1 -1
  52. package/dist/data/EventUtils.js.map +1 -1
  53. package/dist/data/Mutual.d.ts +1 -1
  54. package/dist/data/Mutual.d.ts.map +1 -1
  55. package/dist/data/Mutual.js +2 -2
  56. package/dist/data/Mutual.js.map +1 -1
  57. package/dist/data/Tag.js +1 -1
  58. package/dist/data/Tag.js.map +1 -1
  59. package/dist/helpers/event.d.ts +1 -1
  60. package/dist/helpers/event.d.ts.map +1 -1
  61. package/dist/helpers/event.js +2 -2
  62. package/dist/helpers/event.js.map +1 -1
  63. package/dist/mock/monorise/chapter.d.ts +91 -91
  64. package/dist/mock/monorise/course.d.ts +17 -17
  65. package/dist/mock/monorise/index.d.ts +186 -186
  66. package/dist/mock/monorise/video.d.ts +28 -28
  67. package/dist/processors/create-entity-processor.js +3 -3
  68. package/dist/processors/create-entity-processor.js.map +1 -1
  69. package/dist/processors/mutual-processor.js +5 -5
  70. package/dist/processors/mutual-processor.js.map +1 -1
  71. package/dist/processors/prejoin-processor.js +4 -4
  72. package/dist/processors/prejoin-processor.js.map +1 -1
  73. package/dist/processors/replication-processor.js +3 -3
  74. package/dist/processors/replication-processor.js.map +1 -1
  75. package/dist/processors/tag-processor.js +2 -2
  76. package/dist/processors/tag-processor.js.map +1 -1
  77. package/dist/services/DependencyContainer.d.ts +18 -18
  78. package/dist/services/DependencyContainer.d.ts.map +1 -1
  79. package/dist/services/DependencyContainer.js +19 -19
  80. package/dist/services/DependencyContainer.js.map +1 -1
  81. package/dist/services/entity-service-lifecycle.d.ts +3 -3
  82. package/dist/services/entity-service-lifecycle.d.ts.map +1 -1
  83. package/dist/services/entity-service-lifecycle.js +1 -1
  84. package/dist/services/entity-service-lifecycle.js.map +1 -1
  85. package/dist/services/entity.service.d.ts +5 -5
  86. package/dist/services/entity.service.d.ts.map +1 -1
  87. package/dist/services/entity.service.js +2 -2
  88. package/dist/services/entity.service.js.map +1 -1
  89. package/dist/services/mutual.service.d.ts +5 -5
  90. package/dist/services/mutual.service.d.ts.map +1 -1
  91. package/dist/services/mutual.service.js +3 -3
  92. package/dist/services/mutual.service.js.map +1 -1
  93. package/dist/types/entity.type.d.ts +1 -1
  94. package/dist/types/entity.type.d.ts.map +1 -1
  95. package/package.json +4 -1
  96. package/configs/service.config.ts +0 -14
  97. package/constants/table.ts +0 -3
  98. package/controllers/entity/create-entity.controller.ts +0 -51
  99. package/controllers/entity/delete-entity.controller.ts +0 -35
  100. package/controllers/entity/entity.http +0 -62
  101. package/controllers/entity/get-entity.controller.ts +0 -33
  102. package/controllers/entity/list-entities.controller.ts +0 -69
  103. package/controllers/entity/update-entity.controller.ts +0 -56
  104. package/controllers/entity/upsert-entity.controller.ts +0 -97
  105. package/controllers/mutual/create-mutual.controller.ts +0 -89
  106. package/controllers/mutual/delete-mutual.controller.ts +0 -40
  107. package/controllers/mutual/get-mutual.controller.ts +0 -38
  108. package/controllers/mutual/list-entities-by-entity.controller.ts +0 -76
  109. package/controllers/mutual/mutual.http +0 -88
  110. package/controllers/mutual/update-mutual.controller.ts +0 -50
  111. package/controllers/setupRoutes.ts +0 -73
  112. package/controllers/tag/list-tags.controller.ts +0 -57
  113. package/data/DbUtils.ts +0 -40
  114. package/data/Entity.ts +0 -499
  115. package/data/EventUtils.ts +0 -47
  116. package/data/FileObject.ts +0 -16
  117. package/data/Mutual.ts +0 -779
  118. package/data/ProjectionExpression.ts +0 -8
  119. package/data/Tag.ts +0 -470
  120. package/data/abstract/Item.base.ts +0 -19
  121. package/data/abstract/Repository.base.ts +0 -92
  122. package/errors/api-error.ts +0 -39
  123. package/errors/extendable-error.ts +0 -35
  124. package/errors/standard-error.ts +0 -29
  125. package/helpers/dependencies.ts +0 -10
  126. package/helpers/event.ts +0 -85
  127. package/helpers/fromLastKeyQuery.ts +0 -11
  128. package/helpers/sleep.ts +0 -1
  129. package/helpers/toLastKeyResponse.ts +0 -11
  130. package/index.ts +0 -23
  131. package/middlewares/entity-type-check.ts +0 -20
  132. package/middlewares/mutual-type-check.ts +0 -26
  133. package/mock/entity.ts +0 -12
  134. package/mock/monorise/admin.ts +0 -35
  135. package/mock/monorise/chapter.ts +0 -94
  136. package/mock/monorise/course.ts +0 -149
  137. package/mock/monorise/index.ts +0 -143
  138. package/mock/monorise/learner.ts +0 -66
  139. package/mock/monorise/learning-activity.ts +0 -62
  140. package/mock/monorise/learning-journey-config.ts +0 -34
  141. package/mock/monorise/module.ts +0 -108
  142. package/mock/monorise/organization.ts +0 -63
  143. package/mock/monorise/reference.ts +0 -28
  144. package/mock/monorise/video.ts +0 -36
  145. package/processors/create-entity-processor.ts +0 -55
  146. package/processors/mutual-processor.ts +0 -262
  147. package/processors/prejoin-processor.ts +0 -264
  148. package/processors/replication-processor.ts +0 -261
  149. package/processors/tag-processor.ts +0 -174
  150. package/services/DependencyContainer.ts +0 -208
  151. package/services/entity-service-lifecycle.ts +0 -41
  152. package/services/entity.service.ts +0 -201
  153. package/services/mutual.service.ts +0 -285
  154. package/tsconfig.json +0 -118
  155. package/types/entity.type.ts +0 -62
  156. package/types/event.ts +0 -84
@@ -1,62 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import { z } from 'zod';
3
-
4
- const baseSchema = z.object({
5
- activityType: z.enum(['REFLECTION', 'QUIZ', 'FILE_UPLOAD']),
6
- questionType: z.enum(['TEXT', 'RADIO', 'CHECKBOX']).optional(),
7
- question: z.string(),
8
- explanation: z.string().optional(),
9
- options: z
10
- .object({
11
- label: z.string(),
12
- isCorrect: z.boolean(),
13
- })
14
- .array()
15
- .optional(),
16
- remark: z.string().optional(),
17
- });
18
-
19
- const config = createEntityConfig({
20
- name: 'learning-activity',
21
- displayName: 'Learning Activity',
22
- baseSchema,
23
- effect: (schema) => {
24
- return schema.refine(
25
- (value) => {
26
- if (value.activityType === 'REFLECTION' && value.question) {
27
- return true;
28
- }
29
-
30
- if (value.activityType === 'FILE_UPLOAD' && value.question) {
31
- return true;
32
- }
33
-
34
- if (
35
- (value.questionType === 'CHECKBOX' ||
36
- value.questionType === 'RADIO') &&
37
- value.options?.length &&
38
- value.options.length >= 2 &&
39
- value.options.filter((v) => v.label).length ===
40
- value.options.length &&
41
- value.options.some((v) => v.isCorrect)
42
- ) {
43
- return true;
44
- }
45
-
46
- if (value.questionType === 'TEXT' && value.question) {
47
- return true;
48
- }
49
-
50
- return false;
51
- },
52
- {
53
- message:
54
- 'For checkbox and radio question types, please provide at least two options and at least one correct answer',
55
- path: ['options'],
56
- },
57
- );
58
- },
59
- searchableFields: ['question', 'remark'],
60
- });
61
-
62
- export default config;
@@ -1,34 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import type { Mutual } from '@monorise/react';
3
- import { z } from 'zod';
4
- import { Entity } from '../entity';
5
-
6
- const baseSchema = z.object({}).partial();
7
-
8
- const mutualSchema = z
9
- .object({
10
- courseOrders: z.string().array(),
11
- })
12
- .partial();
13
-
14
- const config = createEntityConfig({
15
- name: 'learning-journey-config',
16
- displayName: 'Learning Journey Config',
17
- baseSchema,
18
- mutual: {
19
- mutualSchema,
20
- mutualFields: {
21
- courseOrders: {
22
- entityType: Entity.COURSE,
23
- mutualDataProcessor: (
24
- ids: string[],
25
- context: Mutual<Entity.LEARNING_JOURNEY_CONFIG, Entity.COURSE>,
26
- ) => {
27
- return { index: ids.indexOf(context.entityId) };
28
- },
29
- },
30
- },
31
- },
32
- });
33
-
34
- export default config;
@@ -1,108 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import type { Mutual } from '@monorise/react';
3
- import { z } from 'zod';
4
- import { Entity } from '../entity';
5
-
6
- const allowedTypes = ['MODULE', 'TOUCHPOINT', 'CHECKPOINT'] as const;
7
-
8
- const baseSchema = z
9
- .object({
10
- title: z.string(),
11
- description: z.string(),
12
- shortDescription: z.string(),
13
- remark: z
14
- .string()
15
- .describe('For internal use, eg. This module is for tracks'),
16
- type: z.enum(allowedTypes),
17
- })
18
- .partial();
19
-
20
- const createSchema = baseSchema.extend({
21
- title: z.string(),
22
- type: z.enum(allowedTypes),
23
- });
24
-
25
- const mutualSchema = z
26
- .object({
27
- chapterOrders: z.string().array(),
28
- })
29
- .partial();
30
-
31
- const config = createEntityConfig({
32
- name: 'module',
33
- displayName: 'Module',
34
- baseSchema,
35
- createSchema,
36
- searchableFields: ['title'],
37
- mutual: {
38
- subscribes: [{ entityType: Entity.CHAPTER }],
39
- mutualSchema,
40
- mutualFields: {
41
- chapterOrders: {
42
- entityType: Entity.CHAPTER,
43
- mutualDataProcessor: (
44
- ids: string[],
45
- context: Mutual<Entity.MODULE, Entity.CHAPTER>,
46
- ) => {
47
- return { index: ids.indexOf(context.entityId) };
48
- },
49
- },
50
- videos: {
51
- entityType: Entity.VIDEO,
52
- mutualDataProcessor: (
53
- ids: string[],
54
- context: Mutual<Entity.MODULE, Entity.VIDEO>,
55
- prejoinContext?: Record<string, any>,
56
- ) => ({
57
- index: ids.indexOf(context.entityId),
58
- chapterId: prejoinContext?.[context.entityId],
59
- }),
60
- },
61
- learningActivities: {
62
- entityType: Entity.LEARNING_ACTIVITY,
63
- mutualDataProcessor: (
64
- ids: string[],
65
- context: Mutual<Entity.MODULE, Entity.LEARNING_ACTIVITY>,
66
- prejoinContext?: Record<string, any>,
67
- ) => ({
68
- index: ids.indexOf(context.entityId),
69
- chapterId: prejoinContext?.[context.entityId],
70
- }),
71
- },
72
- },
73
- prejoins: [
74
- {
75
- mutualField: 'videos',
76
- targetEntityType: Entity.VIDEO,
77
- entityPaths: [
78
- {
79
- entityType: Entity.MODULE,
80
- },
81
- {
82
- entityType: Entity.CHAPTER,
83
- },
84
- {
85
- entityType: Entity.VIDEO,
86
- },
87
- ],
88
- },
89
- {
90
- mutualField: 'learningActivities',
91
- targetEntityType: Entity.LEARNING_ACTIVITY,
92
- entityPaths: [
93
- {
94
- entityType: Entity.MODULE,
95
- },
96
- {
97
- entityType: Entity.CHAPTER,
98
- },
99
- {
100
- entityType: Entity.LEARNING_ACTIVITY,
101
- },
102
- ],
103
- },
104
- ],
105
- },
106
- });
107
-
108
- export default config;
@@ -1,63 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import { z } from 'zod';
3
-
4
- import type { Mutual } from '@monorise/react';
5
- import { Entity } from '../entity';
6
-
7
- export enum EXPIRY_TYPE {
8
- ORG_WIDE = 'ORG_WIDE',
9
- PER_INDIVIDUAL = 'PER_INDIVIDUAL',
10
- }
11
-
12
- const baseSchema = z
13
- .object({
14
- name: z.string(),
15
- licenseCount: z.coerce.number(),
16
- allowSelfRegistration: z.boolean(),
17
- isPrimary: z.boolean(),
18
- domains: z.string().array(),
19
- selfRegistrationDisclaimer: z.string(),
20
- welcomeMessage: z.string(),
21
- pathwayWelcomeMessage: z.string(),
22
- expiryType: z.nativeEnum(EXPIRY_TYPE),
23
- orgExpiryDate: z.string().datetime(),
24
- individualAccessDuration: z.coerce.number(),
25
- })
26
- .partial();
27
-
28
- const createSchema = baseSchema.extend({
29
- name: z.string().min(1, 'Please provide a name for this organization'),
30
- });
31
-
32
- const mutualSchema = z
33
- .object({
34
- organizationOrders: z.string().array(),
35
- })
36
- .partial();
37
-
38
- const config = createEntityConfig({
39
- name: 'organization',
40
- displayName: 'Organization',
41
- baseSchema,
42
- createSchema,
43
- searchableFields: ['name'],
44
- mutual: {
45
- mutualSchema,
46
- mutualFields: {
47
- organizationOrders: {
48
- entityType: Entity.ORGANIZATION,
49
- mutualDataProcessor: (
50
- ids: string[],
51
- context: Mutual<Entity.ORGANIZATION, Entity.ORGANIZATION>,
52
- ) => {
53
- return {
54
- index: ids.indexOf(context.entityId),
55
- primaryOrganizationId: context.byEntityId,
56
- };
57
- },
58
- },
59
- },
60
- },
61
- });
62
-
63
- export default config;
@@ -1,28 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import { z } from 'zod';
3
-
4
- const baseSchema = z
5
- .object({
6
- label: z.string(),
7
- link: z.string(),
8
- prelabel: z.string(),
9
- postlabel: z.string(),
10
- })
11
- .partial();
12
-
13
- const createSchema = baseSchema.extend({
14
- label: z.string().min(1, {
15
- message: 'Label is required',
16
- }),
17
- link: z.string().url('This is not a valid url'),
18
- });
19
-
20
- const config = createEntityConfig({
21
- name: 'reference',
22
- displayName: 'Reference',
23
- baseSchema,
24
- createSchema,
25
- searchableFields: ['label', 'link', 'prelabel', 'postlabel'],
26
- });
27
-
28
- export default config;
@@ -1,36 +0,0 @@
1
- import { createEntityConfig } from '@monorise/cli';
2
- import { z } from 'zod';
3
-
4
- const baseSchema = z
5
- .object({
6
- title: z.string(),
7
- categories: z.string().array(),
8
- additionalFiles: z
9
- .object({
10
- type: z.string(),
11
- id: z.string(),
12
- content: z.any(),
13
- })
14
- .array()
15
- .optional(),
16
- keyTakeaway: z.string(),
17
- remark: z.string(),
18
- duration: z.number(),
19
- })
20
- .partial();
21
-
22
- const createSchema = baseSchema.extend({
23
- title: z.string().min(4, {
24
- message: 'Title must be at least 4 characters.',
25
- }),
26
- });
27
-
28
- const config = createEntityConfig({
29
- name: 'video',
30
- displayName: 'Video',
31
- baseSchema,
32
- createSchema,
33
- searchableFields: ['title', 'remark'],
34
- });
35
-
36
- export default config;
@@ -1,55 +0,0 @@
1
- import type { Entity } from '@monorise/base';
2
- import type { SQSBatchItemFailure, SQSEvent } from 'aws-lambda';
3
- import { StandardError } from '#/errors/standard-error';
4
- import { parseSQSBusEvent } from '#/helpers/event';
5
- import { DependencyContainer } from '#/services/DependencyContainer';
6
-
7
- const container = new DependencyContainer();
8
-
9
- type EventDetailBody = {
10
- entityType: Entity;
11
- entityId?: string;
12
- entityPayload: Record<string, any>;
13
- accountId?: string;
14
- options: {
15
- createAndUpdateDatetime?: string;
16
- mutualId?: string;
17
- };
18
- };
19
-
20
- export const handler = async (ev: SQSEvent) => {
21
- const { entityService } = container;
22
- const batchItemFailures: SQSBatchItemFailure[] = [];
23
-
24
- for (const record of ev.Records) {
25
- const errorContext: Record<string, unknown> = {};
26
- const body = parseSQSBusEvent<EventDetailBody>(record.body);
27
- const { detail } = body;
28
- const { entityType, entityId, entityPayload, accountId, options } = detail;
29
- errorContext.body = body;
30
-
31
- try {
32
- await entityService.createEntity({
33
- entityType,
34
- entityId,
35
- entityPayload,
36
- accountId,
37
- options,
38
- });
39
- } catch (err) {
40
- console.error(
41
- '=====CREATE_ENTITY_PROCESSOR_ERROR=====',
42
- err,
43
- JSON.stringify({ errorContext }, null, 2),
44
- );
45
-
46
- if (err instanceof StandardError && err.code === 'INVALID_ENTITY_TYPE') {
47
- continue; // do not retry
48
- }
49
-
50
- batchItemFailures.push({ itemIdentifier: record.messageId });
51
- }
52
- }
53
-
54
- return { batchItemFailures };
55
- };
@@ -1,262 +0,0 @@
1
- import { TransactionCanceledException } from '@aws-sdk/client-dynamodb';
2
- import type { Entity } from '@monorise/base';
3
- import type { SQSBatchItemFailure, SQSEvent } from 'aws-lambda';
4
- import { Mutual } from '#/data/Mutual';
5
- import { StandardError } from '#/errors/standard-error';
6
- import { parseSQSBusEvent } from '#/helpers/event';
7
- import { EntityConfig } from '#/lambda-layer/monorise';
8
- import { DependencyContainer } from '#/services/DependencyContainer';
9
- import { EVENT } from '#/types/event';
10
-
11
- export type EventDetailBody = {
12
- mutualIds: string[];
13
- byEntityType: Entity;
14
- byEntityId: string;
15
- entityType: Entity;
16
- field: string;
17
- publishedAt: string;
18
- customContext?: Record<string, unknown>;
19
- };
20
-
21
- const container = new DependencyContainer();
22
-
23
- const processEntities = async (
24
- entityIds: string[],
25
- action: (id: string) => Promise<void>,
26
- ) => Promise.allSettled(entityIds.map(action));
27
-
28
- export const handler = async (ev: SQSEvent) => {
29
- const batchItemFailures: SQSBatchItemFailure[] = [];
30
- const { entityRepository, mutualRepository, publishEvent } = container;
31
-
32
- await Promise.allSettled(
33
- ev.Records.map(async (record) => {
34
- const errorContext: Record<string, unknown> = {};
35
- const body = parseSQSBusEvent<EventDetailBody>(record.body);
36
- const { detail } = body;
37
- const {
38
- mutualIds,
39
- byEntityType,
40
- byEntityId,
41
- entityType,
42
- field,
43
- publishedAt,
44
- customContext,
45
- } = detail;
46
- errorContext.body = body;
47
-
48
- try {
49
- // Validate if mutual configuration exists
50
- const config =
51
- EntityConfig[byEntityType]?.mutual?.mutualFields?.[field];
52
-
53
- if (!config) {
54
- throw new StandardError('INVALID_MUTUAL', 'Invalid mutual');
55
- }
56
-
57
- const mutualDataProcessor = config.mutualDataProcessor ?? (() => ({}));
58
-
59
- // Create a lock to prevent concurrent modifications
60
- await mutualRepository.createMutualLock({
61
- byEntityType,
62
- byEntityId,
63
- entityType,
64
- version: publishedAt,
65
- });
66
-
67
- // Fetch related entities in parallel
68
- const [byEntity, mutuals] = await Promise.all([
69
- entityRepository.getEntity(byEntityType, byEntityId),
70
- mutualRepository.listEntitiesByEntity(
71
- byEntityType,
72
- byEntityId,
73
- entityType,
74
- ),
75
- ]);
76
-
77
- // Determine which entities were added, removed, or need updates
78
- const existingEntityIds = new Set(mutuals.items.map((m) => m.entityId));
79
- const newMutualIds = new Set(mutualIds ?? []);
80
-
81
- const addedEntityIds = [...newMutualIds].filter(
82
- (id) => !existingEntityIds.has(id),
83
- );
84
- const deletedEntityIds = [...existingEntityIds].filter(
85
- (id) => !newMutualIds.has(id),
86
- );
87
- const toUpdateEntityIds = [...existingEntityIds].filter((id) =>
88
- newMutualIds.has(id),
89
- );
90
-
91
- errorContext.existingEntityIds = [...existingEntityIds];
92
- errorContext.addedEntityIds = addedEntityIds;
93
- errorContext.deletedEntityIds = deletedEntityIds;
94
- errorContext.toUpdateEntityIds = toUpdateEntityIds;
95
-
96
- const addEntities = await processEntities(
97
- addedEntityIds,
98
- async (id) => {
99
- const entity = await entityRepository.getEntity(entityType, id);
100
- await mutualRepository.createMutual(
101
- byEntityType,
102
- byEntityId,
103
- byEntity.data,
104
- entityType,
105
- id,
106
- entity.data,
107
- mutualDataProcessor(
108
- mutualIds,
109
- new Mutual(
110
- byEntityType,
111
- byEntityId,
112
- byEntity.data,
113
- entityType,
114
- id,
115
- entity.data,
116
- {},
117
- ),
118
- customContext,
119
- ),
120
- {
121
- ConditionExpression:
122
- 'attribute_not_exists(#mutualUpdatedAt) OR #mutualUpdatedAt < :publishedAt',
123
- ExpressionAttributeNames: {
124
- '#mutualUpdatedAt': 'mutualUpdatedAt',
125
- },
126
- ExpressionAttributeValues: {
127
- ':publishedAt': { S: publishedAt },
128
- },
129
- createAndUpdateDatetime: new Date(publishedAt),
130
- },
131
- );
132
- },
133
- );
134
-
135
- const deleteEntities = await processEntities(
136
- deletedEntityIds,
137
- async (id) => {
138
- await mutualRepository.deleteMutual(
139
- byEntityType,
140
- byEntityId,
141
- entityType,
142
- id,
143
- {
144
- ConditionExpression:
145
- 'attribute_exists(PK) AND #mutualUpdatedAt < :publishedAt',
146
- ExpressionAttributeNames: {
147
- '#mutualUpdatedAt': 'mutualUpdatedAt',
148
- },
149
- ExpressionAttributeValues: {
150
- ':publishedAt': { S: publishedAt },
151
- },
152
- },
153
- );
154
- },
155
- );
156
-
157
- const updateEntities = await processEntities(
158
- toUpdateEntityIds,
159
- async (id) => {
160
- await mutualRepository.updateMutual(
161
- byEntityType,
162
- byEntityId,
163
- entityType,
164
- id,
165
- {
166
- mutualData: mutualDataProcessor(
167
- mutualIds,
168
- new Mutual(
169
- byEntityType,
170
- byEntityId,
171
- byEntity.data,
172
- entityType,
173
- id,
174
- {},
175
- {},
176
- ),
177
- customContext,
178
- ),
179
- mutualUpdatedAt: publishedAt,
180
- },
181
- {
182
- ConditionExpression:
183
- 'attribute_exists(PK) AND #mutualUpdatedAt < :publishedAt',
184
- ExpressionAttributeNames: {
185
- '#mutualUpdatedAt': 'mutualUpdatedAt',
186
- },
187
- ExpressionAttributeValues: {
188
- ':publishedAt': { S: publishedAt },
189
- },
190
- },
191
- );
192
- },
193
- );
194
-
195
- errorContext.results = { addEntities, deleteEntities, updateEntities };
196
-
197
- // release lock
198
- await mutualRepository.deleteMutualLock({
199
- byEntityType,
200
- byEntityId,
201
- entityType,
202
- });
203
-
204
- // Check for unprocessable errors in processing results
205
- if (
206
- [...addEntities, ...deleteEntities, ...updateEntities].some(
207
- (res) =>
208
- res.status === 'rejected' &&
209
- !(
210
- res.reason instanceof TransactionCanceledException ||
211
- (res.reason instanceof StandardError &&
212
- res.reason.code === 'MUTUAL_NOT_FOUND')
213
- ),
214
- )
215
- ) {
216
- throw new StandardError(
217
- 'MUTUAL_PROCESSOR_ERROR',
218
- 'Mutual processor error',
219
- null,
220
- errorContext,
221
- );
222
- }
223
-
224
- await publishEvent({
225
- event: EVENT.CORE.ENTITY_MUTUAL_PROCESSED,
226
- payload: {
227
- byEntityType,
228
- byEntityId,
229
- entityType,
230
- field,
231
- mutualIds,
232
- publishedAt,
233
- },
234
- });
235
- } catch (err) {
236
- console.error(
237
- '=====MUTUAL_PROCESSOR_ERROR=====',
238
- err,
239
- JSON.stringify({ errorContext }, null, 2),
240
- );
241
-
242
- // Release the lock to avoid deadlocks
243
- await mutualRepository.deleteMutualLock({
244
- byEntityType,
245
- byEntityId,
246
- entityType,
247
- });
248
-
249
- if (
250
- err instanceof StandardError &&
251
- ['INVALID_MUTUAL', 'MUTUAL_LOCK_CONFLICT'].includes(err.code)
252
- ) {
253
- return;
254
- }
255
-
256
- batchItemFailures.push({ itemIdentifier: record.messageId });
257
- }
258
- }),
259
- );
260
-
261
- return { batchItemFailures };
262
- };