@sincpro/mobile 0.4.3 → 1.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 (197) hide show
  1. package/README.md +3 -3
  2. package/dist/adapters/JsonSerializer.adapter.d.ts +1 -1
  3. package/dist/adapters/JsonSerializer.adapter.js +2 -2
  4. package/dist/adapters/ReceiptExporter.adapter.js +10 -2
  5. package/dist/adapters/repositories/database_table.repository.d.ts +3 -2
  6. package/dist/adapters/repositories/database_table.repository.js +1 -1
  7. package/dist/adapters/repositories/document.repository.d.ts +81 -0
  8. package/dist/adapters/repositories/document.repository.js +653 -0
  9. package/dist/adapters/repositories/domain_event.repository.d.ts +17 -17
  10. package/dist/adapters/repositories/domain_event.repository.js +25 -31
  11. package/dist/adapters/repositories/domain_event_dead_letter.repository.d.ts +10 -10
  12. package/dist/adapters/repositories/domain_event_dead_letter.repository.js +14 -13
  13. package/dist/adapters/repositories/event_row.d.ts +13 -0
  14. package/dist/adapters/repositories/event_row.js +22 -0
  15. package/dist/adapters/repositories/sqlite_document_store.d.ts +33 -0
  16. package/dist/adapters/repositories/sqlite_document_store.js +201 -0
  17. package/dist/domain/connectivity/events.d.ts +5 -5
  18. package/dist/domain/connectivity/events.js +3 -3
  19. package/dist/domain/database/criteria.d.ts +19 -0
  20. package/dist/domain/database/criteria.js +36 -0
  21. package/dist/domain/database/criteria_clock.d.ts +8 -0
  22. package/dist/domain/database/criteria_clock.js +305 -0
  23. package/dist/domain/database/criteria_sql.d.ts +61 -0
  24. package/dist/domain/database/criteria_sql.js +476 -0
  25. package/dist/domain/database/database.d.ts +1 -0
  26. package/dist/domain/database/index.d.ts +3 -1
  27. package/dist/domain/database/index.js +3 -1
  28. package/dist/domain/database/migration_plan.d.ts +14 -0
  29. package/dist/domain/database/migration_plan.js +44 -0
  30. package/dist/domain/entity/change_tracking.d.ts +21 -0
  31. package/dist/domain/entity/change_tracking.js +71 -0
  32. package/dist/domain/entity/checks.d.ts +8 -0
  33. package/dist/domain/entity/checks.js +82 -0
  34. package/dist/domain/entity/entity.d.ts +39 -32
  35. package/dist/domain/entity/entity.js +94 -105
  36. package/dist/domain/entity/entity_collection.d.ts +15 -30
  37. package/dist/domain/entity/entity_collection.js +30 -121
  38. package/dist/domain/entity/index.d.ts +5 -0
  39. package/dist/domain/entity/index.js +5 -0
  40. package/dist/domain/entity/reconcile.d.ts +7 -0
  41. package/dist/domain/entity/reconcile.js +12 -0
  42. package/dist/domain/entity/relations.d.ts +27 -0
  43. package/dist/domain/entity/relations.js +69 -0
  44. package/dist/domain/entity/remote_sync.d.ts +4 -0
  45. package/dist/domain/entity/remote_sync.js +19 -0
  46. package/dist/domain/entity/values.d.ts +6 -0
  47. package/dist/domain/entity/values.js +13 -0
  48. package/dist/domain/events/catalog.d.ts +29 -0
  49. package/dist/domain/{events.js → events/catalog.js} +7 -11
  50. package/dist/domain/events/chain.d.ts +5 -0
  51. package/dist/domain/events/chain.js +6 -0
  52. package/dist/domain/{event_sourcing → events}/domain_event.d.ts +20 -22
  53. package/dist/domain/events/domain_event.js +227 -0
  54. package/dist/domain/events/index.d.ts +8 -0
  55. package/dist/domain/events/index.js +8 -0
  56. package/dist/domain/events/integration_event.d.ts +103 -0
  57. package/dist/domain/events/integration_event.js +72 -0
  58. package/dist/domain/events/label.d.ts +2 -0
  59. package/dist/domain/events/label.js +26 -0
  60. package/dist/domain/index.d.ts +0 -1
  61. package/dist/domain/index.js +0 -1
  62. package/dist/domain/print/events.d.ts +8 -4
  63. package/dist/domain/print/events.js +9 -4
  64. package/dist/domain/repositories/document_store.d.ts +33 -0
  65. package/dist/domain/repositories/document_store.js +5 -0
  66. package/dist/domain/repositories/hooks.d.ts +23 -0
  67. package/dist/domain/repositories/hooks.js +32 -0
  68. package/dist/domain/repositories/index.d.ts +4 -0
  69. package/dist/domain/repositories/index.js +4 -0
  70. package/dist/domain/{database → repositories}/repository.d.ts +9 -3
  71. package/dist/domain/settings.d.ts +4 -1
  72. package/dist/domain/settings.js +3 -0
  73. package/dist/domain/webview/events.d.ts +2 -2
  74. package/dist/domain/webview/events.js +2 -2
  75. package/dist/entrypoints/db/migrations.js +10 -10
  76. package/dist/entrypoints/queue/QueueProcessor.d.ts +1 -1
  77. package/dist/entrypoints/queue/activateDomain.subscriber.d.ts +2 -2
  78. package/dist/entrypoints/queue/activateDomain.subscriber.js +2 -2
  79. package/dist/entrypoints/queue/newAppSettings.handler.d.ts +2 -2
  80. package/dist/entrypoints/queue/newAppSettings.handler.js +1 -1
  81. package/dist/entrypoints/queue/printImage.subscriber.d.ts +1 -1
  82. package/dist/entrypoints/queue/printImage.subscriber.js +2 -2
  83. package/dist/entrypoints/queue/processWebViewMessage.subscriber.d.ts +1 -1
  84. package/dist/entrypoints/queue/processWebViewMessage.subscriber.js +1 -1
  85. package/dist/entrypoints/ui/AppShell.js +2 -2
  86. package/dist/entrypoints/ui/common_provider.d.ts +1 -13
  87. package/dist/entrypoints/ui/common_provider.js +4 -133
  88. package/dist/entrypoints/ui/domain_switcher.d.ts +2 -2
  89. package/dist/event_driven/index.d.ts +1 -0
  90. package/dist/event_driven/index.js +1 -0
  91. package/dist/{domain/event_sourcing/event_handler.d.ts → event_driven/subscriber.d.ts} +1 -1
  92. package/dist/exceptions.d.ts +21 -0
  93. package/dist/exceptions.js +30 -0
  94. package/dist/framework/base_module.d.ts +1 -1
  95. package/dist/framework/createApp.d.ts +3 -3
  96. package/dist/framework/domain_module.d.ts +1 -1
  97. package/dist/framework/feature.d.ts +26 -0
  98. package/dist/framework/feature.js +36 -0
  99. package/dist/framework/kernel.d.ts +1 -1
  100. package/dist/framework/kernel.js +17 -8
  101. package/dist/index.d.ts +1 -0
  102. package/dist/index.js +1 -0
  103. package/dist/infrastructure/database/connector.d.ts +2 -0
  104. package/dist/infrastructure/database/connector.js +22 -0
  105. package/dist/infrastructure/database/index.d.ts +1 -0
  106. package/dist/infrastructure/database/index.js +1 -0
  107. package/dist/infrastructure/database/schema.d.ts +9 -0
  108. package/dist/infrastructure/database/schema.js +61 -0
  109. package/dist/infrastructure/database/utils.d.ts +2 -0
  110. package/dist/infrastructure/database/utils.js +12 -4
  111. package/dist/infrastructure/event_chain.d.ts +6 -0
  112. package/dist/infrastructure/event_chain.js +25 -0
  113. package/dist/infrastructure/interceptor/intercept.d.ts +7 -2
  114. package/dist/infrastructure/interceptor/intercept.js +5 -2
  115. package/dist/infrastructure/telemetry/tracing/tracing_hooks.d.ts +9 -6
  116. package/dist/infrastructure/telemetry/tracing/tracing_hooks.js +61 -35
  117. package/dist/infrastructure/ui/UIEventBus.d.ts +3 -1
  118. package/dist/infrastructure/ui/UIEventBus.js +8 -1
  119. package/dist/infrastructure/ui/activity.d.ts +37 -0
  120. package/dist/infrastructure/ui/activity.js +84 -0
  121. package/dist/infrastructure/workers/CronWorker.d.ts +6 -4
  122. package/dist/infrastructure/workers/CronWorker.js +24 -18
  123. package/dist/infrastructure/workers/EventBus.d.ts +9 -5
  124. package/dist/infrastructure/workers/EventBus.js +68 -33
  125. package/dist/services/bluetooth.service.js +16 -14
  126. package/dist/services/dead_letter_queue.service.d.ts +7 -7
  127. package/dist/services/dead_letter_queue.service.js +0 -2
  128. package/dist/services/event.service.d.ts +3 -3
  129. package/dist/services/event.service.js +1 -1
  130. package/dist/services/network.service.d.ts +1 -1
  131. package/dist/services/network.service.js +17 -15
  132. package/dist/services/printer.service.d.ts +1 -1
  133. package/dist/services/printer.service.js +50 -44
  134. package/dist/tools/utils/date.js +4 -3
  135. package/dist/tools/utils/monetary.d.ts +6 -3
  136. package/dist/tools/utils/monetary.js +33 -21
  137. package/dist/tools/utils/serializer.d.ts +1 -1
  138. package/dist/tools/utils/serializer.js +32 -35
  139. package/dist/ui/activity/DeviceNotices.d.ts +1 -0
  140. package/dist/ui/activity/DeviceNotices.js +29 -0
  141. package/dist/ui/activity/ProcessToast.d.ts +2 -0
  142. package/dist/ui/activity/ProcessToast.js +71 -0
  143. package/dist/ui/{components/molecules → activity}/ProcessToastProvider.d.ts +1 -1
  144. package/dist/ui/activity/index.d.ts +4 -0
  145. package/dist/ui/activity/index.js +4 -0
  146. package/dist/ui/activity/useActivity.d.ts +9 -0
  147. package/dist/ui/activity/useActivity.js +48 -0
  148. package/dist/ui/components/atoms/DebugBanner.d.ts +1 -1
  149. package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.d.ts +1 -1
  150. package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.js +8 -2
  151. package/dist/ui/components/molecules/DeadLetterErrorBlock.d.ts +1 -1
  152. package/dist/ui/components/molecules/EventTimelineItem.d.ts +3 -3
  153. package/dist/ui/components/molecules/EventTimelineItem.js +1 -1
  154. package/dist/ui/components/molecules/GeoPermissionCard.d.ts +1 -1
  155. package/dist/ui/components/molecules/TimeZoneSelector.d.ts +1 -1
  156. package/dist/ui/components/molecules/TimeZoneSelectorModal.d.ts +1 -1
  157. package/dist/ui/components/molecules/TimeZoneSelectorModal.js +5 -3
  158. package/dist/ui/components/molecules/index.d.ts +1 -2
  159. package/dist/ui/components/molecules/index.js +1 -2
  160. package/dist/ui/components/organisms/BluetoothPrinterSelector.d.ts +1 -1
  161. package/dist/ui/components/organisms/BluetoothPrinterSelector.js +3 -0
  162. package/dist/ui/components/organisms/DatabaseInfoRow.d.ts +1 -1
  163. package/dist/ui/components/organisms/DeadLetterQueueRow.d.ts +5 -4
  164. package/dist/ui/components/organisms/EventRow.d.ts +4 -4
  165. package/dist/ui/components/organisms/EventRow.js +1 -1
  166. package/dist/ui/components/organisms/InjectableWebView.d.ts +2 -2
  167. package/dist/ui/components/organisms/InjectableWebView.js +6 -3
  168. package/dist/ui/components/organisms/Receipt.d.ts +2 -1
  169. package/dist/ui/components/organisms/TableInfoInfoRow.d.ts +1 -1
  170. package/dist/ui/screens/database/database.context.d.ts +2 -2
  171. package/dist/ui/screens/database/database.context.js +9 -18
  172. package/dist/ui/screens/database/database.json_detail.d.ts +1 -1
  173. package/dist/ui/screens/database/database.list.d.ts +1 -1
  174. package/dist/ui/screens/database/database.table_rows.d.ts +1 -1
  175. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.context.d.ts +7 -7
  176. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.list.d.ts +1 -1
  177. package/dist/ui/screens/events/events.context.d.ts +6 -6
  178. package/dist/ui/screens/events/events.context.js +20 -25
  179. package/dist/ui/screens/events/events.list.d.ts +1 -1
  180. package/package.json +51 -40
  181. package/dist/domain/event_sourcing/domain_event.js +0 -164
  182. package/dist/domain/event_sourcing/event.d.ts +0 -25
  183. package/dist/domain/event_sourcing/event.js +0 -25
  184. package/dist/domain/event_sourcing/index.d.ts +0 -2
  185. package/dist/domain/event_sourcing/index.js +0 -2
  186. package/dist/domain/events.d.ts +0 -33
  187. package/dist/infrastructure/ui/ToastHost.d.ts +0 -6
  188. package/dist/infrastructure/ui/ToastHost.js +0 -28
  189. package/dist/infrastructure/ui/events.d.ts +0 -1
  190. package/dist/infrastructure/ui/events.js +0 -1
  191. package/dist/ui/components/molecules/ProcessToast.d.ts +0 -8
  192. package/dist/ui/components/molecules/ProcessToast.js +0 -52
  193. /package/dist/domain/{repositories.d.ts → repositories/catalog.d.ts} +0 -0
  194. /package/dist/domain/{repositories.js → repositories/catalog.js} +0 -0
  195. /package/dist/domain/{database → repositories}/repository.js +0 -0
  196. /package/dist/{domain/event_sourcing/event_handler.js → event_driven/subscriber.js} +0 -0
  197. /package/dist/ui/{components/molecules → activity}/ProcessToastProvider.js +0 -0
