kaafil-react-uikit 0.1.0-beta.1 → 0.2.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.
Files changed (61) hide show
  1. package/README.md +12 -6
  2. package/dist/admin/index.cjs +343 -343
  3. package/dist/admin/index.cjs.map +1 -1
  4. package/dist/admin/index.js +6 -6
  5. package/dist/admin/index.js.map +1 -1
  6. package/dist/chunk-57SUK3GD.cjs +110 -0
  7. package/dist/chunk-57SUK3GD.cjs.map +1 -0
  8. package/dist/{chunk-LL243STJ.cjs → chunk-6WV5VYT2.cjs} +111 -95
  9. package/dist/chunk-6WV5VYT2.cjs.map +1 -0
  10. package/dist/{chunk-YDGR7JSY.js → chunk-7ISKFGLW.js} +28 -12
  11. package/dist/chunk-7ISKFGLW.js.map +1 -0
  12. package/dist/{chunk-PTQ2CJKE.cjs → chunk-7UFX3Y2U.cjs} +4 -4
  13. package/dist/{chunk-PTQ2CJKE.cjs.map → chunk-7UFX3Y2U.cjs.map} +1 -1
  14. package/dist/{chunk-6FPAGGFL.js → chunk-A4Z2YBEF.js} +29 -8
  15. package/dist/chunk-A4Z2YBEF.js.map +1 -0
  16. package/dist/{chunk-IIPQ4JNC.js → chunk-GJ2J3PYN.js} +3 -3
  17. package/dist/{chunk-IIPQ4JNC.js.map → chunk-GJ2J3PYN.js.map} +1 -1
  18. package/dist/{chunk-PJRZCOFF.cjs → chunk-HTIY33UH.cjs} +37 -37
  19. package/dist/{chunk-PJRZCOFF.cjs.map → chunk-HTIY33UH.cjs.map} +1 -1
  20. package/dist/chunk-KW5LH6KV.js +105 -0
  21. package/dist/chunk-KW5LH6KV.js.map +1 -0
  22. package/dist/{chunk-XI7MK4Y7.js → chunk-L3QEMEFM.js} +3 -3
  23. package/dist/{chunk-XI7MK4Y7.js.map → chunk-L3QEMEFM.js.map} +1 -1
  24. package/dist/{chunk-WUAFL77X.js → chunk-LJJMNZ7B.js} +7 -101
  25. package/dist/chunk-LJJMNZ7B.js.map +1 -0
  26. package/dist/{chunk-QHUDOVKW.cjs → chunk-OZJ74DVQ.cjs} +33 -17
  27. package/dist/chunk-OZJ74DVQ.cjs.map +1 -0
  28. package/dist/{chunk-VHTSTUCJ.cjs → chunk-RG4YDSCN.cjs} +17 -114
  29. package/dist/chunk-RG4YDSCN.cjs.map +1 -0
  30. package/dist/{chunk-UYJ6LIWP.js → chunk-RSC2ZJUP.js} +35 -19
  31. package/dist/chunk-RSC2ZJUP.js.map +1 -0
  32. package/dist/{chunk-UUGMNP27.js → chunk-SIAPCJ7G.js} +5 -5
  33. package/dist/{chunk-UUGMNP27.js.map → chunk-SIAPCJ7G.js.map} +1 -1
  34. package/dist/{chunk-EM7JV3D7.cjs → chunk-UALMCHNW.cjs} +29 -8
  35. package/dist/chunk-UALMCHNW.cjs.map +1 -0
  36. package/dist/{chunk-ACVU55PZ.cjs → chunk-YNHOPYBK.cjs} +12 -12
  37. package/dist/{chunk-ACVU55PZ.cjs.map → chunk-YNHOPYBK.cjs.map} +1 -1
  38. package/dist/core/index.cjs +126 -120
  39. package/dist/core/index.cjs.map +1 -1
  40. package/dist/core/index.js +19 -13
  41. package/dist/core/index.js.map +1 -1
  42. package/dist/index.css +1 -1
  43. package/dist/manager/index.cjs +278 -283
  44. package/dist/manager/index.cjs.map +1 -1
  45. package/dist/manager/index.js +48 -52
  46. package/dist/manager/index.js.map +1 -1
  47. package/dist/traveller/index.cjs +35 -35
  48. package/dist/traveller/index.js +5 -5
  49. package/package.json +4 -3
  50. package/dist/chunk-6FPAGGFL.js.map +0 -1
  51. package/dist/chunk-EM7JV3D7.cjs.map +0 -1
  52. package/dist/chunk-LL243STJ.cjs.map +0 -1
  53. package/dist/chunk-PZKXLQSU.js +0 -10
  54. package/dist/chunk-PZKXLQSU.js.map +0 -1
  55. package/dist/chunk-QHUDOVKW.cjs.map +0 -1
  56. package/dist/chunk-TOBZFADB.cjs +0 -12
  57. package/dist/chunk-TOBZFADB.cjs.map +0 -1
  58. package/dist/chunk-UYJ6LIWP.js.map +0 -1
  59. package/dist/chunk-VHTSTUCJ.cjs.map +0 -1
  60. package/dist/chunk-WUAFL77X.js.map +0 -1
  61. package/dist/chunk-YDGR7JSY.js.map +0 -1
