@teincfood/core 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.
- package/README.md +44 -0
- package/dist/adapters/auth.d.ts +13 -0
- package/dist/adapters/auth.js +14 -0
- package/dist/adapters/business.d.ts +13 -0
- package/dist/adapters/business.js +14 -0
- package/dist/adapters/connectivity.d.ts +17 -0
- package/dist/adapters/connectivity.js +38 -0
- package/dist/adapters/devices.d.ts +5 -0
- package/dist/adapters/devices.js +14 -0
- package/dist/adapters/http.d.ts +30 -0
- package/dist/adapters/http.js +37 -0
- package/dist/adapters/image-cache.d.ts +8 -0
- package/dist/adapters/image-cache.js +12 -0
- package/dist/adapters/kv-types.d.ts +5 -0
- package/dist/adapters/kv-types.js +2 -0
- package/dist/adapters/kv.d.ts +20 -0
- package/dist/adapters/kv.js +81 -0
- package/dist/adapters/local-node.d.ts +34 -0
- package/dist/adapters/local-node.js +40 -0
- package/dist/adapters/pending-orders.d.ts +17 -0
- package/dist/adapters/pending-orders.js +31 -0
- package/dist/adapters/query-keys.d.ts +17 -0
- package/dist/adapters/query-keys.js +20 -0
- package/dist/adapters/services.d.ts +62 -0
- package/dist/adapters/services.js +95 -0
- package/dist/adapters/sqlite.d.ts +20 -0
- package/dist/adapters/sqlite.js +23 -0
- package/dist/db/connection.d.ts +8 -0
- package/dist/db/connection.js +87 -0
- package/dist/db/migrations.d.ts +9 -0
- package/dist/db/migrations.js +106 -0
- package/dist/db/operations.d.ts +45 -0
- package/dist/db/operations.js +192 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +118 -0
- package/dist/reference/api.d.ts +10 -0
- package/dist/reference/api.js +24 -0
- package/dist/reference/events.d.ts +54 -0
- package/dist/reference/events.js +144 -0
- package/dist/reference/operations.d.ts +11 -0
- package/dist/reference/operations.js +46 -0
- package/dist/reference/service.d.ts +27 -0
- package/dist/reference/service.js +270 -0
- package/dist/reference/types.d.ts +47 -0
- package/dist/reference/types.js +12 -0
- package/dist/repositories/order.repository.d.ts +44 -0
- package/dist/repositories/order.repository.js +132 -0
- package/dist/repositories/pos.repository.d.ts +20 -0
- package/dist/repositories/pos.repository.js +28 -0
- package/dist/sync/command-builder.d.ts +17 -0
- package/dist/sync/command-builder.js +30 -0
- package/dist/sync/command-queue.service.d.ts +41 -0
- package/dist/sync/command-queue.service.js +253 -0
- package/dist/sync/engine.d.ts +53 -0
- package/dist/sync/engine.js +216 -0
- package/dist/sync/order-number.d.ts +20 -0
- package/dist/sync/order-number.js +58 -0
- package/dist/sync/order-snapshots.service.d.ts +46 -0
- package/dist/sync/order-snapshots.service.js +151 -0
- package/dist/sync/pending-orders.service.d.ts +45 -0
- package/dist/sync/pending-orders.service.js +163 -0
- package/dist/sync/transport-local-node.d.ts +14 -0
- package/dist/sync/transport-local-node.js +67 -0
- package/dist/sync/transport-rest.d.ts +17 -0
- package/dist/sync/transport-rest.js +112 -0
- package/dist/sync/types.d.ts +102 -0
- package/dist/sync/types.js +13 -0
- package/dist/sync/use-sync-reconciliation.d.ts +10 -0
- package/dist/sync/use-sync-reconciliation.js +106 -0
- package/dist/types/api/auth.api.d.ts +61 -0
- package/dist/types/api/auth.api.js +3 -0
- package/dist/types/api/business.api.d.ts +137 -0
- package/dist/types/api/business.api.js +3 -0
- package/dist/types/api/conversation.api.d.ts +46 -0
- package/dist/types/api/conversation.api.js +2 -0
- package/dist/types/api/error.api.d.ts +8 -0
- package/dist/types/api/error.api.js +2 -0
- package/dist/types/api/fleet.api.d.ts +98 -0
- package/dist/types/api/fleet.api.js +3 -0
- package/dist/types/api/index.d.ts +11 -0
- package/dist/types/api/index.js +27 -0
- package/dist/types/api/kiosk.api.d.ts +4 -0
- package/dist/types/api/kiosk.api.js +2 -0
- package/dist/types/api/menu.api.d.ts +90 -0
- package/dist/types/api/menu.api.js +2 -0
- package/dist/types/api/pagination.d.ts +10 -0
- package/dist/types/api/pagination.js +2 -0
- package/dist/types/api/rider.api.d.ts +179 -0
- package/dist/types/api/rider.api.js +2 -0
- package/dist/types/api/seller.api.d.ts +164 -0
- package/dist/types/api/seller.api.js +2 -0
- package/dist/types/api/wallet.api.d.ts +27 -0
- package/dist/types/api/wallet.api.js +2 -0
- package/dist/types/pos.types.d.ts +33 -0
- package/dist/types/pos.types.js +5 -0
- package/dist/utils/constants.d.ts +85 -0
- package/dist/utils/constants.js +72 -0
- package/dist/utils/copyToClipBoard.d.ts +5 -0
- package/dist/utils/copyToClipBoard.js +23 -0
- package/dist/utils/currency.d.ts +9 -0
- package/dist/utils/currency.js +37 -0
- package/dist/utils/error.d.ts +4 -0
- package/dist/utils/error.js +73 -0
- package/dist/utils/formatCurrency.d.ts +4 -0
- package/dist/utils/formatCurrency.js +16 -0
- package/dist/utils/formatDate.d.ts +8 -0
- package/dist/utils/formatDate.js +42 -0
- package/dist/utils/phone.d.ts +10 -0
- package/dist/utils/phone.js +71 -0
- package/dist/utils/responsive.d.ts +13 -0
- package/dist/utils/responsive.js +21 -0
- package/dist/utils/storage.d.ts +15 -0
- package/dist/utils/storage.js +60 -0
- package/dist/utils/sync-logger.d.ts +22 -0
- package/dist/utils/sync-logger.js +79 -0
- package/dist/utils/uuid.d.ts +7 -0
- package/dist/utils/uuid.js +47 -0
- package/dist/utils/validation.d.ts +31 -0
- package/dist/utils/validation.js +170 -0
- package/package.json +49 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @teincfood/core — shared offline-first backbone
|
|
4
|
+
*
|
|
5
|
+
* Entry point. Re-exports types, sync engine, DB, reference service, repos and adapters.
|
|
6
|
+
* Host apps call `createTeincCore` once at bootstrap to wire platform adapters.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
25
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
26
|
+
};
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.referenceSyncService = exports.posRepository = exports.orderRepository = exports.orderSnapshotsService = exports.isLocalOrderNumber = exports.generateLocalCalloutNumber = exports.generateLocalOrderNumber = exports.buildCommand = exports.commandQueueService = exports.SyncEngine = exports.getSyncDatabase = exports.openSyncDatabase = exports.dbOps = void 0;
|
|
46
|
+
exports.createTeincCore = createTeincCore;
|
|
47
|
+
exports.getCoreEngine = getCoreEngine;
|
|
48
|
+
// ── Types ──
|
|
49
|
+
__exportStar(require("./types/api"), exports);
|
|
50
|
+
__exportStar(require("./types/pos.types"), exports);
|
|
51
|
+
// ── Utils ──
|
|
52
|
+
__exportStar(require("./utils/constants"), exports);
|
|
53
|
+
__exportStar(require("./utils/currency"), exports);
|
|
54
|
+
__exportStar(require("./utils/error"), exports);
|
|
55
|
+
__exportStar(require("./utils/uuid"), exports);
|
|
56
|
+
__exportStar(require("./utils/sync-logger"), exports);
|
|
57
|
+
// ── DB ──
|
|
58
|
+
__exportStar(require("./db/migrations"), exports);
|
|
59
|
+
exports.dbOps = __importStar(require("./db/operations"));
|
|
60
|
+
var connection_1 = require("./db/connection");
|
|
61
|
+
Object.defineProperty(exports, "openSyncDatabase", { enumerable: true, get: function () { return connection_1.openSyncDatabase; } });
|
|
62
|
+
Object.defineProperty(exports, "getSyncDatabase", { enumerable: true, get: function () { return connection_1.getSyncDatabase; } });
|
|
63
|
+
// ── Sync ──
|
|
64
|
+
__exportStar(require("./sync/types"), exports);
|
|
65
|
+
var engine_1 = require("./sync/engine");
|
|
66
|
+
Object.defineProperty(exports, "SyncEngine", { enumerable: true, get: function () { return engine_1.SyncEngine; } });
|
|
67
|
+
var command_queue_service_1 = require("./sync/command-queue.service");
|
|
68
|
+
Object.defineProperty(exports, "commandQueueService", { enumerable: true, get: function () { return command_queue_service_1.commandQueueService; } });
|
|
69
|
+
var command_builder_1 = require("./sync/command-builder");
|
|
70
|
+
Object.defineProperty(exports, "buildCommand", { enumerable: true, get: function () { return command_builder_1.buildCommand; } });
|
|
71
|
+
var order_number_1 = require("./sync/order-number");
|
|
72
|
+
Object.defineProperty(exports, "generateLocalOrderNumber", { enumerable: true, get: function () { return order_number_1.generateLocalOrderNumber; } });
|
|
73
|
+
Object.defineProperty(exports, "generateLocalCalloutNumber", { enumerable: true, get: function () { return order_number_1.generateLocalCalloutNumber; } });
|
|
74
|
+
Object.defineProperty(exports, "isLocalOrderNumber", { enumerable: true, get: function () { return order_number_1.isLocalOrderNumber; } });
|
|
75
|
+
var order_snapshots_service_1 = require("./sync/order-snapshots.service");
|
|
76
|
+
Object.defineProperty(exports, "orderSnapshotsService", { enumerable: true, get: function () { return order_snapshots_service_1.orderSnapshotsService; } });
|
|
77
|
+
__exportStar(require("./sync/pending-orders.service"), exports);
|
|
78
|
+
// ── Repositories ──
|
|
79
|
+
var order_repository_1 = require("./repositories/order.repository");
|
|
80
|
+
Object.defineProperty(exports, "orderRepository", { enumerable: true, get: function () { return order_repository_1.orderRepository; } });
|
|
81
|
+
var pos_repository_1 = require("./repositories/pos.repository");
|
|
82
|
+
Object.defineProperty(exports, "posRepository", { enumerable: true, get: function () { return pos_repository_1.posRepository; } });
|
|
83
|
+
// ── Reference ──
|
|
84
|
+
__exportStar(require("./reference/types"), exports);
|
|
85
|
+
var service_1 = require("./reference/service");
|
|
86
|
+
Object.defineProperty(exports, "referenceSyncService", { enumerable: true, get: function () { return service_1.referenceSyncService; } });
|
|
87
|
+
// ── Adapters (for host apps to supply) ──
|
|
88
|
+
__exportStar(require("./adapters/sqlite"), exports);
|
|
89
|
+
__exportStar(require("./adapters/kv"), exports);
|
|
90
|
+
__exportStar(require("./adapters/connectivity"), exports);
|
|
91
|
+
__exportStar(require("./adapters/http"), exports);
|
|
92
|
+
__exportStar(require("./adapters/local-node"), exports);
|
|
93
|
+
// ── Init helper ──
|
|
94
|
+
const sqlite_1 = require("./adapters/sqlite");
|
|
95
|
+
const kv_1 = require("./adapters/kv");
|
|
96
|
+
const connectivity_1 = require("./adapters/connectivity");
|
|
97
|
+
const http_1 = require("./adapters/http");
|
|
98
|
+
const engine_2 = require("./sync/engine");
|
|
99
|
+
const transport_rest_1 = require("./sync/transport-rest");
|
|
100
|
+
const transport_local_node_1 = require("./sync/transport-local-node");
|
|
101
|
+
let engine = null;
|
|
102
|
+
function createTeincCore(config = {}) {
|
|
103
|
+
if (config.sqliteDriver)
|
|
104
|
+
(0, sqlite_1.setSqliteDriver)(config.sqliteDriver);
|
|
105
|
+
if (config.kvDriver)
|
|
106
|
+
(0, kv_1.setKVDriver)(config.kvDriver);
|
|
107
|
+
if (config.httpClient)
|
|
108
|
+
(0, http_1.setHttpClient)(config.httpClient);
|
|
109
|
+
if (config.initialConnectivity)
|
|
110
|
+
(0, connectivity_1.setConnectivityState)(config.initialConnectivity);
|
|
111
|
+
engine = new engine_2.SyncEngine({ transports: [transport_rest_1.restTransport, transport_local_node_1.localNodeTransport] });
|
|
112
|
+
return { engine };
|
|
113
|
+
}
|
|
114
|
+
function getCoreEngine() {
|
|
115
|
+
if (!engine)
|
|
116
|
+
throw new Error("TeincFood core not initialised. Call createTeincCore() first.");
|
|
117
|
+
return engine;
|
|
118
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API service for reference data synchronization.
|
|
3
|
+
*
|
|
4
|
+
* These endpoints are expected on the backend. If they are not available,
|
|
5
|
+
* the ReferenceSyncService falls back to legacy menu endpoints.
|
|
6
|
+
*/
|
|
7
|
+
import type { ReferenceDataKey, ReferenceVersionInfo, ReferenceChangeSet } from "./types";
|
|
8
|
+
export declare function fetchReferenceVersions(businessId: string): Promise<ReferenceVersionInfo[]>;
|
|
9
|
+
export declare function fetchReferenceData(businessId: string, keys: ReferenceDataKey[]): Promise<Record<ReferenceDataKey, unknown>>;
|
|
10
|
+
export declare function fetchReferenceChanges<T>(businessId: string, key: ReferenceDataKey, fromVersion: string): Promise<ReferenceChangeSet<T>>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* API service for reference data synchronization.
|
|
4
|
+
*
|
|
5
|
+
* These endpoints are expected on the backend. If they are not available,
|
|
6
|
+
* the ReferenceSyncService falls back to legacy menu endpoints.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.fetchReferenceVersions = fetchReferenceVersions;
|
|
10
|
+
exports.fetchReferenceData = fetchReferenceData;
|
|
11
|
+
exports.fetchReferenceChanges = fetchReferenceChanges;
|
|
12
|
+
const http_1 = require("../adapters/http");
|
|
13
|
+
async function fetchReferenceVersions(businessId) {
|
|
14
|
+
const response = await http_1.api.get(`/businesses/${businessId}/reference-versions`);
|
|
15
|
+
return response.data.data;
|
|
16
|
+
}
|
|
17
|
+
async function fetchReferenceData(businessId, keys) {
|
|
18
|
+
const response = await http_1.api.get(`/businesses/${businessId}/reference-data`, { params: { keys: keys.join(",") } });
|
|
19
|
+
return response.data.data;
|
|
20
|
+
}
|
|
21
|
+
async function fetchReferenceChanges(businessId, key, fromVersion) {
|
|
22
|
+
const response = await http_1.api.get(`/businesses/${businessId}/reference-changes`, { params: { key, from_version: fromVersion } });
|
|
23
|
+
return response.data.data;
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference data change events.
|
|
3
|
+
*
|
|
4
|
+
* Bridges reference-data mutations into the Sync Engine event bus so that
|
|
5
|
+
* every device stays in sync:
|
|
6
|
+
*
|
|
7
|
+
* - The device that mutates a reference-backed entity (e.g. a menu item)
|
|
8
|
+
* publishes `reference_data.changed` via the Sync Engine.
|
|
9
|
+
* - The reconciliation bridge relays that event to LAN clients when this
|
|
10
|
+
* device is the Local Node.
|
|
11
|
+
* - Any device that receives the event (locally or over the LAN) re-syncs
|
|
12
|
+
* the affected reference keys and invalidates its React Query caches.
|
|
13
|
+
*
|
|
14
|
+
* This module intentionally does not import the Sync Engine at runtime (only
|
|
15
|
+
* as a type). The engine is registered via `registerReferenceEventEngine`, so
|
|
16
|
+
* `local-node/service.ts` can depend on this module without creating an
|
|
17
|
+
* import cycle (engine → transport → local-node/service → reference/events).
|
|
18
|
+
*/
|
|
19
|
+
import type { DomainEvent } from "../sync/types";
|
|
20
|
+
import type { SyncEngine } from "../sync/engine";
|
|
21
|
+
import type { ReferenceDataKey } from "./types";
|
|
22
|
+
export declare const REFERENCE_CHANGED_EVENT_TYPE = "reference_data.changed";
|
|
23
|
+
export interface ReferenceChangedEventPayload {
|
|
24
|
+
business_id: string;
|
|
25
|
+
keys: ReferenceDataKey[];
|
|
26
|
+
}
|
|
27
|
+
/** Register the Sync Engine used to publish reference change events. */
|
|
28
|
+
export declare function registerReferenceEventEngine(syncEngine: SyncEngine): void;
|
|
29
|
+
/**
|
|
30
|
+
* Register a callback used to invalidate React Query caches when reference
|
|
31
|
+
* data changes. Returns an unregister function. Mirrors
|
|
32
|
+
* `registerPendingOrdersInvalidator`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function registerReferenceInvalidator(fn: () => void): () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Publish a `reference_data.changed` event so every device (including this
|
|
37
|
+
* one) re-syncs the affected keys. Called after a successful mutation of a
|
|
38
|
+
* reference-backed entity.
|
|
39
|
+
*/
|
|
40
|
+
export declare function emitReferenceChanged(businessId: string, keys: ReferenceDataKey[]): void;
|
|
41
|
+
/**
|
|
42
|
+
* Apply a `reference_data.changed` event: re-sync the affected keys and
|
|
43
|
+
* invalidate caches. Idempotent — duplicate deliveries (local broadcast + LAN
|
|
44
|
+
* broadcast) are safe because the reference sync is version-aware and guarded
|
|
45
|
+
* by a single-flight flag. Errors are logged, never thrown, so a failed
|
|
46
|
+
* reference sync can never crash the LAN event loop.
|
|
47
|
+
*/
|
|
48
|
+
export declare function applyReferenceChangeEvent(event: DomainEvent, origin?: "local" | "lan"): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Best-effort reference data sync when connectivity recovers. Covers devices
|
|
51
|
+
* that missed the change event (offline, not on the LAN) — the next time they
|
|
52
|
+
* get internet they attempt to re-sync all default reference keys.
|
|
53
|
+
*/
|
|
54
|
+
export declare function syncReferenceDataOnReconnect(): Promise<void>;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reference data change events.
|
|
4
|
+
*
|
|
5
|
+
* Bridges reference-data mutations into the Sync Engine event bus so that
|
|
6
|
+
* every device stays in sync:
|
|
7
|
+
*
|
|
8
|
+
* - The device that mutates a reference-backed entity (e.g. a menu item)
|
|
9
|
+
* publishes `reference_data.changed` via the Sync Engine.
|
|
10
|
+
* - The reconciliation bridge relays that event to LAN clients when this
|
|
11
|
+
* device is the Local Node.
|
|
12
|
+
* - Any device that receives the event (locally or over the LAN) re-syncs
|
|
13
|
+
* the affected reference keys and invalidates its React Query caches.
|
|
14
|
+
*
|
|
15
|
+
* This module intentionally does not import the Sync Engine at runtime (only
|
|
16
|
+
* as a type). The engine is registered via `registerReferenceEventEngine`, so
|
|
17
|
+
* `local-node/service.ts` can depend on this module without creating an
|
|
18
|
+
* import cycle (engine → transport → local-node/service → reference/events).
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.REFERENCE_CHANGED_EVENT_TYPE = void 0;
|
|
22
|
+
exports.registerReferenceEventEngine = registerReferenceEventEngine;
|
|
23
|
+
exports.registerReferenceInvalidator = registerReferenceInvalidator;
|
|
24
|
+
exports.emitReferenceChanged = emitReferenceChanged;
|
|
25
|
+
exports.applyReferenceChangeEvent = applyReferenceChangeEvent;
|
|
26
|
+
exports.syncReferenceDataOnReconnect = syncReferenceDataOnReconnect;
|
|
27
|
+
const auth_1 = require("../adapters/auth");
|
|
28
|
+
const business_1 = require("../adapters/business");
|
|
29
|
+
const devices_1 = require("../adapters/devices");
|
|
30
|
+
const uuid_1 = require("../utils/uuid");
|
|
31
|
+
const sync_logger_1 = require("../utils/sync-logger");
|
|
32
|
+
const service_1 = require("./service");
|
|
33
|
+
exports.REFERENCE_CHANGED_EVENT_TYPE = "reference_data.changed";
|
|
34
|
+
/** Injected Sync Engine singleton (set by the reconciliation bridge). */
|
|
35
|
+
let engine = null;
|
|
36
|
+
/** Register the Sync Engine used to publish reference change events. */
|
|
37
|
+
function registerReferenceEventEngine(syncEngine) {
|
|
38
|
+
engine = syncEngine;
|
|
39
|
+
}
|
|
40
|
+
/** Invalidate TanStack Query caches after reference data is re-synced. */
|
|
41
|
+
let invalidator = null;
|
|
42
|
+
/**
|
|
43
|
+
* Register a callback used to invalidate React Query caches when reference
|
|
44
|
+
* data changes. Returns an unregister function. Mirrors
|
|
45
|
+
* `registerPendingOrdersInvalidator`.
|
|
46
|
+
*/
|
|
47
|
+
function registerReferenceInvalidator(fn) {
|
|
48
|
+
invalidator = fn;
|
|
49
|
+
return () => {
|
|
50
|
+
if (invalidator === fn)
|
|
51
|
+
invalidator = null;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Publish a `reference_data.changed` event so every device (including this
|
|
56
|
+
* one) re-syncs the affected keys. Called after a successful mutation of a
|
|
57
|
+
* reference-backed entity.
|
|
58
|
+
*/
|
|
59
|
+
function emitReferenceChanged(businessId, keys) {
|
|
60
|
+
if (!businessId || keys.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
if (!engine)
|
|
63
|
+
return;
|
|
64
|
+
const user = auth_1.useAuthStore.getState().user;
|
|
65
|
+
const event = {
|
|
66
|
+
event_id: (0, uuid_1.generateEventId)(),
|
|
67
|
+
event_type: exports.REFERENCE_CHANGED_EVENT_TYPE,
|
|
68
|
+
event_version: "1.0",
|
|
69
|
+
timestamp: new Date().toISOString(),
|
|
70
|
+
device_id: (0, devices_1.getAppInstanceId)(),
|
|
71
|
+
user_id: user?.id ?? "anonymous",
|
|
72
|
+
entity_id: businessId,
|
|
73
|
+
payload: { business_id: businessId, keys },
|
|
74
|
+
};
|
|
75
|
+
engine.publish(event);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Apply a `reference_data.changed` event: re-sync the affected keys and
|
|
79
|
+
* invalidate caches. Idempotent — duplicate deliveries (local broadcast + LAN
|
|
80
|
+
* broadcast) are safe because the reference sync is version-aware and guarded
|
|
81
|
+
* by a single-flight flag. Errors are logged, never thrown, so a failed
|
|
82
|
+
* reference sync can never crash the LAN event loop.
|
|
83
|
+
*/
|
|
84
|
+
async function applyReferenceChangeEvent(event, origin = "local") {
|
|
85
|
+
try {
|
|
86
|
+
if (event.event_type !== exports.REFERENCE_CHANGED_EVENT_TYPE)
|
|
87
|
+
return;
|
|
88
|
+
const payload = event.payload;
|
|
89
|
+
const businessId = payload?.business_id;
|
|
90
|
+
const keys = payload?.keys;
|
|
91
|
+
if (!businessId || !keys || keys.length === 0)
|
|
92
|
+
return;
|
|
93
|
+
sync_logger_1.syncLogger.info("ReferenceChange", "Reference data changed", {
|
|
94
|
+
origin,
|
|
95
|
+
business_id: businessId,
|
|
96
|
+
keys,
|
|
97
|
+
});
|
|
98
|
+
const result = await service_1.referenceSyncService.sync({
|
|
99
|
+
businessId,
|
|
100
|
+
keys,
|
|
101
|
+
incremental: true,
|
|
102
|
+
});
|
|
103
|
+
if (result.failed.length > 0) {
|
|
104
|
+
sync_logger_1.syncLogger.warn("ReferenceChange", "Reference sync had failures", {
|
|
105
|
+
origin,
|
|
106
|
+
failed: result.failed,
|
|
107
|
+
errors: result.errors,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
invalidator?.();
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
sync_logger_1.syncLogger.error("ReferenceChange", "Failed to apply reference change event", {
|
|
114
|
+
error: String(error),
|
|
115
|
+
event_type: event.event_type,
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Best-effort reference data sync when connectivity recovers. Covers devices
|
|
121
|
+
* that missed the change event (offline, not on the LAN) — the next time they
|
|
122
|
+
* get internet they attempt to re-sync all default reference keys.
|
|
123
|
+
*/
|
|
124
|
+
async function syncReferenceDataOnReconnect() {
|
|
125
|
+
const businessId = business_1.useBusinessStore.getState().activeBusiness?.id;
|
|
126
|
+
if (!businessId)
|
|
127
|
+
return;
|
|
128
|
+
try {
|
|
129
|
+
const result = await service_1.referenceSyncService.sync({
|
|
130
|
+
businessId,
|
|
131
|
+
incremental: true,
|
|
132
|
+
});
|
|
133
|
+
if (result.failed.length > 0) {
|
|
134
|
+
sync_logger_1.syncLogger.warn("ReferenceChange", "Reconnect sync had failures", {
|
|
135
|
+
failed: result.failed,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
sync_logger_1.syncLogger.error("ReferenceChange", "Reconnect sync failed", {
|
|
141
|
+
error: String(error),
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite operations for the business-scoped reference data cache.
|
|
3
|
+
*/
|
|
4
|
+
import type { SQLiteDatabase } from "../adapters/sqlite";
|
|
5
|
+
import type { ReferenceDataKey, ReferenceDataRecord } from "./types";
|
|
6
|
+
export declare function getReferenceData<T>(db: SQLiteDatabase, businessId: string, key: ReferenceDataKey): Promise<ReferenceDataRecord<T> | null>;
|
|
7
|
+
export declare function getReferenceVersion(db: SQLiteDatabase, businessId: string, key: ReferenceDataKey): Promise<string | null>;
|
|
8
|
+
export declare function setReferenceData<T>(db: SQLiteDatabase, businessId: string, record: ReferenceDataRecord<T>): Promise<void>;
|
|
9
|
+
export declare function deleteReferenceData(db: SQLiteDatabase, businessId: string, key: ReferenceDataKey): Promise<void>;
|
|
10
|
+
export declare function deleteReferenceDataForBusiness(db: SQLiteDatabase, businessId: string): Promise<void>;
|
|
11
|
+
export declare function getAllReferenceDataKeys(db: SQLiteDatabase, businessId: string): Promise<ReferenceDataKey[]>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SQLite operations for the business-scoped reference data cache.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getReferenceData = getReferenceData;
|
|
7
|
+
exports.getReferenceVersion = getReferenceVersion;
|
|
8
|
+
exports.setReferenceData = setReferenceData;
|
|
9
|
+
exports.deleteReferenceData = deleteReferenceData;
|
|
10
|
+
exports.deleteReferenceDataForBusiness = deleteReferenceDataForBusiness;
|
|
11
|
+
exports.getAllReferenceDataKeys = getAllReferenceDataKeys;
|
|
12
|
+
async function getReferenceData(db, businessId, key) {
|
|
13
|
+
const row = await db.getFirstAsync("SELECT * FROM reference_data WHERE business_id = ? AND key = ?;", businessId, key);
|
|
14
|
+
if (!row)
|
|
15
|
+
return null;
|
|
16
|
+
return {
|
|
17
|
+
key: row.key,
|
|
18
|
+
version: row.version,
|
|
19
|
+
payload: JSON.parse(row.payload),
|
|
20
|
+
downloadedAt: row.downloaded_at,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async function getReferenceVersion(db, businessId, key) {
|
|
24
|
+
const row = await db.getFirstAsync("SELECT version FROM reference_data WHERE business_id = ? AND key = ?;", businessId, key);
|
|
25
|
+
return row?.version ?? null;
|
|
26
|
+
}
|
|
27
|
+
async function setReferenceData(db, businessId, record) {
|
|
28
|
+
await db.runAsync(`
|
|
29
|
+
INSERT INTO reference_data (business_id, key, version, payload, downloaded_at)
|
|
30
|
+
VALUES (?, ?, ?, ?, ?)
|
|
31
|
+
ON CONFLICT(business_id, key) DO UPDATE SET
|
|
32
|
+
version = excluded.version,
|
|
33
|
+
payload = excluded.payload,
|
|
34
|
+
downloaded_at = excluded.downloaded_at;
|
|
35
|
+
`, businessId, record.key, record.version, JSON.stringify(record.payload), record.downloadedAt);
|
|
36
|
+
}
|
|
37
|
+
async function deleteReferenceData(db, businessId, key) {
|
|
38
|
+
await db.runAsync("DELETE FROM reference_data WHERE business_id = ? AND key = ?;", businessId, key);
|
|
39
|
+
}
|
|
40
|
+
async function deleteReferenceDataForBusiness(db, businessId) {
|
|
41
|
+
await db.runAsync("DELETE FROM reference_data WHERE business_id = ?;", businessId);
|
|
42
|
+
}
|
|
43
|
+
async function getAllReferenceDataKeys(db, businessId) {
|
|
44
|
+
const rows = await db.getAllAsync("SELECT key FROM reference_data WHERE business_id = ? ORDER BY key;", businessId);
|
|
45
|
+
return rows.map((r) => r.key);
|
|
46
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reference Data Synchronization Service.
|
|
3
|
+
*
|
|
4
|
+
* Responsible for downloading, versioning, and caching reference data
|
|
5
|
+
* (menus, categories, modifiers, taxes, printers, etc.) locally.
|
|
6
|
+
*
|
|
7
|
+
* This service is separate from the Sync Engine, which handles transactional
|
|
8
|
+
* commands and events.
|
|
9
|
+
*/
|
|
10
|
+
import type { ReferenceDataKey, ReferenceSyncOptions, ReferenceSyncResult, ReferenceDataRecord } from "./types";
|
|
11
|
+
declare class ReferenceSyncService {
|
|
12
|
+
private isSyncing;
|
|
13
|
+
sync(options: ReferenceSyncOptions): Promise<ReferenceSyncResult>;
|
|
14
|
+
private syncKey;
|
|
15
|
+
private fetchFallback;
|
|
16
|
+
/**
|
|
17
|
+
* Download every image referenced by the given cached reference keys into
|
|
18
|
+
* durable local storage, then prune orphaned files. Covers menu item photos
|
|
19
|
+
* and the business logo/cover. Idempotent — already-cached images are
|
|
20
|
+
* skipped. Errors never propagate: a failed download must not fail the sync.
|
|
21
|
+
*/
|
|
22
|
+
private cacheReferenceImages;
|
|
23
|
+
private hashPayload;
|
|
24
|
+
getCached<T>(businessId: string, key: ReferenceDataKey): Promise<ReferenceDataRecord<T> | null>;
|
|
25
|
+
}
|
|
26
|
+
export declare const referenceSyncService: ReferenceSyncService;
|
|
27
|
+
export {};
|