@@ -0,0 +1,82 @@
1
+ import { heldEntities, relations } from "../../domain/entity/relations";
2
+ import { ChecksFailed, DomainValidationError } from "../../exceptions";
3
+ const CHECK = Symbol("check");
4
+ export function check(watches) {
5
+ return function (_target, _key, descriptor) {
6
+ descriptor.value[CHECK] = watches;
7
+ return descriptor;
8
+ };
9
+ }
10
+ function watchedNames(watches, entity) {
11
+ const names = [];
12
+ const proxy = new Proxy(entity, {
13
+ get(target, prop, receiver) {
14
+ if (typeof prop === "string" && prop !== "constructor")
15
+ names.push(prop);
16
+ return Reflect.get(target, prop, receiver);
17
+ },
18
+ });
19
+ watches(proxy);
20
+ return names;
21
+ }
22
+ function rulesOf(entity) {
23
+ const seen = new Set();
24
+ const rules = [];
25
+ let proto = Object.getPrototypeOf(entity);
26
+ while (proto && proto !== Object.prototype) {
27
+ for (const key of Object.getOwnPropertyNames(proto)) {
28
+ if (seen.has(key))
29
+ continue;
30
+ const value = proto[key];
31
+ const watches = value?.[CHECK];
32
+ if (!watches || typeof value !== "function")
33
+ continue;
34
+ seen.add(key);
35
+ rules.push({ name: key, watches, run: value.bind(entity) });
36
+ }
37
+ proto = Object.getPrototypeOf(proto);
38
+ }
39
+ return rules;
40
+ }
41
+ function failureOf(rule, run) {
42
+ try {
43
+ run();
44
+ return null;
45
+ }
46
+ catch (error) {
47
+ if (error instanceof DomainValidationError) {
48
+ return { rule, message: error.message };
49
+ }
50
+ throw error;
51
+ }
52
+ }
53
+ export function checkWarnings(entity, touched) {
54
+ return collect(entity, [], new Set(touched));
55
+ }
56
+ export function assertChecks(entity) {
57
+ const failures = collect(entity, [], null);
58
+ if (failures.length > 0)
59
+ throw new ChecksFailed(failures);
60
+ }
61
+ function collect(entity, path, touched) {
62
+ const failures = [];
63
+ for (const rule of rulesOf(entity)) {
64
+ if (touched) {
65
+ const fields = watchedNames(rule.watches, entity);
66
+ const reached = fields.some((field) => touched.has(field)) ||
67
+ (path.length > 0 && touched.has(path[0]));
68
+ if (!reached)
69
+ continue;
70
+ }
71
+ const failure = failureOf(rule.name, rule.run);
72
+ if (failure)
73
+ failures.push({ ...failure, path });
74
+ }
75
+ const record = entity;
76
+ for (const relation of relations(entity)) {
77
+ heldEntities(record[relation.field]).forEach((child, index) => {
78
+ failures.push(...collect(child, [...path, relation.field, String(index)], touched));
79
+ });
80
+ }
81
+ return failures;
82
+ }
@@ -1,4 +1,5 @@
1
- import { type DomainEvent, type DomainEventClass, type EventData } from "../../domain/event_sourcing/domain_event";
1
+ import { type DomainEvent, type DomainEventClass, type EventData } from "../../domain/events/domain_event";
2
+ import { IntegrationEvent } from "../../domain/events/integration_event";
2
3
  import { IValueObject, ValueObject } from "./value_object";
