@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
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Node adapters — platform drivers implement these.
|
|
3
|
+
*/
|
|
4
|
+
import type { Command, DomainEvent } from "../sync/types";
|
|
5
|
+
import type { ReferenceDataKey, ReferenceDataRecord } from "../reference/types";
|
|
6
|
+
import type { DiscoveredNode } from "./store";
|
|
7
|
+
export interface DiscoveryAdapter {
|
|
8
|
+
setOptions(opts: {
|
|
9
|
+
deviceId: string;
|
|
10
|
+
deviceName?: string;
|
|
11
|
+
onNodeFound: (node: DiscoveredNode) => void;
|
|
12
|
+
onNodeLost: (deviceId: string) => void;
|
|
13
|
+
}): void;
|
|
14
|
+
startScanning(): void;
|
|
15
|
+
stopScanning(): void;
|
|
16
|
+
startPublishing(opts: {
|
|
17
|
+
deviceId: string;
|
|
18
|
+
deviceName?: string;
|
|
19
|
+
port: number;
|
|
20
|
+
onNodeFound: (node: DiscoveredNode) => void;
|
|
21
|
+
onNodeLost: (deviceId: string) => void;
|
|
22
|
+
}): void;
|
|
23
|
+
stop(): void;
|
|
24
|
+
}
|
|
25
|
+
export interface LocalNodeServer {
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
stop(): Promise<void>;
|
|
28
|
+
isListening(): boolean;
|
|
29
|
+
broadcast(event: DomainEvent): void;
|
|
30
|
+
}
|
|
31
|
+
export interface LocalNodeClient {
|
|
32
|
+
connect(): Promise<void>;
|
|
33
|
+
disconnect(): void;
|
|
34
|
+
isConnected(): boolean;
|
|
35
|
+
execute(command: Command): Promise<DomainEvent[]>;
|
|
36
|
+
requestReferenceData(businessId: string, keys: ReferenceDataKey[]): Promise<{
|
|
37
|
+
data: Partial<Record<ReferenceDataKey, ReferenceDataRecord | null>>;
|
|
38
|
+
}>;
|
|
39
|
+
publishEvent?(event: DomainEvent): Promise<void> | void;
|
|
40
|
+
}
|
|
41
|
+
export interface TransportAdapter {
|
|
42
|
+
createServer(opts: {
|
|
43
|
+
port: number;
|
|
44
|
+
businessId: string;
|
|
45
|
+
secret: string;
|
|
46
|
+
onCommand: (command: Command) => Promise<DomainEvent[]>;
|
|
47
|
+
onRelayEvent: (event: DomainEvent) => void;
|
|
48
|
+
onClientConnected: (info: {
|
|
49
|
+
deviceId: string;
|
|
50
|
+
deviceName?: string;
|
|
51
|
+
host?: string;
|
|
52
|
+
}) => void;
|
|
53
|
+
onClientDisconnected: (deviceId: string) => void;
|
|
54
|
+
}): LocalNodeServer;
|
|
55
|
+
createClient(opts: {
|
|
56
|
+
node: {
|
|
57
|
+
deviceId: string;
|
|
58
|
+
host: string;
|
|
59
|
+
port: number;
|
|
60
|
+
};
|
|
61
|
+
businessId: string;
|
|
62
|
+
secret: string;
|
|
63
|
+
onEvent: (event: DomainEvent) => void;
|
|
64
|
+
onConnected: () => void;
|
|
65
|
+
onDisconnected: () => void;
|
|
66
|
+
onError: (error: unknown) => void;
|
|
67
|
+
}): LocalNodeClient;
|
|
68
|
+
}
|
|
69
|
+
export interface KeepAliveAdapter {
|
|
70
|
+
activate(tag: string): Promise<void>;
|
|
71
|
+
deactivate(tag: string): Promise<void>;
|
|
72
|
+
}
|
|
73
|
+
export interface LocalNodeDeps {
|
|
74
|
+
getDeviceId: () => string | Promise<string>;
|
|
75
|
+
getDeviceName?: () => string | undefined;
|
|
76
|
+
getBusiness: () => {
|
|
77
|
+
id: string;
|
|
78
|
+
} | null;
|
|
79
|
+
getAuth: () => {
|
|
80
|
+
user: unknown | null;
|
|
81
|
+
accessToken: string | null;
|
|
82
|
+
};
|
|
83
|
+
discovery: DiscoveryAdapter;
|
|
84
|
+
transport: TransportAdapter;
|
|
85
|
+
keepAlive?: KeepAliveAdapter;
|
|
86
|
+
cloudCommandTimeoutMs?: number;
|
|
87
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Node security helpers — platform-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* SINGLE OWNER of mesh crypto (formula + inputs). Apps (Business/Desktop/Rust)
|
|
5
|
+
* MUST NOT derive or re-implement this: core derives the secret once per
|
|
6
|
+
* business and hands the opaque value to transports. Transports only carry it.
|
|
7
|
+
*
|
|
8
|
+
* Mesh decision: the secret is business-only — `SHA256("teinc-lan:{id}:")`
|
|
9
|
+
* with a permanently empty owner segment. Same business_id ⇒ same secret on
|
|
10
|
+
* every device, regardless of which owner fields each app's store happens to
|
|
11
|
+
* carry (that variance caused `invalid_proof` between devices). The trailing
|
|
12
|
+
* colon is kept so the wire value is byte-identical to the historic formula.
|
|
13
|
+
*
|
|
14
|
+
* Pure JS WebCrypto/Node fallback so core does not depend on expo-crypto.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Self-contained SHA-256 (FIPS 180-4), no platform dependency. Slower than
|
|
18
|
+
* native but handshake-rate only. Pinned by vectors in security.test.ts.
|
|
19
|
+
*/
|
|
20
|
+
export declare function sha256Pure(data: Uint8Array): Uint8Array;
|
|
21
|
+
export declare function deriveLanSecret(business: {
|
|
22
|
+
id: string;
|
|
23
|
+
}): Promise<string>;
|
|
24
|
+
export declare function generateNonce(): Promise<string>;
|
|
25
|
+
export declare function computeProof(secret: string, nonce: string): Promise<string>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Node security helpers — platform-agnostic.
|
|
3
|
+
*
|
|
4
|
+
* SINGLE OWNER of mesh crypto (formula + inputs). Apps (Business/Desktop/Rust)
|
|
5
|
+
* MUST NOT derive or re-implement this: core derives the secret once per
|
|
6
|
+
* business and hands the opaque value to transports. Transports only carry it.
|
|
7
|
+
*
|
|
8
|
+
* Mesh decision: the secret is business-only — `SHA256("teinc-lan:{id}:")`
|
|
9
|
+
* with a permanently empty owner segment. Same business_id ⇒ same secret on
|
|
10
|
+
* every device, regardless of which owner fields each app's store happens to
|
|
11
|
+
* carry (that variance caused `invalid_proof` between devices). The trailing
|
|
12
|
+
* colon is kept so the wire value is byte-identical to the historic formula.
|
|
13
|
+
*
|
|
14
|
+
* Pure JS WebCrypto/Node fallback so core does not depend on expo-crypto.
|
|
15
|
+
*/
|
|
16
|
+
const LAN_SECRET_SALT = "teinc-lan";
|
|
17
|
+
function bytesToHex(bytes) {
|
|
18
|
+
return Array.from(bytes)
|
|
19
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
20
|
+
.join("");
|
|
21
|
+
}
|
|
22
|
+
function hexToBytes(hex) {
|
|
23
|
+
const out = new Uint8Array(hex.length / 2);
|
|
24
|
+
for (let i = 0; i < out.length; i++)
|
|
25
|
+
out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
async function sha256Hex(input) {
|
|
29
|
+
const data = new TextEncoder().encode(input);
|
|
30
|
+
// 1) WebCrypto (RN Hermes may expose global crypto.subtle, Tauri does)
|
|
31
|
+
try {
|
|
32
|
+
const g = globalThis;
|
|
33
|
+
const subtle = g?.crypto?.subtle;
|
|
34
|
+
if (subtle) {
|
|
35
|
+
const buf = await subtle.digest("SHA-256", data);
|
|
36
|
+
return bytesToHex(new Uint8Array(buf));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
catch { }
|
|
40
|
+
// 2) Node crypto (tests / desktop node)
|
|
41
|
+
try {
|
|
42
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
43
|
+
const nodeCrypto = require("crypto");
|
|
44
|
+
if (nodeCrypto?.createHash)
|
|
45
|
+
return nodeCrypto.createHash("sha256").update(data).digest("hex");
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
// 3) Pure-JS SHA-256 (Hermes/RN has neither subtle nor node crypto).
|
|
49
|
+
// MUST be real SHA-256 — proofs must verify cross-platform, and the old
|
|
50
|
+
// DJB placeholder produced zero-padded non-hashes that silently failed
|
|
51
|
+
// every handshake. No app action needed: identical output everywhere.
|
|
52
|
+
return bytesToHex(sha256Pure(data));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Self-contained SHA-256 (FIPS 180-4), no platform dependency. Slower than
|
|
56
|
+
* native but handshake-rate only. Pinned by vectors in security.test.ts.
|
|
57
|
+
*/
|
|
58
|
+
export function sha256Pure(data) {
|
|
59
|
+
const K = [
|
|
60
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
61
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
62
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
63
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
64
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
65
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
66
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
67
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
68
|
+
];
|
|
69
|
+
let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a;
|
|
70
|
+
let h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19;
|
|
71
|
+
const bitLen = data.length * 8;
|
|
72
|
+
const paddedLen = (((data.length + 8) >> 6) + 1) << 6;
|
|
73
|
+
const msg = new Uint8Array(paddedLen);
|
|
74
|
+
msg.set(data);
|
|
75
|
+
msg[data.length] = 0x80;
|
|
76
|
+
const dv = new DataView(msg.buffer);
|
|
77
|
+
dv.setUint32(paddedLen - 4, bitLen >>> 0, false);
|
|
78
|
+
dv.setUint32(paddedLen - 8, Math.floor(bitLen / 0x100000000), false);
|
|
79
|
+
const w = new Int32Array(64);
|
|
80
|
+
const rotr = (x, n) => (x >>> n) | (x << (32 - n));
|
|
81
|
+
for (let off = 0; off < paddedLen; off += 64) {
|
|
82
|
+
for (let i = 0; i < 16; i++)
|
|
83
|
+
w[i] = dv.getInt32(off + i * 4, false);
|
|
84
|
+
for (let i = 16; i < 64; i++) {
|
|
85
|
+
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >>> 3);
|
|
86
|
+
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >>> 10);
|
|
87
|
+
w[i] = (w[i - 16] + s0 + w[i - 7] + s1) | 0;
|
|
88
|
+
}
|
|
89
|
+
let [a, b, c, d, e, f, g, h] = [h0, h1, h2, h3, h4, h5, h6, h7];
|
|
90
|
+
for (let i = 0; i < 64; i++) {
|
|
91
|
+
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
92
|
+
const ch = (e & f) ^ (~e & g);
|
|
93
|
+
const t1 = (h + S1 + ch + K[i] + w[i]) | 0;
|
|
94
|
+
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
95
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
96
|
+
const t2 = (S0 + maj) | 0;
|
|
97
|
+
h = g;
|
|
98
|
+
g = f;
|
|
99
|
+
f = e;
|
|
100
|
+
e = (d + t1) | 0;
|
|
101
|
+
d = c;
|
|
102
|
+
c = b;
|
|
103
|
+
b = a;
|
|
104
|
+
a = (t1 + t2) | 0;
|
|
105
|
+
}
|
|
106
|
+
h0 = (h0 + a) | 0;
|
|
107
|
+
h1 = (h1 + b) | 0;
|
|
108
|
+
h2 = (h2 + c) | 0;
|
|
109
|
+
h3 = (h3 + d) | 0;
|
|
110
|
+
h4 = (h4 + e) | 0;
|
|
111
|
+
h5 = (h5 + f) | 0;
|
|
112
|
+
h6 = (h6 + g) | 0;
|
|
113
|
+
h7 = (h7 + h) | 0;
|
|
114
|
+
}
|
|
115
|
+
const out = new Uint8Array(32);
|
|
116
|
+
const odv = new DataView(out.buffer);
|
|
117
|
+
[h0, h1, h2, h3, h4, h5, h6, h7].forEach((v, i) => odv.setInt32(i * 4, v, false));
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
export async function deriveLanSecret(business) {
|
|
121
|
+
return sha256Hex(`${LAN_SECRET_SALT}:${business.id}:`);
|
|
122
|
+
}
|
|
123
|
+
export async function generateNonce() {
|
|
124
|
+
try {
|
|
125
|
+
const g = globalThis;
|
|
126
|
+
const cryptoObj = g?.crypto;
|
|
127
|
+
if (cryptoObj?.getRandomValues) {
|
|
128
|
+
const b = new Uint8Array(16);
|
|
129
|
+
cryptoObj.getRandomValues(b);
|
|
130
|
+
return bytesToHex(b);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch { }
|
|
134
|
+
try {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
136
|
+
const nodeCrypto = require("crypto");
|
|
137
|
+
if (nodeCrypto?.randomBytes)
|
|
138
|
+
return bytesToHex(nodeCrypto.randomBytes(16));
|
|
139
|
+
}
|
|
140
|
+
catch { }
|
|
141
|
+
// fallback Math.random
|
|
142
|
+
const b = new Uint8Array(16);
|
|
143
|
+
for (let i = 0; i < 16; i++)
|
|
144
|
+
b[i] = Math.floor(Math.random() * 256);
|
|
145
|
+
return bytesToHex(b);
|
|
146
|
+
}
|
|
147
|
+
export async function computeProof(secret, nonce) {
|
|
148
|
+
return sha256Hex(`${nonce}:${secret}`);
|
|
149
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Local Node Service — mesh, no elected, every isLocalNodeEnabled device is both server and client.
|
|
3
|
+
*/
|
|
4
|
+
import type { Command, DomainEvent } from "../sync/types";
|
|
5
|
+
import type { LocalNodeInfo } from "./types";
|
|
6
|
+
import type { LocalNodeDeps, LocalNodeClient } from "./adapters";
|
|
7
|
+
import type { ReferenceDataKey } from "../reference/types";
|
|
8
|
+
declare class LocalNodeServiceCore {
|
|
9
|
+
private server;
|
|
10
|
+
private peers;
|
|
11
|
+
private peerInfos;
|
|
12
|
+
private mode;
|
|
13
|
+
private businessId;
|
|
14
|
+
private secret;
|
|
15
|
+
private subscribed;
|
|
16
|
+
private cachedDeviceId;
|
|
17
|
+
private lifecyclePromise;
|
|
18
|
+
private starting;
|
|
19
|
+
private deps;
|
|
20
|
+
/** mDNS publish state — a failed publish must never abort discovery. */
|
|
21
|
+
private published;
|
|
22
|
+
/** Whether discovery scanning was successfully started. */
|
|
23
|
+
private discovering;
|
|
24
|
+
init(deps: LocalNodeDeps): void;
|
|
25
|
+
private getDeps;
|
|
26
|
+
private getDeviceId;
|
|
27
|
+
private runLifecycle;
|
|
28
|
+
private runInitialize;
|
|
29
|
+
initialize(): Promise<void>;
|
|
30
|
+
shutdown(): Promise<void>;
|
|
31
|
+
reconnectNow(): void;
|
|
32
|
+
private runShutdown;
|
|
33
|
+
isLocalNode(): boolean;
|
|
34
|
+
isConnectedToNode(): boolean;
|
|
35
|
+
/** Mesh legibility for Diagnostics screens: publish/scan state per leg. */
|
|
36
|
+
getMeshStatus(): {
|
|
37
|
+
mode: string;
|
|
38
|
+
listening: boolean;
|
|
39
|
+
published: boolean;
|
|
40
|
+
discovering: boolean;
|
|
41
|
+
peers: number;
|
|
42
|
+
};
|
|
43
|
+
getClient(): LocalNodeClient | null;
|
|
44
|
+
getElectedNode(): LocalNodeInfo | null;
|
|
45
|
+
broadcastToClients(event: DomainEvent): void;
|
|
46
|
+
private storeUnsub;
|
|
47
|
+
private setupStoreSubscriptions;
|
|
48
|
+
private teardownStoreSubscriptions;
|
|
49
|
+
private startAsNode;
|
|
50
|
+
/**
|
|
51
|
+
* (Re)publish this node's mDNS advertisement. Isolated from server bring-up
|
|
52
|
+
* and discovery: a publish throw must never abort scanning, sweeping, or
|
|
53
|
+
* peer dials. Safe to call repeatedly (drivers dedupe internally).
|
|
54
|
+
*/
|
|
55
|
+
private ensurePublished;
|
|
56
|
+
private startDiscovery;
|
|
57
|
+
/** Start scanning if not already running (idempotent drivers ignore repeats). */
|
|
58
|
+
private ensureDiscovery;
|
|
59
|
+
private dialInFlight;
|
|
60
|
+
private dialTimers;
|
|
61
|
+
private sweepTimer;
|
|
62
|
+
/** deviceId -> timestamp of last business_mismatch rejection. Foreign-business
|
|
63
|
+
* peers (test rigs, neighboring shops) would otherwise be redialed on every
|
|
64
|
+
* discovery event; back off quietly and re-probe after the window. */
|
|
65
|
+
private mismatchBackoff;
|
|
66
|
+
private static readonly MISMATCH_BACKOFF_MS;
|
|
67
|
+
private startPeerSweep;
|
|
68
|
+
private stopPeerSweep;
|
|
69
|
+
private connectToPeer;
|
|
70
|
+
private settleDial;
|
|
71
|
+
handleNodeCommand(command: Command): Promise<DomainEvent | null>;
|
|
72
|
+
requestReferenceData(businessId: string, keys: ReferenceDataKey[]): Promise<Partial<Record<ReferenceDataKey, import("../reference/types").ReferenceDataRecord | null>> | null>;
|
|
73
|
+
getState(): {
|
|
74
|
+
isLocalNode: boolean;
|
|
75
|
+
isConnectedToNode: boolean;
|
|
76
|
+
electedNode: LocalNodeInfo | null;
|
|
77
|
+
client: LocalNodeClient | null;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export declare const localNodeService: LocalNodeServiceCore;
|
|
81
|
+
export declare function initLocalNodeService(deps: LocalNodeDeps): LocalNodeServiceCore;
|
|
82
|
+
export type LocalNodeService = LocalNodeServiceCore;
|
|
83
|
+
export {};
|