@teincfood/core 0.1.1 → 0.1.3

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 (72) hide show
  1. package/dist/adapters/auth.js +2 -6
  2. package/dist/adapters/business.js +2 -6
  3. package/dist/adapters/connectivity.js +6 -14
  4. package/dist/adapters/devices.js +2 -6
  5. package/dist/adapters/http.js +4 -10
  6. package/dist/adapters/image-cache.d.ts +9 -3
  7. package/dist/adapters/image-cache.js +12 -8
  8. package/dist/adapters/kv-types.js +1 -2
  9. package/dist/adapters/kv.js +11 -24
  10. package/dist/adapters/local-node.js +3 -7
  11. package/dist/adapters/pending-orders.js +1 -4
  12. package/dist/adapters/query-keys.js +4 -7
  13. package/dist/adapters/services.js +9 -14
  14. package/dist/adapters/sqlite.js +3 -8
  15. package/dist/db/connection.js +15 -20
  16. package/dist/db/migrations.js +1 -4
  17. package/dist/db/operations.js +19 -36
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.js +43 -93
  20. package/dist/reference/api.js +7 -12
  21. package/dist/reference/events.js +25 -33
  22. package/dist/reference/operations.js +6 -14
  23. package/dist/reference/service.js +36 -39
  24. package/dist/reference/types.js +1 -2
  25. package/dist/repositories/order.repository.js +15 -18
  26. package/dist/repositories/pos.repository.js +6 -9
  27. package/dist/sync/command-builder.js +8 -12
  28. package/dist/sync/command-queue.service.js +35 -38
  29. package/dist/sync/engine.js +38 -42
  30. package/dist/sync/order-number.js +6 -11
  31. package/dist/sync/order-number.test.d.ts +1 -0
  32. package/dist/sync/order-number.test.js +30 -0
  33. package/dist/sync/order-snapshots.service.js +19 -22
  34. package/dist/sync/pending-orders.service.js +27 -33
  35. package/dist/sync/transport-local-node.js +16 -20
  36. package/dist/sync/transport-rest.js +18 -22
  37. package/dist/sync/types.js +1 -2
  38. package/dist/sync/use-sync-reconciliation.js +37 -40
  39. package/dist/types/api/auth.api.js +1 -2
  40. package/dist/types/api/business.api.js +1 -2
  41. package/dist/types/api/conversation.api.js +1 -2
  42. package/dist/types/api/error.api.js +1 -2
  43. package/dist/types/api/fleet.api.js +1 -2
  44. package/dist/types/api/index.js +11 -27
  45. package/dist/types/api/kiosk.api.js +1 -2
  46. package/dist/types/api/menu.api.js +1 -2
  47. package/dist/types/api/pagination.js +1 -2
  48. package/dist/types/api/rider.api.js +1 -2
  49. package/dist/types/api/seller.api.js +1 -2
  50. package/dist/types/api/wallet.api.js +1 -2
  51. package/dist/types/pos.types.js +1 -2
  52. package/dist/utils/constants.js +24 -27
  53. package/dist/utils/copyToClipBoard.js +2 -7
  54. package/dist/utils/currency.js +8 -16
  55. package/dist/utils/currency.test.d.ts +1 -0
  56. package/dist/utils/currency.test.js +17 -0
  57. package/dist/utils/error.js +4 -11
  58. package/dist/utils/formatCurrency.js +1 -4
  59. package/dist/utils/formatDate.js +2 -6
  60. package/dist/utils/phone.js +6 -13
  61. package/dist/utils/phone.test.d.ts +1 -0
  62. package/dist/utils/phone.test.js +19 -0
  63. package/dist/utils/responsive.js +1 -4
  64. package/dist/utils/storage.js +14 -28
  65. package/dist/utils/sync-logger.js +1 -4
  66. package/dist/utils/uuid.js +4 -10
  67. package/dist/utils/uuid.test.d.ts +1 -0
  68. package/dist/utils/uuid.test.js +13 -0
  69. package/dist/utils/validation.js +11 -24
  70. package/dist/utils/validation.test.d.ts +1 -0
  71. package/dist/utils/validation.test.js +23 -0
  72. package/package.json +16 -1
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Sync Engine orchestrator.
4
3
  *
@@ -12,15 +11,13 @@
12
11
  * - Local Node transport
13
12
  * - cloud reconciliation
