@teincfood/core 0.7.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -21
- package/dist/adapters/auth.d.ts +8 -0
- package/dist/adapters/auth.js +36 -0
- package/dist/adapters/devices.d.ts +3 -1
- package/dist/adapters/devices.js +187 -3
- package/dist/adapters/filesystem.d.ts +4 -0
- package/dist/adapters/kv.d.ts +10 -0
- package/dist/adapters/kv.js +23 -7
- package/dist/adapters/local-node.d.ts +4 -6
- package/dist/adapters/local-node.js +9 -32
- package/dist/adapters/notify.d.ts +12 -0
- package/dist/adapters/notify.js +33 -0
- package/dist/adapters/query-keys.d.ts +4 -0
- package/dist/adapters/query-keys.js +4 -0
- package/dist/adapters/services.d.ts +96 -15
- package/dist/adapters/services.js +241 -4
- package/dist/auth/session.d.ts +66 -0
- package/dist/auth/session.js +172 -0
- package/dist/catalog/hooks.d.ts +10 -0
- package/dist/catalog/hooks.js +82 -11
- package/dist/db/migrations.js +274 -0
- package/dist/db/operations.d.ts +53 -2
- package/dist/db/operations.js +177 -8
- package/dist/domain/business/index.d.ts +5 -0
- package/dist/domain/business/index.js +5 -0
- package/dist/domain/orders/lifecycle.d.ts +6 -0
- package/dist/domain/orders/lifecycle.js +6 -0
- package/dist/domain/orders/service.d.ts +24 -0
- package/dist/domain/orders/service.js +242 -0
- package/dist/domain/payments/index.d.ts +6 -0
- package/dist/domain/payments/index.js +5 -0
- package/dist/domain/reference/index.d.ts +8 -0
- package/dist/domain/reference/index.js +8 -0
- package/dist/e2e/harness.d.ts +1 -0
- package/dist/e2e/harness.js +61 -0
- package/dist/hooks/analytics.hooks.d.ts +25 -0
- package/dist/hooks/analytics.hooks.js +214 -0
- package/dist/hooks/business-hours.hooks.d.ts +8 -0
- package/dist/hooks/business-hours.hooks.js +45 -0
- package/dist/hooks/dashboard.hooks.d.ts +30 -0
- package/dist/hooks/dashboard.hooks.js +132 -0
- package/dist/hooks/delivery.hooks.d.ts +225 -0
- package/dist/hooks/delivery.hooks.js +80 -0
- package/dist/hooks/fleet.hooks.d.ts +37 -0
- package/dist/hooks/fleet.hooks.js +229 -0
- package/dist/hooks/image.hooks.d.ts +20 -0
- package/dist/hooks/image.hooks.js +62 -0
- package/dist/hooks/kiosk.hooks.d.ts +22 -5
- package/dist/hooks/kiosk.hooks.js +74 -5
- package/dist/hooks/members.hooks.d.ts +48 -0
- package/dist/hooks/members.hooks.js +302 -0
- package/dist/hooks/offline-orders.hooks.d.ts +9 -0
- package/dist/hooks/offline-orders.hooks.js +51 -0
- package/dist/hooks/orders.hooks.d.ts +18 -39
- package/dist/hooks/orders.hooks.js +124 -343
- package/dist/hooks/places.hooks.d.ts +21 -0
- package/dist/hooks/places.hooks.js +112 -0
- package/dist/hooks/realtime-stubs.d.ts +28 -0
- package/dist/hooks/realtime-stubs.js +85 -0
- package/dist/hooks/rider.hooks.d.ts +470 -0
- package/dist/hooks/rider.hooks.js +373 -0
- package/dist/hooks/use-infinite-list.d.ts +243 -0
- package/dist/hooks/use-infinite-list.js +58 -0
- package/dist/hooks/wallet.hooks.d.ts +219 -0
- package/dist/hooks/wallet.hooks.js +56 -0
- package/dist/image-cache/service.d.ts +8 -0
- package/dist/image-cache/service.js +15 -3
- package/dist/index.d.ts +56 -6
- package/dist/index.js +73 -6
- package/dist/local-node/adapters.d.ts +87 -0
- package/dist/local-node/adapters.js +4 -0
- package/dist/local-node/index.d.ts +5 -0
- package/dist/local-node/index.js +5 -0
- package/dist/local-node/security.d.ts +25 -0
- package/dist/local-node/security.js +149 -0
- package/dist/local-node/service.d.ts +83 -0
- package/dist/local-node/service.js +706 -0
- package/dist/local-node/store.d.ts +50 -0
- package/dist/local-node/store.js +284 -0
- package/dist/local-node/types.d.ts +92 -0
- package/dist/local-node/types.js +4 -0
- package/dist/printer/receipt.d.ts +4 -0
- package/dist/printer/receipt.js +75 -0
- package/dist/printer/service.js +1 -1
- package/dist/providers/query-client.d.ts +13 -0
- package/dist/providers/query-client.js +58 -0
- package/dist/realtime/phoenix-socket.js +30 -1
- package/dist/realtime/useEventsConnection.js +11 -2
- package/dist/reference/api.d.ts +2 -0
- package/dist/reference/api.js +2 -0
- package/dist/reference/capabilities.d.ts +12 -7
- package/dist/reference/capabilities.js +27 -13
- package/dist/reference/hooks.d.ts +34 -0
- package/dist/reference/hooks.js +124 -0
- package/dist/reference/menu-apply.d.ts +29 -0
- package/dist/reference/menu-apply.js +289 -0
- package/dist/reference/menu-record.d.ts +69 -0
- package/dist/reference/menu-record.js +163 -0
- package/dist/reference/operations.d.ts +3 -0
- package/dist/reference/operations.js +35 -1
- package/dist/reference/service.js +36 -9
- package/dist/reference/types.d.ts +1 -1
- package/dist/repositories/order.repository.d.ts +7 -0
- package/dist/repositories/order.repository.js +15 -2
- package/dist/repositories/pos.repository.d.ts +4 -0
- package/dist/repositories/pos.repository.js +4 -0
- package/dist/sync/backoff.d.ts +21 -0
- package/dist/sync/backoff.js +42 -0
- package/dist/sync/command-builder.js +10 -2
- package/dist/sync/command-queue.service.d.ts +12 -0
- package/dist/sync/command-queue.service.js +81 -16
- package/dist/sync/device-lease.service.d.ts +3 -3
- package/dist/sync/device-lease.service.js +80 -20
- package/dist/sync/engine.d.ts +3 -1
- package/dist/sync/engine.js +44 -4
- package/dist/sync/full-sync.d.ts +6 -0
- package/dist/sync/full-sync.js +72 -0
- package/dist/sync/health-probe.d.ts +24 -0
- package/dist/sync/health-probe.js +138 -0
- package/dist/sync/offline-capable.js +25 -0
- package/dist/sync/online-gates.d.ts +17 -0
- package/dist/sync/online-gates.js +55 -0
- package/dist/sync/order-number.d.ts +4 -4
- package/dist/sync/order-number.js +33 -13
- package/dist/sync/order-snapshots.service.js +18 -3
- package/dist/sync/pending-orders.service.d.ts +18 -0
- package/dist/sync/pending-orders.service.js +67 -1
- package/dist/sync/reconciliation/index.d.ts +5 -0
- package/dist/sync/reconciliation/index.js +5 -0
- package/dist/sync/snapshots/entity.d.ts +6 -0
- package/dist/sync/snapshots/entity.js +6 -0
- package/dist/sync/sync-jobs.service.d.ts +18 -0
- package/dist/sync/sync-jobs.service.js +539 -0
- package/dist/sync/transition-endpoints.d.ts +11 -0
- package/dist/sync/transition-endpoints.js +30 -0
- package/dist/sync/transport-local-node.js +3 -2
- package/dist/sync/transport-rest.d.ts +7 -0
- package/dist/sync/transport-rest.js +84 -26
- package/dist/sync/use-sync-reconciliation.js +15 -1
- package/dist/test-helpers/memory-driver.js +182 -4
- package/dist/test-helpers/seed-hours.d.ts +1 -0
- package/dist/test-helpers/seed-hours.js +23 -0
- package/dist/types/api/business.api.d.ts +42 -0
- package/dist/types/api/menu.api.d.ts +15 -0
- package/dist/types/api/seller.api.d.ts +20 -0
- package/dist/types/places.d.ts +19 -0
- package/dist/types/places.js +2 -0
- package/dist/types/rider.d.ts +67 -0
- package/dist/types/rider.js +2 -0
- package/dist/utils/attempt-stats.d.ts +23 -0
- package/dist/utils/attempt-stats.js +61 -0
- package/dist/utils/business-hours.d.ts +37 -0
- package/dist/utils/business-hours.js +96 -0
- package/dist/utils/debug-log.d.ts +23 -0
- package/dist/utils/debug-log.js +153 -0
- package/dist/utils/order-filter.d.ts +1 -1
- package/dist/utils/order-filter.js +1 -1
- package/dist/utils/order-transitions.d.ts +30 -0
- package/dist/utils/order-transitions.js +185 -0
- package/dist/utils/sync-logger.js +5 -4
- package/dist/validation/offline.d.ts +46 -0
- package/dist/validation/offline.js +79 -0
- package/package.json +6 -1
- package/dist/pricing/engine.test.d.ts +0 -1
- package/dist/pricing/engine.test.js +0 -142
- package/dist/reference/lww.test.d.ts +0 -1
- package/dist/reference/lww.test.js +0 -23
- package/dist/reference/operations.test.d.ts +0 -1
- package/dist/reference/operations.test.js +0 -66
- package/dist/standalone.integration.test.d.ts +0 -1
- package/dist/standalone.integration.test.js +0 -235
- package/dist/sync/device-lease.test.d.ts +0 -1
- package/dist/sync/device-lease.test.js +0 -38
- package/dist/sync/offline-integration.test.d.ts +0 -1
- package/dist/sync/offline-integration.test.js +0 -52
- package/dist/sync/order-number.test.d.ts +0 -1
- package/dist/sync/order-number.test.js +0 -51
- package/dist/sync/perms.test.d.ts +0 -1
- package/dist/sync/perms.test.js +0 -15
- package/dist/utils/currency.test.d.ts +0 -1
- package/dist/utils/currency.test.js +0 -17
- package/dist/utils/hlc.test.d.ts +0 -1
- package/dist/utils/hlc.test.js +0 -29
- package/dist/utils/phone.test.d.ts +0 -1
- package/dist/utils/phone.test.js +0 -19
- package/dist/utils/responsive.d.ts +0 -13
- package/dist/utils/responsive.js +0 -18
- package/dist/utils/uuid.test.d.ts +0 -1
- package/dist/utils/uuid.test.js +0 -13
- package/dist/utils/validation.test.d.ts +0 -1
- package/dist/utils/validation.test.js +0 -23
package/README.md
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
TeincFood shared offline-first core — single source of truth for mobile (`TeincFoodBusiness`) and desktop (`TeincFoodDesktop`).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Current: `0.7.31`. UI → hooks → repositories → core → SQLite → SyncEngine (cloud → LAN mesh → queue) → reconciliation → UI.
|
|
6
|
+
|
|
7
|
+
## What lives here
|
|
6
8
|
|
|
7
9
|
- `types/api/*` — snake_case API contracts matching backend
|
|
8
|
-
- `utils/*` — currency, error, format, uuid, order-number (
|
|
9
|
-
- `sync/*` — engine, command-queue, transports,
|
|
10
|
+
- `utils/*` — currency, error, format, uuid, order-number (DD-RRR-CCC), order-transitions, etc.
|
|
11
|
+
- `sync/*` — engine, command-queue, transports (`rest`, `local_node`), pending-orders, order-snapshots, reconciliation
|
|
10
12
|
- `db/*` — migrations + operations (driver-agnostic, takes a `SqliteDriver`)
|
|
11
|
-
- `reference/*` — versioned reference-data cache
|
|
12
|
-
- `repositories/*` — order/pos repositories
|
|
13
|
-
- `
|
|
13
|
+
- `reference/*` — versioned reference-data cache (per-key HLC LWW)
|
|
14
|
+
- `repositories/*` — order/pos repositories (explicit verbs, no `order.update`)
|
|
15
|
+
- `local-node/*` — **LAN mesh**: lib-owned crypto/protocol/orchestration (`docs/MESH.md`)
|
|
16
|
+
- `adapters/*` — platform seams (KV, SQLite, HTTP, local-node, connectivity, devices, auth, business, …)
|
|
14
17
|
|
|
15
18
|
## Adapters
|
|
16
19
|
|
|
@@ -18,27 +21,29 @@ Apps supply platform adapters via `createTeincCore({ storage, db, http, ... })`:
|
|
|
18
21
|
|
|
19
22
|
- `KVStorage` — async `getItem/setItem/removeItem` (MMKV-wrapped on mobile, `plugin-store` on desktop)
|
|
20
23
|
- `SqliteDriver` — `execAsync/runAsync/getFirstAsync/getAllAsync/withTransactionAsync`
|
|
21
|
-
- `HttpClient` — axios instance with auth interceptors (token plumbing stays app-side)
|
|
22
|
-
- `
|
|
24
|
+
- `HttpClient` — axios/fetch instance with auth interceptors (token plumbing stays app-side)
|
|
25
|
+
- `LocalNodeDeps` — `transport {createServer, createClient}`, `discovery {startPublishing, startScanning, ...}`, `getAuth/getBusiness/getDeviceId`. Core derives the LAN secret and owns the mesh lifecycle; apps only provide sockets/mDNS/TLS primitives.
|
|
23
26
|
|
|
24
|
-
##
|
|
27
|
+
## LAN mesh
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const core = createTeincCore({ storage, db, http });
|
|
29
|
-
```
|
|
29
|
+
No election: every `isLocalNodeEnabled` device is server + client. Spec: `docs/MESH.md`.
|
|
30
|
+
Two-process harness (real mDNS + TLS, no apps): `scripts/node-mesh/README.md`.
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
## Docs
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
- `docs/MESH.md` — LAN mesh, single source of truth (crypto, wire protocol, lifecycle, order flow)
|
|
35
|
+
- `docs/OFFLINE_FIRST_STRATEGY.md` — offline-first lifecycles (offline→online, Phoenix, mesh)
|
|
36
|
+
- `docs/CORE_ARCHITECTURE.md` — module map and responsibilities
|
|
37
|
+
- `docs/AUDIT.md` — historical `0.7.10` pre-implementation snapshot (superseded where it conflicts with `MESH.md`)
|
|
38
|
+
|
|
39
|
+
## Checks
|
|
34
40
|
|
|
35
41
|
```bash
|
|
36
|
-
|
|
37
|
-
npm
|
|
42
|
+
npx tsc --noEmit # 0 errors
|
|
43
|
+
npm test # 101/101 (mesh + security vectors + sync)
|
|
38
44
|
```
|
|
39
45
|
|
|
40
|
-
##
|
|
46
|
+
## Publishing
|
|
41
47
|
|
|
42
|
-
-
|
|
43
|
-
|
|
44
|
-
- v0.4 phoenix/events
|
|
48
|
+
Apps consume the packed tarball (`teincfood-core-<version>.tgz` refreshed into
|
|
49
|
+
`TeincFoodBusiness`/`TeincFoodDesktop`) or `npm publish --access public`.
|
package/dist/adapters/auth.d.ts
CHANGED
|
@@ -11,5 +11,13 @@ export declare const useAuthStore: {
|
|
|
11
11
|
user: AuthUser | null;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
+
export declare function subscribeAuth(listener: () => void): () => void;
|
|
14
15
|
export declare function setAuthProvider(fn: () => string | null): void;
|
|
16
|
+
export declare function setAuthRefreshProvider(fn: () => string | null): void;
|
|
17
|
+
export declare function setAuthTokensProvider(fn: (at: string, rt: string) => void): void;
|
|
18
|
+
export declare function setAuthClearProvider(fn: () => void): void;
|
|
15
19
|
export declare function getAuthToken(): string | null;
|
|
20
|
+
export declare function getRefreshToken(): string | null;
|
|
21
|
+
export declare function setAuthTokens(at: string, rt: string): void;
|
|
22
|
+
export declare function clearAuth(): void;
|
|
23
|
+
export declare function notifyAuthChanged(): void;
|
package/dist/adapters/auth.js
CHANGED
|
@@ -9,9 +9,45 @@ export const useAuthStore = {
|
|
|
9
9
|
getState: () => ({ user }),
|
|
10
10
|
};
|
|
11
11
|
let getAccessToken = null;
|
|
12
|
+
let getRefresh = null;
|
|
13
|
+
let setTokens = null;
|
|
14
|
+
let clearFn = null;
|
|
15
|
+
const authListeners = new Set();
|
|
16
|
+
export function subscribeAuth(listener) {
|
|
17
|
+
authListeners.add(listener);
|
|
18
|
+
return () => authListeners.delete(listener);
|
|
19
|
+
}
|
|
20
|
+
function notifyAuth() {
|
|
21
|
+
authListeners.forEach((l) => l());
|
|
22
|
+
}
|
|
12
23
|
export function setAuthProvider(fn) {
|
|
13
24
|
getAccessToken = fn;
|
|
14
25
|
}
|
|
26
|
+
export function setAuthRefreshProvider(fn) {
|
|
27
|
+
getRefresh = fn;
|
|
28
|
+
}
|
|
29
|
+
export function setAuthTokensProvider(fn) {
|
|
30
|
+
setTokens = fn;
|
|
31
|
+
}
|
|
32
|
+
export function setAuthClearProvider(fn) {
|
|
33
|
+
clearFn = fn;
|
|
34
|
+
}
|
|
15
35
|
export function getAuthToken() {
|
|
16
36
|
return getAccessToken ? getAccessToken() : null;
|
|
17
37
|
}
|
|
38
|
+
export function getRefreshToken() {
|
|
39
|
+
return getRefresh ? getRefresh() : null;
|
|
40
|
+
}
|
|
41
|
+
export function setAuthTokens(at, rt) {
|
|
42
|
+
if (setTokens)
|
|
43
|
+
setTokens(at, rt);
|
|
44
|
+
notifyAuth();
|
|
45
|
+
}
|
|
46
|
+
export function clearAuth() {
|
|
47
|
+
if (clearFn)
|
|
48
|
+
clearFn();
|
|
49
|
+
notifyAuth();
|
|
50
|
+
}
|
|
51
|
+
export function notifyAuthChanged() {
|
|
52
|
+
notifyAuth();
|
|
53
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Devices service
|
|
2
|
+
* Devices service — stable per-device UUID for DD lease.
|
|
3
|
+
* Persists via KV sync so DD stays same for life of device (until wipe).
|
|
3
4
|
*/
|
|
4
5
|
export declare function setAppInstanceId(id: string): void;
|
|
5
6
|
export declare function getAppInstanceId(): string;
|
|
7
|
+
export declare function getAppInstanceIdAsync(): Promise<string>;
|
package/dist/adapters/devices.js
CHANGED
|
@@ -1,10 +1,194 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Devices service
|
|
2
|
+
* Devices service — stable per-device UUID for DD lease.
|
|
3
|
+
* Persists via KV sync so DD stays same for life of device (until wipe).
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
+
import { getItemSync, setItemSync, getItem, setItem } from "./kv";
|
|
6
|
+
import { generateUUID } from "../utils/uuid";
|
|
7
|
+
let appInstanceId = null;
|
|
8
|
+
const APP_ID_KEY = "teinc_app_instance_id";
|
|
9
|
+
// For Tauri desktop, try to restore from localStorage synchronously at import to avoid async race generating a new UUID on every cargo tauri dev restart
|
|
10
|
+
try {
|
|
11
|
+
if (typeof localStorage !== "undefined") {
|
|
12
|
+
const ls = localStorage.getItem(APP_ID_KEY);
|
|
13
|
+
if (ls) {
|
|
14
|
+
let v = ls;
|
|
15
|
+
try {
|
|
16
|
+
if (v.startsWith('"'))
|
|
17
|
+
v = JSON.parse(v);
|
|
18
|
+
}
|
|
19
|
+
catch { }
|
|
20
|
+
try {
|
|
21
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
22
|
+
v = JSON.parse(v);
|
|
23
|
+
}
|
|
24
|
+
catch { }
|
|
25
|
+
if (v.length > 8)
|
|
26
|
+
appInstanceId = v;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
5
31
|
export function setAppInstanceId(id) {
|
|
6
32
|
appInstanceId = id;
|
|
33
|
+
try {
|
|
34
|
+
setItemSync(APP_ID_KEY, id);
|
|
35
|
+
}
|
|
36
|
+
catch { }
|
|
7
37
|
}
|
|
8
38
|
export function getAppInstanceId() {
|
|
9
|
-
|
|
39
|
+
if (appInstanceId)
|
|
40
|
+
return appInstanceId;
|
|
41
|
+
// Check localStorage first (covers Tauri webview where KVDriver async may race)
|
|
42
|
+
try {
|
|
43
|
+
const ls = typeof localStorage !== "undefined" ? localStorage.getItem(APP_ID_KEY) : null;
|
|
44
|
+
if (ls) {
|
|
45
|
+
let v = ls;
|
|
46
|
+
try {
|
|
47
|
+
if (v.startsWith('"'))
|
|
48
|
+
v = JSON.parse(v);
|
|
49
|
+
}
|
|
50
|
+
catch { }
|
|
51
|
+
try {
|
|
52
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
53
|
+
v = JSON.parse(v);
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
if (v.length > 8) {
|
|
57
|
+
appInstanceId = v;
|
|
58
|
+
return v;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch { }
|
|
63
|
+
try {
|
|
64
|
+
const stored = getItemSync(APP_ID_KEY);
|
|
65
|
+
if (stored && typeof stored === "string" && stored.length > 8) {
|
|
66
|
+
let v = stored;
|
|
67
|
+
try {
|
|
68
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
69
|
+
v = JSON.parse(v);
|
|
70
|
+
}
|
|
71
|
+
catch { }
|
|
72
|
+
if (v.length > 8) {
|
|
73
|
+
appInstanceId = v;
|
|
74
|
+
try {
|
|
75
|
+
if (typeof localStorage !== "undefined")
|
|
76
|
+
localStorage.setItem(APP_ID_KEY, JSON.stringify(v));
|
|
77
|
+
}
|
|
78
|
+
catch { }
|
|
79
|
+
return v;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch { }
|
|
84
|
+
const id = generateUUID();
|
|
85
|
+
appInstanceId = id;
|
|
86
|
+
try {
|
|
87
|
+
setItemSync(APP_ID_KEY, id);
|
|
88
|
+
}
|
|
89
|
+
catch { }
|
|
90
|
+
try {
|
|
91
|
+
if (typeof localStorage !== "undefined")
|
|
92
|
+
localStorage.setItem(APP_ID_KEY, JSON.stringify(id));
|
|
93
|
+
}
|
|
94
|
+
catch { }
|
|
95
|
+
return id;
|
|
96
|
+
}
|
|
97
|
+
export async function getAppInstanceIdAsync() {
|
|
98
|
+
if (appInstanceId)
|
|
99
|
+
return appInstanceId;
|
|
100
|
+
// Try localStorage directly first (covers desktop webview where KVDriver's async getItem may race with Tauri store load)
|
|
101
|
+
try {
|
|
102
|
+
const ls = typeof localStorage !== "undefined" ? localStorage.getItem(APP_ID_KEY) : null;
|
|
103
|
+
if (ls) {
|
|
104
|
+
let v = ls;
|
|
105
|
+
try {
|
|
106
|
+
if (v.startsWith('"'))
|
|
107
|
+
v = JSON.parse(v);
|
|
108
|
+
}
|
|
109
|
+
catch { }
|
|
110
|
+
// Handle double-stringified "\"xxx\""
|
|
111
|
+
try {
|
|
112
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
113
|
+
v = JSON.parse(v);
|
|
114
|
+
}
|
|
115
|
+
catch { }
|
|
116
|
+
if (v.length > 8) {
|
|
117
|
+
appInstanceId = v;
|
|
118
|
+
return v;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch { }
|
|
123
|
+
try {
|
|
124
|
+
const stored = await getItem(APP_ID_KEY);
|
|
125
|
+
try {
|
|
126
|
+
const { syncLogger } = require("../utils/sync-logger");
|
|
127
|
+
syncLogger.debug("Devices", "getAppInstanceIdAsync getItem", { stored, len: stored?.length });
|
|
128
|
+
}
|
|
129
|
+
catch { }
|
|
130
|
+
if (stored && typeof stored === "string" && stored.length > 8) {
|
|
131
|
+
// Handle double-stringified case "\"xxx\"" from older builds
|
|
132
|
+
let v = stored;
|
|
133
|
+
try {
|
|
134
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
135
|
+
v = JSON.parse(v);
|
|
136
|
+
}
|
|
137
|
+
catch { }
|
|
138
|
+
if (v.length > 8) {
|
|
139
|
+
appInstanceId = v; // also prime localStorage for sync fallback
|
|
140
|
+
try {
|
|
141
|
+
if (typeof localStorage !== "undefined")
|
|
142
|
+
localStorage.setItem(APP_ID_KEY, JSON.stringify(v));
|
|
143
|
+
}
|
|
144
|
+
catch { }
|
|
145
|
+
return v;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch { }
|
|
150
|
+
// fallback to sync check
|
|
151
|
+
try {
|
|
152
|
+
const s = getItemSync(APP_ID_KEY);
|
|
153
|
+
try {
|
|
154
|
+
const { syncLogger } = require("../utils/sync-logger");
|
|
155
|
+
syncLogger.debug("Devices", "getAppInstanceIdAsync getItemSync", { s, len: s?.length });
|
|
156
|
+
}
|
|
157
|
+
catch { }
|
|
158
|
+
if (s && typeof s === "string" && s.length > 8) {
|
|
159
|
+
let v = s;
|
|
160
|
+
try {
|
|
161
|
+
if (v.startsWith('"') && v.endsWith('"'))
|
|
162
|
+
v = JSON.parse(v);
|
|
163
|
+
}
|
|
164
|
+
catch { }
|
|
165
|
+
if (v.length > 8) {
|
|
166
|
+
appInstanceId = v;
|
|
167
|
+
return v;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch { }
|
|
172
|
+
const id = generateUUID();
|
|
173
|
+
appInstanceId = id;
|
|
174
|
+
try {
|
|
175
|
+
const { syncLogger } = require("../utils/sync-logger");
|
|
176
|
+
syncLogger.info("Devices", "generated new appInstanceId", { id });
|
|
177
|
+
}
|
|
178
|
+
catch { }
|
|
179
|
+
try {
|
|
180
|
+
await setItem(APP_ID_KEY, id);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
try {
|
|
184
|
+
setItemSync(APP_ID_KEY, id);
|
|
185
|
+
}
|
|
186
|
+
catch { }
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
if (typeof localStorage !== "undefined")
|
|
190
|
+
localStorage.setItem(APP_ID_KEY, JSON.stringify(id));
|
|
191
|
+
}
|
|
192
|
+
catch { }
|
|
193
|
+
return id;
|
|
10
194
|
}
|
|
@@ -17,6 +17,10 @@ export interface FileSystemAdapter {
|
|
|
17
17
|
}): Promise<void>;
|
|
18
18
|
readDirectoryAsync(path: string): Promise<string[]>;
|
|
19
19
|
getDocumentDirectory(): string;
|
|
20
|
+
readAsStringAsync?(path: string, opts?: {
|
|
21
|
+
encoding?: string;
|
|
22
|
+
}): Promise<string>;
|
|
23
|
+
readAsBase64Async?(path: string): Promise<string>;
|
|
20
24
|
}
|
|
21
25
|
export declare function setFileSystemAdapter(a: FileSystemAdapter | null): void;
|
|
22
26
|
export declare function getFileSystemAdapter(): FileSystemAdapter | null;
|
package/dist/adapters/kv.d.ts
CHANGED
|
@@ -6,6 +6,16 @@ export interface KVDriver {
|
|
|
6
6
|
getItem(key: string): Promise<string | null> | string | null;
|
|
7
7
|
setItem(key: string, value: string): Promise<void> | void;
|
|
8
8
|
removeItem(key: string): Promise<void> | void;
|
|
9
|
+
/**
|
|
10
|
+
* Optional synchronous access. Sync callers (e.g. order-number callout
|
|
11
|
+
* sequencing) MUST read persisted state — an async-only driver makes them
|
|
12
|
+
* fall back to the ephemeral memory map, silently resetting sequences on
|
|
13
|
+
* every launch. Drivers backed by async storage (Tauri store) implement
|
|
14
|
+
* these over a synchronously-readable cache (localStorage + memory).
|
|
15
|
+
*/
|
|
16
|
+
getItemSync?(key: string): string | null;
|
|
17
|
+
setItemSync?(key: string, value: string): void;
|
|
18
|
+
removeItemSync?(key: string): void;
|
|
9
19
|
}
|
|
10
20
|
export declare function setKVDriver(d: KVDriver): void;
|
|
11
21
|
export declare function getKVDriver(): KVDriver;
|
package/dist/adapters/kv.js
CHANGED
|
@@ -49,17 +49,25 @@ export async function removeItem(key) {
|
|
|
49
49
|
await kvRemoveItem(key);
|
|
50
50
|
}
|
|
51
51
|
// Synchronous fallbacks for legacy callers that used MMKV sync API
|
|
52
|
-
// 0.7.1: delegate to driver when driver supports sync (MMKV), otherwise memory
|
|
52
|
+
// 0.7.1: delegate to driver when driver supports sync (MMKV), otherwise memory.
|
|
53
|
+
// Drivers with async storage expose getItemSync/setItemSync over a sync-readable
|
|
54
|
+
// cache — prefer those, else a Promise-returning getItem degrades to the
|
|
55
|
+
// ephemeral memory map (sequences reset every launch).
|
|
53
56
|
export function getItemSync(key) {
|
|
54
57
|
let raw;
|
|
55
58
|
if (driver) {
|
|
56
59
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
if (driver.getItemSync) {
|
|
61
|
+
raw = driver.getItemSync(key) ?? memory.get(key) ?? null;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
const v = driver.getItem(key);
|
|
65
|
+
// if driver returns Promise, we can't await sync — fall back to memory
|
|
66
|
+
if (v instanceof Promise)
|
|
67
|
+
raw = memory.get(key) ?? null;
|
|
68
|
+
else
|
|
69
|
+
raw = v ?? memory.get(key) ?? null;
|
|
70
|
+
}
|
|
63
71
|
}
|
|
64
72
|
catch {
|
|
65
73
|
raw = memory.get(key) ?? null;
|
|
@@ -82,6 +90,10 @@ export function setItemSync(key, value) {
|
|
|
82
90
|
memory.set(key, str);
|
|
83
91
|
if (driver) {
|
|
84
92
|
try {
|
|
93
|
+
if (driver.setItemSync) {
|
|
94
|
+
driver.setItemSync(key, str);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
85
97
|
const r = driver.setItem(key, str);
|
|
86
98
|
// if async, also keep memory
|
|
87
99
|
if (r instanceof Promise)
|
|
@@ -94,6 +106,10 @@ export function removeItemSync(key) {
|
|
|
94
106
|
memory.delete(key);
|
|
95
107
|
if (driver) {
|
|
96
108
|
try {
|
|
109
|
+
if (driver.removeItemSync) {
|
|
110
|
+
driver.removeItemSync(key);
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
97
113
|
const r = driver.removeItem(key);
|
|
98
114
|
if (r instanceof Promise)
|
|
99
115
|
r.catch(() => { });
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local Node
|
|
3
|
-
* Host apps
|
|
2
|
+
* Local Node adapters — re-export core-owned implementation for compat.
|
|
3
|
+
* Host apps should import from @teincfood/core/local-node instead.
|
|
4
4
|
*/
|
|
5
5
|
import type { Command, DomainEvent } from "../sync/types";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
publishEvent?(event: DomainEvent): void | Promise<void>;
|
|
9
|
-
}
|
|
6
|
+
import type { LocalNodeClient as CoreClient } from "../local-node/adapters";
|
|
7
|
+
export type LocalNodeClient = CoreClient;
|
|
10
8
|
export interface ElectedNode {
|
|
11
9
|
deviceId: string;
|
|
12
10
|
}
|
|
@@ -1,36 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Local Node
|
|
3
|
-
* Host apps
|
|
2
|
+
* Local Node adapters — re-export core-owned implementation for compat.
|
|
3
|
+
* Host apps should import from @teincfood/core/local-node instead.
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let isLocalNodeFlag = false;
|
|
8
|
-
let electedNode = null;
|
|
9
|
-
let client = null;
|
|
5
|
+
import { localNodeService as coreService } from "../local-node/service";
|
|
6
|
+
import { useLocalNodeStore as coreStore } from "../local-node/store";
|
|
10
7
|
export function setLocalNodeState(s) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
isConnected = s.isConnectedToNode;
|
|
15
|
-
if (s.isLocalNode !== undefined)
|
|
16
|
-
isLocalNodeFlag = s.isLocalNode;
|
|
17
|
-
if (s.electedNode !== undefined)
|
|
18
|
-
electedNode = s.electedNode;
|
|
19
|
-
if (s.client !== undefined)
|
|
20
|
-
client = s.client;
|
|
8
|
+
// Compat: no-op — core store/service is source of truth.
|
|
9
|
+
// Business/Desktop bootstrap now calls initLocalNodeService(deps).
|
|
10
|
+
void s;
|
|
21
11
|
}
|
|
22
|
-
export const localNodeService =
|
|
23
|
-
|
|
24
|
-
isConnectedToNode: () => isConnected,
|
|
25
|
-
getElectedNode: () => electedNode,
|
|
26
|
-
getClient: () => client,
|
|
27
|
-
broadcastToClients: (_event) => { },
|
|
28
|
-
handleNodeCommand: async (_command) => null,
|
|
29
|
-
};
|
|
30
|
-
export const useLocalNodeStore = {
|
|
31
|
-
getState: () => ({
|
|
32
|
-
isLocalNodeEnabled: isLocalEnabled,
|
|
33
|
-
isConnectedToNode: isConnected,
|
|
34
|
-
electedNode,
|
|
35
|
-
}),
|
|
36
|
-
};
|
|
12
|
+
export const localNodeService = coreService;
|
|
13
|
+
export const useLocalNodeStore = coreStore;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notify adapter — platform toast injection (sonner on desktop,
|
|
3
|
+
* sonner-native on mobile). Core hooks never import a toast library.
|
|
4
|
+
*/
|
|
5
|
+
interface NotifyHandlers {
|
|
6
|
+
success: (message: string) => void;
|
|
7
|
+
error: (message: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function setNotifyHandlers(next: Partial<NotifyHandlers>): void;
|
|
10
|
+
export declare function notifySuccess(message: string): void;
|
|
11
|
+
export declare function notifyError(message: string): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notify adapter — platform toast injection (sonner on desktop,
|
|
3
|
+
* sonner-native on mobile). Core hooks never import a toast library.
|
|
4
|
+
*/
|
|
5
|
+
let handlers = {
|
|
6
|
+
success: (m) => {
|
|
7
|
+
try {
|
|
8
|
+
console.debug("[notify] success", m);
|
|
9
|
+
}
|
|
10
|
+
catch { }
|
|
11
|
+
},
|
|
12
|
+
error: (m) => {
|
|
13
|
+
try {
|
|
14
|
+
console.debug("[notify] error", m);
|
|
15
|
+
}
|
|
16
|
+
catch { }
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
export function setNotifyHandlers(next) {
|
|
20
|
+
handlers = { ...handlers, ...next };
|
|
21
|
+
}
|
|
22
|
+
export function notifySuccess(message) {
|
|
23
|
+
try {
|
|
24
|
+
handlers.success(message);
|
|
25
|
+
}
|
|
26
|
+
catch { }
|
|
27
|
+
}
|
|
28
|
+
export function notifyError(message) {
|
|
29
|
+
try {
|
|
30
|
+
handlers.error(message);
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
|
+
}
|
|
@@ -25,3 +25,7 @@ export const MENU_KEYS = {
|
|
|
25
25
|
export const REFERENCE_KEYS = {
|
|
26
26
|
all: ["reference"],
|
|
27
27
|
};
|
|
28
|
+
export const SELLER_DASHBOARD_KEYS = {
|
|
29
|
+
all: ["seller-dashboard"],
|
|
30
|
+
full: (businessId) => ["seller-dashboard", "full", businessId].filter((x) => x !== undefined),
|
|
31
|
+
};
|