@teincfood/core 0.10.23 → 0.10.25

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.
@@ -19,6 +19,11 @@ import { getConnectivityState } from "../adapters/connectivity";
19
19
  import { CAPABILITY_BY_COMMAND } from "../reference/capabilities";
20
20
  import { openSyncDatabase } from "../db/connection";
21
21
  import { getReferenceData } from "../reference/operations";
22
+ import { commandQueueService } from "./command-queue.service";
23
+ import { applyMenuCommandLocal } from "../reference/menu-apply";
24
+ import { emitReferenceChanged } from "../reference/events";
25
+ import { assertEntitledForCommand } from "../reference/entitlement-guard";
26
+ import { isOnlineCapable } from "./online-gates";
22
27
  export async function runOfflineCapableMutation(options) {
23
28
  // Per-command capability guard before even attempting direct call
24
29
  const required = CAPABILITY_BY_COMMAND[options.commandType];
@@ -26,19 +31,40 @@ export async function runOfflineCapableMutation(options) {
26
31
  // Online-required gate first: these commands can never succeed offline —
27
32
  // throw loud immediately instead of queuing what no transport can fulfill.
28
33
  assertOnlineFor(options.commandType, options.payload);
29
- // Local-first for engine-routed domains (menu:*): commit locally via the
30
- // engine and resolve immediately. Network is sync transport only — never a
31
- // mutation delay. The engine cloud path carries the same 2.5s cap and
32
- // returns the backend response when online.
34
+ // Local-first for engine-routed domains (menu:*): persist to SQLite and the
35
+ // durable outbox immediately, update the local reference cache, and let
36
+ // replay upload to the cloud/LAN in the background. A slow or absent
37
+ // network must never hold the form open.
33
38
  if (options.commandType.startsWith("menu:")) {
39
+ // Preserve the entitlement gate that the engine normally applies before
40
+ // queueing: local-first must not weaken subscription enforcement.
41
+ await assertEntitledForCommand(options.businessId, options.commandType);
34
42
  const command = buildCommand({
35
43
  commandType: options.commandType,
36
44
  businessId: options.businessId,
37
45
  entityId: options.entityId,
38
46
  payload: options.payload,
39
47
  });
40
- const events = await syncEngine.execute(command);
41
- return events[0]?.payload;
48
+ try {
49
+ const { keys } = await applyMenuCommandLocal(options.businessId, command);
50
+ if (keys.length)
51
+ emitReferenceChanged(options.businessId, keys);
52
+ }
53
+ catch (error) {
54
+ syncLogger.debug("OfflineCapable", "menu local apply failed", {
55
+ error: String(error),
56
+ });
57
+ }
58
+ const event = await commandQueueService.enqueue(command);
59
+ if (isOnlineCapable()) {
60
+ // Background only: save must return now.
61
+ void syncEngine.replayQueuedCommands().catch((error) => {
62
+ syncLogger.debug("OfflineCapable", "menu background replay failed", {
63
+ error: String(error),
64
+ });
65
+ });
66
+ }
67
+ return event.payload;
42
68
  }
43
69
  try {
44
70
  const db = await openSyncDatabase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teincfood/core",
3
- "version": "0.10.23",
3
+ "version": "0.10.25",
4
4
  "description": "TeincFood shared offline-first core — types, sync engine, local DB, reference data, and repositories for mobile + desktop",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",