@sincpro/mobile 0.1.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 (232) hide show
  1. package/README.md +74 -0
  2. package/dist/adapters/Bluetooth.adapter.d.ts +14 -0
  3. package/dist/adapters/Bluetooth.adapter.js +100 -0
  4. package/dist/adapters/Geo.adapter.d.ts +8 -0
  5. package/dist/adapters/Geo.adapter.js +30 -0
  6. package/dist/adapters/JsonSerializer.adapter.d.ts +28 -0
  7. package/dist/adapters/JsonSerializer.adapter.js +47 -0
  8. package/dist/adapters/Network.adapter.d.ts +4 -0
  9. package/dist/adapters/Network.adapter.js +13 -0
  10. package/dist/adapters/ReceiptExporter.adapter.d.ts +19 -0
  11. package/dist/adapters/ReceiptExporter.adapter.js +142 -0
  12. package/dist/adapters/repositories/database_table.repository.d.ts +13 -0
  13. package/dist/adapters/repositories/database_table.repository.js +29 -0
  14. package/dist/adapters/repositories/domain_event.repository.d.ts +32 -0
  15. package/dist/adapters/repositories/domain_event.repository.js +147 -0
  16. package/dist/adapters/repositories/domain_event_dead_letter.repository.d.ts +23 -0
  17. package/dist/adapters/repositories/domain_event_dead_letter.repository.js +81 -0
  18. package/dist/adapters/repositories/setting.repository.d.ts +10 -0
  19. package/dist/adapters/repositories/setting.repository.js +21 -0
  20. package/dist/adapters/webview.adapter.d.ts +10 -0
  21. package/dist/adapters/webview.adapter.js +166 -0
  22. package/dist/domain/connectivity/bluetooth.d.ts +19 -0
  23. package/dist/domain/connectivity/bluetooth.js +1 -0
  24. package/dist/domain/connectivity/events.d.ts +17 -0
  25. package/dist/domain/connectivity/events.js +17 -0
  26. package/dist/domain/connectivity/geo.d.ts +4 -0
  27. package/dist/domain/connectivity/geo.js +1 -0
  28. package/dist/domain/connectivity/index.d.ts +3 -0
  29. package/dist/domain/connectivity/index.js +3 -0
  30. package/dist/domain/connectivity/network.d.ts +7 -0
  31. package/dist/domain/connectivity/network.js +1 -0
  32. package/dist/domain/database/database.d.ts +16 -0
  33. package/dist/domain/database/database.js +1 -0
  34. package/dist/domain/database/index.d.ts +2 -0
  35. package/dist/domain/database/index.js +2 -0
  36. package/dist/domain/database/repository.d.ts +19 -0
  37. package/dist/domain/database/repository.js +1 -0
  38. package/dist/domain/entity/entity.d.ts +109 -0
  39. package/dist/domain/entity/entity.js +246 -0
  40. package/dist/domain/entity/entity_collection.d.ts +396 -0
  41. package/dist/domain/entity/entity_collection.js +824 -0
  42. package/dist/domain/entity/index.d.ts +3 -0
  43. package/dist/domain/entity/index.js +3 -0
  44. package/dist/domain/entity/value_object.d.ts +12 -0
  45. package/dist/domain/entity/value_object.js +39 -0
  46. package/dist/domain/event_sourcing/domain_event.d.ts +58 -0
  47. package/dist/domain/event_sourcing/domain_event.js +164 -0
  48. package/dist/domain/event_sourcing/event.d.ts +25 -0
  49. package/dist/domain/event_sourcing/event.js +25 -0
  50. package/dist/domain/event_sourcing/event_handler.d.ts +7 -0
  51. package/dist/domain/event_sourcing/event_handler.js +13 -0
  52. package/dist/domain/event_sourcing/index.d.ts +2 -0
  53. package/dist/domain/event_sourcing/index.js +2 -0
  54. package/dist/domain/events.d.ts +33 -0
  55. package/dist/domain/events.js +32 -0
  56. package/dist/domain/icon.d.ts +1 -0
  57. package/dist/domain/icon.js +1 -0
  58. package/dist/domain/index.d.ts +9 -0
  59. package/dist/domain/index.js +9 -0
  60. package/dist/domain/print/driver_registry.d.ts +4 -0
  61. package/dist/domain/print/driver_registry.js +29 -0
  62. package/dist/domain/print/events.d.ts +13 -0
  63. package/dist/domain/print/events.js +13 -0
  64. package/dist/domain/print/index.d.ts +2 -0
  65. package/dist/domain/print/index.js +1 -0
  66. package/dist/domain/print/printer.d.ts +35 -0
  67. package/dist/domain/print/printer.js +1 -0
  68. package/dist/domain/receipt.d.ts +31 -0
  69. package/dist/domain/receipt.js +1 -0
  70. package/dist/domain/repositories.d.ts +6 -0
  71. package/dist/domain/repositories.js +7 -0
  72. package/dist/domain/settings.d.ts +7 -0
  73. package/dist/domain/settings.js +1 -0
  74. package/dist/domain/webview/events.d.ts +11 -0
  75. package/dist/domain/webview/events.js +11 -0
  76. package/dist/domain/webview/index.d.ts +1 -0
  77. package/dist/domain/webview/index.js +1 -0
  78. package/dist/domain/webview/webview.d.ts +57 -0
  79. package/dist/domain/webview/webview.js +9 -0
  80. package/dist/entrypoints/cron/Cron.d.ts +13 -0
  81. package/dist/entrypoints/cron/Cron.js +57 -0
  82. package/dist/entrypoints/cron/checkNetworkStatus.cron.d.ts +3 -0
  83. package/dist/entrypoints/cron/checkNetworkStatus.cron.js +10 -0
  84. package/dist/entrypoints/db/index.d.ts +2 -0
  85. package/dist/entrypoints/db/index.js +2 -0
  86. package/dist/entrypoints/db/migrations.d.ts +10 -0
  87. package/dist/entrypoints/db/migrations.js +115 -0
  88. package/dist/entrypoints/db/repositories.d.ts +8 -0
  89. package/dist/entrypoints/db/repositories.js +34 -0
  90. package/dist/entrypoints/queue/QueueProcessor.d.ts +12 -0
  91. package/dist/entrypoints/queue/QueueProcessor.js +75 -0
  92. package/dist/entrypoints/queue/activateDomain.subscriber.d.ts +7 -0
  93. package/dist/entrypoints/queue/activateDomain.subscriber.js +15 -0
  94. package/dist/entrypoints/queue/newAppSettings.handler.d.ts +7 -0
  95. package/dist/entrypoints/queue/newAppSettings.handler.js +17 -0
  96. package/dist/entrypoints/queue/printImage.subscriber.d.ts +7 -0
  97. package/dist/entrypoints/queue/printImage.subscriber.js +14 -0
  98. package/dist/entrypoints/queue/processWebViewMessage.subscriber.d.ts +7 -0
  99. package/dist/entrypoints/queue/processWebViewMessage.subscriber.js +23 -0
  100. package/dist/entrypoints/ui/AppShell.d.ts +15 -0
  101. package/dist/entrypoints/ui/AppShell.js +58 -0
  102. package/dist/entrypoints/ui/common_provider.d.ts +35 -0
  103. package/dist/entrypoints/ui/common_provider.js +244 -0
  104. package/dist/entrypoints/ui/domain_switcher.d.ts +19 -0
  105. package/dist/entrypoints/ui/domain_switcher.js +22 -0
  106. package/dist/entrypoints/ui/theme.d.ts +15 -0
  107. package/dist/entrypoints/ui/theme.js +16 -0
  108. package/dist/exceptions.d.ts +22 -0
  109. package/dist/exceptions.js +60 -0
  110. package/dist/framework/base_module.d.ts +14 -0
  111. package/dist/framework/base_module.js +40 -0
  112. package/dist/framework/createApp.d.ts +6 -0
  113. package/dist/framework/createApp.js +9 -0
  114. package/dist/framework/domain_module.d.ts +13 -0
  115. package/dist/framework/domain_module.js +18 -0
  116. package/dist/framework/kernel.d.ts +18 -0
  117. package/dist/framework/kernel.js +60 -0
  118. package/dist/framework/orchestrator.d.ts +29 -0
  119. package/dist/framework/orchestrator.js +118 -0
  120. package/dist/index.d.ts +16 -0
  121. package/dist/index.js +11 -0
  122. package/dist/infrastructure/database/connector.d.ts +13 -0
  123. package/dist/infrastructure/database/connector.js +165 -0
  124. package/dist/infrastructure/database/index.d.ts +2 -0
  125. package/dist/infrastructure/database/index.js +2 -0
  126. package/dist/infrastructure/database/mapped.d.ts +128 -0
  127. package/dist/infrastructure/database/mapped.js +174 -0
  128. package/dist/infrastructure/database/utils.d.ts +10 -0
  129. package/dist/infrastructure/database/utils.js +35 -0
  130. package/dist/infrastructure/logger.d.ts +45 -0
  131. package/dist/infrastructure/logger.js +125 -0
  132. package/dist/infrastructure/ui/ToastHost.d.ts +1 -0
  133. package/dist/infrastructure/ui/ToastHost.js +19 -0
  134. package/dist/infrastructure/ui/UIEventBus.d.ts +12 -0
  135. package/dist/infrastructure/ui/UIEventBus.js +65 -0
  136. package/dist/infrastructure/ui/errorHandler.d.ts +1 -0
  137. package/dist/infrastructure/ui/errorHandler.js +20 -0
  138. package/dist/infrastructure/ui/events.d.ts +1 -0
  139. package/dist/infrastructure/ui/events.js +1 -0
  140. package/dist/infrastructure/workers/CronWorker.d.ts +42 -0
  141. package/dist/infrastructure/workers/CronWorker.js +143 -0
  142. package/dist/infrastructure/workers/EventBus.d.ts +67 -0
  143. package/dist/infrastructure/workers/EventBus.js +279 -0
  144. package/dist/infrastructure/workers/index.d.ts +2 -0
  145. package/dist/infrastructure/workers/index.js +2 -0
  146. package/dist/services/bluetooth.service.d.ts +14 -0
  147. package/dist/services/bluetooth.service.js +72 -0
  148. package/dist/services/database_table.service.d.ts +8 -0
  149. package/dist/services/database_table.service.js +19 -0
  150. package/dist/services/dead_letter_queue.service.d.ts +38 -0
  151. package/dist/services/dead_letter_queue.service.js +99 -0
  152. package/dist/services/event.service.d.ts +7 -0
  153. package/dist/services/event.service.js +24 -0
  154. package/dist/services/network.service.d.ts +7 -0
  155. package/dist/services/network.service.js +43 -0
  156. package/dist/services/printer.service.d.ts +25 -0
  157. package/dist/services/printer.service.js +220 -0
  158. package/dist/services/webview.service.d.ts +17 -0
  159. package/dist/services/webview.service.js +59 -0
  160. package/dist/tools/utils/Initials.d.ts +1 -0
  161. package/dist/tools/utils/Initials.js +12 -0
  162. package/dist/tools/utils/collections.d.ts +120 -0
  163. package/dist/tools/utils/collections.js +158 -0
  164. package/dist/tools/utils/date.d.ts +70 -0
  165. package/dist/tools/utils/date.js +126 -0
  166. package/dist/tools/utils/maps.d.ts +4 -0
  167. package/dist/tools/utils/maps.js +20 -0
  168. package/dist/tools/utils/monetary.d.ts +3 -0
  169. package/dist/tools/utils/monetary.js +31 -0
  170. package/dist/tools/utils/quantity.d.ts +11 -0
  171. package/dist/tools/utils/quantity.js +44 -0
  172. package/dist/tools/utils/searchTools.d.ts +39 -0
  173. package/dist/tools/utils/searchTools.js +56 -0
  174. package/dist/tools/utils/serializer.d.ts +2 -0
  175. package/dist/tools/utils/serializer.js +44 -0
  176. package/dist/ui/components/atoms/DebugBanner.d.ts +2 -0
  177. package/dist/ui/components/atoms/DebugBanner.js +15 -0
  178. package/dist/ui/components/atoms/index.d.ts +1 -0
  179. package/dist/ui/components/atoms/index.js +1 -0
  180. package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.d.ts +8 -0
  181. package/dist/ui/components/molecules/BluetoothDeviceSelectorModal.js +61 -0
  182. package/dist/ui/components/molecules/DeadLetterErrorBlock.d.ts +8 -0
  183. package/dist/ui/components/molecules/DeadLetterErrorBlock.js +14 -0
  184. package/dist/ui/components/molecules/EventTimelineItem.d.ts +7 -0
  185. package/dist/ui/components/molecules/EventTimelineItem.js +65 -0
  186. package/dist/ui/components/molecules/ProcessToast.d.ts +5 -0
  187. package/dist/ui/components/molecules/ProcessToast.js +51 -0
  188. package/dist/ui/components/molecules/ProcessToastProvider.d.ts +4 -0
  189. package/dist/ui/components/molecules/ProcessToastProvider.js +5 -0
  190. package/dist/ui/components/molecules/index.d.ts +5 -0
  191. package/dist/ui/components/molecules/index.js +5 -0
  192. package/dist/ui/components/organisms/BluetoothPrinterSelector.d.ts +7 -0
  193. package/dist/ui/components/organisms/BluetoothPrinterSelector.js +92 -0
  194. package/dist/ui/components/organisms/DatabaseInfoRow.d.ts +11 -0
  195. package/dist/ui/components/organisms/DatabaseInfoRow.js +8 -0
  196. package/dist/ui/components/organisms/DeadLetterQueueRow.d.ts +7 -0
  197. package/dist/ui/components/organisms/DeadLetterQueueRow.js +72 -0
  198. package/dist/ui/components/organisms/EventRow.d.ts +7 -0
  199. package/dist/ui/components/organisms/EventRow.js +90 -0
  200. package/dist/ui/components/organisms/InjectableWebView.d.ts +35 -0
  201. package/dist/ui/components/organisms/InjectableWebView.js +169 -0
  202. package/dist/ui/components/organisms/Receipt.d.ts +11 -0
  203. package/dist/ui/components/organisms/Receipt.js +207 -0
  204. package/dist/ui/components/organisms/TableInfoInfoRow.d.ts +9 -0
  205. package/dist/ui/components/organisms/TableInfoInfoRow.js +19 -0
  206. package/dist/ui/components/organisms/index.d.ts +7 -0
  207. package/dist/ui/components/organisms/index.js +7 -0
  208. package/dist/ui/index.d.ts +4 -0
  209. package/dist/ui/index.js +4 -0
  210. package/dist/ui/layouts/router_layouts.d.ts +17 -0
  211. package/dist/ui/layouts/router_layouts.js +20 -0
  212. package/dist/ui/screens/database/database.context.d.ts +32 -0
  213. package/dist/ui/screens/database/database.context.js +158 -0
  214. package/dist/ui/screens/database/database.json_detail.d.ts +2 -0
  215. package/dist/ui/screens/database/database.json_detail.js +19 -0
  216. package/dist/ui/screens/database/database.list.d.ts +1 -0
  217. package/dist/ui/screens/database/database.list.js +41 -0
  218. package/dist/ui/screens/database/database.table_rows.d.ts +2 -0
  219. package/dist/ui/screens/database/database.table_rows.js +10 -0
  220. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.context.d.ts +34 -0
  221. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.context.js +166 -0
  222. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.list.d.ts +2 -0
  223. package/dist/ui/screens/dead_letter_queue/dead_letter_queue.list.js +24 -0
  224. package/dist/ui/screens/events/events.context.d.ts +25 -0
  225. package/dist/ui/screens/events/events.context.js +113 -0
  226. package/dist/ui/screens/events/events.list.d.ts +1 -0
  227. package/dist/ui/screens/events/events.list.js +26 -0
  228. package/dist/ui/screens/events/index.d.ts +1 -0
  229. package/dist/ui/screens/events/index.js +1 -0
  230. package/dist/ui/screens/index.d.ts +3 -0
  231. package/dist/ui/screens/index.js +3 -0
  232. package/package.json +125 -0