3
4
  export declare enum ERemoteState {
4
5
  SYNCED = "SYNCED",
@@ -9,31 +10,32 @@ export interface IRemote {
9
10
  remoteId?: number;
10
11
  remoteRef?: string;
11
12
  remoteState: ERemoteState;
13
+ ackedVersion: number;
14
+ readonly isDirty: boolean;
12
15
  fromRemoteDTO: (data: any) => this;
13
16
  mergeWithRemote: (data: this) => void;
14
17
  remotePayload(): any;
15
18
  }
16
- export interface IEventSourced {
17
- addDomainEvent<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload?: EventData<T>): string;
18
- addDomainEventWithEntity<T extends DomainEvent>(EventClass: DomainEventClass<T>): string;
19
- getDomainEvents(): readonly DomainEvent[];
20
- clearDomainEvents(): void;
21
- publishAllDomainEvents(): Promise<void>;
22
- publishAllDomainEventsSync(): Promise<void>;
23
- publishDomainEvent<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload: Partial<T>): Promise<void>;
24
- publishDomainEventSync<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload: Partial<T>): Promise<void>;
25
- publishDomainEventWithEntity<T extends DomainEvent>(EventClass: DomainEventClass<T>): Promise<void>;
26
- publishDomainEventWithEntitySync<T extends DomainEvent>(EventClass: DomainEventClass<T>): Promise<void>;
27
- publishEventWith<T extends DomainEvent>(EventClass: DomainEventClass<T>, selector: (entity: this) => Partial<T>): Promise<void>;
28
- publishEventWithSync<T extends DomainEvent>(EventClass: DomainEventClass<T>, selector: (entity: this) => Partial<T>): Promise<void>;
29
- copyDomainEventsFrom(source: Entity): void;
30
- }
31
- export interface IEntity extends IEventSourced, IValueObject {
19
+ export interface IEntity extends IValueObject {
32
20
  uuid: string;
33
21
  name?: string;
34
22
  eventIds: string[];
23
+ createdAt: string;
24
+ updatedAt: string | null;
25
+ version: number;
26
+ readonly isNew: boolean;
35
27
  equals(other: IEntity): boolean;
36
28
  clone(): this;
29
+ record<C extends DomainEventClass<DomainEvent>>(EventClass: C, payload?: EventData<InstanceType<C>>): string;
30
+ recordEntity<C extends DomainEventClass<DomainEvent>>(EventClass: C): string;
31
+ recordedEvents(): readonly DomainEvent[];
32
+ pullEvents(): DomainEvent[];
33
+ releaseDeliverable(): IntegrationEvent[];
34
+ restoreRecorded(events: readonly DomainEvent[]): void;
35
+ copyRecordedFrom(source: Entity): void;
36
+ replaceRecorded(events: readonly DomainEvent[]): void;
37
+ noteHeld(): void;
38
+ heldIds(field: string): readonly string[];
37
39
  }
38
40
  export interface IEntityRemote extends IEntity, IRemote {
39
41
  }
@@ -41,11 +43,16 @@ export declare class Entity extends ValueObject implements IEntity {
41
43
  uuid: string;
42
44
  name?: string;
43
45
  eventIds: string[];
44
- protected _domainEventsV2: DomainEvent[];
45
- protected _correlationIdV2: string | null;
46
+ createdAt: string;
47
+ updatedAt: string | null;
48
+ version: number;
49
+ protected _recordedEvents: DomainEvent[];
50
+ protected _correlationId: string | null;
51
+ private _held;
46
52
  protected readonly REPOSITORY: string | null;
47
53
  protected constructor();
48
54
  static obj<T>(data?: Partial<T>): T;
55
+ get isNew(): boolean;
49
56
  /**
50
57
  * Resolves domain events collection in runtime from repository.
51
58
  * Uses @mapped decorator to automatically query events by eventIds.
@@ -66,24 +73,23 @@ export declare class Entity extends ValueObject implements IEntity {
66
73
  */
67
74
  reload(): Promise<this>;
68
75
  equals(other: any): boolean;
69
- addDomainEvent<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload?: EventData<T>): string;
70
- addDomainEventWithEntity<T extends DomainEvent>(EventClass: DomainEventClass<T>): string;
71
- getDomainEvents(): readonly DomainEvent[];
72
- copyDomainEventsFrom(source: Entity): void;
73
- clearDomainEvents(): void;
74
- publishAllDomainEvents(): Promise<void>;
75
- publishAllDomainEventsSync(): Promise<void>;
76
- publishDomainEvent<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload: Partial<T>): Promise<void>;
77
- publishDomainEventSync<T extends DomainEvent>(EventClass: DomainEventClass<T>, payload: Partial<T>): Promise<void>;
78
- publishDomainEventWithEntity<T extends DomainEvent>(EventClass: DomainEventClass<T>): Promise<void>;
79
- publishDomainEventWithEntitySync<T extends DomainEvent>(EventClass: DomainEventClass<T>): Promise<void>;
80
- publishEventWith<T extends DomainEvent>(EventClass: DomainEventClass<T>, selector: (entity: this) => Partial<T>): Promise<void>;
81
- publishEventWithSync<T extends DomainEvent>(EventClass: DomainEventClass<T>, selector: (entity: this) => Partial<T>): Promise<void>;
76
+ record<C extends DomainEventClass<DomainEvent>>(EventClass: C, payload?: EventData<InstanceType<C>>): string;
77
+ recordEntity<C extends DomainEventClass<DomainEvent>>(EventClass: C): string;
78
+ recordedEvents(): readonly DomainEvent[];
79
+ pullEvents(): DomainEvent[];
80
+ releaseDeliverable(): IntegrationEvent[];
81
+ restoreRecorded(events: readonly DomainEvent[]): void;
82
+ replaceRecorded(events: readonly DomainEvent[]): void;
83
+ copyRecordedFrom(source: Entity): void;
84
+ noteHeld(): void;
85
+ heldIds(field: string): readonly string[];
86
+ private stageDomainEvent;
82
87
  }
