@teincfood/core 0.7.9 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/README.md +26 -21
  2. package/dist/adapters/auth.d.ts +8 -0
  3. package/dist/adapters/auth.js +36 -0
  4. package/dist/adapters/devices.d.ts +3 -1
  5. package/dist/adapters/devices.js +187 -3
  6. package/dist/adapters/filesystem.d.ts +4 -0
  7. package/dist/adapters/kv.d.ts +10 -0
  8. package/dist/adapters/kv.js +23 -7
  9. package/dist/adapters/local-node.d.ts +4 -6
  10. package/dist/adapters/local-node.js +9 -32
  11. package/dist/adapters/notify.d.ts +12 -0
  12. package/dist/adapters/notify.js +33 -0
  13. package/dist/adapters/query-keys.d.ts +4 -0
  14. package/dist/adapters/query-keys.js +4 -0
  15. package/dist/adapters/services.d.ts +96 -15
  16. package/dist/adapters/services.js +241 -4
  17. package/dist/auth/session.d.ts +66 -0
  18. package/dist/auth/session.js +172 -0
  19. package/dist/catalog/hooks.d.ts +10 -0
  20. package/dist/catalog/hooks.js +82 -11
  21. package/dist/db/migrations.js +274 -0
  22. package/dist/db/operations.d.ts +53 -2
  23. package/dist/db/operations.js +177 -8
  24. package/dist/domain/business/index.d.ts +5 -0
  25. package/dist/domain/business/index.js +5 -0
  26. package/dist/domain/orders/lifecycle.d.ts +6 -0
  27. package/dist/domain/orders/lifecycle.js +6 -0
  28. package/dist/domain/orders/service.d.ts +24 -0
  29. package/dist/domain/orders/service.js +242 -0
  30. package/dist/domain/payments/index.d.ts +6 -0
  31. package/dist/domain/payments/index.js +5 -0
  32. package/dist/domain/reference/index.d.ts +8 -0
  33. package/dist/domain/reference/index.js +8 -0
  34. package/dist/e2e/harness.d.ts +1 -0
  35. package/dist/e2e/harness.js +61 -0
  36. package/dist/hooks/analytics.hooks.d.ts +25 -0
  37. package/dist/hooks/analytics.hooks.js +214 -0
  38. package/dist/hooks/business-hours.hooks.d.ts +8 -0
  39. package/dist/hooks/business-hours.hooks.js +45 -0
  40. package/dist/hooks/dashboard.hooks.d.ts +30 -0
  41. package/dist/hooks/dashboard.hooks.js +132 -0
  42. package/dist/hooks/delivery.hooks.d.ts +225 -0
  43. package/dist/hooks/delivery.hooks.js +80 -0
  44. package/dist/hooks/fleet.hooks.d.ts +37 -0
  45. package/dist/hooks/fleet.hooks.js +229 -0
  46. package/dist/hooks/image.hooks.d.ts +24 -0
  47. package/dist/hooks/image.hooks.js +66 -0
  48. package/dist/hooks/kiosk.hooks.d.ts +22 -5
  49. package/dist/hooks/kiosk.hooks.js +74 -5
  50. package/dist/hooks/members.hooks.d.ts +48 -0
  51. package/dist/hooks/members.hooks.js +302 -0
  52. package/dist/hooks/offline-orders.hooks.d.ts +9 -0
  53. package/dist/hooks/offline-orders.hooks.js +51 -0
  54. package/dist/hooks/orders.hooks.d.ts +18 -39
  55. package/dist/hooks/orders.hooks.js +124 -343
  56. package/dist/hooks/places.hooks.d.ts +21 -0
  57. package/dist/hooks/places.hooks.js +112 -0
  58. package/dist/hooks/realtime-stubs.d.ts +28 -0
  59. package/dist/hooks/realtime-stubs.js +85 -0
  60. package/dist/hooks/rider.hooks.d.ts +470 -0
  61. package/dist/hooks/rider.hooks.js +373 -0
  62. package/dist/hooks/use-infinite-list.d.ts +243 -0
  63. package/dist/hooks/use-infinite-list.js +58 -0
  64. package/dist/hooks/wallet.hooks.d.ts +219 -0
  65. package/dist/hooks/wallet.hooks.js +56 -0
  66. package/dist/image-cache/service.d.ts +28 -0
  67. package/dist/image-cache/service.js +51 -3
  68. package/dist/index.d.ts +56 -6
  69. package/dist/index.js +73 -6
  70. package/dist/local-node/adapters.d.ts +87 -0
  71. package/dist/local-node/adapters.js +4 -0
  72. package/dist/local-node/index.d.ts +5 -0
  73. package/dist/local-node/index.js +5 -0
  74. package/dist/local-node/security.d.ts +25 -0
  75. package/dist/local-node/security.js +149 -0
  76. package/dist/local-node/service.d.ts +83 -0
  77. package/dist/local-node/service.js +706 -0
  78. package/dist/local-node/store.d.ts +50 -0
  79. package/dist/local-node/store.js +284 -0
  80. package/dist/local-node/types.d.ts +92 -0
  81. package/dist/local-node/types.js +4 -0
  82. package/dist/printer/receipt.d.ts +4 -0
  83. package/dist/printer/receipt.js +75 -0
  84. package/dist/printer/service.js +1 -1
  85. package/dist/providers/query-client.d.ts +13 -0
  86. package/dist/providers/query-client.js +58 -0
  87. package/dist/realtime/phoenix-socket.js +30 -1
  88. package/dist/realtime/useEventsConnection.js +11 -2
  89. package/dist/reference/api.d.ts +2 -0
  90. package/dist/reference/api.js +2 -0
  91. package/dist/reference/capabilities.d.ts +12 -7
  92. package/dist/reference/capabilities.js +27 -13
  93. package/dist/reference/hooks.d.ts +34 -0
  94. package/dist/reference/hooks.js +124 -0
  95. package/dist/reference/menu-apply.d.ts +29 -0
  96. package/dist/reference/menu-apply.js +289 -0
  97. package/dist/reference/menu-record.d.ts +69 -0
  98. package/dist/reference/menu-record.js +168 -0
  99. package/dist/reference/operations.d.ts +3 -0
  100. package/dist/reference/operations.js +35 -1
  101. package/dist/reference/service.js +36 -9
  102. package/dist/reference/types.d.ts +1 -1
  103. package/dist/repositories/order.repository.d.ts +7 -0
  104. package/dist/repositories/order.repository.js +15 -2
  105. package/dist/repositories/pos.repository.d.ts +4 -0
  106. package/dist/repositories/pos.repository.js +4 -0
  107. package/dist/sync/backoff.d.ts +21 -0
  108. package/dist/sync/backoff.js +42 -0
  109. package/dist/sync/command-builder.js +10 -2
  110. package/dist/sync/command-queue.service.d.ts +12 -0
  111. package/dist/sync/command-queue.service.js +81 -16
  112. package/dist/sync/device-lease.service.d.ts +3 -3
  113. package/dist/sync/device-lease.service.js +80 -20
  114. package/dist/sync/engine.d.ts +3 -1
  115. package/dist/sync/engine.js +44 -4
  116. package/dist/sync/full-sync.d.ts +6 -0
  117. package/dist/sync/full-sync.js +72 -0
  118. package/dist/sync/health-probe.d.ts +24 -0
  119. package/dist/sync/health-probe.js +138 -0
  120. package/dist/sync/offline-capable.js +25 -0
  121. package/dist/sync/online-gates.d.ts +17 -0
  122. package/dist/sync/online-gates.js +55 -0
  123. package/dist/sync/order-number.d.ts +4 -4
  124. package/dist/sync/order-number.js +33 -13
  125. package/dist/sync/order-snapshots.service.js +18 -3
  126. package/dist/sync/pending-orders.service.d.ts +18 -0
  127. package/dist/sync/pending-orders.service.js +67 -1
  128. package/dist/sync/reconciliation/index.d.ts +5 -0
  129. package/dist/sync/reconciliation/index.js +5 -0
  130. package/dist/sync/snapshots/entity.d.ts +6 -0
  131. package/dist/sync/snapshots/entity.js +6 -0
  132. package/dist/sync/sync-jobs.service.d.ts +18 -0
  133. package/dist/sync/sync-jobs.service.js +539 -0
  134. package/dist/sync/transition-endpoints.d.ts +11 -0
  135. package/dist/sync/transition-endpoints.js +30 -0
  136. package/dist/sync/transport-local-node.js +3 -2
  137. package/dist/sync/transport-rest.d.ts +7 -0
  138. package/dist/sync/transport-rest.js +84 -26
  139. package/dist/sync/use-sync-reconciliation.js +15 -1
  140. package/dist/test-helpers/memory-driver.js +182 -4
  141. package/dist/test-helpers/seed-hours.d.ts +1 -0
  142. package/dist/test-helpers/seed-hours.js +23 -0
  143. package/dist/types/api/business.api.d.ts +42 -0
  144. package/dist/types/api/menu.api.d.ts +15 -0
  145. package/dist/types/api/seller.api.d.ts +20 -0
  146. package/dist/types/places.d.ts +19 -0
  147. package/dist/types/places.js +2 -0
  148. package/dist/types/rider.d.ts +67 -0
  149. package/dist/types/rider.js +2 -0
  150. package/dist/utils/attempt-stats.d.ts +23 -0
  151. package/dist/utils/attempt-stats.js +61 -0
  152. package/dist/utils/business-hours.d.ts +37 -0
  153. package/dist/utils/business-hours.js +96 -0
  154. package/dist/utils/debug-log.d.ts +23 -0
  155. package/dist/utils/debug-log.js +153 -0
  156. package/dist/utils/order-filter.d.ts +1 -1
  157. package/dist/utils/order-filter.js +1 -1
  158. package/dist/utils/order-transitions.d.ts +30 -0
  159. package/dist/utils/order-transitions.js +185 -0
  160. package/dist/utils/sync-logger.js +5 -4
  161. package/dist/validation/offline.d.ts +46 -0
  162. package/dist/validation/offline.js +79 -0
  163. package/package.json +6 -1
  164. package/dist/pricing/engine.test.d.ts +0 -1
  165. package/dist/pricing/engine.test.js +0 -142
  166. package/dist/reference/lww.test.d.ts +0 -1
  167. package/dist/reference/lww.test.js +0 -23
  168. package/dist/reference/operations.test.d.ts +0 -1
  169. package/dist/reference/operations.test.js +0 -66
  170. package/dist/standalone.integration.test.d.ts +0 -1
  171. package/dist/standalone.integration.test.js +0 -235
  172. package/dist/sync/device-lease.test.d.ts +0 -1
  173. package/dist/sync/device-lease.test.js +0 -38
  174. package/dist/sync/offline-integration.test.d.ts +0 -1
  175. package/dist/sync/offline-integration.test.js +0 -52
  176. package/dist/sync/order-number.test.d.ts +0 -1
  177. package/dist/sync/order-number.test.js +0 -51
  178. package/dist/sync/perms.test.d.ts +0 -1
  179. package/dist/sync/perms.test.js +0 -15
  180. package/dist/utils/currency.test.d.ts +0 -1
  181. package/dist/utils/currency.test.js +0 -17
  182. package/dist/utils/hlc.test.d.ts +0 -1
  183. package/dist/utils/hlc.test.js +0 -29
  184. package/dist/utils/phone.test.d.ts +0 -1
  185. package/dist/utils/phone.test.js +0 -19
  186. package/dist/utils/responsive.d.ts +0 -13
  187. package/dist/utils/responsive.js +0 -18
  188. package/dist/utils/uuid.test.d.ts +0 -1
  189. package/dist/utils/uuid.test.js +0 -13
  190. package/dist/utils/validation.test.d.ts +0 -1
  191. package/dist/utils/validation.test.js +0 -23
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Wallet hooks — offline-first. Balances and history serve the persisted
3
+ * query cache instantly offline; the network refreshes silently when online.
4
+ * (No SQLite wallet cache — the persisted TanStack cache is the offline
5
+ * source; both apps persist it.)
6
+ */
7
+ import type { WalletBalanceResponse, WalletEntry } from "../types/api/wallet.api";
8
+ export declare const WALLET_KEYS: {
9
+ all: readonly ["wallet"];
10
+ balance: (scope?: string) => readonly ["wallet", "balance", string | undefined];
11
+ history: (scope?: string) => readonly ["wallet", "history", string | undefined];
12
+ };
13
+ export declare function useAllBalancesQuery(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<WalletBalanceResponse, Error>;
14
+ export declare function useBusinessWalletBalanceQuery(enabled?: boolean): import("@tanstack/react-query").UseQueryResult<WalletBalanceResponse, Error>;
15
+ export declare function useWalletHistoryQuery(enabled?: boolean): {
16
+ dataUpdatedAt: number;
17
+ errorUpdatedAt: number;
18
+ failureCount: number;
19
+ failureReason: Error | null;
20
+ errorUpdateCount: number;
21
+ isFetched: boolean;
22
+ isFetchedAfterMount: boolean;
23
+ isFetching: boolean;
24
+ isInitialLoading: boolean;
25
+ isPaused: boolean;
26
+ isRefetching: boolean;
27
+ isStale: boolean;
28
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
34
+ hasPreviousPage: boolean;
35
+ isFetchingNextPage: boolean;
36
+ isFetchingPreviousPage: boolean;
37
+ error: Error;
38
+ isError: true;
39
+ isPending: false;
40
+ isLoading: false;
41
+ isLoadingError: true;
42
+ isRefetchError: false;
43
+ isFetchNextPageError: false;
44
+ isFetchPreviousPageError: false;
45
+ isSuccess: false;
46
+ isPlaceholderData: false;
47
+ status: 'error';
48
+ data: WalletEntry[] | undefined;
49
+ } | {
50
+ dataUpdatedAt: number;
51
+ errorUpdatedAt: number;
52
+ failureCount: number;
53
+ failureReason: Error | null;
54
+ errorUpdateCount: number;
55
+ isFetched: boolean;
56
+ isFetchedAfterMount: boolean;
57
+ isFetching: boolean;
58
+ isInitialLoading: boolean;
59
+ isPaused: boolean;
60
+ isRefetching: boolean;
61
+ isStale: boolean;
62
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
68
+ hasPreviousPage: boolean;
69
+ isFetchingNextPage: boolean;
70
+ isFetchingPreviousPage: boolean;
71
+ error: null;
72
+ isError: false;
73
+ isPending: true;
74
+ isLoading: true;
75
+ isLoadingError: false;
76
+ isRefetchError: false;
77
+ isFetchNextPageError: false;
78
+ isFetchPreviousPageError: false;
79
+ isSuccess: false;
80
+ isPlaceholderData: false;
81
+ status: 'pending';
82
+ data: WalletEntry[] | undefined;
83
+ } | {
84
+ dataUpdatedAt: number;
85
+ errorUpdatedAt: number;
86
+ failureCount: number;
87
+ failureReason: Error | null;
88
+ errorUpdateCount: number;
89
+ isFetched: boolean;
90
+ isFetchedAfterMount: boolean;
91
+ isFetching: boolean;
92
+ isLoading: boolean;
93
+ isInitialLoading: boolean;
94
+ isPaused: boolean;
95
+ isRefetching: boolean;
96
+ isStale: boolean;
97
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
103
+ hasPreviousPage: boolean;
104
+ isFetchingNextPage: boolean;
105
+ isFetchingPreviousPage: boolean;
106
+ error: null;
107
+ isError: false;
108
+ isPending: true;
109
+ isLoadingError: false;
110
+ isRefetchError: false;
111
+ isFetchNextPageError: false;
112
+ isFetchPreviousPageError: false;
113
+ isSuccess: false;
114
+ isPlaceholderData: false;
115
+ status: 'pending';
116
+ data: WalletEntry[] | undefined;
117
+ } | {
118
+ dataUpdatedAt: number;
119
+ errorUpdatedAt: number;
120
+ failureCount: number;
121
+ failureReason: Error | null;
122
+ errorUpdateCount: number;
123
+ isFetched: boolean;
124
+ isFetchedAfterMount: boolean;
125
+ isFetching: boolean;
126
+ isInitialLoading: boolean;
127
+ isPaused: boolean;
128
+ isRefetching: boolean;
129
+ isStale: boolean;
130
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
136
+ hasPreviousPage: boolean;
137
+ isFetchingNextPage: boolean;
138
+ isFetchingPreviousPage: boolean;
139
+ isError: false;
140
+ error: null;
141
+ isPending: false;
142
+ isLoading: false;
143
+ isLoadingError: false;
144
+ isRefetchError: false;
145
+ isSuccess: true;
146
+ isPlaceholderData: true;
147
+ isFetchNextPageError: false;
148
+ isFetchPreviousPageError: false;
149
+ status: 'success';
150
+ data: WalletEntry[] | undefined;
151
+ } | {
152
+ dataUpdatedAt: number;
153
+ errorUpdatedAt: number;
154
+ failureCount: number;
155
+ failureReason: Error | null;
156
+ errorUpdateCount: number;
157
+ isFetched: boolean;
158
+ isFetchedAfterMount: boolean;
159
+ isFetching: boolean;
160
+ isInitialLoading: boolean;
161
+ isPaused: boolean;
162
+ isRefetching: boolean;
163
+ isStale: boolean;
164
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
170
+ hasPreviousPage: boolean;
171
+ isFetchNextPageError: boolean;
172
+ isFetchingNextPage: boolean;
173
+ isFetchPreviousPageError: boolean;
174
+ isFetchingPreviousPage: boolean;
175
+ error: Error;
176
+ isError: true;
177
+ isPending: false;
178
+ isLoading: false;
179
+ isLoadingError: false;
180
+ isRefetchError: true;
181
+ isSuccess: false;
182
+ isPlaceholderData: false;
183
+ status: 'error';
184
+ data: WalletEntry[] | undefined;
185
+ } | {
186
+ dataUpdatedAt: number;
187
+ errorUpdatedAt: number;
188
+ failureCount: number;
189
+ failureReason: Error | null;
190
+ errorUpdateCount: number;
191
+ isFetched: boolean;
192
+ isFetchedAfterMount: boolean;
193
+ isFetching: boolean;
194
+ isInitialLoading: boolean;
195
+ isPaused: boolean;
196
+ isRefetching: boolean;
197
+ isStale: boolean;
198
+ isEnabled: boolean;
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
+ hasNextPage: boolean;
204
+ hasPreviousPage: boolean;
205
+ isFetchingNextPage: boolean;
206
+ isFetchingPreviousPage: boolean;
207
+ error: null;
208
+ isError: false;
209
+ isPending: false;
210
+ isLoading: false;
211
+ isLoadingError: false;
212
+ isRefetchError: false;
213
+ isFetchNextPageError: false;
214
+ isFetchPreviousPageError: false;
215
+ isSuccess: true;
216
+ isPlaceholderData: false;
217
+ status: 'success';
218
+ data: WalletEntry[] | undefined;
219
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Wallet hooks — offline-first. Balances and history serve the persisted
3
+ * query cache instantly offline; the network refreshes silently when online.
4
+ * (No SQLite wallet cache — the persisted TanStack cache is the offline
5
+ * source; both apps persist it.)
6
+ */
7
+ import { useQuery } from "@tanstack/react-query";
8
+ import { useSyncExternalStore } from "react";
9
+ import { getActiveBusiness, subscribeBusiness } from "../adapters/business";
10
+ import { walletService } from "../adapters/services";
11
+ import { useInfiniteList } from "./use-infinite-list";
12
+ export const WALLET_KEYS = {
13
+ all: ["wallet"],
14
+ balance: (scope) => [...WALLET_KEYS.all, "balance", scope],
15
+ history: (scope) => [...WALLET_KEYS.all, "history", scope],
16
+ };
17
+ function useBusinessId() {
18
+ const id = useSyncExternalStore(subscribeBusiness, () => getActiveBusiness()?.id ?? null, () => null);
19
+ return id ?? undefined;
20
+ }
21
+ export function useAllBalancesQuery(enabled = true) {
22
+ return useQuery({
23
+ queryKey: WALLET_KEYS.balance("all"),
24
+ queryFn: () => walletService.fetchAllBalances(),
25
+ enabled,
26
+ placeholderData: (prev) => prev,
27
+ staleTime: 30000,
28
+ retry: false,
29
+ networkMode: "offlineFirst",
30
+ });
31
+ }
32
+ export function useBusinessWalletBalanceQuery(enabled = true) {
33
+ const businessId = useBusinessId();
34
+ return useQuery({
35
+ queryKey: WALLET_KEYS.balance(businessId),
36
+ queryFn: () => walletService.fetchBusinessWalletBalance(businessId),
37
+ enabled: enabled && Boolean(businessId),
38
+ placeholderData: (prev) => prev,
39
+ staleTime: 30000,
40
+ retry: false,
41
+ networkMode: "offlineFirst",
42
+ });
43
+ }
44
+ export function useWalletHistoryQuery(enabled = true) {
45
+ const businessId = useBusinessId();
46
+ return useInfiniteList({
47
+ key: [...WALLET_KEYS.history(businessId)],
48
+ enabled: enabled && Boolean(businessId),
49
+ pageSize: 20,
50
+ staleTime: 30000,
51
+ onlineFetch: async (page, pageSize) => {
52
+ const res = (await walletService.fetchWalletHistory({ businessId, page, pageSize }));
53
+ return { data: res.data.entries, pagination: res.pagination };
54
+ },
55
+ });
56
+ }
@@ -14,6 +14,34 @@ export declare function stableCacheUrl(url: string): string;
14
14
  export declare function getCachedImagePath(url: string): string;
15
15
  export declare function ensureImageCacheDir(): Promise<string>;
16
16
  export declare function getCachedImageInfo(url: string): Promise<ImageCacheEntry>;
17
+ /**
18
+ * Only http(s) URLs can be fetched by the host downloader. Anything else
19
+ * (tfimg:// disk URIs leaked from another device, data:, blob:, file:)
20
+ * is either already local or unfetchable — attempting a download throws
21
+ * per-attempt errors (e.g. iOS NSURLError -1002) and, worse, feeds the
22
+ * hook's warm-then-invalidate cycle into an unbounded retry storm.
23
+ */
24
+ export declare function isDownloadableImageUrl(url: string): boolean;
25
+ /**
26
+ * URI schemes React Native's `<Image>` can actually load on device. Anything
27
+ * else has no RCTImageURLLoader on iOS ("No suitable image URL loader
28
+ * found") and crashes the screen — notably `tfimg://` disk URIs leaked from
29
+ * desktop rows, bare S3 keys (`menus/biz/img.jpg`), and `blob:` preview
30
+ * URLs. The hook maps these to null so callers render their placeholder
31
+ * branch instead of feeding a fatal URI to the native loader.
32
+ */
33
+ export declare function isLoadableImageUri(uri: string): boolean;
34
+ /** Map a resolved URI to one RN `<Image>` can load, else null (placeholder). */
35
+ export declare function toRenderableUri(uri: string | null | undefined): string | null;
36
+ /**
37
+ * Values safe to persist as a menu image reference: S3 keys, http(s) URLs,
38
+ * null. Preview URIs (tfimg:, blob:, file:, data:) must never be stored —
39
+ * the backend keeps non-http values verbatim and they poison every other
40
+ * device (mobile has no native loader for tfimg:// and crashes). Returns
41
+ * null for un-storable values, so re-saving a poisoned row self-heals it
42
+ * (caller re-uploads to restore the image).
43
+ */
44
+ export declare function toStorableImageUrl(value: string | null | undefined): string | null;
17
45
  export declare function cacheRemoteImage(url: string | null | undefined, opts?: {
18
46
  skipIfCached?: boolean;
19
47
  removeOnFailure?: boolean;
@@ -49,6 +49,53 @@ export async function getCachedImageInfo(url) {
49
49
  const info = await fs.getInfoAsync(localPath);
50
50
  return { remoteUrl: url, localUri: info.exists && !info.isDirectory ? localPath : null, etag: null, lastModified: null, cachedAt: info.exists ? new Date().toISOString() : null };
51
51
  }
52
+ const DOWNLOADABLE_RE = /^https?:\/\//i;
53
+ /**
54
+ * Only http(s) URLs can be fetched by the host downloader. Anything else
55
+ * (tfimg:// disk URIs leaked from another device, data:, blob:, file:)
56
+ * is either already local or unfetchable — attempting a download throws
57
+ * per-attempt errors (e.g. iOS NSURLError -1002) and, worse, feeds the
58
+ * hook's warm-then-invalidate cycle into an unbounded retry storm.
59
+ */
60
+ export function isDownloadableImageUrl(url) {
61
+ return DOWNLOADABLE_RE.test(url);
62
+ }
63
+ const LOADABLE_RE = /^(https?|file|data|asset|content):/i;
64
+ /**
65
+ * URI schemes React Native's `<Image>` can actually load on device. Anything
66
+ * else has no RCTImageURLLoader on iOS ("No suitable image URL loader
67
+ * found") and crashes the screen — notably `tfimg://` disk URIs leaked from
68
+ * desktop rows, bare S3 keys (`menus/biz/img.jpg`), and `blob:` preview
69
+ * URLs. The hook maps these to null so callers render their placeholder
70
+ * branch instead of feeding a fatal URI to the native loader.
71
+ */
72
+ export function isLoadableImageUri(uri) {
73
+ return LOADABLE_RE.test(uri);
74
+ }
75
+ /** Map a resolved URI to one RN `<Image>` can load, else null (placeholder). */
76
+ export function toRenderableUri(uri) {
77
+ if (!uri)
78
+ return null;
79
+ return isLoadableImageUri(uri) ? uri : null;
80
+ }
81
+ const URI_SCHEME_RE = /^[a-z][a-z0-9+.-]*:/i;
82
+ /**
83
+ * Values safe to persist as a menu image reference: S3 keys, http(s) URLs,
84
+ * null. Preview URIs (tfimg:, blob:, file:, data:) must never be stored —
85
+ * the backend keeps non-http values verbatim and they poison every other
86
+ * device (mobile has no native loader for tfimg:// and crashes). Returns
87
+ * null for un-storable values, so re-saving a poisoned row self-heals it
88
+ * (caller re-uploads to restore the image).
89
+ */
90
+ export function toStorableImageUrl(value) {
91
+ if (!value)
92
+ return null;
93
+ if (URI_SCHEME_RE.test(value) && !DOWNLOADABLE_RE.test(value)) {
94
+ syncLogger.warn("ImageCache", "Dropping un-storable image URL", { value: value.slice(0, 32) });
95
+ return null;
96
+ }
97
+ return value;
98
+ }
52
99
  export async function cacheRemoteImage(url, opts = {}) {
53
100
  if (!url)
54
101
  return null;
@@ -58,9 +105,12 @@ export async function cacheRemoteImage(url, opts = {}) {
58
105
  await ensureImageCacheDir();
59
106
  const localPath = getCachedImagePath(url);
60
107
  const existing = await fs.getInfoAsync(localPath);
61
- if (opts.skipIfCached && existing.exists && !existing.isDirectory) {
108
+ if (existing.exists && !existing.isDirectory) {
62
109
  return { remoteUrl: url, localUri: localPath, etag: null, lastModified: null, cachedAt: new Date().toISOString() };
63
110
  }
111
+ if (!isDownloadableImageUrl(url)) {
112
+ return { remoteUrl: url, localUri: null, etag: null, lastModified: null, cachedAt: null };
113
+ }
64
114
  try {
65
115
  const res = await fs.downloadAsync(url, localPath);
66
116
  if (res.uri)
@@ -71,8 +121,6 @@ export async function cacheRemoteImage(url, opts = {}) {
71
121
  }
72
122
  if (opts.removeOnFailure)
73
123
  await fs.deleteAsync(localPath, { idempotent: true }).catch(() => { });
74
- if (existing.exists && !existing.isDirectory)
75
- return { remoteUrl: url, localUri: localPath, etag: null, lastModified: null, cachedAt: new Date().toISOString() };
76
124
  return { remoteUrl: url, localUri: null, etag: null, lastModified: null, cachedAt: null };
77
125
  }
78
126
  export async function cacheImageBatch(urls, opts = {}) {
package/dist/index.d.ts CHANGED
@@ -6,6 +6,9 @@
6
6
  */
7
7
  export * from "./types/api";
8
8
  export * from "./types/pos.types";
9
+ export * from "./types/rider";
10
+ export * from "./types/places";
11
+ export * from "./adapters/notify";
9
12
  export { calculatePricing, calculateTaxLines, calculateExclusiveTax, calculateInclusiveTaxShare, } from "./pricing/engine";
10
13
  export type { PricingInput, PricingResult } from "./pricing/engine";
11
14
  export * from "./utils/constants";
@@ -13,24 +16,39 @@ export * from "./utils/currency";
13
16
  export * from "./utils/error";
14
17
  export * from "./utils/uuid";
15
18
  export * from "./utils/sync-logger";
19
+ export * from "./utils/debug-log";
20
+ export * from "./utils/attempt-stats";
16
21
  export { PHONE_COUNTRIES, getDialCodeFromCountry, getCountryOption, normalizePhoneForCountry, isLikelyE164 } from "./utils/phone";
17
22
  export type { PhoneCountryOption } from "./utils/phone";
18
23
  export * from "./utils/formatCurrency";
19
24
  export { formatDate, formatRelativeTime } from "./utils/formatDate";
20
25
  export * from "./utils/validation";
21
- export * from "./utils/responsive";
26
+ export * from "./validation/offline";
22
27
  export * from "./utils/copyToClipBoard";
23
28
  export * from "./utils/customer-display";
24
29
  export * from "./utils/order-filter";
30
+ export { useReferenceData } from "./reference/hooks";
31
+ export { setNotifyHandlers } from "./adapters/notify";
32
+ export { walletService, riderService, fleetService, deliveryService, dashboardService, analyticsService, placesService } from "./adapters/services";
33
+ export { buildMenuItemEnvelope, buildMenuCategoryEnvelope } from "./reference/menu-record";
34
+ export { validateMenuItemInput, validateMenuCategoryInput, validateOrderCreateInput, validateInviteInput } from "./validation/offline";
35
+ export { useBusinessDeliveriesQuery } from "./hooks/delivery.hooks";
36
+ export { useBusinessReferenceDataSync } from "./reference/hooks";
37
+ export { createAppQueryClient, createQueryPersister } from "./providers/query-client";
38
+ export { useSellerAnalyticsQuery } from "./hooks/analytics.hooks";
39
+ export { useSellerDashboardQuery } from "./hooks/dashboard.hooks";
40
+ export { useRealtimeInvalidation, useOrderRealtimeUpdates } from "./hooks/realtime-stubs";
41
+ export { useAcceptFleetInvitationMutation, useAcceptBusinessInvitationMutation, useUserInvitationsQuery, } from "./hooks/members.hooks";
42
+ export { useJoinRequestsQuery } from "./hooks/fleet.hooks";
25
43
  export * from "./db/migrations";
26
44
  export * from "./db/operations";
27
45
  export * as dbOps from "./db/operations";
28
46
  export { openSyncDatabase, getSyncDatabase, closeSyncDatabase } from "./db/connection";
29
47
  export * from "./sync/types";
48
+ export * from "./sync/online-gates";
30
49
  export * from "./sync/use-sync-reconciliation";
31
50
  export { SyncEngine, syncEngine } from "./sync/engine";
32
51
  export * from "./sync/command-builder";
33
- export * from "./sync/command-queue.service";
34
52
  export { commandQueueService } from "./sync/command-queue.service";
35
53
  export { buildCommand } from "./sync/command-builder";
36
54
  export { generateLocalOrderNumber, generateLocalCalloutNumber, isLocalOrderNumber, generateOrderNumber, generateOrderNumberForBusiness, isOfflineOrderNumber, parseOrderNumber, resetCalloutForTests, } from "./sync/order-number";
@@ -53,29 +71,51 @@ export type { CreateOrderInput, AssignRiderInput, OrderActionInput } from "./rep
53
71
  export { posRepository } from "./repositories/pos.repository";
54
72
  export type { POSOrderPreviewInput } from "./repositories/pos.repository";
55
73
  export * from "./hooks/orders.hooks";
74
+ export * from "./hooks/use-infinite-list";
75
+ export * from "./hooks/wallet.hooks";
76
+ export * from "./hooks/rider.hooks";
77
+ export * from "./hooks/fleet.hooks";
78
+ export * from "./hooks/delivery.hooks";
79
+ export * from "./hooks/dashboard.hooks";
80
+ export * from "./hooks/analytics.hooks";
81
+ export * from "./hooks/members.hooks";
82
+ export * from "./hooks/places.hooks";
83
+ export * from "./hooks/offline-orders.hooks";
84
+ export * from "./hooks/image.hooks";
85
+ export * from "./hooks/realtime-stubs";
86
+ export * from "./providers/query-client";
87
+ export { KIOSK_KEYS, useKioskOrdersQuery, useAvailableRidersQuery, type AvailableRider, useAcceptKioskOrderMutation, useRejectKioskOrderMutation, useStartPreparingKioskOrderMutation, useMarkKioskOrderReadyMutation, } from "./hooks/kiosk.hooks";
56
88
  export * from "./reference/types";
57
89
  export * from "./reference/operations";
58
- export { fetchReferenceVersions, fetchReferenceData, fetchReferenceChanges, setReferenceLocalNodeFetcher } from "./reference/api";
90
+ export { fetchReferenceVersions, fetchReferenceData, fetchReferenceChanges, setReferenceLocalNodeFetcher, setReferenceData, mergeReferenceData, setOperatingHoursLocal, setBusinessProfileLocal } from "./reference/api";
59
91
  export type { ReferenceLocalNodeFetcher } from "./reference/api";
60
92
  export { emitReferenceChanged, applyReferenceChangeEvent, syncReferenceDataOnReconnect, registerReferenceEventEngine, registerReferenceInvalidator } from "./reference/events";
61
93
  export * from "./reference/events";
62
94
  export * from "./reference/service";
95
+ export * from "./reference/hooks";
63
96
  export { referenceSyncService } from "./reference/service";
97
+ export * from "./reference/menu-record";
98
+ export * from "./reference/menu-apply";
64
99
  export * from "./reference/capabilities";
65
100
  export * from "./adapters/sqlite";
66
101
  export { KVDriver, setKVDriver, getKVDriver, kvGetItem, kvSetItem, kvRemoveItem, getItem, setItem, removeItem, getItemSync, setItemSync } from "./adapters/kv";
67
102
  export * from "./adapters/connectivity";
68
103
  export * from "./adapters/http";
69
- export * from "./adapters/local-node";
104
+ export * from "./local-node/types";
105
+ export * from "./local-node/store";
106
+ export * from "./local-node/security";
107
+ export * from "./local-node/adapters";
108
+ export * from "./local-node/service";
109
+ export { setLocalNodeState } from "./adapters/local-node";
70
110
  export * from "./adapters/services";
71
111
  export * from "./adapters/devices";
72
- export { setAuthProvider, getAuthToken } from "./adapters/auth";
112
+ export { setAuthProvider, getAuthToken, setAuthRefreshProvider, getRefreshToken, setAuthTokensProvider, setAuthTokens, setAuthClearProvider, clearAuth } from "./adapters/auth";
73
113
  export { imageCacheService } from "./adapters/image-cache";
74
114
  export * from "./adapters/business";
75
115
  export * from "./adapters/pending-orders";
76
116
  export * from "./adapters/print";
77
117
  export * from "./adapters/filesystem";
78
- export { KIOSK_KEYS, SELLER_ORDERS_KEYS, BUSINESS_DELIVERIES_KEYS, MENU_KEYS, REFERENCE_KEYS } from "./adapters/query-keys";
118
+ export { SELLER_ORDERS_KEYS, BUSINESS_DELIVERIES_KEYS, MENU_KEYS, REFERENCE_KEYS } from "./adapters/query-keys";
79
119
  export * from "./printer/types";
80
120
  export * from "./printer/store";
81
121
  export * from "./printer/receipt";
@@ -84,10 +124,20 @@ export * from "./printer/hooks";
84
124
  export * from "./cart/store";
85
125
  export * from "./cart/hooks";
86
126
  export * from "./catalog/hooks";
127
+ export * from "./utils/order-transitions";
128
+ export * from "./utils/business-hours";
129
+ export * from "./hooks/business-hours.hooks";
130
+ export * from "./domain/orders/service";
87
131
  export { phoenixSocket } from "./realtime/phoenix-socket";
88
132
  export { eventsService } from "./realtime/events.service";
89
133
  export { orderEventsService } from "./realtime/order-events.service";
90
134
  export { useEventsConnection } from "./realtime/useEventsConnection";
135
+ export { getSyncJobsPendingCount, debugDumpSyncJobs, drainPending } from "./sync/sync-jobs.service";
136
+ export { performFullSync } from "./sync/full-sync";
137
+ export { stopHealthProbe } from "./sync/health-probe";
138
+ export { notifyAuthChanged, subscribeAuth } from "./adapters/auth";
139
+ export { ACCESS_EXPIRED_CODE, SESSION_DEAD_CODES, SKIP_AUTH_RETRY, extractAuthFailure, isAccessExpired, isSessionDead, hasAuthRetrySkip, refreshSession, withAuthRetry, } from "./auth/session";
140
+ export type { AuthFailure, SessionTokens } from "./auth/session";
91
141
  export { getCachedImagePath, ensureImageCacheDir, getCachedImageInfo, cacheRemoteImage, cacheImageBatch, clearImageCache, pruneImageCache, resolveImageSource, stableCacheUrl } from "./image-cache/service";
92
142
  import { type SqliteDriver } from "./adapters/sqlite";
93
143
  import { type KVDriver } from "./adapters/kv";