@@ -1,10 +0,0 @@
1
- import { useRequiredContext, OfflineEngineContext } from './chunk-6FPAGGFL.js';
2
-
3
- // src/core/hooks/useOfflineEngine.ts
4
- function useOfflineEngine() {
5
- return useRequiredContext(OfflineEngineContext, "useOfflineEngine", "OfflineShell");
6
- }
7
-
8
- export { useOfflineEngine };
9
- //# sourceMappingURL=chunk-PZKXLQSU.js.map
10
- //# sourceMappingURL=chunk-PZKXLQSU.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/hooks/useOfflineEngine.ts"],"names":[],"mappings":";;;AAgBO,SAAS,gBAAA,GAAkC;AAChD,EAAA,OAAO,kBAAA,CAAmB,oBAAA,EAAsB,kBAAA,EAAoB,cAAc,CAAA;AACpF","file":"chunk-PZKXLQSU.js","sourcesContent":["'use client';\n\n// `08-core-hooks.md §2.1`. The escape hatch underneath every hook in §2 — a\n// composite should reach for a narrower hook before this one.\n\nimport type { OfflineEngine, OutboxOp } from 'kaafil-js/client';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { useRequiredContext } from '../internal/useRequiredContext';\n\n// Re-exported so a composite (`ManagerSyncCenterSection.types.ts`) can name\n// one outbox op's shape without importing `kaafil-js/client` directly —\n// hard rule #1.\nexport type { OutboxOp };\n\n/** Returns the engine instance `OfflineShell` opened via\n * `client.openOffline(options)`. Throws outside the provider tree. */\nexport function useOfflineEngine(): OfflineEngine {\n return useRequiredContext(OfflineEngineContext, 'useOfflineEngine', 'OfflineShell');\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/hooks/useConflicts.ts","../src/core/hooks/useManagerMe.ts","../src/core/hooks/useNotifications.ts"],"names":["useContext","OfflineEngineContext","useState","useOfflineEvent","useMemo","useKaafilClient","useEffect"],"mappings":";;;;;AA4BA,SAAS,kBAAkB,EAAA,EAAuB;AAChD,EAAA,OAAO,EAAA,CAAG,MAAA,KAAW,QAAA,IAAY,EAAA,CAAG,YAAY,IAAA,KAAS,kBAAA;AAC3D;AAEO,SAAS,aAAa,OAAA,EAAkC;AAK7D,EAAA,MAAM,MAAA,GAASA,iBAAWC,sCAAoB,CAAA;AAM9C,EAAA,MAAM,CAAC,IAAA,EAAM,YAAY,CAAA,GAAIC,eAAS,CAAC,CAAA;AAEvC,EAAAC,iCAAA,CAAgB,cAAc,MAAM,YAAA,CAAa,CAAC,OAAA,KAAY,OAAA,GAAU,CAAC,CAAC,CAAA;AAC1E,EAAAA,iCAAA,CAAgB,gBAAgB,MAAM,YAAA,CAAa,CAAC,OAAA,KAAY,OAAA,GAAU,CAAC,CAAC,CAAA;AAG5E,EAAA,MAAM,WAAA,GAAcC,aAAA;AAAA,IAClB,MACE,MAAA,KAAW,IAAA,GACP,EAAC,GACD,OAAO,MAAA,CAAO,GAAA,EAAI,CAAE,MAAA,CAAO,CAAC,EAAA,KAAO,EAAA,CAAG,YAAY,OAAA,IAAW,iBAAA,CAAkB,EAAE,CAAC,CAAA;AAAA;AAAA,IAExF,CAAC,MAAA,EAAQ,OAAA,EAAS,IAAI;AAAA,GACxB;AAEA,EAAA,MAAM,SAAA,GACJ,WAAW,IAAA,GACP,KACA,WAAA,CAAY,GAAA,CAAI,CAAC,EAAA,KAAO;AACtB,IAAA,MAAM,YAAA,GACJ,GAAG,MAAA,KAAW,MAAA,GACV,OAAO,QAAA,CACJ,IAAA,CAAK,GAAG,OAAA,EAAS,EAAA,CAAG,OAAO,QAAQ,CAAA,CACnC,KAAK,CAAC,GAAA,KAAQ,IAAI,EAAA,KAAO,EAAA,CAAG,MAAA,EAAQ,EAAE,CAAA,GACzC,MAAA;AACN,IAAA,OAAO;AAAA,MACL,MAAM,EAAA,CAAG,EAAA;AAAA,MACT,MAAA,EAAQ,EAAA,CAAG,MAAA,EAAQ,QAAA,IAAY,EAAA,CAAG,IAAA;AAAA,MAClC,aAAa,EAAA,CAAG,IAAA;AAAA,MAChB;AAAA,KACF;AAAA,EACF,CAAC,CAAA;AAEP,EAAA,eAAe,OAAA,CAAQ,MAAc,MAAA,EAAuD;AAC1F,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA;AAAA,IACF;AACA,IAAA,MAAM,EAAA,GAAK,MAAA,CAAO,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AACjC,IAAA,IAAI,OAAO,MAAA,EAAW;AACpB,MAAA;AAAA,IACF;AACA,IAAA,IAAI,WAAW,cAAA,EAAgB;AAC7B,MAAA,MAAM,MAAA,CAAO,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA;AAC7B,MAAA;AAAA,IACF;AAMA,IAAA,MAAM,QAAA,GACJ,GAAG,MAAA,KAAW,MAAA,GACV,OAAO,QAAA,CACJ,IAAA,CAAK,GAAG,OAAA,EAAS,EAAA,CAAG,OAAO,QAAQ,CAAA,CACnC,KAAK,CAAC,GAAA,KAAQ,IAAI,EAAA,KAAO,EAAA,CAAG,MAAA,EAAQ,EAAE,CAAA,GACzC,MAAA;AACN,IAAA,MAAM,eAAe,QAAA,EAAU,OAAA;AAC/B,IAAA,MAAM,MAAA,CAAO,MAAA,CAAO,OAAA,CAAQ,IAAA,EAAM,YAAA,KAAiB,MAAA,GAAY,EAAE,OAAA,EAAS,YAAA,EAAa,GAAI,EAAE,CAAA;AAC7F,IAAA,MAAA,CAAO,QAAQ,IAAA,EAAK;AAAA,EACtB;AAEA,EAAA,OAAO,EAAE,WAAW,OAAA,EAAQ;AAC9B;AClDO,SAAS,YAAA,GAAgC;AAC9C,EAAA,MAAM,SAASC,iCAAA,EAAgB;AAC/B,EAAA,MAAM,CAAC,QAAQ,SAAS,CAAA,GAAIH,eAA0B,EAAE,MAAA,EAAQ,WAAW,CAAA;AAE3E,EAAAI,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,SAAA,CAAU,EAAE,MAAA,EAAQ,SAAA,EAAW,CAAA;AAC/B,IAAA,MAAA,CAAO,SAAA,CACJ,SAAA,EAAU,CACV,IAAA,CAAK,CAAC,QAAA,KAAa;AAClB,MAAA,IAAI,SAAA,EAAW;AACb,QAAA;AAAA,MACF;AACA,MAAA,MAAM,EAAE,IAAA,EAAM,GAAG,IAAA,EAAK,GAAI,QAAA;AAC1B,MAAA,SAAA,CAAU,EAAE,QAAQ,OAAA,EAAS,GAAG,MAAM,QAAA,EAAU,IAAA,CAAK,YAAY,CAAA;AAAA,IACnE,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,SAAA,CAAU,EAAE,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,MAC/B;AAAA,IACF,CAAC,CAAA;AACH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,MAAA;AACT;ACXA,SAAS,YACP,IAAA,EAC6D;AAC7D,EAAA,OAAO,YAAA,IAAgB,IAAA,IAAQ,IAAA,CAAK,UAAA,KAAe,IAAA;AACrD;AAEO,SAAS,gBAAA,GAAwC;AACtD,EAAA,MAAM,SAASD,iCAAA,EAAgB;AAC/B,EAAA,MAAM,CAAC,QAAQ,SAAS,CAAA,GAAIH,eAA8B,EAAE,MAAA,EAAQ,WAAW,CAAA;AAE/E,EAAAI,gBAAU,MAAM;AACd,IAAA,IAAI,SAAA,GAAY,KAAA;AAChB,IAAA,SAAA,CAAU,EAAE,MAAA,EAAQ,SAAA,EAAW,CAAA;AAC/B,IAAA,MAAA,CAAO,aAAA,CACJ,IAAA,EAAK,CACL,IAAA,CAAK,CAAC,QAAA,KAAa;AAClB,MAAA,IAAI,SAAA,EAAW;AACb,QAAA;AAAA,MACF;AACA,MAAA,MAAM,aAAA,GAAgB,SAAS,KAAA,CAAM,MAAA;AAAA,QACnC,CAAC,IAAA,KAAsC,CAAC,WAAA,CAAY,IAAI;AAAA,OAC1D;AACA,MAAA,SAAA,CAAU;AAAA,QACR,MAAA,EAAQ,OAAA;AAAA,QACR,aAAA;AAAA,QACA,WAAA,EAAa,cAAc,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,IAAI,CAAA,CAAE,MAAA;AAAA,QAC5D,QAAA,EAAU,OAAO,EAAA,KAAe;AAC9B,UAAA,MAAM,MAAA,CAAO,aAAA,CAAc,QAAA,CAAS,EAAE,IAAI,CAAA;AAAA,QAC5C,CAAA;AAAA,QACA,QAAA,EAAU,SAAS,IAAA,CAAK;AAAA,OACzB,CAAA;AAAA,IACH,CAAC,CAAA,CACA,KAAA,CAAM,MAAM;AACX,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,SAAA,CAAU,EAAE,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,MAC/B;AAAA,IACF,CAAC,CAAA;AACH,IAAA,OAAO,MAAM;AACX,MAAA,SAAA,GAAY,IAAA;AAAA,IACd,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,OAAO,MAAA;AACT","file":"chunk-QHUDOVKW.cjs","sourcesContent":["'use client';\n\n// `08-core-hooks.md §2.7`. Every `409 CONFLICT_VERSION` op currently parked\n// and awaiting a human choice for this trip — entity-agnostic on purpose, so\n// the one shared `ConflictResolver` UI covers rooming/seating/checklist/\n// every versioned entity (`07-offline-and-sync.md §6`).\n//\n// VERIFIED SHAPE (`kaafil-js/src/offline/{outbox,reconcile}.ts`, this\n// session): a \"surface\" conflict reaches `Outbox.park()` with only\n// `{ status, code: 'CONFLICT_VERSION', userMessage }` — no row of either\n// side. The fresh server row, however, was already written into\n// `SnapshotStore` by `reconcileConflict()` before the park (its own \"why the\n// entity is re-pulled first\" header) whenever `op.entity` was set and the\n// re-read succeeded. `currentValue` below is read from there — the snapshot\n// — rather than invented on this hook's own read. `queuedValue` is the\n// parked op's own `body`, the intent that was never applied.\n\nimport type { OutboxOp } from 'kaafil-js/client';\nimport { useContext, useMemo, useState } from 'react';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport type { ConflictRecord } from '../types/offline.types';\nimport { useOfflineEvent } from './useOfflineEvent';\n\nexport interface ConflictsResult {\n readonly conflicts: readonly ConflictRecord[];\n readonly resolve: (opId: string, choice: 'keep-queued' | 'keep-current') => Promise<void>;\n}\n\nfunction isVersionConflict(op: OutboxOp): boolean {\n return op.status === 'parked' && op.parkReason?.code === 'CONFLICT_VERSION';\n}\n\nexport function useConflicts(tripRef: string): ConflictsResult {\n // NOT `useOfflineEngine()` (its throwing form) — called from inside a\n // domain hook's unconditional `build()` (`createDomainHook.ts`), including\n // the render(s) before `OfflineShell` has opened an engine. No engine yet\n // means no ops to have conflicted yet — `conflicts: []`, never a crash.\n const engine = useContext(OfflineEngineContext);\n // `tick` itself is never read below beyond being a `useMemo` dependency —\n // `engine.outbox.all()` is a plain synchronous read with no reactive\n // identity of its own, so bumping this on every `sync.error`/`sync.drained`\n // is what makes the memo below re-run on the events that can change what\n // it returns.\n const [tick, forceRefresh] = useState(0);\n\n useOfflineEvent('sync.error', () => forceRefresh((current) => current + 1));\n useOfflineEvent('sync.drained', () => forceRefresh((current) => current + 1));\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: tick is a deliberate side-channel dep, forcing a re-run against the outbox's own non-reactive state on every sync event (see its declaration above).\n const conflictOps = useMemo(\n () =>\n engine === null\n ? []\n : engine.outbox.all().filter((op) => op.tripRef === tripRef && isVersionConflict(op)),\n // eslint-disable-next-line react-hooks/exhaustive-deps -- same reasoning, see the biome-ignore comment above.\n [engine, tripRef, tick],\n );\n\n const conflicts: readonly ConflictRecord[] =\n engine === null\n ? []\n : conflictOps.map((op) => {\n const currentValue =\n op.entity !== undefined\n ? engine.snapshot\n .list(op.tripRef, op.entity.listName)\n .find((row) => row.id === op.entity?.id)\n : undefined;\n return {\n opId: op.id,\n entity: op.entity?.listName ?? op.path,\n queuedValue: op.body,\n currentValue,\n };\n });\n\n async function resolve(opId: string, choice: 'keep-queued' | 'keep-current'): Promise<void> {\n if (engine === null) {\n return;\n }\n const op = engine.outbox.get(opId);\n if (op === undefined) {\n return;\n }\n if (choice === 'keep-current') {\n await engine.outbox.drop(opId);\n return;\n }\n // `keep-queued`: re-issue with the fresh version. The fresh row's own\n // `version` field is what `07-offline-and-sync.md §6` calls\n // `details.currentVersion`; reading it off the snapshot row this hook\n // already fetched above is the same value, sourced from the same\n // re-read `reconcileConflict()` already performed.\n const freshRow =\n op.entity !== undefined\n ? engine.snapshot\n .list(op.tripRef, op.entity.listName)\n .find((row) => row.id === op.entity?.id)\n : undefined;\n const freshVersion = freshRow?.version;\n await engine.outbox.reissue(opId, freshVersion !== undefined ? { ifMatch: freshVersion } : {});\n engine.drainer.kick();\n }\n\n return { conflicts, resolve };\n}\n","'use client';\n\n// `families/manager/01-surface.md`'s own \"trip-discovery gap\" note is now\n// stale — verified against the real engine: `GET /manager/me/trips`\n// (`client.managerMe.listTrips()`) resolves a manager's own live trip\n// assignments plus a sensible `defaultTripId`, and now also the manager's\n// own `fullName` (this build's own small engine addition —\n// `manager-me.dto.ts`'s `manager` field). This session's own product\n// decision overrides that spec note for `ManagerNowSection` and any future\n// manager composite that needs \"which trip(s) does THIS manager see\" —\n// never a host-supplied `assignedTrips` prop for those composites (that\n// prop still exists for `KaafilManagerApp`/`MyTripsScreen` themselves, per\n// spec, since a Surface's own trip-list PANE is a separate, larger\n// decision this hook does not revisit).\n//\n// Same deliberately minimal shape as `useManagerToday.ts`: a plain\n// `client.managerMe.listTrips()` call behind `useEffect`/`useState`, no\n// offline/outbox machinery (this is a live read with no mutation of its\n// own to queue), no capability gate (which trips a manager is assigned to\n// is an ingest fact, not a capability — `01-surface.md`'s own \"Gating\"\n// field, cited).\n\nimport type { ManagerOwnTrip, ManagerOwnTripsResponse } from 'kaafil-js/client';\nimport { useEffect, useState } from 'react';\nimport { useKaafilClient } from './useKaafilClient';\n\n// Re-exported so a composite (`ManagerTripSection.types.ts`, `TripHero.tsx`)\n// can name one trip row's shape without importing `kaafil-js/client`\n// directly — hard rule #1.\nexport type { ManagerOwnTrip };\n\nexport interface ManagerMeLoading {\n readonly status: 'loading';\n}\n\nexport interface ManagerMeError {\n readonly status: 'error';\n}\n\nexport interface ManagerMeReady extends ManagerOwnTripsResponse {\n readonly status: 'ready';\n /** The server timestamp this read landed with (`meta.serverTime`) — never\n * a local clock read (hard rule #6). */\n readonly syncedAt: string;\n}\n\nexport type ManagerMeResult = ManagerMeLoading | ManagerMeError | ManagerMeReady;\n\n/**\n * `client.managerMe.listTrips()` behind a plain fetch-on-mount effect —\n * this read takes no parameter (it resolves entirely off the authenticated\n * principal, `manager-me.routes.ts`'s own header, cited), so it never\n * re-fetches on a prop change the way `useManagerToday(tripRef)` does.\n * A caller wanting \"refresh now\" re-mounts this hook's owning component.\n */\nexport function useManagerMe(): ManagerMeResult {\n const client = useKaafilClient();\n const [result, setResult] = useState<ManagerMeResult>({ status: 'loading' });\n\n useEffect(() => {\n let cancelled = false;\n setResult({ status: 'loading' });\n client.managerMe\n .listTrips()\n .then((response) => {\n if (cancelled) {\n return;\n }\n const { meta, ...data } = response;\n setResult({ status: 'ready', ...data, syncedAt: meta.serverTime });\n })\n .catch(() => {\n if (!cancelled) {\n setResult({ status: 'error' });\n }\n });\n return () => {\n cancelled = true;\n };\n }, [client]);\n\n return result;\n}\n","'use client';\n\n// `08-core-hooks.md §3` table, row `useNotifications()`. Primary SDK surface\n// (verified, `kaafil-js/src/resources/notifications.ts`):\n// `notifications.list` (`managerAuth`-only), `notifications.markRead`\n// (likewise `managerAuth`-only). NOT trip-scoped — the only hook in this\n// table taking no `tripRef`. `managerAuth` is the ONLY scheme either\n// operation accepts, so this hook is structurally unreachable from the\n// `admin`/`traveller` families. `list` takes an optional `?since=` delta\n// cursor passed straight through, never a UIKit-invented filter language.\n//\n// Deliberately the same minimal shape as `useManagerToday.ts`/\n// `useManagerMe.ts`: a plain fetch-on-mount effect, no offline/outbox\n// machinery. `families/manager/11-offline-sync-and-notifications.md\n// §NotificationsFeed`'s own \"write: markRead enqueues through the outbox\n// with a fixed idempotency key\" contract is that COMPOSITE's job once it\n// is built — this hook exists now only so `ManagerNowSection`'s header\n// bell can show a real (honestly zero, until something writes a\n// notification) unread count, which needs `list()` alone. `markRead` is\n// still exposed as a direct SDK call (never mints its own idempotency key,\n// hard rule #4 — mark-read is naturally idempotent server-side per the\n// SDK's own doc comment, so no key is needed here at all) so an early\n// caller isn't blocked, but a future `NotificationsFeed` composite should\n// route its OWN write through the outbox instead of reusing this hook's\n// `markRead` as-is.\n//\n// The wire's `items` array is a discriminated union (a live row, or a\n// `{ _tombstone: true; id; version; deletedAt }` delete marker) — this hook\n// filters tombstones out of `notifications` (a plain unread-count/list\n// consumer has no use for a deleted row) rather than exposing the union to\n// every caller.\n\nimport type { NotificationsResource } from 'kaafil-js/client';\nimport { useEffect, useState } from 'react';\nimport { useKaafilClient } from './useKaafilClient';\n\n// `notifications.ts`'s resource module exports no named response type of its\n// own (unlike `manager-me.ts`'s `ManagerOwnTripsResponse`) — derived off the\n// resource's own method signature instead, `useFiles.ts`/`useExpenses.ts`'s\n// established precedent for this exact situation.\ntype NotificationListResponse = Awaited<ReturnType<NotificationsResource['list']>>;\ntype NotificationListItem = NotificationListResponse['items'][number];\n\n/** The live-row half of `NotificationListItem`'s union — a tombstone never\n * reaches a caller of this hook (see this file's own header). */\nexport type ManagerNotification = Exclude<NotificationListItem, { _tombstone: true }>;\n\nexport interface NotificationsLoading {\n readonly status: 'loading';\n}\n\nexport interface NotificationsError {\n readonly status: 'error';\n}\n\nexport interface NotificationsReady {\n readonly status: 'ready';\n readonly notifications: readonly ManagerNotification[];\n /** `notifications.filter((n) => n.readAt === null).length` — the wire\n * carries no numeric unread field of its own (verified against\n * `NotificationListResponse`), so this is a real derivation off real\n * rows, never a fabricated count. */\n readonly unreadCount: number;\n readonly markRead: (id: string) => Promise<void>;\n /** The server timestamp this read landed with (`meta.serverTime`) —\n * never a local clock read (hard rule #6). */\n readonly syncedAt: string;\n}\n\nexport type NotificationsResult = NotificationsLoading | NotificationsError | NotificationsReady;\n\nfunction isTombstone(\n item: NotificationListItem,\n): item is Extract<NotificationListItem, { _tombstone: true }> {\n return '_tombstone' in item && item._tombstone === true;\n}\n\nexport function useNotifications(): NotificationsResult {\n const client = useKaafilClient();\n const [result, setResult] = useState<NotificationsResult>({ status: 'loading' });\n\n useEffect(() => {\n let cancelled = false;\n setResult({ status: 'loading' });\n client.notifications\n .list()\n .then((response) => {\n if (cancelled) {\n return;\n }\n const notifications = response.items.filter(\n (item): item is ManagerNotification => !isTombstone(item),\n );\n setResult({\n status: 'ready',\n notifications,\n unreadCount: notifications.filter((n) => n.readAt === null).length,\n markRead: async (id: string) => {\n await client.notifications.markRead({ id });\n },\n syncedAt: response.meta.serverTime,\n });\n })\n .catch(() => {\n if (!cancelled) {\n setResult({ status: 'error' });\n }\n });\n return () => {\n cancelled = true;\n };\n }, [client]);\n\n return result;\n}\n"]}
@@ -1,12 +0,0 @@
1
- 'use strict';
2
-
3
- var chunkEM7JV3D7_cjs = require('./chunk-EM7JV3D7.cjs');
4
-
5
- // src/core/hooks/useOfflineEngine.ts
6
- function useOfflineEngine() {
7
- return chunkEM7JV3D7_cjs.useRequiredContext(chunkEM7JV3D7_cjs.OfflineEngineContext, "useOfflineEngine", "OfflineShell");
8
- }
9
-
10
- exports.useOfflineEngine = useOfflineEngine;
11
- //# sourceMappingURL=chunk-TOBZFADB.cjs.map
12
- //# sourceMappingURL=chunk-TOBZFADB.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/core/hooks/useOfflineEngine.ts"],"names":["useRequiredContext","OfflineEngineContext"],"mappings":";;;;;AAgBO,SAAS,gBAAA,GAAkC;AAChD,EAAA,OAAOA,oCAAA,CAAmBC,sCAAA,EAAsB,kBAAA,EAAoB,cAAc,CAAA;AACpF","file":"chunk-TOBZFADB.cjs","sourcesContent":["'use client';\n\n// `08-core-hooks.md §2.1`. The escape hatch underneath every hook in §2 — a\n// composite should reach for a narrower hook before this one.\n\nimport type { OfflineEngine, OutboxOp } from 'kaafil-js/client';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { useRequiredContext } from '../internal/useRequiredContext';\n\n// Re-exported so a composite (`ManagerSyncCenterSection.types.ts`) can name\n// one outbox op's shape without importing `kaafil-js/client` directly —\n// hard rule #1.\nexport type { OutboxOp };\n\n/** Returns the engine instance `OfflineShell` opened via\n * `client.openOffline(options)`. Throws outside the provider tree. */\nexport function useOfflineEngine(): OfflineEngine {\n return useRequiredContext(OfflineEngineContext, 'useOfflineEngine', 'OfflineShell');\n}\n"]}