83
88
  export declare class RemoteEntity extends Entity implements IRemote {
84
89
  remoteId?: number;
85
90
  remoteRef?: string;
86
91
  remoteState: ERemoteState;
92
+ ackedVersion: number;
87
93
  protected constructor();
88
94
  static fromRemoteDTO(data: any): RemoteEntity;
89
95
  fromRemoteDTO(data: any): this;
@@ -101,6 +107,7 @@ export declare class RemoteEntity extends Entity implements IRemote {
101
107
  * const refreshed = await product.reloadByRemoteId();
102
108
  */
103
109
  reloadByRemoteId(): Promise<this>;
110
+ get isDirty(): boolean;
104
111
  mergeWithRemote(data: this): void;
105
112
  remotePayload(): any;
106
113
  markAsSynced(): void;
@@ -7,12 +7,13 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
7
7
  var __metadata = (this && this.__metadata) || function (k, v) {
8
8
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
9
  };
10
- import { ECommonRepository } from "../../domain/repositories";
10
+ import { IntegrationEvent } from "../../domain/events/integration_event";
11
+ import { ECommonRepository } from "../../domain/repositories/catalog";
11
12
  import { DomainValidationError } from "../../exceptions";
12
13
  import { mapped, resolveEntity } from "../../infrastructure/database";
13
14
  import { generateUUID } from "../../infrastructure/database/utils";
14
15
  import { loggerQueueProcessor } from "../../infrastructure/logger";
15
- import { EventBus } from "../../infrastructure/workers";
16
+ import { heldEntities, relations } from "./relations";
16
17
  import { ValueObject } from "./value_object";
17
18
  export var ERemoteState;
18
19
  (function (ERemoteState) {
@@ -24,8 +25,12 @@ export class Entity extends ValueObject {
24
25
  uuid;
25
26
  name;
26
27
  eventIds = [];
27
- _domainEventsV2 = [];
28
- _correlationIdV2 = null;
28
+ createdAt = "";
29
+ updatedAt = null;
30
+ version = 0;
31
+ _recordedEvents = [];
32
+ _correlationId = null;
33
+ _held = {};
29
34
  REPOSITORY = null;
30
35
  constructor() {
31
36
  super();
@@ -38,8 +43,17 @@ export class Entity extends ValueObject {
38
43
  if (!instance.uuid) {
39
44
  instance.uuid = generateUUID();
40
45
  }
46
+ if (!instance.createdAt) {
47
+ instance.createdAt = new Date().toISOString();
48
+ }
49
+ if (typeof instance.version !== "number") {
50
+ instance.version = 0;
51
+ }
41
52
  return instance;
42
53
  }
54
+ get isNew() {
55
+ return this.version === 0;
56
+ }
43
57
  /**
44
58
  * Resolves domain events collection in runtime from repository.
45
59
  * Uses @mapped decorator to automatically query events by eventIds.
@@ -73,118 +87,81 @@ export class Entity extends ValueObject {
73
87
  return false;
74
88
  return this.uuid === other.uuid;
75
89
  }
76
- addDomainEvent(EventClass, payload) {
77
- const event = EventClass.create(payload);
78
- const existingEvent = this._domainEventsV2.find((e) => e.hasSameBusinessPayload(event));
79
- if (existingEvent) {
80
- loggerQueueProcessor.warn(`class ${this.constructor.name} - V2 Event: '${event.name}' with identical payload already exists for entity '${this.uuid}'. Skipping duplicate.`);
81
- return existingEvent.uuid;
90
+ record(EventClass, payload) {
91
+ return this.stageDomainEvent(EventClass.create(payload));
92
+ }
93
+ recordEntity(EventClass) {
94
+ return this.stageDomainEvent(EventClass.create({ record: this }));
95
+ }
96
+ recordedEvents() {
97
+ return this._recordedEvents.map((event) => event.clone());
98
+ }
99
+ pullEvents() {
100
+ const events = this._recordedEvents;
101
+ this._recordedEvents = [];
102
+ this._correlationId = null;
103
+ return events;
104
+ }
105
+ releaseDeliverable() {
106
+ const kept = [];
107
+ const released = [];
108
+ for (const event of this._recordedEvents) {
109
+ if (event instanceof IntegrationEvent)
110
+ released.push(event);
111
+ else
112
+ kept.push(event);
82
113
  }
83
- if (!this._correlationIdV2) {
84
- this._correlationIdV2 = generateUUID();
114
+ this._recordedEvents = kept;
115
+ if (kept.length === 0)
116
+ this._correlationId = null;
117
+ if (released.length > 0) {
118
+ const gone = new Set(released.map((event) => event.uuid));
119
+ this.eventIds = this.eventIds.filter((id) => !gone.has(id));
85
120
  }
86
- event
87
- .withAggregateId(this.uuid)
88
- .withCorrelationId(this._correlationIdV2)
89
- .withSequence(this._domainEventsV2.length + 1);
90
- this._domainEventsV2.push(event);
91
- this.eventIds.push(event.uuid);
92
- return event.uuid;
121
+ return released;
93
122
  }
94
- addDomainEventWithEntity(EventClass) {
95
- const event = EventClass.create({ record: this });
96
- const existingEvent = this._domainEventsV2.find((e) => e.hasSameBusinessPayload(event));
97
- if (existingEvent) {
98
- loggerQueueProcessor.warn(`class ${this.constructor.name} - V2 Event: '${event.name}' with identical payload already exists for entity '${this.uuid}'. Skipping duplicate.`);
99
- return existingEvent.uuid;
100
- }
101
- if (!this._correlationIdV2) {
102
- this._correlationIdV2 = generateUUID();
103
- }
104
- event
105
- .withAggregateId(this.uuid)
106
- .withCorrelationId(this._correlationIdV2)
107
- .withSequence(this._domainEventsV2.length + 1);
108
- this._domainEventsV2.push(event);
109
- this.eventIds.push(event.uuid);
110
- return event.uuid;
111
- }
112
- getDomainEvents() {
113
- return this._domainEventsV2.map((e) => e.clone());
114
- }
115
- copyDomainEventsFrom(source) {
116
- for (const event of source.getDomainEvents()) {
117
- const clonedEvent = event
118
- .clone()
119
- .withAggregateId(this.uuid)
120
- .withCorrelationId(this._correlationIdV2 || generateUUID())
121
- .withSequence(this._domainEventsV2.length + 1);
122
- this._domainEventsV2.push(clonedEvent);
123
- this.eventIds.push(clonedEvent.uuid);
123
+ restoreRecorded(events) {
124
+ for (const event of events) {
125
+ this._recordedEvents.push(event);
126
+ if (!this.eventIds.includes(event.uuid))
127
+ this.eventIds.push(event.uuid);
124
128
  }
125
129
  }
126
- clearDomainEvents() {
127
- this._domainEventsV2 = [];
128
- this._correlationIdV2 = null;
130
+ replaceRecorded(events) {
131
+ this._recordedEvents = [...events];
129
132
  }
130
- async publishAllDomainEvents() {
131
- const events = this._domainEventsV2;
132
- if (events.length > 1) {
133
- loggerQueueProcessor.info(`class ${this.constructor.name} - Publishing total [${events.length}] V2 domain events for entity '${this.uuid}'`);
133
+ copyRecordedFrom(source) {
134
+ for (const event of source.recordedEvents()) {
135
+ this.stageDomainEvent(event.clone());
134
136
  }
135
- for (const event of events) {
136
- await EventBus.publish(event);
137
- }
138
- this.clearDomainEvents();
139
137
  }
140
- async publishAllDomainEventsSync() {
141
- const events = this._domainEventsV2;
142
- if (events.length > 1) {
143
- loggerQueueProcessor.info(`class ${this.constructor.name} - Publishing total [${events.length}] V2 domain events for entity '${this.uuid}'`);
144
- }
145
- const errors = [];
146
- for (const event of events) {
147
- try {
148
- await EventBus.publishSync(event);
149
- }
150
- catch (error) {
151
- loggerQueueProcessor.warn(`class ${this.constructor.name} - Error publishing V2 domain event '${event.name}' for entity '${this.uuid}': ${error.message}`);
152
- errors.push(error);
153
- }
154
- }
155
- this.clearDomainEvents();
156
- if (errors.length > 0) {
157
- const errorList = errors.map((e) => ` - ${e.message}`).join("\n");
158
- throw new Error(`Errors occurred while publishing V2 domain events synchronously:\n${errorList}`);
138
+ noteHeld() {
139
+ const held = {};
140
+ for (const relation of relations(this)) {
141
+ held[relation.field] = heldEntities(this[relation.field]).map((child) => child.uuid);
159
142
  }
143
+ this._held = held;
160
144
  }
161
- async publishDomainEvent(EventClass, payload) {
162
- this.addDomainEvent(EventClass, payload);
163
- await this.publishAllDomainEvents();
164
- }
165
- async publishDomainEventSync(EventClass, payload) {
166
- this.addDomainEvent(EventClass, payload);
167
- await this.publishAllDomainEventsSync();
168
- }
169
- async publishDomainEventWithEntity(EventClass) {
170
- this.addDomainEventWithEntity(EventClass);
171
- await this.publishAllDomainEvents();
172
- }
173
- async publishDomainEventWithEntitySync(EventClass) {
174
- this.addDomainEventWithEntity(EventClass);
175
- await this.publishAllDomainEventsSync();
176
- }
177
- async publishEventWith(EventClass, selector) {
178
- const event = EventClass.create(selector(this));
179
- event.withAggregateId(this.uuid);
180
- this._domainEventsV2.push(event);
181
- await this.publishAllDomainEvents();
145
+ heldIds(field) {
146
+ return this._held[field] ?? [];
182
147
  }
183
- async publishEventWithSync(EventClass, selector) {
184
- const event = EventClass.create(selector(this));
185
- event.withAggregateId(this.uuid);
186
- this._domainEventsV2.push(event);
187
- await this.publishAllDomainEventsSync();
148
+ stageDomainEvent(event) {
149
+ const existingEvent = this._recordedEvents.find((recorded) => recorded.hasSameBusinessPayload(event));
150
+ if (existingEvent) {
151
+ loggerQueueProcessor.warn(`class ${this.constructor.name} - Event '${event.name}' is already recorded for '${this.uuid}' with the same payload. Skipping.`);
152
+ return existingEvent.uuid;
153
+ }
154
+ if (!this._correlationId) {
155
+ this._correlationId = generateUUID();
156
+ }
157
+ event
158
+ .withEntityType(this.constructor.name)
159
+ .withAggregateId(this.uuid)
160
+ .withSequence(this._recordedEvents.length + 1)
161
+ .applyChain(this._correlationId);
162
+ this._recordedEvents.push(event);
163
+ this.eventIds.push(event.uuid);
164
+ return event.uuid;
188
165
  }
189
166
  }
190
167
  __decorate([
@@ -196,6 +173,7 @@ export class RemoteEntity extends Entity {
196
173
  remoteId;
197
174
  remoteRef;
198
175
  remoteState = ERemoteState.PENDING;
176
+ ackedVersion = 0;
199
177
  constructor() {
200
178
  super();
201
179
  }
@@ -224,12 +202,23 @@ export class RemoteEntity extends Entity {
224
202
  }
225
203
  return (await resolveEntity(this.REPOSITORY, this.remoteId, true));
226
204
  }
205
+ get isDirty() {
206
+ return this.version === 0 || this.version !== this.ackedVersion;
207
+ }
227
208
  mergeWithRemote(data) {
228
209
  const preservedUuid = this.uuid;
229
210
  const preservedEventIds = this.eventIds;
211
+ const preservedVersion = this.version;
212
+ const preservedAcked = this.ackedVersion;
213
+ const preservedState = this.remoteState;
214
+ const preservedCreatedAt = this.createdAt;
230
215
  Object.assign(this, data);
231
216
  this.uuid = preservedUuid;
232
217
  this.eventIds = preservedEventIds;
218
+ this.version = preservedVersion;
219
+ this.ackedVersion = preservedAcked;
220
+ this.remoteState = preservedState;
221
+ this.createdAt = preservedCreatedAt;
233
222
  }
234
223
  remotePayload() {
235
224
  throw new Error(`${this.name}.remotePayload debe ser implementado`);
@@ -1,15 +1,10 @@
1
- import { DomainEvent, type DomainEventClass } from "../../domain/event_sourcing/domain_event";
1
+ import { type DocumentCriteria } from "../../domain/database/criteria";
2
+ import { type DomainEventClass, type EventData } from "../../domain/events/domain_event";
3
+ import { type IntegrationEvent } from "../../domain/events/integration_event";
2
4
  import { type Entity, type RemoteEntity } from "./entity";
3
5
  import { ValueObject } from "./value_object";
4
- export type CriteriaOperator = "=" | "!=" | "in" | "not_in" | "like" | ">" | "<" | ">=" | "<=";
5
- export interface ICriteria<T = any> {
6
- field: keyof T;
7
- operator: CriteriaOperator;
8
- value: any;
9
- }
10
6
  /**
11
- * Type-safe, immutable collection for Entity aggregates with event sourcing support.
12
- * Implements IEventSourced for domain event publishing and provides functional operations.
7
+ * Collection of aggregates. Records integration events for the set and offers the list operations.
13
8
  *
14
9
  * @example
15
10
  * const collection = new EntityCollection([priceList1, priceList2]);
@@ -25,15 +20,15 @@ export interface ICriteria<T = any> {
25
20
  * const union = collection1.union(collection2);
26
21
  * const common = collection1.intersect(collection2);
27
22
  *
28
- * // Event sourcing
29
- * await collection.publishEventWith(PRICE_LISTS_SYNCED, pl => ({ id: pl.remoteId, name: pl.name }));
23
+ * // Record an integration event for the set
24
+ * collection.record(PriceListsSynced, { count: collection.length });
30
25
  */
31
26
  export declare class EntityCollection<T extends Entity> extends ValueObject {
32
27
  uuid: string;
33
28
  eventIds: string[];
34
29
  private entities;
35
- private _domainEventsV2;
36
- private _correlationIdV2;
30
+ private _recordedEvents;
31
+ private _correlationId;
37
32
  constructor(entities?: T[]);
38
33
  /** Factory method for creating instances - override in subclasses */
39
34
  protected createInstance(entities: T[]): this;
@@ -236,16 +231,11 @@ export declare class EntityCollection<T extends Entity> extends ValueObject {
236
231
  * const entity = byUuid.get("abc-123"); // Fast lookup
237
232
  */
238
233
  toMapByUuid(): Map<string, T>;
239
- addDomainEvent<E extends DomainEvent>(EventClass: DomainEventClass<E>, payload: Partial<E>): string;
240
- addDomainEventWithEntities<E extends DomainEvent>(EventClass: DomainEventClass<E>): string;
241
- getDomainEvents(): readonly DomainEvent[];
242
- clearDomainEvents(): void;
243
- publishAllDomainEvents(): Promise<void>;
244
- publishAllDomainEventsSync(): Promise<void>;
245
- publishDomainEvent<E extends DomainEvent>(EventClass: DomainEventClass<E>, payload: Partial<E>): Promise<void>;
246
- publishDomainEventSync<E extends DomainEvent>(EventClass: DomainEventClass<E>, payload: Partial<E>): Promise<void>;
247
- publishDomainEventWithEntities<E extends DomainEvent>(EventClass: DomainEventClass<E>): Promise<void>;
248
- publishDomainEventWithEntitiesSync<E extends DomainEvent>(EventClass: DomainEventClass<E>): Promise<void>;
234
+ record<C extends DomainEventClass<IntegrationEvent>>(EventClass: C, payload: EventData<InstanceType<C>>): string;
235
+ recordEntities<C extends DomainEventClass<IntegrationEvent>>(EventClass: C): string;
236
+ private stageDomainEvent;
237
+ recordedEvents(): readonly IntegrationEvent[];
238
+ pullEvents(): IntegrationEvent[];
249
239
  /**
250
240
  * Serializes collection as array of entity JSONs.
251
241
  * Collection is a manager, not an entity, so it serializes as pure entity list.
@@ -255,14 +245,9 @@ export declare class EntityCollection<T extends Entity> extends ValueObject {
255
245
  */
256
246
  asJSON(pretty?: boolean): string;
257
247
  /**
258
- * Filters entities using criteria array. All criteria must match (AND).
259
- * @example
260
- * const filtered = collection.findByCriteria([
261
- * { field: 'customerId', operator: '=', value: 123 },
262
- * { field: 'state', operator: 'in', value: ['draft', 'posted'] }
263
- * ]);
248
+ * The entities that answer a criteria. The filter is `selection`.
264
249
  */
265
- findByCriteria(criteria: ICriteria<T>[]): this;
250
+ findByCriteria(criteria: DocumentCriteria<T>): this;
266
251
  /**
267
252
  * Deserializes collection from array of entity JSONs.
268
253
  * Collection is a manager, not an entity, so it deserializes from pure entity list.