14
13
  */
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.syncEngine = exports.SyncEngine = void 0;
17
- const transport_rest_1 = require("./transport-rest");
18
- const transport_local_node_1 = require("./transport-local-node");
19
- const command_queue_service_1 = require("./command-queue.service");
20
- const connectivity_1 = require("../adapters/connectivity");
21
- const http_1 = require("../adapters/http");
22
- const sync_logger_1 = require("../utils/sync-logger");
23
- const constants_1 = require("../utils/constants");
14
+ import { restTransport } from "./transport-rest";
15
+ import { localNodeTransport } from "./transport-local-node";
16
+ import { commandQueueService } from "./command-queue.service";
17
+ import { getConnectivityState, setConnectivityState } from "../adapters/connectivity";
18
+ import { ApiError } from "../adapters/http";
19
+ import { syncLogger } from "../utils/sync-logger";
20
+ import { CLOUD_COMMAND_TIMEOUT_MS } from "../utils/constants";
24
21
  function withTimeout(promise, ms) {
25
22
  return new Promise((resolve, reject) => {
26
23
  const timer = setTimeout(() => {
@@ -35,7 +32,7 @@ function withTimeout(promise, ms) {
35
32
  });
36
33
  });
37
34
  }
38
- class SyncEngine {
35
+ export class SyncEngine {
39
36
  constructor(options) {
40
37
  this.eventSubscribers = [];
41
38
  this.transports = options.transports;
@@ -53,37 +50,37 @@ class SyncEngine {
53
50
  * quickly instead of blocking the terminal for the full HTTP timeout.
54
51
  */
55
52
  async execute(command) {
56
- sync_logger_1.syncLogger.command(command, "issued");
53
+ syncLogger.command(command, "issued");
57
54
  let strategy = this.resolveStrategy(command);
58
- const { isCloudReachable, isOnline } = (0, connectivity_1.getConnectivityState)();
59
- sync_logger_1.syncLogger.info("SyncEngine", "Command strategy resolved", {
55
+ const { isCloudReachable, isOnline } = getConnectivityState();
56
+ syncLogger.info("SyncEngine", "Command strategy resolved", {
60
57
  command_id: command.command_id,
61
58
  command_type: command.command_type,
62
59
  strategy,
63
60
  isCloudReachable,
64
61
  isOnline,
65
- cloud_available: transport_rest_1.restTransport.isAvailable(),
66
- lan_available: transport_local_node_1.localNodeTransport.isAvailable(),
62
+ cloud_available: restTransport.isAvailable(),
63
+ lan_available: localNodeTransport.isAvailable(),
67
64
  });
68
65
  if (strategy === "queue") {
69
- const event = await command_queue_service_1.commandQueueService.enqueue(command);
66
+ const event = await commandQueueService.enqueue(command);
70
67
  this.broadcast(event);
71
68
  return [event];
72
69
  }
73
70
  if (strategy === "cloud") {
74
71
  try {
75
- const events = await withTimeout(transport_rest_1.restTransport.execute(command), constants_1.CLOUD_COMMAND_TIMEOUT_MS);
72
+ const events = await withTimeout(restTransport.execute(command), CLOUD_COMMAND_TIMEOUT_MS);
76
73
  for (const event of events) {
77
74
  this.broadcast(event);
78
75
  }
79
- sync_logger_1.syncLogger.command(command, "completed", {
76
+ syncLogger.command(command, "completed", {
80
77
  event_count: events.length,
81
78
  });
82
79
  // Cloud just worked: it is reachable again. Mark it so future commands
83
80
  // go cloud-first, and replay anything queued during the outage.
84
- (0, connectivity_1.setConnectivityState)({ isCloudReachable: "reachable" });
81
+ setConnectivityState({ isCloudReachable: "reachable" });
85
82
  this.replayQueuedCommands().catch((error) => {
86
- sync_logger_1.syncLogger.error("SyncEngine", "Replay after cloud success failed", {
83
+ syncLogger.error("SyncEngine", "Replay after cloud success failed", {
87
84
  error: String(error),
88
85
  });
89
86
  });
@@ -94,8 +91,8 @@ class SyncEngine {
94
91
  // decision (e.g. PAYMENT_REQUIRED, FORBIDDEN). Surface it to the
95
92
  // caller instead of masking it as a connectivity problem and silently
96
93
  // queueing a command that can never succeed.
97
- if (error instanceof http_1.ApiError && error.status >= 400 && error.status < 500) {
98
- sync_logger_1.syncLogger.warn("SyncEngine", "Cloud command rejected by server", {
94
+ if (error instanceof ApiError && error.status >= 400 && error.status < 500) {
95
+ syncLogger.warn("SyncEngine", "Cloud command rejected by server", {
99
96
  command_type: command.command_type,
100
97
  command_id: command.command_id,
101
98
  status: error.status,
@@ -105,18 +102,18 @@ class SyncEngine {
105
102
  }
106
103
  // Cloud is slow or unreachable: mark it and fall back to the Local
107
104
  // Node or the outbox so the terminal stays responsive.
108
- sync_logger_1.syncLogger.warn("SyncEngine", "Cloud command timed out, falling back", {
105
+ syncLogger.warn("SyncEngine", "Cloud command timed out, falling back", {
109
106
  command_type: command.command_type,
110
107
  error: String(error),
111
108
  });
112
- (0, connectivity_1.setConnectivityState)({ isCloudReachable: "unreachable" });
109
+ setConnectivityState({ isCloudReachable: "unreachable" });
113
110
  strategy = this.resolveStrategy(command);
114
111
  if (strategy === "queue") {
115
- const event = await command_queue_service_1.commandQueueService.enqueue(command);
112
+ const event = await commandQueueService.enqueue(command);
116
113
  this.broadcast(event);
117
114
  return [event];
118
115
  }
119
- sync_logger_1.syncLogger.info("SyncEngine", "Cloud timed out, using LAN fallback", {
116
+ syncLogger.info("SyncEngine", "Cloud timed out, using LAN fallback", {
120
117
  command_id: command.command_id,
121
118
  command_type: command.command_type,
122
119
  strategy,
@@ -124,7 +121,7 @@ class SyncEngine {
124
121
  }
125
122
  }
126
123
  const transport = this.selectTransport(command, strategy);
127
- sync_logger_1.syncLogger.info("SyncEngine", "Executing via transport", {
124
+ syncLogger.info("SyncEngine", "Executing via transport", {
128
125
  command_id: command.command_id,
129
126
  command_type: command.command_type,
130
127
  strategy,
@@ -134,7 +131,7 @@ class SyncEngine {
134
131
  for (const event of events) {
135
132
  this.broadcast(event);
136
133
  }
137
- sync_logger_1.syncLogger.command(command, "completed", {
134
+ syncLogger.command(command, "completed", {
138
135
  event_count: events.length,
139
136
  transport: transport.name,
140
137
  });
@@ -144,7 +141,7 @@ class SyncEngine {
144
141
  * Trigger replay of queued commands when connectivity returns.
145
142
  */
146
143
  async replayQueuedCommands() {
147
- await command_queue_service_1.commandQueueService.replay();
144
+ await commandQueueService.replay();
148
145
  }
149
146
  subscribe(handler) {
150
147
  this.eventSubscribers.push(handler);
@@ -165,17 +162,17 @@ class SyncEngine {
165
162
  this.broadcast(event);
166
163
  }
167
164
  resolveStrategy(_command) {
168
- const { isCloudReachable, isOnline } = (0, connectivity_1.getConnectivityState)();
165
+ const { isCloudReachable, isOnline } = getConnectivityState();
169
166
  // Cloud-first when we believe it is reachable OR we have not yet verified
170
167
  // it (unknown). Only a confirmed "unreachable" status falls back to the
171
168
  // Local Node / outbox. Commands issued on a healthy connection must never
172
169
  // get stuck in the local outbox.
173
170
  if ((isCloudReachable === "reachable" || isCloudReachable === "unknown") &&
174
- transport_rest_1.restTransport.isAvailable()) {
171
+ restTransport.isAvailable()) {
175
172
  return "cloud";
176
173
  }
177
174
  // Local Node fallback when enabled and connected.
178
- if (transport_local_node_1.localNodeTransport.isAvailable()) {
175
+ if (localNodeTransport.isAvailable()) {
179
176
  return "local_node";
180
177
  }
181
178
  // No network at all: queue immediately.
@@ -192,11 +189,11 @@ class SyncEngine {
192
189
  return "cloud";
193
190
  }
194
191
  selectTransport(_command, strategy) {
195
- if (strategy === "local_node" && transport_local_node_1.localNodeTransport.isAvailable()) {
196
- return transport_local_node_1.localNodeTransport;
192
+ if (strategy === "local_node" && localNodeTransport.isAvailable()) {
193
+ return localNodeTransport;
197
194
  }
198
- if (strategy === "cloud" && transport_rest_1.restTransport.isAvailable()) {
199
- return transport_rest_1.restTransport;
195
+ if (strategy === "cloud" && restTransport.isAvailable()) {
196
+ return restTransport;
200
197
  }
201
198
  const transport = this.transports.find((t) => t.isAvailable()) ?? this.transports[0];
202
199
  if (!transport) {
@@ -205,12 +202,11 @@ class SyncEngine {
205
202
  return transport;
206
203
  }
207
204
  broadcast(event) {
208
- sync_logger_1.syncLogger.event(event, "broadcast");
205
+ syncLogger.event(event, "broadcast");
209
206
  this.eventSubscribers.forEach((handler) => handler(event));
210
207
  }
211
208
  }
212
- exports.SyncEngine = SyncEngine;
213
- exports.syncEngine = new SyncEngine({
214
- transports: [transport_rest_1.restTransport, transport_local_node_1.localNodeTransport],
209
+ export const syncEngine = new SyncEngine({
210
+ transports: [restTransport, localNodeTransport],
215
211
  });
216
- command_queue_service_1.commandQueueService.setSyncEngine(exports.syncEngine);
212
+ commandQueueService.setSyncEngine(syncEngine);
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Local order number allocation for offline/LAN operation.
4
3
  *
@@ -7,11 +6,7 @@
7
6
  * `TFL-YYYYMMDD-NNNN`. These are reconciled with permanent cloud order numbers
8
7
  * once connectivity returns.
9
8
  */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.generateLocalOrderNumber = generateLocalOrderNumber;
12
- exports.generateLocalCalloutNumber = generateLocalCalloutNumber;
13
- exports.isLocalOrderNumber = isLocalOrderNumber;
14
- const kv_1 = require("../adapters/kv");
9
+ import { getItemSync as getItem, setItemSync as setItem } from "../adapters/kv";
15
10
  const LOCAL_ORDER_SEQ_KEY = "local_order_sequence";
16
11
  const LOCAL_CALLOUT_SEQ_KEY = "local_callout_sequence";
17
12
  function formatDatePart(date) {
@@ -21,7 +16,7 @@ function formatDatePart(date) {
21
16
  return `${year}${month}${day}`;
22
17
  }
23
18
  function getNextSequence(datePart, key) {
24
- const stored = (0, kv_1.getItemSync)(key);
19
+ const stored = getItem(key);
25
20
  const map = stored ?? {};
26
21
  const next = (map[datePart] ?? 0) + 1;
27
22
  map[datePart] = next;
@@ -32,13 +27,13 @@ function getNextSequence(datePart, key) {
32
27
  delete map[mapKey];
33
28
  }
34
29
  }
35
- (0, kv_1.setItemSync)(key, map);
30
+ setItem(key, map);
36
31
  return next;
37
32
  }
38
33
  /**
39
34
  * Generate a local order number for offline-created orders.
40
35
  */
41
- function generateLocalOrderNumber(date = new Date()) {
36
+ export function generateLocalOrderNumber(date = new Date()) {
42
37
  const datePart = formatDatePart(date);
43
38
  const seq = getNextSequence(datePart, LOCAL_ORDER_SEQ_KEY);
44
39
  return `TFL-${datePart}-${String(seq).padStart(4, "0")}`;
@@ -46,13 +41,13 @@ function generateLocalOrderNumber(date = new Date()) {
46
41
  /**
47
42
  * Generate a local callout number for offline-created orders.
48
43
  */
49
- function generateLocalCalloutNumber(date = new Date()) {
44
+ export function generateLocalCalloutNumber(date = new Date()) {
50
45
  const datePart = formatDatePart(date);
51
46
  return getNextSequence(datePart, LOCAL_CALLOUT_SEQ_KEY);
52
47
  }
53
48
  /**
54
49
  * Check whether an order number was locally allocated.
55
50
  */
56
- function isLocalOrderNumber(orderNumber) {
51
+ export function isLocalOrderNumber(orderNumber) {
57
52
  return orderNumber.startsWith("TFL-");
58
53
  }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect, beforeEach } from "vitest";
2
+ import { generateLocalOrderNumber, generateLocalCalloutNumber, isLocalOrderNumber } from "./order-number";
3
+ import { removeItemSync } from "../adapters/kv";
4
+ // Use in-memory KV for tests (default driver is memory)
5
+ describe("order-number", () => {
6
+ beforeEach(() => {
7
+ removeItemSync("local_order_sequence");
8
+ removeItemSync("local_callout_sequence");
9
+ });
10
+ it("generates TFL order numbers with date and sequence", () => {
11
+ const d = new Date("2026-08-24T10:00:00.000Z");
12
+ const a = generateLocalOrderNumber(d);
13
+ const b = generateLocalOrderNumber(d);
14
+ expect(a).toBe("TFL-20260824-0001");
15
+ expect(b).toBe("TFL-20260824-0002");
16
+ expect(isLocalOrderNumber(a)).toBe(true);
17
+ expect(isLocalOrderNumber("KF-260701-0042")).toBe(false);
18
+ });
19
+ it("generates incremental callout numbers per day", () => {
20
+ const d = new Date("2026-08-24T10:00:00.000Z");
21
+ expect(generateLocalCalloutNumber(d)).toBe(1);
22
+ expect(generateLocalCalloutNumber(d)).toBe(2);
23
+ });
24
+ it("isolates sequences per day", () => {
25
+ const d1 = new Date("2026-08-24T10:00:00.000Z");
26
+ const d2 = new Date("2026-08-25T10:00:00.000Z");
27
+ expect(generateLocalOrderNumber(d1)).toBe("TFL-20260824-0001");
28
+ expect(generateLocalOrderNumber(d2)).toBe("TFL-20260825-0001");
29
+ });
30
+ });
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Durable order read-model.
4
3
  *
@@ -14,11 +13,9 @@
14
13
  * 2. Successful order list fetches are written through as snapshots so the
15
14
  * exact list last seen while online is available offline.
16
15
  */
17
- Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.orderSnapshotsService = void 0;
19
- const connection_1 = require("../db/connection");
20
- const operations_1 = require("../db/operations");
21
- const sync_logger_1 = require("../utils/sync-logger");
16
+ import { openSyncDatabase } from "../db/connection";
17
+ import { insertEvent, upsertEntitySnapshot, getEntitySnapshot, getEntitySnapshotsByType, pruneEntitySnapshots, } from "../db/operations";
18
+ import { syncLogger } from "../utils/sync-logger";
22
19
  const RETAIN_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
23
20
  const ORDER_EVENT_TYPES = new Set([
24
21
  "order.created",
@@ -39,13 +36,13 @@ class OrderSnapshotsService {
39
36
  if (!ORDER_EVENT_TYPES.has(event.event_type))
40
37
  return false;
41
38
  try {
42
- const db = await (0, connection_1.openSyncDatabase)();
43
- await (0, operations_1.insertEvent)(db, { event, origin });
39
+ const db = await openSyncDatabase();
40
+ await insertEvent(db, { event, origin });
44
41
  await this.applyOrderStatusToReadModel(db, event);
45
42
  return true;
46
43
  }
47
44
  catch (error) {
48
- sync_logger_1.syncLogger.error("OrderSnapshots", "Failed to persist order event", {
45
+ syncLogger.error("OrderSnapshots", "Failed to persist order event", {
49
46
  error: String(error),
50
47
  event_type: event.event_type,
51
48
  });
@@ -65,14 +62,14 @@ class OrderSnapshotsService {
65
62
  return;
66
63
  }
67
64
  try {
68
- const lists = await (0, operations_1.getEntitySnapshotsByType)(db, "seller_orders");
65
+ const lists = await getEntitySnapshotsByType(db, "seller_orders");
69
66
  for (const list of lists) {
70
67
  const data = list.payload.data ?? [];
71
68
  const idx = data.findIndex((o) => o.id === orderId);
72
69
  if (idx === -1)
73
70
  continue;
74
71
  const updated = data.map((o, i) => i === idx ? { ...o, status: toStatus } : o);
75
- await (0, operations_1.upsertEntitySnapshot)(db, {
72
+ await upsertEntitySnapshot(db, {
76
73
  entityType: "seller_orders",
77
74
  entityId: list.entity_id,
78
75
  businessId: list.business_id,
@@ -83,7 +80,7 @@ class OrderSnapshotsService {
83
80
  }
84
81
  }
85
82
  catch (error) {
86
- sync_logger_1.syncLogger.error("OrderSnapshots", "Failed to apply status to read model", {
83
+ syncLogger.error("OrderSnapshots", "Failed to apply status to read model", {
87
84
  error: String(error),
88
85
  });
89
86
  }
@@ -97,8 +94,8 @@ class OrderSnapshotsService {
97
94
  if (!businessId)
98
95
  return;
99
96
  try {
100
- const db = await (0, connection_1.openSyncDatabase)();
101
- await (0, operations_1.upsertEntitySnapshot)(db, {
97
+ const db = await openSyncDatabase();
98
+ await upsertEntitySnapshot(db, {
102
99
  entityType: "seller_orders",
103
100
  entityId: scope,
104
101
  businessId,
@@ -108,7 +105,7 @@ class OrderSnapshotsService {
108
105
  });
109
106
  }
110
107
  catch (error) {
111
- sync_logger_1.syncLogger.error("OrderSnapshots", "Failed to persist seller list", {
108
+ syncLogger.error("OrderSnapshots", "Failed to persist seller list", {
112
109
  error: String(error),
113
110
  businessId,
114
111
  });
@@ -119,14 +116,14 @@ class OrderSnapshotsService {
119
116
  */
120
117
  async getSellerList(businessId, scope) {
121
118
  try {
122
- const db = await (0, connection_1.openSyncDatabase)();
123
- const snap = await (0, operations_1.getEntitySnapshot)(db, "seller_orders", scope);
119
+ const db = await openSyncDatabase();
120
+ const snap = await getEntitySnapshot(db, "seller_orders", scope);
124
121
  if (!snap || snap.business_id !== businessId)
125
122
  return null;
126
123
  return snap.payload.data ?? null;
127
124
  }
128
125
  catch (error) {
129
- sync_logger_1.syncLogger.error("OrderSnapshots", "Failed to read seller list", {
126
+ syncLogger.error("OrderSnapshots", "Failed to read seller list", {
130
127
  error: String(error),
131
128
  });
132
129
  return null;
@@ -138,14 +135,14 @@ class OrderSnapshotsService {
138
135
  async pruneOld() {
139
136
  try {
140
137
  const cutoff = new Date(Date.now() - RETAIN_MS).toISOString();
141
- const db = await (0, connection_1.openSyncDatabase)();
142
- await (0, operations_1.pruneEntitySnapshots)(db, "seller_orders", cutoff);
138
+ const db = await openSyncDatabase();
139
+ await pruneEntitySnapshots(db, "seller_orders", cutoff);
143
140
  }
144
141
  catch (error) {
145
- sync_logger_1.syncLogger.error("OrderSnapshots", "Failed to prune", {
142
+ syncLogger.error("OrderSnapshots", "Failed to prune", {
146
143
  error: String(error),
147
144
  });
148
145
  }
149
146
  }
150
147
  }
151
- exports.orderSnapshotsService = new OrderSnapshotsService();
148
+ export const orderSnapshotsService = new OrderSnapshotsService();
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * Pending Orders Service.
4
3
  *
@@ -15,16 +14,11 @@
15
14
  * itself; `order.created` carries `local_order_number` matching the optimistic
16
15
  * order's `order_number`.
17
16
  */
18
- Object.defineProperty(exports, "__esModule", { value: true });
19
- exports.registerPendingOrdersInvalidator = registerPendingOrdersInvalidator;
20
- exports.hydratePendingOrders = hydratePendingOrders;
21
- exports.applyOrderStateChangeEvent = applyOrderStateChangeEvent;
22
- exports.applyPendingOrderEvent = applyPendingOrderEvent;
23
- const connection_1 = require("../db/connection");
24
- const operations_1 = require("../db/operations");
25
- const pending_orders_1 = require("../adapters/pending-orders");
26
- const order_snapshots_service_1 = require("./order-snapshots.service");
27
- const sync_logger_1 = require("../utils/sync-logger");
17
+ import { openSyncDatabase } from "../db/connection";
18
+ import { insertEvent, getUnsyncedEvents, markEventsSynced, } from "../db/operations";
19
+ import { usePendingOrdersStore } from "../adapters/pending-orders";
20
+ import { orderSnapshotsService } from "./order-snapshots.service";
21
+ import { syncLogger } from "../utils/sync-logger";
28
22
  const PENDING_EVENT_TYPE = "order.create_queued";
29
23
  /** Order/delivery state-change events that should refresh every terminal. */
30
24
  const ORDER_STATE_EVENT_TYPES = new Set([
@@ -37,7 +31,7 @@ let invalidator = null;
37
31
  * Register a callback used to invalidate TanStack Query caches when a pending
38
32
  * order is reconciled. Returns an unregister function.
39
33
  */
40
- function registerPendingOrdersInvalidator(fn) {
34
+ export function registerPendingOrdersInvalidator(fn) {
41
35
  invalidator = fn;
42
36
  return () => {
43
37
  if (invalidator === fn)
@@ -48,15 +42,15 @@ function registerPendingOrdersInvalidator(fn) {
48
42
  * Load persisted unsynced order:create_queued events into the store.
49
43
  * Idempotent; safe to call after app restart while still offline.
50
44
  */
51
- async function hydratePendingOrders() {
52
- const store = pending_orders_1.usePendingOrdersStore.getState();
45
+ export async function hydratePendingOrders() {
46
+ const store = usePendingOrdersStore.getState();
53
47
  if (store.hydrated)
54
48
  return;
55
49
  try {
56
- const db = await (0, connection_1.openSyncDatabase)();
50
+ const db = await openSyncDatabase();
57
51
  const byNumber = new Map();
58
52
  for (const origin of ["local", "lan"]) {
59
- const events = await (0, operations_1.getUnsyncedEvents)(db, origin, Number.MAX_SAFE_INTEGER);
53
+ const events = await getUnsyncedEvents(db, origin, Number.MAX_SAFE_INTEGER);
60
54
  for (const event of events) {
61
55
  if (event.event_type !== PENDING_EVENT_TYPE)
62
56
  continue;
@@ -65,15 +59,15 @@ async function hydratePendingOrders() {
65
59
  byNumber.set(order.order_number, order);
66
60
  }
67
61
  }
68
- pending_orders_1.usePendingOrdersStore.setState({ orders: [...byNumber.values()] });
62
+ usePendingOrdersStore.setState({ orders: [...byNumber.values()] });
69
63
  }
70
64
  catch (error) {
71
- sync_logger_1.syncLogger.error("PendingOrders", "Hydration failed", {
65
+ syncLogger.error("PendingOrders", "Hydration failed", {
72
66
  error: String(error),
73
67
  });
74
68
  }
75
69
  finally {
76
- pending_orders_1.usePendingOrdersStore.getState().setHydrated(true);
70
+ usePendingOrdersStore.getState().setHydrated(true);
77
71
  }
78
72
  }
79
73
  /**
@@ -92,36 +86,36 @@ async function hydratePendingOrders() {
92
86
  * pending-orders store (only queued creations are); this only fires the
93
87
  * invalidator. Idempotent — duplicate deliveries are harmless.
94
88
  */
95
- async function applyOrderStateChangeEvent(event, origin = "local") {
89
+ export async function applyOrderStateChangeEvent(event, origin = "local") {
96
90
  try {
97
91
  if (!ORDER_STATE_EVENT_TYPES.has(event.event_type))
98
92
  return;
99
- sync_logger_1.syncLogger.debug("OrderState", "Order state changed", {
93
+ syncLogger.debug("OrderState", "Order state changed", {
100
94
  origin,
101
95
  event_type: event.event_type,
102
96
  entity_id: event.entity_id,
103
97
  });
104
98
  // Persist the event into the durable journal and patch the offline read
105
99
  // model so every terminal keeps the same order states after a restart.
106
- await order_snapshots_service_1.orderSnapshotsService.persistOrderEvent(event, origin);
100
+ await orderSnapshotsService.persistOrderEvent(event, origin);
107
101
  invalidator?.();
108
102
  }
109
103
  catch (error) {
110
- sync_logger_1.syncLogger.error("OrderState", "Failed to apply order state change", {
104
+ syncLogger.error("OrderState", "Failed to apply order state change", {
111
105
  error: String(error),
112
106
  event_type: event.event_type,
113
107
  });
114
108
  }
115
109
  }
116
- async function applyPendingOrderEvent(event, origin = "local") {
110
+ export async function applyPendingOrderEvent(event, origin = "local") {
117
111
  try {
118
112
  if (event.event_type === PENDING_EVENT_TYPE) {
119
113
  const order = event.payload;
120
114
  if (!order?.order_number)
121
115
  return;
122
- pending_orders_1.usePendingOrdersStore.getState().addOrder(order);
123
- const db = await (0, connection_1.openSyncDatabase)();
124
- await (0, operations_1.insertEvent)(db, { event, origin });
116
+ usePendingOrdersStore.getState().addOrder(order);
117
+ const db = await openSyncDatabase();
118
+ await insertEvent(db, { event, origin });
125
119
  return;
126
120
  }
127
121
  if (event.event_type === "order.created") {
@@ -129,16 +123,16 @@ async function applyPendingOrderEvent(event, origin = "local") {
129
123
  const localOrderNumber = payload?.local_order_number;
130
124
  if (typeof localOrderNumber !== "string")
131
125
  return;
132
- pending_orders_1.usePendingOrdersStore.getState().removeByOrderNumber(localOrderNumber);
126
+ usePendingOrdersStore.getState().removeByOrderNumber(localOrderNumber);
133
127
  // Persist the cloud acknowledgment into the durable journal + read model.
134
- await order_snapshots_service_1.orderSnapshotsService.persistOrderEvent(event, "cloud");
135
- const db = await (0, connection_1.openSyncDatabase)();
128
+ await orderSnapshotsService.persistOrderEvent(event, "cloud");
129
+ const db = await openSyncDatabase();
136
130
  // Mark every persisted optimistic event for this local order number as
137
131
  // synced so it does not rehydrate as pending after a restart. Check both
138
132
  // origins: the creating terminal persisted "local", LAN clients "lan".
139
133
  const ids = [];
140
134
  for (const origin of ["local", "lan"]) {
141
- const unsynced = await (0, operations_1.getUnsyncedEvents)(db, origin, Number.MAX_SAFE_INTEGER);
135
+ const unsynced = await getUnsyncedEvents(db, origin, Number.MAX_SAFE_INTEGER);
142
136
  for (const e of unsynced) {
143
137
  if (e.event_type !== PENDING_EVENT_TYPE)
144
138
  continue;
@@ -149,13 +143,13 @@ async function applyPendingOrderEvent(event, origin = "local") {
149
143
  }
150
144
  }
151
145
  if (ids.length > 0) {
152
- await (0, operations_1.markEventsSynced)(db, ids);
146
+ await markEventsSynced(db, ids);
153
147
  }
154
148
  invalidator?.();
155
149
  }
156
150
  }
157
151
  catch (error) {
158
- sync_logger_1.syncLogger.error("PendingOrders", "Failed to apply event", {
152
+ syncLogger.error("PendingOrders", "Failed to apply event", {
159
153
  error: String(error),
160
154
  event_type: event.event_type,
161
155
  });
@@ -1,67 +1,63 @@
1
- "use strict";
2
1
  /**
3
2
  * Local Node Transport.
4
3
  *
5
4
  * Routes commands to the elected Local Node over the LAN and receives events
6
5
  * broadcast by the Local Node.
7
6
  */
8
- Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.localNodeTransport = exports.LocalNodeTransport = void 0;
10
- const local_node_1 = require("../adapters/local-node");
11
- const sync_logger_1 = require("../utils/sync-logger");
12
- class LocalNodeTransport {
7
+ import { useLocalNodeStore, localNodeService } from "../adapters/local-node";
8
+ import { syncLogger } from "../utils/sync-logger";
9
+ export class LocalNodeTransport {
13
10
  constructor() {
14
11
  this.name = "local_node";
15
12
  }
16
13
  isAvailable() {
17
- const store = local_node_1.useLocalNodeStore.getState();
14
+ const store = useLocalNodeStore.getState();
18
15
  if (!store.isLocalNodeEnabled)
19
16
  return false;
20
17
  // If this device is the Local Node, it is always available.
21
- if (local_node_1.localNodeService.isLocalNode())
18
+ if (localNodeService.isLocalNode())
22
19
  return true;
23
20
  // Otherwise, we must be connected to the elected node.
24
- return local_node_1.localNodeService.isConnectedToNode();
21
+ return localNodeService.isConnectedToNode();
25
22
  }
26
23
  subscribe() {
27
24
  // Events are received through the LocalNodeService event pipeline.
28
25
  return () => undefined;
29
26
  }
30
27
  async execute(command) {
31
- sync_logger_1.syncLogger.transport(this, "executing", {
28
+ syncLogger.transport(this, "executing", {
32
29
  command_type: command.command_type,
33
30
  command_id: command.command_id,
34
31
  });
35
- if (local_node_1.localNodeService.isLocalNode()) {
32
+ if (localNodeService.isLocalNode()) {
36
33
  // This device is the Local Node: execute locally.
37
- sync_logger_1.syncLogger.info("LocalNodeTransport", "Executing on local node (self)", {
34
+ syncLogger.info("LocalNodeTransport", "Executing on local node (self)", {
38
35
  command_type: command.command_type,
39
36
  command_id: command.command_id,
40
37
  });
41
- const event = await local_node_1.localNodeService.handleNodeCommand(command);
42
- sync_logger_1.syncLogger.transport(this, "completed", {
38
+ const event = await localNodeService.handleNodeCommand(command);
39
+ syncLogger.transport(this, "completed", {
43
40
  command_type: command.command_type,
44
41
  event_type: event?.event_type,
45
42
  });
46
43
  return event ? [event] : [];
47
44
  }
48
45
  // Client: send command to the Local Node.
49
- const client = local_node_1.localNodeService.getClient();
46
+ const client = localNodeService.getClient();
50
47
  if (!client) {
51
48
  throw new Error("LocalNodeTransport: no client connected to Local Node");
52
49
  }
53
- sync_logger_1.syncLogger.info("LocalNodeTransport", "Sending command to Local Node", {
50
+ syncLogger.info("LocalNodeTransport", "Sending command to Local Node", {
54
51
  command_type: command.command_type,
55
52
  command_id: command.command_id,
56
- node_device_id: local_node_1.localNodeService.getElectedNode()?.deviceId,
53
+ node_device_id: localNodeService.getElectedNode()?.deviceId,
57
54
  });
58
55
  const events = await client.execute(command);
59
- sync_logger_1.syncLogger.transport(this, "completed", {
56
+ syncLogger.transport(this, "completed", {
60
57
  command_type: command.command_type,
61
58
  event_count: events.length,
62
59
  });
63
60
  return events;
64
61
  }
65
62
  }
66
- exports.LocalNodeTransport = LocalNodeTransport;
67
- exports.localNodeTransport = new LocalNodeTransport();
63
+ export const localNodeTransport = new LocalNodeTransport();