@teincfood/core 0.7.2 → 0.7.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.
- package/dist/adapters/query-keys.d.ts +10 -0
- package/dist/adapters/query-keys.js +10 -0
- package/dist/db/migrations.js +24 -0
- package/dist/db/operations.d.ts +3 -0
- package/dist/db/operations.js +25 -0
- package/dist/sync/command-queue.service.js +16 -1
- package/dist/sync/pending-orders.service.js +6 -0
- package/dist/sync/use-sync-reconciliation.js +6 -2
- package/dist/utils/constants.d.ts +3 -3
- package/dist/utils/constants.js +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,16 @@ export declare const POS_KEYS: {
|
|
|
8
8
|
};
|
|
9
9
|
export declare const SELLER_KEYS: {
|
|
10
10
|
all: readonly ["seller"];
|
|
11
|
+
orders: (businessId?: string) => readonly unknown[];
|
|
12
|
+
};
|
|
13
|
+
export declare const KIOSK_KEYS: {
|
|
14
|
+
all: readonly ["kiosk"];
|
|
15
|
+
};
|
|
16
|
+
export declare const SELLER_ORDERS_KEYS: {
|
|
17
|
+
all: readonly ["seller-orders"];
|
|
18
|
+
};
|
|
19
|
+
export declare const BUSINESS_DELIVERIES_KEYS: {
|
|
20
|
+
all: readonly ["business-deliveries"];
|
|
11
21
|
};
|
|
12
22
|
export declare const MENU_KEYS: {
|
|
13
23
|
all: readonly ["menu"];
|
|
@@ -8,6 +8,16 @@ export const POS_KEYS = {
|
|
|
8
8
|
};
|
|
9
9
|
export const SELLER_KEYS = {
|
|
10
10
|
all: ["seller"],
|
|
11
|
+
orders: (businessId) => ["seller", "orders", businessId].filter((x) => x !== undefined),
|
|
12
|
+
};
|
|
13
|
+
export const KIOSK_KEYS = {
|
|
14
|
+
all: ["kiosk"],
|
|
15
|
+
};
|
|
16
|
+
export const SELLER_ORDERS_KEYS = {
|
|
17
|
+
all: ["seller-orders"],
|
|
18
|
+
};
|
|
19
|
+
export const BUSINESS_DELIVERIES_KEYS = {
|
|
20
|
+
all: ["business-deliveries"],
|
|
11
21
|
};
|
|
12
22
|
export const MENU_KEYS = {
|
|
13
23
|
all: ["menu"],
|
package/dist/db/migrations.js
CHANGED
|
@@ -110,4 +110,28 @@ export const MIGRATIONS = [
|
|
|
110
110
|
`);
|
|
111
111
|
},
|
|
112
112
|
},
|
|
113
|
+
{
|
|
114
|
+
version: 4,
|
|
115
|
+
up: async (db) => {
|
|
116
|
+
// Clear stale completed outbox rows and legacy TFL- order numbers that
|
|
117
|
+
// accumulated before 0.7.0's DD-RRR-CCC cutover. Pending/failed/in_flight
|
|
118
|
+
// are kept so an in-flight replay is not lost; only completed + legacy
|
|
119
|
+
// payloads are pruned. Also clears legacy optimistic events.
|
|
120
|
+
await db.execAsync(`
|
|
121
|
+
DELETE FROM commands WHERE status = 'completed';
|
|
122
|
+
`);
|
|
123
|
+
try {
|
|
124
|
+
await db.execAsync(`
|
|
125
|
+
DELETE FROM commands WHERE payload LIKE '%TFL-%';
|
|
126
|
+
`);
|
|
127
|
+
}
|
|
128
|
+
catch { }
|
|
129
|
+
try {
|
|
130
|
+
await db.execAsync(`
|
|
131
|
+
DELETE FROM events WHERE payload LIKE '%TFL-%';
|
|
132
|
+
`);
|
|
133
|
+
}
|
|
134
|
+
catch { }
|
|
135
|
+
},
|
|
136
|
+
},
|
|
113
137
|
];
|
package/dist/db/operations.d.ts
CHANGED
|
@@ -43,3 +43,6 @@ export declare function getEntitySnapshot<T>(db: SQLiteDatabase, entityType: str
|
|
|
43
43
|
export declare function getEntitySnapshotsByType<T>(db: SQLiteDatabase, entityType: string): Promise<EntitySnapshot<T>[]>;
|
|
44
44
|
export declare function deleteEntitySnapshot(db: SQLiteDatabase, entityType: string, entityId: string): Promise<void>;
|
|
45
45
|
export declare function pruneEntitySnapshots(db: SQLiteDatabase, entityType: string, cutoffIso: string): Promise<void>;
|
|
46
|
+
export declare function clearAllSyncData(db: SQLiteDatabase): Promise<void>;
|
|
47
|
+
export declare function clearReferenceData(db: SQLiteDatabase): Promise<void>;
|
|
48
|
+
export declare function clearCompletedCommandsAndOrphans(db: SQLiteDatabase): Promise<void>;
|
package/dist/db/operations.js
CHANGED
|
@@ -173,3 +173,28 @@ function rowToDomainEvent(row) {
|
|
|
173
173
|
timestamp: row.timestamp,
|
|
174
174
|
};
|
|
175
175
|
}
|
|
176
|
+
// ─────────────────────────────────────────────────────────────
|
|
177
|
+
// Maintenance — clear stale local data (used by Diagnostics)
|
|
178
|
+
// ─────────────────────────────────────────────────────────────
|
|
179
|
+
export async function clearAllSyncData(db) {
|
|
180
|
+
await db.execAsync(`DELETE FROM commands;`);
|
|
181
|
+
await db.execAsync(`DELETE FROM events;`);
|
|
182
|
+
await db.execAsync(`DELETE FROM entity_snapshots;`);
|
|
183
|
+
// Keep reference_data — it is business-scoped and expensive to re-fetch;
|
|
184
|
+
// only order/command state is cleared. If full wipe needed, call
|
|
185
|
+
// clearReferenceData below.
|
|
186
|
+
}
|
|
187
|
+
export async function clearReferenceData(db) {
|
|
188
|
+
await db.execAsync(`DELETE FROM reference_data;`);
|
|
189
|
+
}
|
|
190
|
+
export async function clearCompletedCommandsAndOrphans(db) {
|
|
191
|
+
await db.execAsync(`DELETE FROM commands WHERE status = 'completed';`);
|
|
192
|
+
try {
|
|
193
|
+
await db.execAsync(`DELETE FROM commands WHERE payload LIKE '%TFL-%';`);
|
|
194
|
+
}
|
|
195
|
+
catch { }
|
|
196
|
+
try {
|
|
197
|
+
await db.execAsync(`DELETE FROM events WHERE payload LIKE '%TFL-%';`);
|
|
198
|
+
}
|
|
199
|
+
catch { }
|
|
200
|
+
}
|
|
@@ -13,6 +13,7 @@ import { insertCommand, getPendingCommands, markCommandInFlight, updateCommandSt
|
|
|
13
13
|
import { syncLogger } from "../utils/sync-logger";
|
|
14
14
|
import { generateEventId } from "../utils/uuid";
|
|
15
15
|
import { generateLocalCalloutNumber, generateOrderNumberForBusiness, } from "./order-number";
|
|
16
|
+
import { subscribeConnectivity } from "../adapters/connectivity";
|
|
16
17
|
const MAX_RETRIES = 5;
|
|
17
18
|
const QUEUED_STATUS_BY_COMMAND = {
|
|
18
19
|
"order:accept": "accepted",
|
|
@@ -142,6 +143,17 @@ class CommandQueueService {
|
|
|
142
143
|
}
|
|
143
144
|
setSyncEngine(engine) {
|
|
144
145
|
this.syncEngine = engine;
|
|
146
|
+
// Auto-replay when the cloud becomes reachable again (e.g. after a
|
|
147
|
+
// timeout-induced `unreachable` flip, then the next successful probe sets
|
|
148
|
+
// `reachable`). No polling — event-driven via connectivity state.
|
|
149
|
+
try {
|
|
150
|
+
subscribeConnectivity((s) => {
|
|
151
|
+
if (s.isCloudReachable === "reachable" && s.isOnline) {
|
|
152
|
+
this.replay().catch(() => { });
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
145
157
|
}
|
|
146
158
|
/**
|
|
147
159
|
* Enqueue a command because no transport is currently available.
|
|
@@ -206,7 +218,10 @@ class CommandQueueService {
|
|
|
206
218
|
await markCommandInFlight(db, command.command_id);
|
|
207
219
|
try {
|
|
208
220
|
const events = await this.syncEngine.execute(parsedCommand);
|
|
209
|
-
|
|
221
|
+
// Outbox is an ephemeral queue — remove the row on success so the
|
|
222
|
+
// Diagnostics outbox count drops to 0 and old completed rows never
|
|
223
|
+
// accumulate. The optimistic event stays in `events` (marked synced).
|
|
224
|
+
await deleteCommand(db, command.command_id);
|
|
210
225
|
syncLogger.command(parsedCommand, "completed", {
|
|
211
226
|
event_count: events.length,
|
|
212
227
|
});
|
|
@@ -133,6 +133,12 @@ export async function applyPendingOrderEvent(event, origin = "local") {
|
|
|
133
133
|
usePendingOrdersStore.getState().addOrder(order);
|
|
134
134
|
const db = await openSyncDatabase();
|
|
135
135
|
await insertEvent(db, { event, origin });
|
|
136
|
+
// Ensure every screen (POS, Orders, Kitchen) sees the optimistic order
|
|
137
|
+
// even when there is no Local Node — TanStack queries that merge pending
|
|
138
|
+
// orders will re-render due to store change, but also invalidate so
|
|
139
|
+
// server-backed lists that are currently cached refresh with the pending
|
|
140
|
+
// overlay.
|
|
141
|
+
invalidator?.();
|
|
136
142
|
return;
|
|
137
143
|
}
|
|
138
144
|
if (QUEUED_STATUS_EVENT_TYPES.has(event.event_type)) {
|
|
@@ -15,7 +15,7 @@ import { localNodeService } from "../adapters/local-node";
|
|
|
15
15
|
import { getSyncDatabase } from "../db/connection";
|
|
16
16
|
import { markEventsSynced } from "../db/operations";
|
|
17
17
|
import { syncLogger } from "../utils/sync-logger";
|
|
18
|
-
import { POS_KEYS, SELLER_KEYS, MENU_KEYS, REFERENCE_KEYS } from "../adapters/query-keys";
|
|
18
|
+
import { POS_KEYS, SELLER_KEYS, KIOSK_KEYS, SELLER_ORDERS_KEYS, BUSINESS_DELIVERIES_KEYS, MENU_KEYS, REFERENCE_KEYS, } from "../adapters/query-keys";
|
|
19
19
|
import { applyReferenceChangeEvent, registerReferenceInvalidator, registerReferenceEventEngine, REFERENCE_CHANGED_EVENT_TYPE, } from "../reference/events";
|
|
20
20
|
function isLocalOrderEvent(event) {
|
|
21
21
|
const payload = event.payload;
|
|
@@ -39,10 +39,14 @@ export function useSyncReconciliation() {
|
|
|
39
39
|
// server-confirmed order replaces the optimistic one. Invalidate from the
|
|
40
40
|
// broadest key: POS_KEYS.orders() without a businessId would produce
|
|
41
41
|
// ['pos','orders',undefined] which does not prefix-match business-scoped
|
|
42
|
-
// keys.
|
|
42
|
+
// keys. Also cover kiosk/seller-orders/business-deliveries so boards
|
|
43
|
+
// refresh even when there is no Local Node (offline queue + Phoenix).
|
|
43
44
|
const unregisterInvalidator = registerPendingOrdersInvalidator(() => {
|
|
44
45
|
queryClient.invalidateQueries({ queryKey: POS_KEYS.all });
|
|
45
46
|
queryClient.invalidateQueries({ queryKey: SELLER_KEYS.all });
|
|
47
|
+
queryClient.invalidateQueries({ queryKey: KIOSK_KEYS.all });
|
|
48
|
+
queryClient.invalidateQueries({ queryKey: SELLER_ORDERS_KEYS.all });
|
|
49
|
+
queryClient.invalidateQueries({ queryKey: BUSINESS_DELIVERIES_KEYS.all });
|
|
46
50
|
});
|
|
47
51
|
// Reference-change events are published through the Sync Engine but are
|
|
48
52
|
// not backed by a command, so the engine has no transport dependency on
|
|
@@ -10,7 +10,7 @@ export declare function setApiBaseUrl(url: string | undefined): void;
|
|
|
10
10
|
export declare function setWsBaseUrl(url: string | undefined): void;
|
|
11
11
|
/** App metadata */
|
|
12
12
|
export declare const APP_NAME = "Teinc Food Business";
|
|
13
|
-
export declare const APP_VERSION = "0.7.
|
|
13
|
+
export declare const APP_VERSION = "0.7.3";
|
|
14
14
|
/** Async storage keys */
|
|
15
15
|
export declare const STORAGE_KEYS: {
|
|
16
16
|
readonly AUTH_TOKEN: "auth_token";
|
|
@@ -49,13 +49,13 @@ export declare const DEFAULT_PAGE_SIZE = 20;
|
|
|
49
49
|
* Keeps the terminal responsive (fast) even when the internet is slow.
|
|
50
50
|
*/
|
|
51
51
|
export declare const CLOUD_COMMAND_TIMEOUT_MS = 2500;
|
|
52
|
-
export declare const appVersion = "0.7.
|
|
52
|
+
export declare const appVersion = "0.7.3";
|
|
53
53
|
/** Default config bundle for createTeincCore overrides */
|
|
54
54
|
export declare const DEFAULTS: {
|
|
55
55
|
readonly API_BASE_URL: string;
|
|
56
56
|
readonly WS_BASE_URL: string;
|
|
57
57
|
readonly APP_NAME: "Teinc Food Business";
|
|
58
|
-
readonly APP_VERSION: "0.7.
|
|
58
|
+
readonly APP_VERSION: "0.7.3";
|
|
59
59
|
readonly STORAGE_KEYS: {
|
|
60
60
|
readonly AUTH_TOKEN: "auth_token";
|
|
61
61
|
readonly REFRESH_TOKEN: "refresh_token";
|
package/dist/utils/constants.js
CHANGED
|
@@ -38,7 +38,7 @@ export function setWsBaseUrl(url) {
|
|
|
38
38
|
}
|
|
39
39
|
/** App metadata */
|
|
40
40
|
export const APP_NAME = "Teinc Food Business";
|
|
41
|
-
export const APP_VERSION = "0.7.
|
|
41
|
+
export const APP_VERSION = "0.7.3";
|
|
42
42
|
/** Async storage keys */
|
|
43
43
|
export const STORAGE_KEYS = {
|
|
44
44
|
AUTH_TOKEN: "auth_token",
|
package/package.json
CHANGED