@@ -0,0 +1,118 @@
1
+ import { cron } from "../entrypoints/cron/Cron";
2
+ import { QueueProcessor } from "../entrypoints/queue/QueueProcessor";
3
+ import logger from "../infrastructure/logger";
4
+ import { AppState } from "react-native";
5
+ class Orchestrator {
6
+ kernel = null;
7
+ authenticated = false;
8
+ activeDomains = new Set();
9
+ sharedKeys = new Set();
10
+ appStateSubscription = null;
11
+ appStateCallbacks = [];
12
+ mutex = Promise.resolve();
13
+ configure(kernel) {
14
+ this.kernel = kernel;
15
+ this.authenticated = false;
16
+ this.sharedKeys = new Set(kernel.sharedKeys());
17
+ this.activeDomains = new Set(kernel.keys());
18
+ }
19
+ requireKernel() {
20
+ if (!this.kernel) {
21
+ throw new Error("Orchestrator not configured. Call createApp() first.");
22
+ }
23
+ return this.kernel;
24
+ }
25
+ async withMutex(operation) {
26
+ const previous = this.mutex;
27
+ let release;
28
+ this.mutex = new Promise((resolve) => (release = resolve));
29
+ try {
30
+ await previous;
31
+ return await operation();
32
+ }
33
+ finally {
34
+ release();
35
+ }
36
+ }
37
+ async orchestrateQueue() {
38
+ await QueueProcessor.sync(this.activeDomains, this.authenticated, this.requireKernel().subscribersByKey());
39
+ }
40
+ async orchestrateCron() {
41
+ await cron.sync(this.activeDomains, this.authenticated, this.requireKernel().cronsByKey());
42
+ }
43
+ async restoreConsistency() {
44
+ await this.orchestrateQueue();
45
+ await this.orchestrateCron();
46
+ }
47
+ initAppStateWatcher() {
48
+ if (this.appStateSubscription)
49
+ return;
50
+ const subscription = AppState.addEventListener("change", async (state) => {
51
+ if (state === "active") {
52
+ await this.restoreConsistency();
53
+ }
54
+ this.appStateCallbacks.forEach((callback) => callback(state));
55
+ });
56
+ this.appStateSubscription = () => subscription.remove();
57
+ }
58
+ async bootstrap() {
59
+ await this.requireKernel().bootstrap();
60
+ QueueProcessor.start();
61
+ await this.orchestrateQueue();
62
+ await this.orchestrateCron();
63
+ this.initAppStateWatcher();
64
+ logger.info("[Orchestrator] Infrastructure ready");
65
+ }
66
+ async authenticateSession() {
67
+ this.authenticated = true;
68
+ await this.orchestrateQueue();
69
+ await this.orchestrateCron();
70
+ }
71
+ async restoreSession() {
72
+ this.authenticated = true;
73
+ await this.orchestrateQueue();
74
+ await this.orchestrateCron();
75
+ }
76
+ async unauthenticateSession(cleanData = true) {
77
+ this.authenticated = false;
78
+ await this.orchestrateQueue();
79
+ await this.orchestrateCron();
80
+ if (cleanData) {
81
+ await QueueProcessor.clearQueue();
82
+ await this.requireKernel().restartDatabase();
83
+ }
84
+ }
85
+ async enableDomain(key) {
86
+ if (this.activeDomains.has(key))
87
+ return;
88
+ this.activeDomains.add(key);
89
+ await this.withMutex(async () => {
90
+ await this.orchestrateQueue();
91
+ await this.orchestrateCron();
92
+ });
93
+ }
94
+ async disableDomain(key) {
95
+ if (this.sharedKeys.has(key))
96
+ return;
97
+ if (!this.activeDomains.has(key))
98
+ return;
99
+ this.activeDomains.delete(key);
100
+ await this.withMutex(async () => {
101
+ await this.orchestrateQueue();
102
+ await this.orchestrateCron();
103
+ });
104
+ }
105
+ isSessionAuthenticated() {
106
+ return this.authenticated;
107
+ }
108
+ subscribeToAppState(callback) {
109
+ this.appStateCallbacks.push(callback);
110
+ return () => {
111
+ const index = this.appStateCallbacks.indexOf(callback);
112
+ if (index > -1) {
113
+ this.appStateCallbacks.splice(index, 1);
114
+ }
115
+ };
116
+ }
117
+ }
118
+ export const orchestrator = new Orchestrator();
@@ -0,0 +1,16 @@
1
+ export type { AppShellConfig } from "./entrypoints/ui/AppShell";
2
+ export { createAppShell } from "./entrypoints/ui/AppShell";
3
+ export type { TimezoneLocale } from "./entrypoints/ui/common_provider";
4
+ export { CommonProvider, useCommon } from "./entrypoints/ui/common_provider";
5
+ export type { DomainApp } from "./entrypoints/ui/domain_switcher";
6
+ export { ActiveDomainApp, DomainSwitcherProvider, useDomainSwitcher, } from "./entrypoints/ui/domain_switcher";
7
+ export type { DeepPartial, ThemeTokens } from "./entrypoints/ui/theme";
8
+ export { createTheme } from "./entrypoints/ui/theme";
9
+ export { BaseModule, baseModule } from "./framework/base_module";
10
+ export type { AppConfig } from "./framework/createApp";
11
+ export { createApp } from "./framework/createApp";
12
+ export { DomainModule } from "./framework/domain_module";
13
+ export { Kernel } from "./framework/kernel";
14
+ export { orchestrator } from "./framework/orchestrator";
15
+ export { installGlobalErrorHandler } from "./infrastructure/ui/errorHandler";
16
+ export { PlainLayout, TabNavigatorLayout } from "./ui/layouts/router_layouts";
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ export { createAppShell } from "./entrypoints/ui/AppShell";
2
+ export { CommonProvider, useCommon } from "./entrypoints/ui/common_provider";
3
+ export { ActiveDomainApp, DomainSwitcherProvider, useDomainSwitcher, } from "./entrypoints/ui/domain_switcher";
4
+ export { createTheme } from "./entrypoints/ui/theme";
5
+ export { BaseModule, baseModule } from "./framework/base_module";
6
+ export { createApp } from "./framework/createApp";
7
+ export { DomainModule } from "./framework/domain_module";
8
+ export { Kernel } from "./framework/kernel";
9
+ export { orchestrator } from "./framework/orchestrator";
10
+ export { installGlobalErrorHandler } from "./infrastructure/ui/errorHandler";
11
+ export { PlainLayout, TabNavigatorLayout } from "./ui/layouts/router_layouts";
@@ -0,0 +1,13 @@
1
+ import { SQLiteDatabase, SQLiteRunResult, SQLiteVariadicBindParams } from "expo-sqlite";
2
+ export declare const DB_NAME = "distribution.db";
3
+ export declare function getDatabase(): Promise<SQLiteDatabase>;
4
+ export declare function getDatabaseSync(): SQLiteDatabase;
5
+ export declare const DBCursor: {
6
+ mutateDatabase(query: string, ...params: SQLiteVariadicBindParams): Promise<SQLiteRunResult>;
7
+ getFirstAsync<T>(query: string, ...params: SQLiteVariadicBindParams): Promise<T | null>;
8
+ getAllAsync<T>(query: string, ...params: SQLiteVariadicBindParams): Promise<T[]>;
9
+ execAsync(query: string): Promise<void>;
10
+ getFirstSync<T>(query: string, ...params: SQLiteVariadicBindParams): T | null;
11
+ getAllSync<T>(query: string, ...params: SQLiteVariadicBindParams): T[];
12
+ mutateDatabaseSync(query: string, ...params: SQLiteVariadicBindParams): SQLiteRunResult;
13
+ };
@@ -0,0 +1,165 @@
1
+ import logger, { loggerRepositories } from "../../infrastructure/logger";
2
+ import { Mutex } from "async-mutex";
3
+ import { openDatabaseAsync, openDatabaseSync, } from "expo-sqlite";
4
+ export const DB_NAME = "distribution.db";
5
+ let dbInstance = null;
6
+ const dbLock = new Mutex();
7
+ const SKIP_LOG_TABLES = ["event_queue", "dead_letter_queue"];
8
+ function shouldLogQuery(query) {
9
+ const lowerQuery = query.toLowerCase();
10
+ return !SKIP_LOG_TABLES.some((table) => lowerQuery.includes(table));
11
+ }
12
+ async function initDatabase() {
13
+ logger.info("Initializing database connection...");
14
+ const db = await openDatabaseAsync(DB_NAME);
15
+ await db.execAsync("PRAGMA journal_mode = WAL;");
16
+ await db.execAsync("PRAGMA foreign_keys = ON;");
17
+ return db;
18
+ }
19
+ export async function getDatabase() {
20
+ if (!dbInstance) {
21
+ dbInstance = await initDatabase();
22
+ }
23
+ return dbInstance;
24
+ }
25
+ function initDatabaseSync() {
26
+ logger.info("Initializing database connection (sync)...");
27
+ const db = openDatabaseSync(DB_NAME);
28
+ db.execSync("PRAGMA journal_mode = WAL;");
29
+ db.execSync("PRAGMA foreign_keys = ON;");
30
+ return db;
31
+ }
32
+ export function getDatabaseSync() {
33
+ if (!dbInstance) {
34
+ dbInstance = initDatabaseSync();
35
+ }
36
+ return dbInstance;
37
+ }
38
+ async function withDB(fn) {
39
+ return dbLock.runExclusive(async () => fn(await getDatabase()));
40
+ }
41
+ function withDBSync(fn) {
42
+ return fn(getDatabaseSync());
43
+ }
44
+ export const DBCursor = {
45
+ async mutateDatabase(query, ...params) {
46
+ const safeQuery = `${query.trim()};`;
47
+ return withDB(async (db) => {
48
+ try {
49
+ if (shouldLogQuery(safeQuery)) {
50
+ loggerRepositories.info(`Database mutation: ${safeQuery}]`);
51
+ }
52
+ const result = await db.runAsync(safeQuery, ...params);
53
+ if (shouldLogQuery(safeQuery)) {
54
+ loggerRepositories.debug("Database mutation result:", result.lastInsertRowId);
55
+ }
56
+ return result;
57
+ }
58
+ catch (error) {
59
+ loggerRepositories.error("Database mutation error:", error);
60
+ loggerRepositories.error("SQL:", safeQuery, params);
61
+ throw error;
62
+ }
63
+ });
64
+ },
65
+ async getFirstAsync(query, ...params) {
66
+ const safeQuery = `${query.trim()};`;
67
+ return withDB(async (db) => {
68
+ try {
69
+ if (shouldLogQuery(safeQuery)) {
70
+ loggerRepositories.info("Database query:", safeQuery, params);
71
+ }
72
+ return await db.getFirstAsync(safeQuery, ...params);
73
+ }
74
+ catch (error) {
75
+ loggerRepositories.error("Database query error:", error);
76
+ loggerRepositories.error("SQL:", safeQuery, params);
77
+ throw error;
78
+ }
79
+ });
80
+ },
81
+ async getAllAsync(query, ...params) {
82
+ const safeQuery = `${query.trim()};`;
83
+ return withDB(async (db) => {
84
+ try {
85
+ if (shouldLogQuery(safeQuery)) {
86
+ loggerRepositories.info("Database query:", safeQuery, params);
87
+ }
88
+ return await db.getAllAsync(safeQuery, ...params);
89
+ }
90
+ catch (error) {
91
+ loggerRepositories.error("Database query error:", error);
92
+ loggerRepositories.error("SQL:", safeQuery, params);
93
+ throw error;
94
+ }
95
+ });
96
+ },
97
+ async execAsync(query) {
98
+ const safeQuery = `${query.trim()};`;
99
+ return withDB(async (db) => {
100
+ try {
101
+ if (shouldLogQuery(safeQuery)) {
102
+ loggerRepositories.info("Executing database command:", safeQuery);
103
+ }
104
+ await db.execAsync(safeQuery);
105
+ }
106
+ catch (error) {
107
+ loggerRepositories.error("Database command error:", error);
108
+ loggerRepositories.error("SQL:", safeQuery);
109
+ throw error;
110
+ }
111
+ });
112
+ },
113
+ getFirstSync(query, ...params) {
114
+ const safeQuery = `${query.trim()};`;
115
+ return withDBSync((db) => {
116
+ try {
117
+ if (shouldLogQuery(safeQuery)) {
118
+ loggerRepositories.debug("Sync database query:", safeQuery);
119
+ }
120
+ return db.getFirstSync(safeQuery, ...params);
121
+ }
122
+ catch (error) {
123
+ loggerRepositories.error("Sync database query error:", error);
124
+ loggerRepositories.error("SQL:", safeQuery, params);
125
+ throw error;
126
+ }
127
+ });
128
+ },
129
+ getAllSync(query, ...params) {
130
+ const safeQuery = `${query.trim()};`;
131
+ return withDBSync((db) => {
132
+ try {
133
+ if (shouldLogQuery(safeQuery)) {
134
+ loggerRepositories.debug("Sync database query:", safeQuery);
135
+ }
136
+ return db.getAllSync(safeQuery, ...params);
137
+ }
138
+ catch (error) {
139
+ loggerRepositories.error("Sync database query error:", error);
140
+ loggerRepositories.error("SQL:", safeQuery, params);
141
+ throw error;
142
+ }
143
+ });
144
+ },
145
+ mutateDatabaseSync(query, ...params) {
146
+ const safeQuery = `${query.trim()};`;
147
+ return withDBSync((db) => {
148
+ try {
149
+ if (shouldLogQuery(safeQuery)) {
150
+ loggerRepositories.debug("Sync database mutation:", safeQuery);
151
+ }
152
+ const result = db.runSync(safeQuery, ...params);
153
+ if (shouldLogQuery(safeQuery)) {
154
+ loggerRepositories.debug("Sync mutation result:", result.lastInsertRowId);
155
+ }
156
+ return result;
157
+ }
158
+ catch (error) {
159
+ loggerRepositories.error("Sync database mutation error:", error);
160
+ loggerRepositories.error("SQL:", safeQuery, params);
161
+ throw error;
162
+ }
163
+ });
164
+ },
165
+ };
@@ -0,0 +1,2 @@
1
+ export { DB_NAME, DBCursor } from "./connector";
2
+ export { mapped, resolveEntity } from "./mapped";
@@ -0,0 +1,2 @@
1
+ export { DB_NAME, DBCursor } from "./connector";
2
+ export { mapped, resolveEntity } from "./mapped";
@@ -0,0 +1,128 @@
1
+ import type { RepositoriesContainer } from "../../entrypoints/db/repositories";
2
+ /**
3
+ * Initializes the repository facade for use with the @mapped decorator.
4
+ *
5
+ * This function MUST be called during application bootstrap, after all repositories
6
+ * are loaded but before any entity with @mapped decorator is instantiated.
7
+ *
8
+ * @param repos - The repository facade object containing all domain repositories
9
+ *
10
+ * @example
11
+ * // In your app bootstrap (e.g., InfrastructureOrchestrator)
12
+ * import { initializeRepositoryFacade } from "../../infrastructure/database";
13
+ * import { repos } from "../../entrypoints/db";
14
+ *
15
+ * async function bootstrap() {
16
+ * await initDatabase();
17
+ * initializeRepositoryFacade(repos); // ← Initialize after DB and repos are ready
18
+ * await runMigrations();
19
+ * }
20
+ */
21
+ export declare function initializeRepositoryFacade(repos: RepositoriesContainer): void;
22
+ /**
23
+ * Resolves an entity or collection from repository by foreign key value.
24
+ *
25
+ * @param repositoryKey - Repository enum key (EDistributionRepository, ECommonRepository)
26
+ * @param fkValue - Foreign key: single ID (uuid/remoteId) or array of IDs
27
+ * @param remote - Use remoteId lookup instead of uuid (default: false)
28
+ * @returns Single entity, EntityCollection, or undefined if not found
29
+ * @throws DomainAppError if repository key doesn't exist in registry
30
+ *
31
+ * @example
32
+ * // Local entity by uuid
33
+ * const customer = resolveEntity(EDistributionRepository.CUSTOMER, "uuid-123");
34
+ *
35
+ * @example
36
+ * // Remote entity by remoteId
37
+ * const product = resolveEntity(EDistributionRepository.PRODUCT, 456, true);
38
+ *
39
+ * @example
40
+ * // Collection by array of IDs
41
+ * const payments = resolveEntity(EDistributionRepository.PAYMENT, [1, 2, 3], true);
42
+ *
43
+ * @example
44
+ * // Usage in Entity to refresh from DB
45
+ * async getRefreshedEntity(repositoryKey: string): Promise<this> {
46
+ * return resolveEntity(repositoryKey, this.uuid) as this;
47
+ * }
48
+ */
49
+ export declare function resolveEntity(repositoryKey: string, fkValue: any, remote?: boolean): any;
50
+ /**
51
+ * Decorator for automatic runtime resolution of database relations using synchronous queries.
52
+ *
53
+ * This decorator enables entities to resolve their relationships automatically using getters,
54
+ * eliminating the need for manual hydration functions and avoiding circular import issues.
55
+ *
56
+ * **Important:** This decorator does NOT cache results. Every access to the getter will
57
+ * query the database to ensure you always get fresh, up-to-date data.
58
+ *
59
+ * It works by:
60
+ * 1. Detecting the foreign key type (scalar vs array) automatically
61
+ * 2. Calling the appropriate repository sync method (findByIdSync or findByIdsSync)
62
+ * 3. Returning fresh data on every access (no caching)
63
+ *
64
+ * @param repositoryKey - The repository key from the enum (EDistributionRepository or ECommonRepository)
65
+ * @param foreignKey - The name of the property on the entity that contains the foreign key (ID or array of IDs)
66
+ *
67
+ * @param remote - Optional flag indicating if the foreign keys are remote IDs.
68
+ * @returns A decorator function that can be applied to entity getters
69
+ *
70
+ * @example
71
+ * // One-to-One relationship (hasOne)
72
+ * import { mapped } from "../../infrastructure/database";
73
+ * import { EDistributionDomainRepository } from "../../entrypoints/db";
74
+ *
75
+ * export class SaleOrder {
76
+ * customerId: number;
77
+ *
78
+ * @mapped(EDistributionDomainRepository.CUSTOMER, "customerId")
79
+ * get customer() {
80
+ * return undefined; // This value is replaced by the decorator at runtime
81
+ * }
82
+ * }
83
+ *
84
+ * // Usage:
85
+ * const order = new SaleOrder({ id: 1, customerId: 123 });
86
+ * console.log(order.customer.name); // Queries database on every access
87
+ * console.log(order.customer.vat); // Queries database again (fresh data)
88
+ *
89
+ * @example
90
+ * // One-to-Many relationship (hasMany)
91
+ * export class SaleOrder {
92
+ * paymentIds: number[];
93
+ *
94
+ * @mapped(EDistributionRepository.PAYMENT, "paymentIds")
95
+ * get payments() {
96
+ * return []; // This value is replaced by the decorator at runtime
97
+ * }
98
+ * }
99
+ *
100
+ * // Usage:
101
+ * const order = new SaleOrder({ id: 1, paymentIds: [10, 20, 30] });
102
+ * order.payments.forEach(payment => console.log(payment.amount)); // Fresh data on every access
103
+ *
104
+ * @remarks
105
+ * **Requirements:**
106
+ * - The target repository MUST implement `findByIdSync()` for scalar foreign keys
107
+ * - The target repository MUST implement `findByIdsSync()` for array foreign keys
108
+ * - The database must be initialized before accessing decorated properties
109
+ *
110
+ * **Advantages:**
111
+ * - ✅ No circular import issues (uses enum-based repository keys resolved at runtime)
112
+ * - ✅ Automatic type detection (scalar vs array)
113
+ * - ✅ Always returns fresh data from the database (no stale cache)
114
+ * - ✅ Clean, declarative syntax
115
+ * - ✅ Type-safe when using repository enums
116
+ * - ✅ No memory overhead from caching
117
+ * - ✅ No domain knowledge needed - just use the enum
118
+ *
119
+ * **Limitations:**
120
+ * - ⚠️ Blocks the main thread on every access (uses synchronous SQLite queries)
121
+ * - ⚠️ Performance cost on repeated access (queries database each time)
122
+ * - ⚠️ Only works for simple ID-based lookups (no complex filters or joins)
123
+ * - ⚠️ Repository must support sync operations (optional methods in IRepository)
124
+ *
125
+ * @see {@link IRepository.findByIdSync} - Required repository method for hasOne relations
126
+ * @see {@link IRepository.findByIdsSync} - Required repository method for hasMany relations
127
+ */
128
+ export declare function mapped(repositoryKey: string, foreignKey: string, remote?: boolean): (target: any, propertyKey: string, descriptor?: PropertyDescriptor) => void;
@@ -0,0 +1,174 @@
1
+ import { DomainAppError } from "../../exceptions";
2
+ import { loggerRepositories } from "../../infrastructure/logger";
3
+ /**
4
+ * Repository facade reference that will be injected after initialization.
5
+ * This avoids circular import issues by delaying the repository resolution.
6
+ */
7
+ let repositoryFacade = null;
8
+ /**
9
+ * Initializes the repository facade for use with the @mapped decorator.
10
+ *
11
+ * This function MUST be called during application bootstrap, after all repositories
12
+ * are loaded but before any entity with @mapped decorator is instantiated.
13
+ *
14
+ * @param repos - The repository facade object containing all domain repositories
15
+ *
16
+ * @example
17
+ * // In your app bootstrap (e.g., InfrastructureOrchestrator)
18
+ * import { initializeRepositoryFacade } from "../../infrastructure/database";
19
+ * import { repos } from "../../entrypoints/db";
20
+ *
21
+ * async function bootstrap() {
22
+ * await initDatabase();
23
+ * initializeRepositoryFacade(repos); // ← Initialize after DB and repos are ready
24
+ * await runMigrations();
25
+ * }
26
+ */
27
+ export function initializeRepositoryFacade(repos) {
28
+ repositoryFacade = repos;
29
+ loggerRepositories.info("[Mapped] Repository facade initialized for @mapped decorator");
30
+ }
31
+ function resolveEntityInternal(context, repositoryKey, fkValue, remote = false) {
32
+ if (!repositoryFacade) {
33
+ throw new DomainAppError(`[${context}] Repository facade not initialized. ` +
34
+ "Call initializeRepositoryFacade(repos) during app bootstrap.");
35
+ }
36
+ try {
37
+ repositoryFacade.get(repositoryKey);
38
+ }
39
+ catch (error) {
40
+ throw new DomainAppError(`[${context}] ${error.message}`);
41
+ }
42
+ return repositoryFacade.resolveRelation(repositoryKey, fkValue, remote);
43
+ }
44
+ /**
45
+ * Resolves an entity or collection from repository by foreign key value.
46
+ *
47
+ * @param repositoryKey - Repository enum key (EDistributionRepository, ECommonRepository)
48
+ * @param fkValue - Foreign key: single ID (uuid/remoteId) or array of IDs
49
+ * @param remote - Use remoteId lookup instead of uuid (default: false)
50
+ * @returns Single entity, EntityCollection, or undefined if not found
51
+ * @throws DomainAppError if repository key doesn't exist in registry
52
+ *
53
+ * @example
54
+ * // Local entity by uuid
55
+ * const customer = resolveEntity(EDistributionRepository.CUSTOMER, "uuid-123");
56
+ *
57
+ * @example
58
+ * // Remote entity by remoteId
59
+ * const product = resolveEntity(EDistributionRepository.PRODUCT, 456, true);
60
+ *
61
+ * @example
62
+ * // Collection by array of IDs
63
+ * const payments = resolveEntity(EDistributionRepository.PAYMENT, [1, 2, 3], true);
64
+ *
65
+ * @example
66
+ * // Usage in Entity to refresh from DB
67
+ * async getRefreshedEntity(repositoryKey: string): Promise<this> {
68
+ * return resolveEntity(repositoryKey, this.uuid) as this;
69
+ * }
70
+ */
71
+ export function resolveEntity(repositoryKey, fkValue, remote = false) {
72
+ return resolveEntityInternal("resolveEntity", repositoryKey, fkValue, remote);
73
+ }
74
+ /**
75
+ * Decorator for automatic runtime resolution of database relations using synchronous queries.
76
+ *
77
+ * This decorator enables entities to resolve their relationships automatically using getters,
78
+ * eliminating the need for manual hydration functions and avoiding circular import issues.
79
+ *
80
+ * **Important:** This decorator does NOT cache results. Every access to the getter will
81
+ * query the database to ensure you always get fresh, up-to-date data.
82
+ *
83
+ * It works by:
84
+ * 1. Detecting the foreign key type (scalar vs array) automatically
85
+ * 2. Calling the appropriate repository sync method (findByIdSync or findByIdsSync)
86
+ * 3. Returning fresh data on every access (no caching)
87
+ *
88
+ * @param repositoryKey - The repository key from the enum (EDistributionRepository or ECommonRepository)
89
+ * @param foreignKey - The name of the property on the entity that contains the foreign key (ID or array of IDs)
90
+ *
91
+ * @param remote - Optional flag indicating if the foreign keys are remote IDs.
92
+ * @returns A decorator function that can be applied to entity getters
93
+ *
94
+ * @example
95
+ * // One-to-One relationship (hasOne)
96
+ * import { mapped } from "../../infrastructure/database";
97
+ * import { EDistributionDomainRepository } from "../../entrypoints/db";
98
+ *
99
+ * export class SaleOrder {
100
+ * customerId: number;
101
+ *
102
+ * @mapped(EDistributionDomainRepository.CUSTOMER, "customerId")
103
+ * get customer() {
104
+ * return undefined; // This value is replaced by the decorator at runtime
105
+ * }
106
+ * }
107
+ *
108
+ * // Usage:
109
+ * const order = new SaleOrder({ id: 1, customerId: 123 });
110
+ * console.log(order.customer.name); // Queries database on every access
111
+ * console.log(order.customer.vat); // Queries database again (fresh data)
112
+ *
113
+ * @example
114
+ * // One-to-Many relationship (hasMany)
115
+ * export class SaleOrder {
116
+ * paymentIds: number[];
117
+ *
118
+ * @mapped(EDistributionRepository.PAYMENT, "paymentIds")
119
+ * get payments() {
120
+ * return []; // This value is replaced by the decorator at runtime
121
+ * }
122
+ * }
123
+ *
124
+ * // Usage:
125
+ * const order = new SaleOrder({ id: 1, paymentIds: [10, 20, 30] });
126
+ * order.payments.forEach(payment => console.log(payment.amount)); // Fresh data on every access
127
+ *
128
+ * @remarks
129
+ * **Requirements:**
130
+ * - The target repository MUST implement `findByIdSync()` for scalar foreign keys
131
+ * - The target repository MUST implement `findByIdsSync()` for array foreign keys
132
+ * - The database must be initialized before accessing decorated properties
133
+ *
134
+ * **Advantages:**
135
+ * - ✅ No circular import issues (uses enum-based repository keys resolved at runtime)
136
+ * - ✅ Automatic type detection (scalar vs array)
137
+ * - ✅ Always returns fresh data from the database (no stale cache)
138
+ * - ✅ Clean, declarative syntax
139
+ * - ✅ Type-safe when using repository enums
140
+ * - ✅ No memory overhead from caching
141
+ * - ✅ No domain knowledge needed - just use the enum
142
+ *
143
+ * **Limitations:**
144
+ * - ⚠️ Blocks the main thread on every access (uses synchronous SQLite queries)
145
+ * - ⚠️ Performance cost on repeated access (queries database each time)
146
+ * - ⚠️ Only works for simple ID-based lookups (no complex filters or joins)
147
+ * - ⚠️ Repository must support sync operations (optional methods in IRepository)
148
+ *
149
+ * @see {@link IRepository.findByIdSync} - Required repository method for hasOne relations
150
+ * @see {@link IRepository.findByIdsSync} - Required repository method for hasMany relations
151
+ */
152
+ export function mapped(repositoryKey, foreignKey, remote = false) {
153
+ return function (target, propertyKey, descriptor) {
154
+ loggerRepositories.warn(`[Mapped] Setting up mapped relation for ${target.constructor.name}.${propertyKey} ` +
155
+ `using repository "${repositoryKey}" and foreign key "${foreignKey}"`);
156
+ const getter = function () {
157
+ const fkValue = this[foreignKey];
158
+ if (!fkValue) {
159
+ return undefined;
160
+ }
161
+ return resolveEntityInternal("mapped", repositoryKey, fkValue, remote);
162
+ };
163
+ if (descriptor) {
164
+ descriptor.get = getter;
165
+ }
166
+ else {
167
+ Object.defineProperty(target, propertyKey, {
168
+ get: getter,
169
+ enumerable: true,
170
+ configurable: true,
171
+ });
172
+ }
173
+ };
174
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Constructs a SQL placeholder string and corresponding values for use in a query based on the provided field and data.
3
+ *
4
+ * @param {string} field - The database field name to be used in the placeholder condition.
5
+ * @param {any} data - The data used to generate placeholders and corresponding values. Can be an array, object, set, or a single value.
6
+ * @return {[string, string]} - A tuple where the first element is the formatted placeholder condition string,
7
+ * and the second element is the corresponding values. IE: `["field IN (?, ?, ?)", [value1, value2, value3]]`.
8
+ */
9
+ export declare function getPlaceholders(field: string, data: any | any[]): [string, string];
10
+ export declare function generateUUID(): string;