@teincfood/core 0.9.8 → 0.9.10
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/db/operations.d.ts +1 -1
- package/dist/db/operations.js +6 -1
- package/dist/hooks/delivery.hooks.d.ts +24 -24
- package/dist/hooks/rider.hooks.d.ts +48 -48
- package/dist/hooks/use-infinite-list.d.ts +24 -24
- package/dist/hooks/wallet.hooks.d.ts +24 -24
- package/dist/local-node/service.js +4 -5
- package/dist/printer/receipt.js +1 -5
- package/dist/reference/menu-record.js +3 -2
- package/dist/reference/service.js +11 -3
- package/dist/sync/command-queue.service.d.ts +14 -0
- package/dist/sync/command-queue.service.js +112 -21
- package/dist/sync/engine.js +10 -7
- package/dist/sync/health-probe.d.ts +6 -4
- package/dist/sync/health-probe.js +20 -10
- package/dist/sync/sync-jobs.service.js +70 -7
- package/dist/sync/transport-rest.js +24 -0
- package/dist/test-helpers/memory-driver.js +17 -0
- package/package.json +1 -1
package/dist/db/operations.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface InsertCommandInput {
|
|
|
9
9
|
}
|
|
10
10
|
export declare function insertCommand(db: SQLiteDatabase, input: InsertCommandInput): Promise<PersistedCommand>;
|
|
11
11
|
export declare function getPendingCommands(db: SQLiteDatabase, limit?: number): Promise<PersistedCommand[]>;
|
|
12
|
-
export declare function updateCommandStatus(db: SQLiteDatabase, commandId: string, status: PersistedCommand["status"], error?: string): Promise<void>;
|
|
12
|
+
export declare function updateCommandStatus(db: SQLiteDatabase, commandId: string, status: PersistedCommand["status"], error?: string, incrementRetry?: boolean): Promise<void>;
|
|
13
13
|
export declare function markCommandInFlight(db: SQLiteDatabase, commandId: string): Promise<void>;
|
|
14
14
|
export declare function deleteCommand(db: SQLiteDatabase, commandId: string): Promise<void>;
|
|
15
15
|
export declare function clearCompletedCommands(db: SQLiteDatabase, olderThanHours?: number): Promise<void>;
|
package/dist/db/operations.js
CHANGED
|
@@ -33,7 +33,7 @@ export async function getPendingCommands(db, limit = 100) {
|
|
|
33
33
|
`, limit);
|
|
34
34
|
return rows.map(rowToPersistedCommand);
|
|
35
35
|
}
|
|
36
|
-
export async function updateCommandStatus(db, commandId, status, error) {
|
|
36
|
+
export async function updateCommandStatus(db, commandId, status, error, incrementRetry) {
|
|
37
37
|
const now = new Date().toISOString();
|
|
38
38
|
if (status === "failed") {
|
|
39
39
|
await db.runAsync(`
|
|
@@ -46,6 +46,11 @@ export async function updateCommandStatus(db, commandId, status, error) {
|
|
|
46
46
|
else if (status === "completed") {
|
|
47
47
|
await db.runAsync("UPDATE commands SET status = ?, error = NULL, updated_at = ? WHERE command_id = ?;", status, now, commandId);
|
|
48
48
|
}
|
|
49
|
+
else if (incrementRetry) {
|
|
50
|
+
// Bounded 4xx retries count attempts without failing the row, so
|
|
51
|
+
// MAX_RETRIES caps blind retries while 5xx/network stay indefinite.
|
|
52
|
+
await db.runAsync("UPDATE commands SET status = ?, error = ?, retry_count = retry_count + 1, updated_at = ? WHERE command_id = ?;", status, error ?? null, now, commandId);
|
|
53
|
+
}
|
|
49
54
|
else {
|
|
50
55
|
await db.runAsync("UPDATE commands SET status = ?, error = ?, updated_at = ? WHERE command_id = ?;", status, error ?? null, now, commandId);
|
|
51
56
|
}
|
|
@@ -32,10 +32,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
32
32
|
isRefetching: boolean;
|
|
33
33
|
isStale: boolean;
|
|
34
34
|
isEnabled: boolean;
|
|
35
|
-
refetch: (options?: import("@tanstack/query
|
|
36
|
-
fetchStatus: import("@tanstack/query
|
|
37
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
38
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
35
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
36
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
37
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
38
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
39
39
|
hasNextPage: boolean;
|
|
40
40
|
hasPreviousPage: boolean;
|
|
41
41
|
isFetchingNextPage: boolean;
|
|
@@ -66,10 +66,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
66
66
|
isRefetching: boolean;
|
|
67
67
|
isStale: boolean;
|
|
68
68
|
isEnabled: boolean;
|
|
69
|
-
refetch: (options?: import("@tanstack/query
|
|
70
|
-
fetchStatus: import("@tanstack/query
|
|
71
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
72
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
69
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
70
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
71
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
72
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
73
73
|
hasNextPage: boolean;
|
|
74
74
|
hasPreviousPage: boolean;
|
|
75
75
|
isFetchingNextPage: boolean;
|
|
@@ -101,10 +101,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
101
101
|
isRefetching: boolean;
|
|
102
102
|
isStale: boolean;
|
|
103
103
|
isEnabled: boolean;
|
|
104
|
-
refetch: (options?: import("@tanstack/query
|
|
105
|
-
fetchStatus: import("@tanstack/query
|
|
106
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
107
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
104
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
105
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
106
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
107
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
108
108
|
hasNextPage: boolean;
|
|
109
109
|
hasPreviousPage: boolean;
|
|
110
110
|
isFetchingNextPage: boolean;
|
|
@@ -134,10 +134,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
134
134
|
isRefetching: boolean;
|
|
135
135
|
isStale: boolean;
|
|
136
136
|
isEnabled: boolean;
|
|
137
|
-
refetch: (options?: import("@tanstack/query
|
|
138
|
-
fetchStatus: import("@tanstack/query
|
|
139
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
140
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
137
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
138
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
139
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
140
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
141
141
|
hasNextPage: boolean;
|
|
142
142
|
hasPreviousPage: boolean;
|
|
143
143
|
isFetchingNextPage: boolean;
|
|
@@ -168,10 +168,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
168
168
|
isRefetching: boolean;
|
|
169
169
|
isStale: boolean;
|
|
170
170
|
isEnabled: boolean;
|
|
171
|
-
refetch: (options?: import("@tanstack/query
|
|
172
|
-
fetchStatus: import("@tanstack/query
|
|
173
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
174
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
171
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
172
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
173
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
174
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
175
175
|
hasNextPage: boolean;
|
|
176
176
|
hasPreviousPage: boolean;
|
|
177
177
|
isFetchNextPageError: boolean;
|
|
@@ -202,10 +202,10 @@ export declare function useBusinessDeliveriesQuery(enabled?: boolean, filters?:
|
|
|
202
202
|
isRefetching: boolean;
|
|
203
203
|
isStale: boolean;
|
|
204
204
|
isEnabled: boolean;
|
|
205
|
-
refetch: (options?: import("@tanstack/query
|
|
206
|
-
fetchStatus: import("@tanstack/query
|
|
207
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
208
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
205
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
206
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
207
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
208
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<BusinessDelivery>, unknown>, Error>>;
|
|
209
209
|
hasNextPage: boolean;
|
|
210
210
|
hasPreviousPage: boolean;
|
|
211
211
|
isFetchingNextPage: boolean;
|
|
@@ -47,10 +47,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
47
47
|
isRefetching: boolean;
|
|
48
48
|
isStale: boolean;
|
|
49
49
|
isEnabled: boolean;
|
|
50
|
-
refetch: (options?: import("@tanstack/query
|
|
51
|
-
fetchStatus: import("@tanstack/query
|
|
52
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
53
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
50
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
51
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
52
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
53
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
54
54
|
hasNextPage: boolean;
|
|
55
55
|
hasPreviousPage: boolean;
|
|
56
56
|
isFetchingNextPage: boolean;
|
|
@@ -81,10 +81,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
81
81
|
isRefetching: boolean;
|
|
82
82
|
isStale: boolean;
|
|
83
83
|
isEnabled: boolean;
|
|
84
|
-
refetch: (options?: import("@tanstack/query
|
|
85
|
-
fetchStatus: import("@tanstack/query
|
|
86
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
87
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
84
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
85
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
86
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
87
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
88
88
|
hasNextPage: boolean;
|
|
89
89
|
hasPreviousPage: boolean;
|
|
90
90
|
isFetchingNextPage: boolean;
|
|
@@ -116,10 +116,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
116
116
|
isRefetching: boolean;
|
|
117
117
|
isStale: boolean;
|
|
118
118
|
isEnabled: boolean;
|
|
119
|
-
refetch: (options?: import("@tanstack/query
|
|
120
|
-
fetchStatus: import("@tanstack/query
|
|
121
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
122
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
119
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
120
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
121
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
122
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
123
123
|
hasNextPage: boolean;
|
|
124
124
|
hasPreviousPage: boolean;
|
|
125
125
|
isFetchingNextPage: boolean;
|
|
@@ -149,10 +149,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
149
149
|
isRefetching: boolean;
|
|
150
150
|
isStale: boolean;
|
|
151
151
|
isEnabled: boolean;
|
|
152
|
-
refetch: (options?: import("@tanstack/query
|
|
153
|
-
fetchStatus: import("@tanstack/query
|
|
154
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
155
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
152
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
153
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
154
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
155
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
156
156
|
hasNextPage: boolean;
|
|
157
157
|
hasPreviousPage: boolean;
|
|
158
158
|
isFetchingNextPage: boolean;
|
|
@@ -183,10 +183,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
183
183
|
isRefetching: boolean;
|
|
184
184
|
isStale: boolean;
|
|
185
185
|
isEnabled: boolean;
|
|
186
|
-
refetch: (options?: import("@tanstack/query
|
|
187
|
-
fetchStatus: import("@tanstack/query
|
|
188
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
189
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
186
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
187
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
188
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
189
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
190
190
|
hasNextPage: boolean;
|
|
191
191
|
hasPreviousPage: boolean;
|
|
192
192
|
isFetchNextPageError: boolean;
|
|
@@ -217,10 +217,10 @@ export declare function useRiderDeliveriesQuery(enabled?: boolean, filters?: {
|
|
|
217
217
|
isRefetching: boolean;
|
|
218
218
|
isStale: boolean;
|
|
219
219
|
isEnabled: boolean;
|
|
220
|
-
refetch: (options?: import("@tanstack/query
|
|
221
|
-
fetchStatus: import("@tanstack/query
|
|
222
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
223
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
220
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
221
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
222
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
223
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<RiderDelivery>, unknown>, Error>>;
|
|
224
224
|
hasNextPage: boolean;
|
|
225
225
|
hasPreviousPage: boolean;
|
|
226
226
|
isFetchingNextPage: boolean;
|
|
@@ -261,10 +261,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
261
261
|
isRefetching: boolean;
|
|
262
262
|
isStale: boolean;
|
|
263
263
|
isEnabled: boolean;
|
|
264
|
-
refetch: (options?: import("@tanstack/query
|
|
265
|
-
fetchStatus: import("@tanstack/query
|
|
266
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
267
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
264
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
265
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
266
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
267
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
268
268
|
hasNextPage: boolean;
|
|
269
269
|
hasPreviousPage: boolean;
|
|
270
270
|
isFetchingNextPage: boolean;
|
|
@@ -295,10 +295,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
295
295
|
isRefetching: boolean;
|
|
296
296
|
isStale: boolean;
|
|
297
297
|
isEnabled: boolean;
|
|
298
|
-
refetch: (options?: import("@tanstack/query
|
|
299
|
-
fetchStatus: import("@tanstack/query
|
|
300
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
301
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
298
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
299
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
300
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
301
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
302
302
|
hasNextPage: boolean;
|
|
303
303
|
hasPreviousPage: boolean;
|
|
304
304
|
isFetchingNextPage: boolean;
|
|
@@ -330,10 +330,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
330
330
|
isRefetching: boolean;
|
|
331
331
|
isStale: boolean;
|
|
332
332
|
isEnabled: boolean;
|
|
333
|
-
refetch: (options?: import("@tanstack/query
|
|
334
|
-
fetchStatus: import("@tanstack/query
|
|
335
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
336
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
333
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
334
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
335
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
336
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
337
337
|
hasNextPage: boolean;
|
|
338
338
|
hasPreviousPage: boolean;
|
|
339
339
|
isFetchingNextPage: boolean;
|
|
@@ -363,10 +363,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
363
363
|
isRefetching: boolean;
|
|
364
364
|
isStale: boolean;
|
|
365
365
|
isEnabled: boolean;
|
|
366
|
-
refetch: (options?: import("@tanstack/query
|
|
367
|
-
fetchStatus: import("@tanstack/query
|
|
368
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
369
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
366
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
367
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
368
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
369
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
370
370
|
hasNextPage: boolean;
|
|
371
371
|
hasPreviousPage: boolean;
|
|
372
372
|
isFetchingNextPage: boolean;
|
|
@@ -397,10 +397,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
397
397
|
isRefetching: boolean;
|
|
398
398
|
isStale: boolean;
|
|
399
399
|
isEnabled: boolean;
|
|
400
|
-
refetch: (options?: import("@tanstack/query
|
|
401
|
-
fetchStatus: import("@tanstack/query
|
|
402
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
403
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
400
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
401
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
402
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
403
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
404
404
|
hasNextPage: boolean;
|
|
405
405
|
hasPreviousPage: boolean;
|
|
406
406
|
isFetchNextPageError: boolean;
|
|
@@ -431,10 +431,10 @@ export declare function useRiderWalletHistoryQuery(enabled?: boolean): {
|
|
|
431
431
|
isRefetching: boolean;
|
|
432
432
|
isStale: boolean;
|
|
433
433
|
isEnabled: boolean;
|
|
434
|
-
refetch: (options?: import("@tanstack/query
|
|
435
|
-
fetchStatus: import("@tanstack/query
|
|
436
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
437
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
434
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
435
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
436
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
437
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<Record<string, unknown>>, unknown>, Error>>;
|
|
438
438
|
hasNextPage: boolean;
|
|
439
439
|
hasPreviousPage: boolean;
|
|
440
440
|
isFetchingNextPage: boolean;
|
|
@@ -50,10 +50,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
50
50
|
isRefetching: boolean;
|
|
51
51
|
isStale: boolean;
|
|
52
52
|
isEnabled: boolean;
|
|
53
|
-
refetch: (options?: import("@tanstack/query
|
|
54
|
-
fetchStatus: import("@tanstack/query
|
|
55
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
56
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
53
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
54
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
55
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
56
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
57
57
|
hasNextPage: boolean;
|
|
58
58
|
hasPreviousPage: boolean;
|
|
59
59
|
isFetchingNextPage: boolean;
|
|
@@ -84,10 +84,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
84
84
|
isRefetching: boolean;
|
|
85
85
|
isStale: boolean;
|
|
86
86
|
isEnabled: boolean;
|
|
87
|
-
refetch: (options?: import("@tanstack/query
|
|
88
|
-
fetchStatus: import("@tanstack/query
|
|
89
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
90
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
87
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
88
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
89
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
90
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
91
91
|
hasNextPage: boolean;
|
|
92
92
|
hasPreviousPage: boolean;
|
|
93
93
|
isFetchingNextPage: boolean;
|
|
@@ -119,10 +119,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
119
119
|
isRefetching: boolean;
|
|
120
120
|
isStale: boolean;
|
|
121
121
|
isEnabled: boolean;
|
|
122
|
-
refetch: (options?: import("@tanstack/query
|
|
123
|
-
fetchStatus: import("@tanstack/query
|
|
124
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
125
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
122
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
123
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
124
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
125
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
126
126
|
hasNextPage: boolean;
|
|
127
127
|
hasPreviousPage: boolean;
|
|
128
128
|
isFetchingNextPage: boolean;
|
|
@@ -152,10 +152,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
152
152
|
isRefetching: boolean;
|
|
153
153
|
isStale: boolean;
|
|
154
154
|
isEnabled: boolean;
|
|
155
|
-
refetch: (options?: import("@tanstack/query
|
|
156
|
-
fetchStatus: import("@tanstack/query
|
|
157
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
158
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
155
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
156
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
157
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
158
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
159
159
|
hasNextPage: boolean;
|
|
160
160
|
hasPreviousPage: boolean;
|
|
161
161
|
isFetchingNextPage: boolean;
|
|
@@ -186,10 +186,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
186
186
|
isRefetching: boolean;
|
|
187
187
|
isStale: boolean;
|
|
188
188
|
isEnabled: boolean;
|
|
189
|
-
refetch: (options?: import("@tanstack/query
|
|
190
|
-
fetchStatus: import("@tanstack/query
|
|
191
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
192
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
189
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
190
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
191
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
192
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
193
193
|
hasNextPage: boolean;
|
|
194
194
|
hasPreviousPage: boolean;
|
|
195
195
|
isFetchNextPageError: boolean;
|
|
@@ -220,10 +220,10 @@ export declare function useInfiniteList<T>(options: InfiniteListOptions<T>): {
|
|
|
220
220
|
isRefetching: boolean;
|
|
221
221
|
isStale: boolean;
|
|
222
222
|
isEnabled: boolean;
|
|
223
|
-
refetch: (options?: import("@tanstack/query
|
|
224
|
-
fetchStatus: import("@tanstack/query
|
|
225
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
226
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
223
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
224
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
225
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
226
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<ListPage<T>, unknown>, Error>>;
|
|
227
227
|
hasNextPage: boolean;
|
|
228
228
|
hasPreviousPage: boolean;
|
|
229
229
|
isFetchingNextPage: boolean;
|
|
@@ -26,10 +26,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
26
26
|
isRefetching: boolean;
|
|
27
27
|
isStale: boolean;
|
|
28
28
|
isEnabled: boolean;
|
|
29
|
-
refetch: (options?: import("@tanstack/query
|
|
30
|
-
fetchStatus: import("@tanstack/query
|
|
31
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
32
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
29
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
30
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
31
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
32
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
33
33
|
hasNextPage: boolean;
|
|
34
34
|
hasPreviousPage: boolean;
|
|
35
35
|
isFetchingNextPage: boolean;
|
|
@@ -60,10 +60,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
60
60
|
isRefetching: boolean;
|
|
61
61
|
isStale: boolean;
|
|
62
62
|
isEnabled: boolean;
|
|
63
|
-
refetch: (options?: import("@tanstack/query
|
|
64
|
-
fetchStatus: import("@tanstack/query
|
|
65
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
66
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
63
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
64
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
65
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
66
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
67
67
|
hasNextPage: boolean;
|
|
68
68
|
hasPreviousPage: boolean;
|
|
69
69
|
isFetchingNextPage: boolean;
|
|
@@ -95,10 +95,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
95
95
|
isRefetching: boolean;
|
|
96
96
|
isStale: boolean;
|
|
97
97
|
isEnabled: boolean;
|
|
98
|
-
refetch: (options?: import("@tanstack/query
|
|
99
|
-
fetchStatus: import("@tanstack/query
|
|
100
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
101
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
98
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
99
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
100
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
101
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
102
102
|
hasNextPage: boolean;
|
|
103
103
|
hasPreviousPage: boolean;
|
|
104
104
|
isFetchingNextPage: boolean;
|
|
@@ -128,10 +128,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
128
128
|
isRefetching: boolean;
|
|
129
129
|
isStale: boolean;
|
|
130
130
|
isEnabled: boolean;
|
|
131
|
-
refetch: (options?: import("@tanstack/query
|
|
132
|
-
fetchStatus: import("@tanstack/query
|
|
133
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
134
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
131
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
132
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
133
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
134
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
135
135
|
hasNextPage: boolean;
|
|
136
136
|
hasPreviousPage: boolean;
|
|
137
137
|
isFetchingNextPage: boolean;
|
|
@@ -162,10 +162,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
162
162
|
isRefetching: boolean;
|
|
163
163
|
isStale: boolean;
|
|
164
164
|
isEnabled: boolean;
|
|
165
|
-
refetch: (options?: import("@tanstack/query
|
|
166
|
-
fetchStatus: import("@tanstack/query
|
|
167
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
168
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
165
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
166
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
167
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
168
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
169
169
|
hasNextPage: boolean;
|
|
170
170
|
hasPreviousPage: boolean;
|
|
171
171
|
isFetchNextPageError: boolean;
|
|
@@ -196,10 +196,10 @@ export declare function useWalletHistoryQuery(enabled?: boolean): {
|
|
|
196
196
|
isRefetching: boolean;
|
|
197
197
|
isStale: boolean;
|
|
198
198
|
isEnabled: boolean;
|
|
199
|
-
refetch: (options?: import("@tanstack/query
|
|
200
|
-
fetchStatus: import("@tanstack/query
|
|
201
|
-
fetchNextPage: (options?: import("@tanstack/query
|
|
202
|
-
fetchPreviousPage: (options?: import("@tanstack/query
|
|
199
|
+
refetch: (options?: import("@tanstack/react-query").RefetchOptions) => Promise<import("@tanstack/react-query").QueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
200
|
+
fetchStatus: import("@tanstack/react-query").FetchStatus;
|
|
201
|
+
fetchNextPage: (options?: import("@tanstack/react-query").FetchNextPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
202
|
+
fetchPreviousPage: (options?: import("@tanstack/react-query").FetchPreviousPageOptions) => Promise<import("@tanstack/react-query").InfiniteQueryObserverResult<import("@tanstack/react-query").InfiniteData<import("./use-infinite-list").ListPage<WalletEntry>, unknown>, Error>>;
|
|
203
203
|
hasNextPage: boolean;
|
|
204
204
|
hasPreviousPage: boolean;
|
|
205
205
|
isFetchingNextPage: boolean;
|
|
@@ -13,7 +13,7 @@ import { applyReferenceChangeEvent } from "../reference/events";
|
|
|
13
13
|
import { openSyncDatabase } from "../db/connection";
|
|
14
14
|
import { insertOrder } from "../db/operations";
|
|
15
15
|
import { createLocalOrder, transitionLocalOrder } from "../domain/orders/service";
|
|
16
|
-
import { getConnectivityState
|
|
16
|
+
import { getConnectivityState } from "../adapters/connectivity";
|
|
17
17
|
import { deriveLanSecret as deriveSecretCore } from "./security";
|
|
18
18
|
const KEEP_AWAKE_TAG = "TeincLocalNode";
|
|
19
19
|
const RECONNECT_BASE = 1000;
|
|
@@ -742,11 +742,10 @@ class LocalNodeServiceCore {
|
|
|
742
742
|
rejectionStatus < 500) {
|
|
743
743
|
throw error;
|
|
744
744
|
}
|
|
745
|
+
// Flag-neutral (probe owns isCloudReachable): a failed forward is
|
|
746
|
+
// never evidence the cloud is down. Fall back to the queue; the
|
|
747
|
+
// probe detects real outages and replays trigger on recovery.
|
|
745
748
|
syncLogger.warn("LocalNodeService", "Cloud forward failed, queueing", { error: String(error) });
|
|
746
|
-
try {
|
|
747
|
-
setConnectivityState({ isCloudReachable: "unreachable" });
|
|
748
|
-
}
|
|
749
|
-
catch { }
|
|
750
749
|
event = await commandQueueService.enqueue(command);
|
|
751
750
|
}
|
|
752
751
|
}
|
package/dist/printer/receipt.js
CHANGED
|
@@ -421,7 +421,6 @@ export function generateEscpos(order, logoRasterB64) {
|
|
|
421
421
|
push(LF);
|
|
422
422
|
// Footer — template §4 company block (centered, never truncated)
|
|
423
423
|
const company = getCompanyInfo();
|
|
424
|
-
const contactLine = `${company.address} | ${company.phone}`;
|
|
425
424
|
push(ESC_ALIGN_CENTER);
|
|
426
425
|
pushT(paymentLineEscpos(order));
|
|
427
426
|
push(LF);
|
|
@@ -430,9 +429,6 @@ export function generateEscpos(order, logoRasterB64) {
|
|
|
430
429
|
push("Thank you for your order!" + LF);
|
|
431
430
|
push("Come back soon!" + LF);
|
|
432
431
|
push(LF);
|
|
433
|
-
pushT(company.brand + LF);
|
|
434
|
-
pushT(contactLine + LF);
|
|
435
|
-
pushT(company.supportEmail + LF);
|
|
436
432
|
pushT(company.website + LF);
|
|
437
433
|
pushT(`Powered by ${company.name}` + LF);
|
|
438
434
|
push(ESC_FEED_3);
|
|
@@ -585,7 +581,7 @@ export function generateHtml(order, logoDataUri) {
|
|
|
585
581
|
</div>
|
|
586
582
|
<div class="footer">
|
|
587
583
|
Thank you for your order!<br>Come back soon!
|
|
588
|
-
<br><br>${escHtml(company.
|
|
584
|
+
<br><br>${escHtml(company.website)}<br>Powered by ${escHtml(company.name)}
|
|
589
585
|
</div>
|
|
590
586
|
</body></html>`;
|
|
591
587
|
}
|
|
@@ -114,8 +114,9 @@ export function getCachedCategoryName(qc, businessId, categoryId) {
|
|
|
114
114
|
}
|
|
115
115
|
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
116
116
|
/**
|
|
117
|
-
* A variant/extra id is only safe to send when it is a real
|
|
118
|
-
*
|
|
117
|
+
* A variant/extra id is only safe to send when it is a real UUID. Single
|
|
118
|
+
* global id space: clients generate UUIDs up front and the backend stores
|
|
119
|
+
* them verbatim. Non-UUID junk must be omitted: the backend treats a
|
|
119
120
|
* missing/empty id as "insert new", but Repo.get/3 raises on a non-UUID.
|
|
120
121
|
*/
|
|
121
122
|
function wireId(id) {
|
|
@@ -19,6 +19,11 @@ import { anchorServerTime } from "./entitlement-clock";
|
|
|
19
19
|
import { isServerAuthoritativeKey } from "./entitlements";
|
|
20
20
|
import { fetchReferenceVersions, fetchReferenceData, fetchReferenceChanges, } from "./api";
|
|
21
21
|
const DEFAULT_SYNC_KEYS = [
|
|
22
|
+
// Server-authoritative plan proof first: every gated command evaluates
|
|
23
|
+
// against this, so it must never starve behind slow/heavy keys (menu
|
|
24
|
+
// pagination). Capabilities second for the same reason (nav + guards).
|
|
25
|
+
"subscription:entitlements",
|
|
26
|
+
"capabilities",
|
|
22
27
|
"menu:items",
|
|
23
28
|
"menu:categories",
|
|
24
29
|
"roles",
|
|
@@ -28,8 +33,6 @@ const DEFAULT_SYNC_KEYS = [
|
|
|
28
33
|
"operating-hours",
|
|
29
34
|
"delivery-settings",
|
|
30
35
|
"payment-settings",
|
|
31
|
-
"subscription:entitlements",
|
|
32
|
-
"capabilities",
|
|
33
36
|
];
|
|
34
37
|
class ReferenceSyncService {
|
|
35
38
|
constructor() {
|
|
@@ -193,6 +196,11 @@ class ReferenceSyncService {
|
|
|
193
196
|
await anchorServerTime(envelope.server_time);
|
|
194
197
|
}
|
|
195
198
|
catch { }
|
|
199
|
+
syncLogger.info("ReferenceSync", `Server-authoritative ${key} cached`, {
|
|
200
|
+
businessId,
|
|
201
|
+
version: envelope.version,
|
|
202
|
+
server_time: envelope.server_time,
|
|
203
|
+
});
|
|
196
204
|
return wrote;
|
|
197
205
|
}
|
|
198
206
|
await mergeReferenceData(db, businessId, key, payload, hlc, `evt_${hlc}`);
|
|
@@ -368,7 +376,7 @@ class ReferenceSyncService {
|
|
|
368
376
|
hash = (hash << 5) - hash + char;
|
|
369
377
|
hash |= 0;
|
|
370
378
|
}
|
|
371
|
-
return `
|
|
379
|
+
return `hash-${Math.abs(hash).toString(16)}`;
|
|
372
380
|
}
|
|
373
381
|
async getCached(businessId, key) {
|
|
374
382
|
const db = await openSyncDatabase();
|
|
@@ -24,6 +24,20 @@ declare class CommandQueueService {
|
|
|
24
24
|
* Try to execute a single pending command through the current transport.
|
|
25
25
|
*/
|
|
26
26
|
processCommand(command: PersistedCommand): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Mark a command permanently failed: loud toast + optimistic revert, then
|
|
29
|
+
* replay continues to the next command. Shared by the exhausted-retry and
|
|
30
|
+
* permanent-rejection paths.
|
|
31
|
+
*/
|
|
32
|
+
private failPermanently;
|
|
33
|
+
/**
|
|
34
|
+
* Already-applied absorb: pull server truth, and if the order is already
|
|
35
|
+
* at this command's target status, delete the command as success. The
|
|
36
|
+
* absorb ONLY fires when the pull actually touched the row (hlc change) —
|
|
37
|
+
* otherwise a stale local optimistic write could mask a genuine race and
|
|
38
|
+
* delete work the server never applied.
|
|
39
|
+
*/
|
|
40
|
+
private absorbIfApplied;
|
|
27
41
|
/**
|
|
28
42
|
* Replay all pending commands in order. Stops on the first failure to keep
|
|
29
43
|
* ordering consistent; the next replay will retry from the failed command.
|
|
@@ -19,7 +19,18 @@ import { generateEventId } from "../utils/uuid";
|
|
|
19
19
|
import { generateLocalCalloutNumber, generateOrderNumberForBusiness, generateOrderNumber, } from "./order-number";
|
|
20
20
|
import { getConnectivityState, subscribeConnectivity } from "../adapters/connectivity";
|
|
21
21
|
import { canBusinessSync } from "./sync-guard";
|
|
22
|
+
import { backoffDelayMs } from "./backoff";
|
|
22
23
|
const MAX_RETRIES = 5;
|
|
24
|
+
/**
|
|
25
|
+
* 4xx that deserve another chance: transient races and rate limits, never
|
|
26
|
+
* permanent verdicts. Anything else 4xx (400 validation, 401 session,
|
|
27
|
+
* 402 plan, 403 forbidden) fails fast with a toast. 409 ORDER_NUMBER_TAKEN
|
|
28
|
+
* has its own regen path below and is not capped (every attempt mints a
|
|
29
|
+
* new order number, so it is never a blind retry).
|
|
30
|
+
*/
|
|
31
|
+
const RETRYABLE_4XX = new Set([404, 408, 409, 422, 429]);
|
|
32
|
+
/** In-memory next-eligible time per command (shared 2s→5min curve). */
|
|
33
|
+
const retryNotBefore = new Map();
|
|
23
34
|
const QUEUED_STATUS_BY_COMMAND = {
|
|
24
35
|
"order:accept": "accepted",
|
|
25
36
|
"order:reject": "cancelled",
|
|
@@ -268,6 +279,12 @@ class CommandQueueService {
|
|
|
268
279
|
await updateCommandStatus(db, command.command_id, "failed", "Max retry count exceeded");
|
|
269
280
|
return;
|
|
270
281
|
}
|
|
282
|
+
// Backoff pacing for retryable failures: the next replay skips (defers)
|
|
283
|
+
// this command until its slot, preserving FIFO without a hot loop.
|
|
284
|
+
const notBefore = retryNotBefore.get(command.command_id);
|
|
285
|
+
if (notBefore !== undefined && notBefore > Date.now()) {
|
|
286
|
+
throw new TransitionError(TRANSITION_ERROR_CODES.REPLAY_DEFERRED, "In retry backoff, deferring queued command");
|
|
287
|
+
}
|
|
271
288
|
if (!this.syncEngine) {
|
|
272
289
|
throw new Error("CommandQueueService: SyncEngine not initialized");
|
|
273
290
|
}
|
|
@@ -323,31 +340,45 @@ class CommandQueueService {
|
|
|
323
340
|
await updateCommandStatus(db, command.command_id, "failed", `order_number_taken:${message}`);
|
|
324
341
|
throw error;
|
|
325
342
|
}
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
status: apiErr.status,
|
|
335
|
-
error: message,
|
|
336
|
-
});
|
|
337
|
-
// Loud toast + revert: the optimistic local write is rolled back so
|
|
338
|
-
// the UI never shows what the backend refused.
|
|
343
|
+
const status = typeof apiErr?.status === "number" ? apiErr.status : undefined;
|
|
344
|
+
// Already-applied absorb: a 422/404 against an order the server
|
|
345
|
+
// already moved (duplicate tap, earlier drain won the race) is
|
|
346
|
+
// success, not failure. Verified against server truth via pull
|
|
347
|
+
// (HLC-guarded: pulled rows overwrite local), never the optimistic row.
|
|
348
|
+
if (status === 422 ||
|
|
349
|
+
code === "INVALID_TRANSITION" ||
|
|
350
|
+
(status === 404 && command.command_type !== "order:create")) {
|
|
339
351
|
try {
|
|
340
|
-
|
|
341
|
-
|
|
352
|
+
if (await this.absorbIfApplied(command))
|
|
353
|
+
return;
|
|
342
354
|
}
|
|
343
355
|
catch { }
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
356
|
+
}
|
|
357
|
+
// Retryable 4xx (FIFO races, rate limits): back off on the shared
|
|
358
|
+
// 2s→5min curve, then fail loudly after MAX_RETRIES. Throw a
|
|
359
|
+
// transport-neutral deferral so replay STOPS here (FIFO ordering) —
|
|
360
|
+
// rethrowing the 4xx itself would make the loop `continue` past it.
|
|
361
|
+
if (status !== undefined && RETRYABLE_4XX.has(status)) {
|
|
362
|
+
const attempts = command.retry_count + 1;
|
|
363
|
+
if (attempts >= MAX_RETRIES) {
|
|
364
|
+
await this.failPermanently(db, command, message, `retryable 4xx exhausted after ${attempts} attempts`);
|
|
365
|
+
return;
|
|
349
366
|
}
|
|
350
|
-
|
|
367
|
+
retryNotBefore.set(command.command_id, Date.now() + backoffDelayMs(command.retry_count));
|
|
368
|
+
await updateCommandStatus(db, command.command_id, "pending", `retry_4xx:${message}`, true);
|
|
369
|
+
syncLogger.warn("CommandQueueService", "Retryable 4xx — backing off", {
|
|
370
|
+
command_id: command.command_id,
|
|
371
|
+
command_type: command.command_type,
|
|
372
|
+
status,
|
|
373
|
+
attempt: attempts,
|
|
374
|
+
});
|
|
375
|
+
throw new TransitionError(TRANSITION_ERROR_CODES.REPLAY_DEFERRED, `Retryable ${status} on ${command.command_type}, backing off`);
|
|
376
|
+
}
|
|
377
|
+
const isNonRetryable = status !== undefined &&
|
|
378
|
+
status >= 400 &&
|
|
379
|
+
status < 500;
|
|
380
|
+
if (isNonRetryable) {
|
|
381
|
+
await this.failPermanently(db, command, message, "permanent 4xx");
|
|
351
382
|
// Do not throw — allow replay to continue to next command.
|
|
352
383
|
return;
|
|
353
384
|
}
|
|
@@ -360,6 +391,66 @@ class CommandQueueService {
|
|
|
360
391
|
throw error;
|
|
361
392
|
}
|
|
362
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* Mark a command permanently failed: loud toast + optimistic revert, then
|
|
396
|
+
* replay continues to the next command. Shared by the exhausted-retry and
|
|
397
|
+
* permanent-rejection paths.
|
|
398
|
+
*/
|
|
399
|
+
async failPermanently(db, command, message, reason) {
|
|
400
|
+
await updateCommandStatus(db, command.command_id, "failed", `permanent:${message}`);
|
|
401
|
+
syncLogger.warn("CommandQueueService", `Queued command failed (${reason})`, {
|
|
402
|
+
command_id: command.command_id,
|
|
403
|
+
command_type: command.command_type,
|
|
404
|
+
error: message,
|
|
405
|
+
});
|
|
406
|
+
try {
|
|
407
|
+
const { notifyError } = await import("../adapters/notify");
|
|
408
|
+
notifyError(`Server rejected ${command.command_type}: ${message}`);
|
|
409
|
+
}
|
|
410
|
+
catch { }
|
|
411
|
+
try {
|
|
412
|
+
if (command.command_type.startsWith("menu:") && command.entity_id) {
|
|
413
|
+
const { revertMenuCommand } = await import("../reference/menu-apply");
|
|
414
|
+
await revertMenuCommand(command.business_id, command.command_type, command.entity_id);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch { }
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Already-applied absorb: pull server truth, and if the order is already
|
|
421
|
+
* at this command's target status, delete the command as success. The
|
|
422
|
+
* absorb ONLY fires when the pull actually touched the row (hlc change) —
|
|
423
|
+
* otherwise a stale local optimistic write could mask a genuine race and
|
|
424
|
+
* delete work the server never applied.
|
|
425
|
+
*/
|
|
426
|
+
async absorbIfApplied(command) {
|
|
427
|
+
const target = QUEUED_STATUS_BY_COMMAND[command.command_type];
|
|
428
|
+
if (!target || !command.entity_id)
|
|
429
|
+
return false;
|
|
430
|
+
try {
|
|
431
|
+
const db = getSyncDatabase();
|
|
432
|
+
const before = await db.getFirstAsync(`SELECT hlc FROM orders WHERE business_id = ? AND id = ?;`, command.business_id, command.entity_id);
|
|
433
|
+
const { pullRemoteOrders } = await import("./sync-jobs.service");
|
|
434
|
+
await pullRemoteOrders(command.business_id);
|
|
435
|
+
const afterHlc = await db.getFirstAsync(`SELECT hlc FROM orders WHERE business_id = ? AND id = ?;`, command.business_id, command.entity_id);
|
|
436
|
+
if (!afterHlc || afterHlc.hlc === before?.hlc)
|
|
437
|
+
return false;
|
|
438
|
+
const { getOrderById } = await import("../db/operations");
|
|
439
|
+
const order = await getOrderById(db, command.business_id, command.entity_id);
|
|
440
|
+
if (order && order.status === target) {
|
|
441
|
+
await deleteCommand(db, command.command_id);
|
|
442
|
+
retryNotBefore.delete(command.command_id);
|
|
443
|
+
syncLogger.info("CommandQueueService", "Transition already applied on server, absorbing", {
|
|
444
|
+
command_id: command.command_id,
|
|
445
|
+
command_type: command.command_type,
|
|
446
|
+
status: target,
|
|
447
|
+
});
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch { }
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
363
454
|
/**
|
|
364
455
|
* Replay all pending commands in order. Stops on the first failure to keep
|
|
365
456
|
* ordering consistent; the next replay will retry from the failed command.
|
package/dist/sync/engine.js
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { restTransport } from "./transport-rest";
|
|
15
15
|
import { localNodeTransport } from "./transport-local-node";
|
|
16
16
|
import { commandQueueService } from "./command-queue.service";
|
|
17
|
-
import { getConnectivityState
|
|
17
|
+
import { getConnectivityState } from "../adapters/connectivity";
|
|
18
18
|
import { ApiError } from "../adapters/http";
|
|
19
19
|
import { errorCodeOf } from "./transition-errors";
|
|
20
20
|
import { syncLogger } from "../utils/sync-logger";
|
|
@@ -155,9 +155,9 @@ export class SyncEngine {
|
|
|
155
155
|
syncLogger.command(command, "completed", {
|
|
156
156
|
event_count: events.length,
|
|
157
157
|
});
|
|
158
|
-
// Cloud just worked:
|
|
159
|
-
//
|
|
160
|
-
|
|
158
|
+
// Cloud just worked: replay anything queued during the outage.
|
|
159
|
+
// Flag-neutral: only the health probe writes isCloudReachable — a
|
|
160
|
+
// single success here is not its decision to make either.
|
|
161
161
|
this.replayQueuedCommands().catch((error) => {
|
|
162
162
|
syncLogger.error("SyncEngine", "Replay after cloud success failed", {
|
|
163
163
|
error: String(error),
|
|
@@ -199,13 +199,16 @@ export class SyncEngine {
|
|
|
199
199
|
});
|
|
200
200
|
throw error;
|
|
201
201
|
}
|
|
202
|
-
// Cloud is slow or unreachable:
|
|
203
|
-
//
|
|
202
|
+
// Cloud is slow or unreachable: fall back to the Local Node or the
|
|
203
|
+
// outbox so the terminal stays responsive. Flag-neutral: only the
|
|
204
|
+
// health probe writes isCloudReachable — a failed request is never
|
|
205
|
+
// evidence the cloud is down (it may be a logic rejection without a
|
|
206
|
+
// numeric status, e.g. TransitionError). The probe detects real
|
|
207
|
+
// outages; queued work replays when it reports recovery.
|
|
204
208
|
syncLogger.warn("SyncEngine", "Cloud command timed out, falling back", {
|
|
205
209
|
command_type: command.command_type,
|
|
206
210
|
error: String(error),
|
|
207
211
|
});
|
|
208
|
-
setConnectivityState({ isCloudReachable: "unreachable" });
|
|
209
212
|
strategy = this.resolveStrategy(command);
|
|
210
213
|
if (strategy === "queue") {
|
|
211
214
|
// Replays must never re-enqueue-then-delete (the command would eat
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core Health Probe — periodic cloud reachability check.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* SOLE OWNER of the `isCloudReachable` flag: success marks reachable
|
|
5
|
+
* (triggers sync replay via connectivity subscribers), failure marks
|
|
6
|
+
* unreachable and schedules a retry with exponential backoff (15s floor →
|
|
7
|
+
* 5min cap, ±20% jitter). No request path may write the flag — a single
|
|
8
|
+
* failed request is never evidence the cloud is down (see SyncEngine,
|
|
9
|
+
* LocalNodeService), so all failure handling there is flag-neutral.
|
|
8
10
|
*
|
|
9
11
|
* Started automatically by `createTeincCore()`. Host apps should not need
|
|
10
12
|
* to call this directly.
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core Health Probe — periodic cloud reachability check.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* SOLE OWNER of the `isCloudReachable` flag: success marks reachable
|
|
5
|
+
* (triggers sync replay via connectivity subscribers), failure marks
|
|
6
|
+
* unreachable and schedules a retry with exponential backoff (15s floor →
|
|
7
|
+
* 5min cap, ±20% jitter). No request path may write the flag — a single
|
|
8
|
+
* failed request is never evidence the cloud is down (see SyncEngine,
|
|
9
|
+
* LocalNodeService), so all failure handling there is flag-neutral.
|
|
8
10
|
*
|
|
9
11
|
* Started automatically by `createTeincCore()`. Host apps should not need
|
|
10
12
|
* to call this directly.
|
|
@@ -62,12 +64,20 @@ export async function probeCloudHealth() {
|
|
|
62
64
|
return true;
|
|
63
65
|
}
|
|
64
66
|
catch {
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
// Sole owner rule: the probe is the only writer of isCloudReachable.
|
|
68
|
+
// A failed probe IS evidence (dedicated check, short timeout), unlike a
|
|
69
|
+
// failed business request — mark unreachable so readers stop attempting
|
|
70
|
+
// cloud work until recovery is detected. Backoff bounds the retry rate.
|
|
71
|
+
const was = getConnectivityState().isCloudReachable;
|
|
72
|
+
if (was !== "unreachable") {
|
|
73
|
+
setCloudReachable("unreachable");
|
|
74
|
+
syncLogger.info("HealthProbe", "Cloud unreachable", { previous: was });
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
syncLogger.debug("HealthProbe", "Probe failed — still unreachable, will retry", {
|
|
78
|
+
previous: was,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
71
81
|
scheduleRetry();
|
|
72
82
|
return false;
|
|
73
83
|
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Core-only, single in_flight per business, coalesced via isOnline gate.
|
|
5
5
|
*/
|
|
6
6
|
import { openSyncDatabase } from "../db/connection";
|
|
7
|
-
import { insertOrder } from "../db/operations";
|
|
7
|
+
import { insertOrder, getOrderById } from "../db/operations";
|
|
8
8
|
import { getConnectivityState, subscribeConnectivity } from "../adapters/connectivity";
|
|
9
9
|
import { getRefreshToken, setAuthTokens, clearAuth, subscribeAuth } from "../adapters/auth";
|
|
10
10
|
import { getActiveBusiness, subscribeBusiness } from "../adapters/business";
|
|
@@ -16,11 +16,14 @@ import { BackoffTracker } from "./backoff";
|
|
|
16
16
|
import { generateOrderNumber } from "./order-number";
|
|
17
17
|
import { orderSnapshotsService } from "./order-snapshots.service";
|
|
18
18
|
import { getTransitionPath, DELIVERY_COMMANDS } from "./transition-endpoints";
|
|
19
|
+
import { getQueuedStatus } from "../utils/order-transitions";
|
|
19
20
|
import { extractApiErrorCode } from "../utils/error";
|
|
20
21
|
import { canBusinessSync, isAuthenticated } from "./sync-guard";
|
|
21
22
|
const inflight = new Map();
|
|
22
23
|
const retryTimers = new Map();
|
|
23
24
|
const backoffTracker = new BackoffTracker();
|
|
25
|
+
/** Blind 4xx retries stop here, loudly. 5xx/network retry indefinitely. */
|
|
26
|
+
const MAX_SYNC_JOB_ATTEMPTS = 5;
|
|
24
27
|
function isOnline() {
|
|
25
28
|
const s = getConnectivityState();
|
|
26
29
|
return s.isOnline && s.isCloudReachable !== "unreachable";
|
|
@@ -215,6 +218,34 @@ async function tryRest(businessId, payload, commandType) {
|
|
|
215
218
|
};
|
|
216
219
|
}
|
|
217
220
|
}
|
|
221
|
+
/**
|
|
222
|
+
* Already-applied absorb for sync_jobs rows: pull server truth, and if the
|
|
223
|
+
* order is already at this command's target status, complete the job. Only
|
|
224
|
+
* fires when the pull actually touched the row (hlc change) so a stale
|
|
225
|
+
* local optimistic write can never delete work the server never applied.
|
|
226
|
+
*/
|
|
227
|
+
async function absorbSyncJobIfApplied(db, businessId, entityId, commandType, jobId) {
|
|
228
|
+
const target = getQueuedStatus(commandType);
|
|
229
|
+
if (!target || !entityId)
|
|
230
|
+
return false;
|
|
231
|
+
const before = await db.getFirstAsync(`SELECT hlc FROM orders WHERE business_id = ? AND id = ?;`, businessId, entityId);
|
|
232
|
+
await pullRemoteOrders(businessId);
|
|
233
|
+
const afterHlc = await db.getFirstAsync(`SELECT hlc FROM orders WHERE business_id = ? AND id = ?;`, businessId, entityId);
|
|
234
|
+
if (!afterHlc || afterHlc.hlc === before?.hlc)
|
|
235
|
+
return false;
|
|
236
|
+
const order = await getOrderById(db, businessId, entityId);
|
|
237
|
+
if (order && order.status === target) {
|
|
238
|
+
await db.runAsync(`UPDATE sync_jobs SET status='completed', updated_at=? WHERE id=?;`, new Date().toISOString(), jobId);
|
|
239
|
+
syncLogger.info("SyncJobs", "Transition already applied on server, absorbing job", {
|
|
240
|
+
businessId,
|
|
241
|
+
entityId,
|
|
242
|
+
commandType,
|
|
243
|
+
status: target,
|
|
244
|
+
});
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
218
249
|
export async function drainOne(businessId, entityId) {
|
|
219
250
|
if (!businessId || !canBusinessSync(businessId)) {
|
|
220
251
|
syncLogger.debug("SyncJobs", "drainOne early-return — no business/auth", { businessId, entityId });
|
|
@@ -355,14 +386,15 @@ export async function drainOne(businessId, entityId) {
|
|
|
355
386
|
return;
|
|
356
387
|
}
|
|
357
388
|
// Permanent 4xx: mark failed to stop the retry loop.
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
389
|
+
// Retryable (bounded, 5 attempts): 401 (refresh owns it below), 408,
|
|
390
|
+
// 409, 422, 429, any 404 (FIFO race: earlier command still in flight),
|
|
391
|
+
// BUSINESS_CLOSED (pending-by-design). Everything else 4xx (400
|
|
392
|
+
// validation, 402 plan, 403 forbidden) fails fast. Backend codes are
|
|
393
|
+
// exact (no message matching).
|
|
362
394
|
const isBusinessClosed = rest.code === "BUSINESS_CLOSED" || rest.code === "HOURS_NOT_SYNCED";
|
|
363
395
|
const is4xx = rest.status && rest.status >= 400 && rest.status < 500;
|
|
364
|
-
const isRetryable4xx = rest.status === 401 || rest.status === 408 || rest.status === 409
|
|
365
|
-
||
|
|
396
|
+
const isRetryable4xx = rest.status === 401 || rest.status === 408 || rest.status === 409
|
|
397
|
+
|| rest.status === 422 || rest.status === 429 || rest.status === 404
|
|
366
398
|
|| isBusinessClosed;
|
|
367
399
|
if (is4xx && !isRetryable4xx) {
|
|
368
400
|
syncLogger.warn("SyncJobs", "Permanent 4xx — marking job failed to stop retry loop", { businessId, entityId, status: rest.status, code: rest.code, message: rest.message });
|
|
@@ -385,6 +417,37 @@ export async function drainOne(businessId, entityId) {
|
|
|
385
417
|
}
|
|
386
418
|
return;
|
|
387
419
|
}
|
|
420
|
+
// Already-applied absorb for transitions: the server already moved the
|
|
421
|
+
// order (duplicate tap, earlier drain won the race) — complete the job
|
|
422
|
+
// instead of failing it. Server truth only (hlc-guarded pull), never the
|
|
423
|
+
// optimistic row.
|
|
424
|
+
if ((rest.status === 422 || rest.code === "INVALID_TRANSITION" ||
|
|
425
|
+
(rest.status === 404 && row.command_type !== "order:create")) &&
|
|
426
|
+
getQueuedStatus(row.command_type) !== null) {
|
|
427
|
+
try {
|
|
428
|
+
if (await absorbSyncJobIfApplied(db, businessId, row.entity_id, row.command_type, row.id)) {
|
|
429
|
+
clearRetry(businessId);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch { }
|
|
434
|
+
}
|
|
435
|
+
// Bounded retries: blind 4xx retries stop after 5 attempts with a loud
|
|
436
|
+
// toast (attempts only increments on the keep-pending path below).
|
|
437
|
+
if (is4xx && isRetryable4xx && (row.attempts ?? 0) + 1 >= 5) {
|
|
438
|
+
syncLogger.warn("SyncJobs", "Retryable 4xx exhausted — marking job failed", { businessId, entityId, status: rest.status, code: rest.code, attempts: row.attempts });
|
|
439
|
+
try {
|
|
440
|
+
await db.runAsync(`UPDATE sync_jobs SET status='failed', last_error=?, updated_at=? WHERE id=?;`, `${rest.status} ${rest.code ?? ""} ${rest.message ?? ""} (after ${MAX_SYNC_JOB_ATTEMPTS} attempts)`.trim(), new Date().toISOString(), row.id);
|
|
441
|
+
}
|
|
442
|
+
catch { }
|
|
443
|
+
clearRetry(businessId);
|
|
444
|
+
try {
|
|
445
|
+
const { notifyError } = await import("../adapters/notify");
|
|
446
|
+
notifyError(`Server rejected ${row.command_type}: ${rest.message ?? rest.code ?? rest.status} (after retries)`);
|
|
447
|
+
}
|
|
448
|
+
catch { }
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
388
451
|
if (isBusinessClosed) {
|
|
389
452
|
syncLogger.warn("SyncJobs", "Business closed — keeping pending for retry after hours sync", { businessId, entityId, code: rest.code });
|
|
390
453
|
try {
|
|
@@ -10,6 +10,7 @@ import { syncLogger } from "../utils/sync-logger";
|
|
|
10
10
|
import { generateEventId } from "../utils/uuid";
|
|
11
11
|
import { createLocalOrder, transitionLocalOrder } from "../domain/orders/service";
|
|
12
12
|
import { isFinalGuardRejection } from "./transition-errors";
|
|
13
|
+
import { getQueuedStatus } from "../utils/order-transitions";
|
|
13
14
|
import { openSyncDatabase } from "../db/connection";
|
|
14
15
|
import { getOrderById, updateOrderStatus } from "../db/operations";
|
|
15
16
|
export class RestTransport {
|
|
@@ -143,6 +144,29 @@ export class RestTransport {
|
|
|
143
144
|
*/
|
|
144
145
|
async executeOrderTransition(command, action, timestamp, restFallback, eventType = "order.status_changed") {
|
|
145
146
|
const { business_id, entity_id } = command;
|
|
147
|
+
// Idempotent absorb: a duplicate tap / replayed command whose target
|
|
148
|
+
// status is already applied locally succeeds without touching the
|
|
149
|
+
// guards or the network (this was the "Cannot mark_ready from ready"
|
|
150
|
+
// error storm: the throw also poisoned global reachability before the
|
|
151
|
+
// probe-ownership rule). Genuinely invalid transitions still throw
|
|
152
|
+
// INVALID_TRANSITION from transitionLocalOrder below.
|
|
153
|
+
const target = getQueuedStatus(command.command_type);
|
|
154
|
+
if (target && entity_id) {
|
|
155
|
+
try {
|
|
156
|
+
const db = await openSyncDatabase();
|
|
157
|
+
const local = await getOrderById(db, business_id, entity_id);
|
|
158
|
+
if (local && local.status === target) {
|
|
159
|
+
syncLogger.info("RestTransport", "transition already applied, absorbing", {
|
|
160
|
+
command_type: command.command_type,
|
|
161
|
+
entity_id,
|
|
162
|
+
status: target,
|
|
163
|
+
});
|
|
164
|
+
const data = { ...local, order_id: local.id };
|
|
165
|
+
return this.wrapResponse(eventType, data, local.id, timestamp, command);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
catch { }
|
|
169
|
+
}
|
|
146
170
|
try {
|
|
147
171
|
const order = await transitionLocalOrder(business_id, entity_id, action);
|
|
148
172
|
const data = { ...order, order_id: order.id };
|
|
@@ -207,6 +207,17 @@ export function createMemoryDriver() {
|
|
|
207
207
|
}
|
|
208
208
|
return { lastInsertRowId: 0, changes: 1 };
|
|
209
209
|
}
|
|
210
|
+
// sync_jobs update status=failed with last_error (permanent + exhausted retries)
|
|
211
|
+
if (s.includes("UPDATE sync_jobs SET status='failed'")) {
|
|
212
|
+
const [last_error, updated_at, id] = args;
|
|
213
|
+
const row = tables.sync_jobs.find((r) => r.id === id);
|
|
214
|
+
if (row) {
|
|
215
|
+
row.status = "failed";
|
|
216
|
+
row.last_error = last_error;
|
|
217
|
+
row.updated_at = updated_at;
|
|
218
|
+
}
|
|
219
|
+
return { lastInsertRowId: 0, changes: 1 };
|
|
220
|
+
}
|
|
210
221
|
if (s.includes("UPDATE sync_jobs SET payload=")) {
|
|
211
222
|
const [payload, updated_at, id] = args;
|
|
212
223
|
const row = tables.sync_jobs.find((r) => r.id === id);
|
|
@@ -321,6 +332,12 @@ export function createMemoryDriver() {
|
|
|
321
332
|
const row = tables.orders.find((r) => r.business_id === business_id && (r.id === id1 || r.order_number === id2));
|
|
322
333
|
return row ?? null;
|
|
323
334
|
}
|
|
335
|
+
// orders hlc probe (absorb-if-applied touch detection)
|
|
336
|
+
if (s.includes("SELECT hlc FROM orders WHERE business_id = ? AND id = ?")) {
|
|
337
|
+
const [business_id, id] = args;
|
|
338
|
+
const row = tables.orders.find((r) => r.business_id === business_id && r.id === id);
|
|
339
|
+
return (row ? { hlc: row.hlc } : null);
|
|
340
|
+
}
|
|
324
341
|
// sync_jobs pending single
|
|
325
342
|
if (s.includes("SELECT * FROM sync_jobs WHERE business_id = ? AND entity_id = ? AND status='pending'")) {
|
|
326
343
|
const [business_id, entity_id] = args;
|
package/package.json
CHANGED