kaafil-react-uikit 0.2.0 → 0.3.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.
- package/dist/admin/index.cjs +73 -73
- package/dist/admin/index.js +3 -3
- package/dist/{chunk-6WV5VYT2.cjs → chunk-6TI6YQPE.cjs} +171 -7
- package/dist/chunk-6TI6YQPE.cjs.map +1 -0
- package/dist/{chunk-RG4YDSCN.cjs → chunk-BBC5EX5O.cjs} +4 -4
- package/dist/{chunk-RG4YDSCN.cjs.map → chunk-BBC5EX5O.cjs.map} +1 -1
- package/dist/{chunk-7UFX3Y2U.cjs → chunk-ECCQW5LN.cjs} +5 -2
- package/dist/chunk-ECCQW5LN.cjs.map +1 -0
- package/dist/{chunk-OZJ74DVQ.cjs → chunk-HACH2NUM.cjs} +3 -3
- package/dist/chunk-HACH2NUM.cjs.map +1 -0
- package/dist/{chunk-HTIY33UH.cjs → chunk-IU2UM5JP.cjs} +21 -21
- package/dist/{chunk-HTIY33UH.cjs.map → chunk-IU2UM5JP.cjs.map} +1 -1
- package/dist/{chunk-RSC2ZJUP.js → chunk-JHMN6Q5R.js} +172 -8
- package/dist/chunk-JHMN6Q5R.js.map +1 -0
- package/dist/{chunk-SIAPCJ7G.js → chunk-RO2RNHQP.js} +4 -4
- package/dist/{chunk-SIAPCJ7G.js.map → chunk-RO2RNHQP.js.map} +1 -1
- package/dist/{chunk-7ISKFGLW.js → chunk-RWLO6IFX.js} +3 -3
- package/dist/chunk-RWLO6IFX.js.map +1 -0
- package/dist/{chunk-L3QEMEFM.js → chunk-VLP323AD.js} +5 -2
- package/dist/chunk-VLP323AD.js.map +1 -0
- package/dist/{chunk-LJJMNZ7B.js → chunk-YU2242AR.js} +3 -3
- package/dist/{chunk-LJJMNZ7B.js.map → chunk-YU2242AR.js.map} +1 -1
- package/dist/core/index.cjs +56 -56
- package/dist/core/index.js +7 -7
- package/dist/manager/index.cjs +48 -48
- package/dist/manager/index.js +2 -2
- package/dist/traveller/index.cjs +4 -4
- package/dist/traveller/index.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-6WV5VYT2.cjs.map +0 -1
- package/dist/chunk-7ISKFGLW.js.map +0 -1
- package/dist/chunk-7UFX3Y2U.cjs.map +0 -1
- package/dist/chunk-L3QEMEFM.js.map +0 -1
- package/dist/chunk-OZJ74DVQ.cjs.map +0 -1
- package/dist/chunk-RSC2ZJUP.js.map +0 -1
|
@@ -32,7 +32,7 @@ function useConflicts(tripRef) {
|
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
if (choice === "keep-current") {
|
|
35
|
-
await engine.
|
|
35
|
+
await engine.discard(opId);
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
const freshRow = op.entity !== void 0 ? engine.snapshot.list(op.tripRef, op.entity.listName).find((row) => row.id === op.entity?.id) : void 0;
|
|
@@ -119,5 +119,5 @@ function useNotifications() {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
export { useConflicts, useManagerMe, useNotifications };
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
123
|
-
//# sourceMappingURL=chunk-
|
|
122
|
+
//# sourceMappingURL=chunk-RWLO6IFX.js.map
|
|
123
|
+
//# sourceMappingURL=chunk-RWLO6IFX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/hooks/useConflicts.ts","../src/core/hooks/useManagerMe.ts","../src/core/hooks/useNotifications.ts"],"names":["useContext","useState","useEffect"],"mappings":"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","file":"chunk-RWLO6IFX.js","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 // `engine.discard()`, NOT `outbox.drop()`. The queue knows nothing about\n // the snapshot, so dropping a CREATE through it leaves the row the\n // manager just chose to discard on screen permanently: it is keyed on an\n // id only this device ever knew, so no pull, no delta and no tombstone\n // can ever remove it. `discard()` takes the optimistic row with the op.\n await engine.discard(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 {\n KaafilClient,\n ManagerOwnTrip,\n ManagerOwnTripsResponse,\n OfflineEngine,\n} from 'kaafil-js/client';\nimport { useContext, useEffect, useState } from 'react';\nimport { OfflineEngineContext } from '../internal/contexts';\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 * The last answer this read actually got, per open client — the same\n * module-level, instance-keyed `WeakMap` shape `../internal/ensureTripPulled.ts`\n * already uses, and for the same reason: five composites\n * (`KaafilManagerApp`, `ManagerNowSection`, `ManagerTripSection`,\n * `ManagerChecklistSection`, `ManagerMeSection`) call this hook, and the\n * field surface mounts and unmounts them as the manager moves between tabs.\n *\n * Without this, EVERY tab switch was a fresh network read that the field\n * persona is by definition not guaranteed to be able to make. On a manager's\n * phone with no signal the read rejected, the hook reported `'error'`, and\n * every one of those composites renders nothing at all for that status — so\n * losing the network and then touching a tab emptied the trip screen, with\n * no way back short of a page reload (`architecture/06-offline-first.md`:\n * the field half must serve what it last knew rather than blank).\n *\n * It is not a cache in front of `kaafil-js` (hard rule #3): nothing is\n * reconciled, no cursor is kept, no event is subscribed to, and a live read\n * still fires on every mount so \"re-mount to refresh\" keeps working. It only\n * stops a failed read from erasing an answer the session already has.\n *\n * It dies with the tab, which is the whole reason for the durable lane below.\n */\nconst lastKnown = new WeakMap<KaafilClient, ManagerMeReady>();\n\n/**\n * The key this hook's answer is cached under in the engine's durable read\n * cache (`kaafil-js`'s `engine.reads`, credential-scoped by the engine).\n *\n * The `WeakMap` above survives a tab switch; it does not survive a RELOAD, and\n * a reload is the field surface's normal case rather than an edge one — a\n * manager's phone discards a backgrounded tab on its own. So an offline\n * manager who reloaded got `'error'` from the very first read, and every\n * composite that reads this hook renders nothing for that status: a blank\n * trip list, with their queued writes sitting intact in IndexedDB behind a\n * screen with no way into them. Durable writes the manager could not reach\n * are indistinguishable, from where they are standing, from lost ones.\n *\n * This response cannot live in the snapshot store: its rows carry a\n * `tripRef`, a name and a status but no `id` and no `version`, so there is\n * nothing for a version-guarded merge to guard (`kaafil-js/src/offline/\n * reads.ts` explains the split at length). It is a whole answer or nothing,\n * which is exactly the promise `engine.reads` makes.\n */\nconst READ_CACHE_KEY = 'manager.me.trips';\n\n/** What is actually persisted — the response plus the `meta.serverTime` it\n * landed with. The store keeps `syncedAt` itself, so only the body goes in. */\ntype CachedManagerMe = ManagerOwnTripsResponse;\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 // The raw context, not `useOfflineEngine()`'s throwing form: this hook is\n // read by desk composites too, and a desk mount has no `OfflineShell` and\n // therefore no engine. With none, everything below degrades to exactly the\n // in-memory behaviour this hook had before — which is right for a surface\n // that is online by definition.\n const engine = useContext(OfflineEngineContext);\n\n // Seeded from what is already known, in order: this session's own answer,\n // then the durable one from a previous session. Both beat a skeleton, and\n // the durable one is the only one that exists after a reload.\n const [result, setResult] = useState<ManagerMeResult>(\n () => lastKnown.get(client) ?? readCached(engine) ?? { status: 'loading' },\n );\n\n useEffect(() => {\n let cancelled = false;\n setResult(lastKnown.get(client) ?? readCached(engine) ?? { status: 'loading' });\n client.managerMe\n .listTrips()\n .then((response) => {\n const { meta, ...data } = response;\n const ready: ManagerMeReady = { status: 'ready', ...data, syncedAt: meta.serverTime };\n // Recorded before the cancellation check: a response that landed is\n // true regardless of whether THIS component is still mounted to\n // render it, and the next mount should not have to re-ask.\n lastKnown.set(client, ready);\n // Fire-and-forget, and deliberately not awaited before the state is\n // set: painting the fresh answer must not wait on a disk write, and a\n // failed write costs the NEXT reload's first paint rather than this\n // one's correctness. `meta.serverTime`, never a device clock — the\n // store has no setter that would accept one (hard rule #6).\n void engine?.reads.set(READ_CACHE_KEY, data, meta.serverTime).catch(() => {\n // A full or unavailable store is not this read's problem to report.\n // The live answer above is already rendered and already correct.\n });\n if (!cancelled) {\n setResult(ready);\n }\n })\n .catch(() => {\n if (cancelled) {\n return;\n }\n // `'error'` ONLY when NOTHING is known — not this session, not the\n // last one. A read that failed after one succeeded means the device\n // is offline or the engine is unreachable, not that the manager\n // stopped being assigned to their trips; reporting `'error'` there is\n // what blanked the field surface, and after a reload it blanked it\n // from the very first read. `syncedAt` on the held value already\n // tells a caller how old the reading is.\n setResult(lastKnown.get(client) ?? readCached(engine) ?? { status: 'error' });\n });\n return () => {\n cancelled = true;\n };\n }, [client, engine]);\n\n return result;\n}\n\n/**\n * The last answer a PREVIOUS session got, if this surface has a durable store\n * at all. Returns `undefined` rather than an `'error'` so every call site can\n * fall through to the next-best source in one expression.\n */\nfunction readCached(engine: OfflineEngine | null): ManagerMeReady | undefined {\n const cached = engine?.reads.get<CachedManagerMe>(READ_CACHE_KEY);\n if (cached === undefined) {\n return undefined;\n }\n return { status: 'ready', ...cached.value, syncedAt: cached.syncedAt };\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"]}
|
|
@@ -12,6 +12,9 @@ function useServerTime() {
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
const unsubscribe = engine.events.on("snapshot.updated", (event) => {
|
|
15
|
+
if (event.serverTime === void 0) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
15
18
|
observedAtPerfRef.current = performance.now();
|
|
16
19
|
setLastServerTime(event.serverTime);
|
|
17
20
|
});
|
|
@@ -34,5 +37,5 @@ function useServerTime() {
|
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export { useServerTime };
|
|
37
|
-
//# sourceMappingURL=chunk-
|
|
38
|
-
//# sourceMappingURL=chunk-
|
|
40
|
+
//# sourceMappingURL=chunk-VLP323AD.js.map
|
|
41
|
+
//# sourceMappingURL=chunk-VLP323AD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/hooks/useServerTime.ts"],"names":[],"mappings":";;;AA8BA,IAAM,gBAAA,GAAmB,GAAA;AAElB,SAAS,aAAA,GAA+B;AAC7C,EAAA,MAAM,MAAA,GAAS,WAAW,oBAAoB,CAAA;AAC9C,EAAA,MAAM,CAAC,cAAA,EAAgB,iBAAiB,CAAA,GAAI,SAA6B,MAAS,CAAA;AAClF,EAAA,MAAM,iBAAA,GAAoB,OAA2B,MAAS,CAAA;AAC9D,EAAA,MAAM,GAAG,SAAS,CAAA,GAAI,SAAS,CAAC,CAAA;AAEhC,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,WAAW,IAAA,EAAM;AACnB,MAAA;AAAA,IACF;AAKA,IAAA,MAAM,cAAc,MAAA,CAAO,MAAA,CAAO,EAAA,CAAG,kBAAA,EAAoB,CAAC,KAAA,KAAU;AASlE,MAAA,IAAI,KAAA,CAAM,eAAe,MAAA,EAAW;AAClC,QAAA;AAAA,MACF;AACA,MAAA,iBAAA,CAAkB,OAAA,GAAU,YAAY,GAAA,EAAI;AAC5C,MAAA,iBAAA,CAAkB,MAAM,UAAU,CAAA;AAAA,IACpC,CAAC,CAAA;AACD,IAAA,OAAO,WAAA;AAAA,EACT,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAEX,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,EAAA,GAAK,YAAY,MAAM,SAAA,CAAU,CAAC,IAAA,KAAS,IAAA,GAAO,CAAC,CAAA,EAAG,gBAAgB,CAAA;AAC5E,IAAA,OAAO,MAAM,cAAc,EAAE,CAAA;AAAA,EAC/B,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,SAAS,GAAA,GAAc;AACrB,IAAA,IAAI,cAAA,KAAmB,MAAA,IAAa,iBAAA,CAAkB,OAAA,KAAY,MAAA,EAAW;AAY3E,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OAEF;AAAA,IACF;AACA,IAAA,MAAM,SAAA,GAAY,WAAA,CAAY,GAAA,EAAI,GAAI,iBAAA,CAAkB,OAAA;AACxD,IAAA,OAAO,IAAI,KAAK,IAAA,CAAK,KAAA,CAAM,cAAc,CAAA,GAAI,SAAS,EAAE,WAAA,EAAY;AAAA,EACtE;AAEA,EAAA,OAAO,EAAE,GAAA,EAAK,aAAA,EAAe,cAAA,EAAe;AAC9C","file":"chunk-VLP323AD.js","sourcesContent":["'use client';\n\n// `08-core-hooks.md §1.6`. The single place that turns the stream of\n// `meta.serverTime` stamps into a usable clock, so no composite reads\n// `meta.serverTime` off an individual response by hand.\n//\n// Hard rule #6 (\"Zero `Date.now()`/`new Date()` local getters in\n// `src/core`\") bans exactly the two calls that fabricate \"now\" from the\n// local wall clock: `Date.now()` and no-argument `new Date()`. This file\n// never calls either. Advancing a SERVER-supplied timestamp by an elapsed\n// delta necessarily needs SOME measure of \"how much local time passed\" —\n// this file measures that with `performance.now()`, a monotonic clock with\n// no relationship to wall-clock \"now\" (it cannot be read as a date, only as\n// a duration), and applies the delta with `new Date(<epoch-ms>)` /\n// `Date.parse(<iso-string>)` — both single-argument forms that operate on a\n// value already anchored to `meta.serverTime`, never on the local clock.\n\nimport { useContext, useEffect, useRef, useState } from 'react';\nimport { OfflineEngineContext } from '../internal/contexts';\n\nexport interface ServerTimeApi {\n now: () => string;\n sinceLastSync: string | undefined;\n}\n\n/** Re-renders any hook consumer often enough for a mounted countdown to look\n * live, without pretending the underlying value moved forward on its own\n * merits (`08-core-hooks.md §1.6`'s sandbox time-travel caveat: this timer\n * forces a re-render, it never advances the stamp past what the last real\n * response justified). */\nconst TICK_INTERVAL_MS = 1000;\n\nexport function useServerTime(): ServerTimeApi {\n const engine = useContext(OfflineEngineContext);\n const [lastServerTime, setLastServerTime] = useState<string | undefined>(undefined);\n const observedAtPerfRef = useRef<number | undefined>(undefined);\n const [, forceTick] = useState(0);\n\n useEffect(() => {\n if (engine === null) {\n return;\n }\n // `snapshot.updated` is the one event in `OfflineEventMap` that carries\n // `serverTime` (`kaafil-js/src/offline/events.ts`, verified this\n // session) — the engine's other five events do not, so this is the only\n // subscription this hook can build without inventing a stamp.\n const unsubscribe = engine.events.on('snapshot.updated', (event) => {\n // `serverTime` is ABSENT on a change that never involved the server —\n // an optimistic create painted while offline, or an op the host\n // discarded (`kaafil-js/src/offline/events.ts`). Those are real snapshot\n // changes and a list must repaint for them, but they carry no reading,\n // and taking `undefined` here would erase the last real one this\n // session had: `now()` would start throwing again mid-session, on a\n // device that HAS heard from the server, because the manager ticked\n // something off out of signal.\n if (event.serverTime === undefined) {\n return;\n }\n observedAtPerfRef.current = performance.now();\n setLastServerTime(event.serverTime);\n });\n return unsubscribe;\n }, [engine]);\n\n useEffect(() => {\n const id = setInterval(() => forceTick((tick) => tick + 1), TICK_INTERVAL_MS);\n return () => clearInterval(id);\n }, []);\n\n function now(): string {\n if (lastServerTime === undefined || observedAtPerfRef.current === undefined) {\n // No response has ever landed in this session yet. Fabricating a\n // value from the local wall clock is exactly what hard rule #6\n // forbids — this is the one case this hook cannot silently satisfy\n // its own non-optional return type, so it says so loudly instead.\n // CALLERS: this is a real, expected window — React runs an effect\n // (which is how this hook's own subscription above starts) strictly\n // AFTER the render that needs `now()`'s result has already committed,\n // so a component's very FIRST render can hit this throw even when\n // wired up correctly. Guard the call site, matching\n // `useStaleness.ts`'s own precedent, rather than reaching for a\n // device-clock fallback here (hard rule #6 forbids exactly that).\n throw new Error(\n 'useServerTime().now() was called before any response carrying meta.serverTime ' +\n 'had been observed — there is no server timestamp yet to advance from.',\n );\n }\n const elapsedMs = performance.now() - observedAtPerfRef.current;\n return new Date(Date.parse(lastServerTime) + elapsedMs).toISOString();\n }\n\n return { now, sinceLastSync: lastServerTime };\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useOfflineEngine } from './chunk-KW5LH6KV.js';
|
|
2
|
-
import { useServerTime } from './chunk-
|
|
2
|
+
import { useServerTime } from './chunk-VLP323AD.js';
|
|
3
3
|
import { useKaafilClient, usePersona, isDevelopment, useOfflineEvent, useOfflineMutation, OfflineEngineContext } from './chunk-A4Z2YBEF.js';
|
|
4
4
|
import { SyncOpMethod } from 'kaafil-js/client';
|
|
5
5
|
import { useState, useCallback, useEffect, useContext } from 'react';
|
|
@@ -242,5 +242,5 @@ function useShareSnapshot(token, options) {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
export { useShareForms, useShareSnapshot };
|
|
245
|
-
//# sourceMappingURL=chunk-
|
|
246
|
-
//# sourceMappingURL=chunk-
|
|
245
|
+
//# sourceMappingURL=chunk-YU2242AR.js.map
|
|
246
|
+
//# sourceMappingURL=chunk-YU2242AR.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/hooks/useShareForms.ts","../src/core/hooks/useShareSnapshot.ts"],"names":["useState","useEffect"],"mappings":"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","file":"chunk-LJJMNZ7B.js","sourcesContent":["'use client';\n\n// `08-core-hooks.md §3` (new row — `ShareFormsSection`'s `Backed by`,\n// `ui-kit/families/traveller/02-forms.md`, cited): the write-back half of\n// the traveller share surface. `forms` is the ONLY write-back section on\n// the whole share surface; every other section is read-only through\n// `useShareSnapshot()` alone. This hook wraps the four dedicated\n// `shareAuth`-only routes `share.forms.{list,render,save,submit}`\n// (`kaafil-js/src/resources/share.ts`, verified this session).\n//\n// ── WHY THIS HOOK DOES NOT ALSO CALL `useShareSnapshot()` ──────────────────\n//\n// `02-forms.md`'s `Backed by` field says the section's own `/core` hook\n// \"composes both\" — the snapshot (for `forms` section presence) and the\n// dedicated routes (for the actual list/render/save/submit). This file\n// deliberately does NOT reproduce the snapshot fetch: `ShareFormsSection`\n// (future work, not this file) is only ever mounted once its own call to\n// `useShareSnapshot(token)` has already confirmed `sections.has('forms')`\n// (`01-share-sections.md`'s registry-driven mount rule) — duplicating that\n// fetch here would be a second, redundant read of the same snapshot for no\n// new information, and this hook has nothing to add to a presence check it\n// does not own. What this file DOES independently reproduce is\n// `useShareSnapshot()`'s own persona gate and its `share.expired`/\n// `share.revoked` subscriptions (`08-core-hooks.md §0`: \"every domain hook\n// is capability-gated internally\" — the share-surface's equivalent gate is\n// the persona check, applied the same way every other hook in this catalog\n// applies its own).\n//\n// ── SPEC TENSION FLAGGED: \"cache-first\" vs. \"the dedicated routes\" ─────────\n//\n// `02-forms.md`'s `Offline` field says the list \"rides the scoped share\n// snapshot cache-first, same as every other section\", but its own `Backed\n// by` field says in the same breath that \"the actual form list/render/\n// save/submit calls ride the dedicated forms-share routes\" — and\n// `ShareSnapshotResponse`'s per-section shape (verified,\n// `useShareSnapshot.ts`) carries no registered `forms` array with\n// `fillState`/`opensAt`/`closesAt` fields; only `ShareFormsListResponse`\n// (`GET /api/v1/share/{token}/forms`) does. This file follows the more\n// specific, SDK-verified statement — a LIVE `share.forms.list()` call,\n// refreshable on demand — the same \"own live-fetch sub-state, not a\n// `snapshot.updated` subscription\" pattern `useRooming.ts`'s\n// `unassignedPool` already uses for an analogous non-delta read. Flagged\n// for the doc owner to resolve; not silently picked one way with no trace.\n//\n// ── `clientToken` IS NOT A HOOK-MINTED IDEMPOTENCY KEY ──────────────────────\n//\n// `ShareSaveFormRequest`/`ShareSubmitFormRequest` (verified,\n// `kaafil-js/openapi/openapi.json`) require a body-level `clientToken`\n// (16-255 chars) — the SDK's own comment on `share.ts` calls it \"this\n// route's own de-dupe key, distinct from the automatic `Idempotency-Key`\n// header\", and `modules/forms/FRD.md §4.1/§8` calls it \"a fixed\n// `clientToken` generated once at enqueue and reused on every retry\" —\n// i.e. exactly the write-once, replay-unchanged lifecycle hard rule #4\n// reserves for `OfflineEngine.enqueue()`'s own internal idempotency-key\n// minting. This hook does NOT invent a value for it (that would be exactly\n// the \"hook mints its own idempotency key\" anti-pattern hard rule #4\n// forbids, even though `clientToken` is a different field from the\n// transport `Idempotency-Key` header `enqueue()` mints separately and\n// automatically for every op, share writes included). Instead\n// `ShareFormWriteInput.clientToken` is a REQUIRED field the CALLER\n// supplies — a future `ShareFormsSection`/`ShareFormFillScreen` generates\n// one value per form-fill session (e.g. once, the first time a field is\n// touched) and passes the SAME value to every `save()`/`submit()` call for\n// that session, which is what makes retries of the SAME logical write\n// dedupe wire-side. This hook only ever forwards it into the body verbatim.\n//\n// ── REVOCATION DROPS QUEUED WRITES — A REAL SDK GAP, WORKED AROUND HERE ────\n//\n// `02-forms.md`'s `Offline` field: \"Revocation is different and has no\n// grace: a `REVOKED` token drops queued writes unsent and purges the local\n// copy immediately.\" Verified against `kaafil-js/src/offline/share.ts`\n// this session: `ShareGuard.invalidate()` treats `'expired'` and\n// `'revoked'` IDENTICALLY — it purges the read snapshot in both cases and\n// only PRESERVES (never drops) the outbox either way; nothing in\n// `kaafil-js` currently distinguishes \"grace-covered\" from \"unsent, drop\n// it\" at the outbox level. This is a genuine SDK/spec disagreement — see\n// this file's final report note. Rather than leave the spec's hard\n// requirement unmet, this hook enforces it locally on `share.revoked`,\n// riding the outbox's own existing `drop()` primitive (the identical call\n// `useConflicts()`'s `'keep-current'` resolution already makes) — this is\n// composing an existing primitive in reaction to an event, not a second\n// sync engine (hard rule #3): no retry ladder, no cache, no idempotency\n// logic is reimplemented here, only \"remove this op from the outbox\".\n\nimport type { KaafilClient, OutboxOp } from 'kaafil-js/client';\nimport { SyncOpMethod } from 'kaafil-js/client';\nimport { useCallback, useEffect, useState } from 'react';\nimport { isDevelopment } from '../internal/isDevelopment';\nimport { useKaafilClient } from './useKaafilClient';\nimport { useOfflineEngine } from './useOfflineEngine';\nimport { useOfflineEvent } from './useOfflineEvent';\nimport { useOfflineMutation } from './useOfflineMutation';\nimport { usePersona } from './usePersona';\nimport { useServerTime } from './useServerTime';\n\ntype ShareFormsClient = Pick<KaafilClient, 'share'>;\n\n/** One row of `GET /api/v1/share/{token}/forms` — `ShareFormsListResponse`\n * (verified, `kaafil-js/openapi/openapi.json`). Metadata only: no prefill,\n * no field list, no answers (`FRD:traveller-share §4.8`) — that detail\n * arrives only from `renderForm()` below. */\nexport interface ShareFormListItem {\n readonly formId: string;\n readonly key: string;\n readonly title: string;\n readonly phase: string;\n readonly required: boolean;\n readonly fillState: string;\n readonly opensAt: string | null;\n readonly closesAt: string | null;\n readonly responseStatus: string | null;\n readonly submittedAt: string | null;\n}\n\n/** One answer in a `save`/`submit` body — `ShareSaveFormRequest.answers[]`\n * / `ShareSubmitFormRequest.answers[]` (verified). */\nexport interface ShareFormAnswer {\n readonly fieldKey: string;\n readonly value: unknown;\n}\n\nexport interface ShareFormWriteInput {\n readonly formId: string;\n readonly answers: readonly ShareFormAnswer[];\n /** This route's own de-dupe key — REQUIRED by the wire schema. See this\n * file's header (\"`clientToken` IS NOT A HOOK-MINTED IDEMPOTENCY KEY\") —\n * the caller mints this once per form-fill session and reuses it across\n * every save/submit/retry of that session; this hook never generates it. */\n readonly clientToken: string;\n /** Group fill within the same `TripTraveller.partyId` — omit when the\n * token itself already scopes to a single traveller. */\n readonly travellerRef?: string;\n readonly startNew?: boolean;\n readonly isAnonymous?: boolean;\n}\n\nexport type ShareFormsListStatus = 'loading' | 'list-empty' | 'list-populated' | 'not-found';\n\n/**\n * The write-side status a `save()`/`submit()` call's tracked `OutboxOp`\n * resolves to. Deliberately excludes `'filling'` (`02-forms.md`'s own\n * `States` list also names it): `'filling'` is \"the traveller is editing\n * fields, no request in flight yet\" — a pure local UI mode with no\n * server/outbox signal behind it, so it belongs to the composite that owns\n * the form's field state, never to this hook, which only ever reflects\n * something async.\n */\nexport type ShareFormsWriteStatus =\n | 'idle'\n | 'saving'\n | 'submitting'\n | 'submitted'\n | 'conflicted'\n | 'subject-required'\n | 'queued-offline'\n | 'dropped-on-revoke';\n\nexport interface ShareFormsResult {\n readonly status: ShareFormsListStatus;\n /** `[]` in both the `'loading'` and the `'list-empty'` states — a\n * consumer distinguishes them via `status`, never via array emptiness\n * alone (`02-forms.md`'s `Gating`: an empty list is a NORMAL steady\n * state, never an error, never a placeholder). */\n readonly forms: readonly ShareFormListItem[];\n readonly serverTime: string | undefined;\n /** Re-runs `share.forms.list()`. A composite calls this after a\n * `submit()` lands, since submitting can change another form's\n * `fillState` (e.g. an any-phase trigger opening a follow-up form). */\n readonly refresh: () => Promise<void>;\n /** `GET /api/v1/share/{token}/forms/{formId}` — the fully-resolved,\n * ready-to-paint form (definition merged with any in-progress answers).\n * An open shape (`ShareRenderResponse` has no closed schema yet,\n * verified) — a live call, not cached, matching `save`/`submit`'s own\n * un-cached write path. */\n readonly renderForm: (\n formId: string,\n options?: { readonly travellerRef?: string },\n ) => Promise<Record<string, unknown>>;\n /** An in-progress save — no required-field validation server-side. */\n readonly save: (input: ShareFormWriteInput) => Promise<OutboxOp>;\n /** Finalizes the response — full validation, one transaction. */\n readonly submit: (input: ShareFormWriteInput) => Promise<OutboxOp>;\n /** The combined save/submit write status — see `ShareFormsWriteStatus`. */\n readonly writeStatus: ShareFormsWriteStatus;\n /** The most recently tracked save/submit `OutboxOp`, or `undefined`\n * before either has ever been called. */\n readonly writeOp: OutboxOp | undefined;\n}\n\nfunction deriveListStatus(\n forms: readonly ShareFormListItem[] | undefined,\n listFailed: boolean,\n): ShareFormsListStatus {\n if (forms === undefined) {\n return listFailed ? 'not-found' : 'loading';\n }\n return forms.length === 0 ? 'list-empty' : 'list-populated';\n}\n\nfunction deriveWriteStatus(\n revoked: boolean,\n saveOp: OutboxOp | undefined,\n submitOp: OutboxOp | undefined,\n isOnline: boolean,\n): { readonly status: ShareFormsWriteStatus; readonly op: OutboxOp | undefined } {\n if (revoked) {\n return { status: 'dropped-on-revoke', op: submitOp ?? saveOp };\n }\n // `submit` always takes precedence when both are in play — finishing a\n // submission is the more advanced, more important-to-surface state of\n // the two for the same form.\n const active = submitOp !== undefined ? { op: submitOp, kind: 'submit' as const } : undefined;\n const fallback =\n active ?? (saveOp !== undefined ? { op: saveOp, kind: 'save' as const } : undefined);\n if (fallback === undefined) {\n return { status: 'idle', op: undefined };\n }\n const { op, kind } = fallback;\n if (op.status === 'parked') {\n if (op.parkReason?.code === 'CONFLICT_VERSION') {\n return { status: 'conflicted', op };\n }\n if (op.parkReason?.code === 'SUBJECT_REQUIRED') {\n return { status: 'subject-required', op };\n }\n // Any other park reason (e.g. `ShareWriteGraceExpired` —\n // `kaafil-js/src/offline/share.ts`, a grace window that closed before\n // this op ever synced) reports the same as a still-queued offline\n // write: the honest \"still catching up\" framing until it is provably\n // gone (`02-forms.md`'s `Offline` field). A distinct terminal wording\n // for that specific park reason is `ShareFormsSection`'s own\n // presentation concern, not this hook's.\n return { status: 'queued-offline', op };\n }\n if (op.status === 'done') {\n return { status: kind === 'submit' ? 'submitted' : 'idle', op };\n }\n // pending or inflight.\n if (!isOnline) {\n return { status: 'queued-offline', op };\n }\n return { status: kind === 'submit' ? 'submitting' : 'saving', op };\n}\n\nexport function useShareForms(token: string): ShareFormsResult {\n const client = useKaafilClient() as ShareFormsClient;\n const persona = usePersona();\n const engine = useOfflineEngine();\n const { now, sinceLastSync } = useServerTime();\n // `now()` throws before this session's first `snapshot.updated` event —\n // see `useServerTime.ts`'s own \"CALLERS: guard the call site\" note. This\n // hook's writes stay legal without a stamp (see the `enqueuedAt` call\n // sites below), so the guard is \"can I use it\", never \"must I have it\".\n const serverTimeKnown = sinceLastSync !== undefined;\n\n const [forms, setForms] = useState<readonly ShareFormListItem[] | undefined>(undefined);\n const [serverTime, setServerTime] = useState<string | undefined>(undefined);\n const [listFailed, setListFailed] = useState(false);\n const [revoked, setRevoked] = useState(false);\n const [isOnline, setIsOnline] = useState(\n () => typeof navigator === 'undefined' || navigator.onLine,\n );\n\n const fetchList = useCallback(async (): Promise<void> => {\n try {\n const response = await client.share.forms.list({ token });\n setForms(response.items);\n setServerTime(response.meta.serverTime);\n setListFailed(false);\n } catch {\n // `GET .../forms` only ever fails `RESOURCE_NOT_FOUND` (`FRD:\n // traveller-share §4.1`'s route table, verified) — the share 404\n // carve-out means dark/cross-scope/genuinely-gone collapse to one\n // shape, same reasoning `useShareSnapshot()` applies to its own read.\n setListFailed(true);\n }\n }, [client, token]);\n\n useEffect(() => {\n if (persona !== 'share') {\n if (isDevelopment()) {\n throw new Error(\n 'useShareForms() was called from a manager/agencyAdmin session — ' +\n 'this hook is `share`-only (families/traveller/02-forms.md, `ShareFormsSection`).',\n );\n }\n return;\n }\n void fetchList();\n }, [persona, fetchList]);\n\n // A browser-level connectivity signal, same source `useOutboxStatus()`\n // reads (`kaafil-js`'s `OfflineEngine` exposes no queryable connectivity\n // flag of its own — see that hook's own header, verified again here).\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n const handleOnline = (): void => setIsOnline(true);\n const handleOffline = (): void => setIsOnline(false);\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }, []);\n\n useOfflineEvent('share.revoked', () => {\n setRevoked(true);\n // See this file's header (\"REVOCATION DROPS QUEUED WRITES\"). Only this\n // token's own lane, and only ops still in play (a `'done'` op already\n // landed and has nothing left to drop).\n for (const op of engine.outbox.all()) {\n if (op.tripRef === token && (op.status === 'pending' || op.status === 'parked')) {\n void engine.outbox.drop(op.id);\n }\n }\n });\n\n const saveMutation = useOfflineMutation<ShareFormWriteInput>({\n tripRef: token,\n enqueue: (mutationEngine, input) => {\n const query =\n input.travellerRef !== undefined\n ? `?travellerRef=${encodeURIComponent(input.travellerRef)}`\n : '';\n return mutationEngine.enqueue({\n tripRef: token,\n method: SyncOpMethod.Post,\n path: `/api/v1/share/${token}/forms/${input.formId}/save${query}`,\n // Hardcoded literal, not imported: `OperationId` is not exported\n // from `kaafil-js/client`'s public surface (same reasoning\n // `useRooming.ts` documents). Value verified against\n // `kaafil-js/src/generated/security.ts` this session:\n // `OperationId.ShareSaveForm === 'shareSaveForm'`.\n operationId: 'shareSaveForm' as never,\n body: {\n answers: input.answers,\n clientToken: input.clientToken,\n ...(input.startNew !== undefined ? { startNew: input.startNew } : {}),\n ...(input.isAnonymous !== undefined ? { isAnonymous: input.isAnonymous } : {}),\n },\n // The server-anchored \"now\" this write was created at — never\n // `Date.now()`/`new Date()` (hard rule #6) — `EnqueueWriteOptions\n // .enqueuedAt`'s own doc comment: \"client-attested and only ever\n // used by the server to REFUSE\" (the 7-day post-expiry grace\n // check). Optional on the wire, and genuinely omitted here on a\n // cold session: `useServerTime().now()` throws before this\n // session's very first `snapshot.updated` event has landed (its\n // own documented behaviour, guarded at the call site exactly as\n // its header instructs) — a share write attempted in that narrow\n // window still enqueues durably, just without a client-attested\n // stamp for the server's grace check to read.\n ...(serverTimeKnown ? { enqueuedAt: now() } : {}),\n });\n },\n });\n\n const submitMutation = useOfflineMutation<ShareFormWriteInput>({\n tripRef: token,\n enqueue: (mutationEngine, input) => {\n const query =\n input.travellerRef !== undefined\n ? `?travellerRef=${encodeURIComponent(input.travellerRef)}`\n : '';\n return mutationEngine.enqueue({\n tripRef: token,\n method: SyncOpMethod.Post,\n path: `/api/v1/share/${token}/forms/${input.formId}/submit${query}`,\n operationId: 'shareSubmitForm' as never,\n body: {\n answers: input.answers,\n clientToken: input.clientToken,\n ...(input.startNew !== undefined ? { startNew: input.startNew } : {}),\n ...(input.isAnonymous !== undefined ? { isAnonymous: input.isAnonymous } : {}),\n },\n // See the identical `save` enqueue above for why this is guarded.\n ...(serverTimeKnown ? { enqueuedAt: now() } : {}),\n });\n },\n });\n\n const renderForm = useCallback(\n async (\n formId: string,\n options?: { readonly travellerRef?: string },\n ): Promise<Record<string, unknown>> => {\n const response = await client.share.forms.render({\n token,\n formId,\n ...(options?.travellerRef !== undefined ? { travellerRef: options.travellerRef } : {}),\n });\n return response;\n },\n [client, token],\n );\n\n const { status: writeStatus, op: writeOp } = deriveWriteStatus(\n revoked,\n saveMutation.op,\n submitMutation.op,\n isOnline,\n );\n\n return {\n status: deriveListStatus(forms, listFailed),\n forms: forms ?? [],\n serverTime,\n refresh: fetchList,\n renderForm,\n save: saveMutation.mutate,\n submit: submitMutation.mutate,\n writeStatus,\n writeOp,\n };\n}\n","'use client';\n\n// `08-core-hooks.md §3.1`. The single assembled read behind the whole\n// traveller share surface. Wraps `share.snapshot()` (verified `shareAuth`\n// -only in `security.ts` — no `apiKeyAuth` alternative exists for any\n// `share.*` operation), read cache-first from the snapshot once\n// `OfflineEngine`'s `share` option is configured.\n//\n// VERIFIED SHAPE (`openapi/openapi.json`'s `ShareSnapshotResponse`, this\n// session): a flat object with one property PER section key, each present\n// only when the link exposes it and data exists — never `null`, never an\n// empty placeholder — plus a `trip` echo (`name`/`startDate`/`endDate`/\n// `timezone`/`phase`) that is NOT one of the thirteen section flags\n// (`09-registries.md §5`). This hook builds `sections` by taking every own\n// key off the response except `trip` and `meta` — additive-safe against a\n// future 14th section key without needing this file to enumerate all\n// thirteen by name.\n//\n// `trip` and the server clock are surfaced as their OWN top-level fields on\n// `ShareSnapshotResult`, never folded into `sections`: every consumer of\n// `sections` (starting with `KaafilShareView`, which walks the map and\n// renders one composite per key) treats \"is this key present\" as \"should I\n// render a section for it\" — letting `trip`/`meta` leak into that map would\n// make the view try to mount a `<ShareTripSection>`/`<ShareMetaSection>`\n// that has never existed. But every traveller composite still needs BOTH:\n// `trip.timezone` is the one zone `DateDisplay`/`TimeDisplay` may legally\n// anchor to on this surface (never the device zone, never a fabricated\n// `'UTC'`), `trip.phase` lets a composite react to PRE_DEPARTURE/ON_TRIP/\n// POST_TRIP, and `meta.serverTime` is the only trusted \"now\" a share\n// composite may read without going through `useServerTime()` (hard rule\n// #6 — no `Date.now()`/`new Date()` in `src/core`). Hence: two extra return\n// fields, kept structurally apart from the section map they must never\n// pollute.\n\nimport type { KaafilClient } from 'kaafil-js/client';\nimport { useContext, useEffect, useState } from 'react';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { isDevelopment } from '../internal/isDevelopment';\nimport { useKaafilClient } from './useKaafilClient';\nimport { usePersona } from './usePersona';\n\nexport interface ShareSnapshotOptions {\n readonly travellerRef?: string;\n}\n\n// Derived from the SDK's own return type rather than hand-copied — this\n// stays correct for free if `kaafil-js` grows another `trip` field, instead\n// of silently drifting the way the old `'UTC'` constants did.\ntype ShareSnapshotResponse = Awaited<ReturnType<KaafilClient['share']['snapshot']>>;\n\n/** The trip echo every snapshot response carries — `name`/`startDate`/\n * `endDate` plus the two fields this hook used to throw away:\n * `timezone` (the IANA zone every traveller-facing render must anchor to)\n * and `phase` (server-computed `PRE_DEPARTURE`/`ON_TRIP`/`POST_TRIP`). */\nexport type ShareSnapshotTrip = ShareSnapshotResponse['trip'];\n\nexport interface ShareSnapshotResult {\n readonly status: 'loading' | 'ready' | 'expired' | 'revoked' | 'not-found';\n readonly sections: ReadonlyMap<string, unknown>;\n /** The snapshot's `trip` echo, or `undefined` before any response has\n * landed (mirrors `sections`' own \"empty until ready\" behaviour). NEVER a\n * section key — see this file's header. */\n readonly trip: ShareSnapshotTrip | undefined;\n /** `meta.serverTime` off the most recently landed snapshot response — the\n * only trusted clock a share composite may read (hard rule #6). Kept\n * separate from `useServerTime()`'s own stream (which advances off\n * `OfflineEngine`'s `snapshot.updated` event, not this hook's own fetch)\n * so a composite that only ever calls `useShareSnapshot()` still has a\n * real server stamp to compare against without also wiring the offline\n * engine's event stream. `undefined` before any response has landed. */\n readonly serverTime: string | undefined;\n}\n\nconst NON_SECTION_KEYS = new Set(['trip', 'meta']);\n\nexport function useShareSnapshot(\n token: string,\n options?: ShareSnapshotOptions,\n): ShareSnapshotResult {\n void options; // `travellerRef` narrows which subject-token rows the server\n // itself returns for a `travellerRef`-scoped share link — this hook has no\n // client-side use for it beyond passing the token through; the server does\n // the scoping (`09-registries.md §5`, `families/traveller/01-share-sections.md`, cited).\n\n const client = useKaafilClient();\n const persona = usePersona();\n const engine = useContext(OfflineEngineContext);\n const [sections, setSections] = useState<ReadonlyMap<string, unknown> | undefined>(undefined);\n const [trip, setTrip] = useState<ShareSnapshotTrip | undefined>(undefined);\n const [serverTime, setServerTime] = useState<string | undefined>(undefined);\n const [terminal, setTerminal] = useState<'expired' | 'revoked' | 'not-found' | undefined>(\n undefined,\n );\n\n useEffect(() => {\n if (persona !== 'share') {\n if (isDevelopment()) {\n throw new Error(\n 'useShareSnapshot() was called from a manager/agencyAdmin session — ' +\n 'this hook is `share`-only (08-core-hooks.md §3.1).',\n );\n }\n return;\n }\n\n let cancelled = false;\n async function load(): Promise<void> {\n try {\n const response = await client.share.snapshot({ token });\n if (cancelled) {\n return;\n }\n const map = new Map<string, unknown>();\n for (const [key, value] of Object.entries(response)) {\n if (!NON_SECTION_KEYS.has(key)) {\n map.set(key, value);\n }\n }\n setSections(map);\n setTrip(response.trip);\n setServerTime(response.meta.serverTime);\n } catch {\n // `06-capability-and-personas.md §9`: dark, cross-scope, and\n // genuinely-gone all collapse to the identical shape here — this\n // hook cannot and must not try to distinguish them, so any failure\n // to read the snapshot at all reports the same `'not-found'`.\n if (!cancelled) {\n setTerminal('not-found');\n }\n }\n }\n void load();\n\n if (engine === null) {\n return () => {\n cancelled = true;\n };\n }\n const unsubscribeExpired = engine.events.on('share.expired', () => setTerminal('expired'));\n const unsubscribeRevoked = engine.events.on('share.revoked', () => setTerminal('revoked'));\n return () => {\n cancelled = true;\n unsubscribeExpired();\n unsubscribeRevoked();\n };\n }, [client, persona, token, engine]);\n\n if (terminal !== undefined) {\n return { status: terminal, sections: sections ?? new Map(), trip, serverTime };\n }\n if (sections === undefined) {\n return { status: 'loading', sections: new Map(), trip: undefined, serverTime: undefined };\n }\n return { status: 'ready', sections, trip, serverTime };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/hooks/useShareForms.ts","../src/core/hooks/useShareSnapshot.ts"],"names":["useState","useEffect"],"mappings":"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","file":"chunk-YU2242AR.js","sourcesContent":["'use client';\n\n// `08-core-hooks.md §3` (new row — `ShareFormsSection`'s `Backed by`,\n// `ui-kit/families/traveller/02-forms.md`, cited): the write-back half of\n// the traveller share surface. `forms` is the ONLY write-back section on\n// the whole share surface; every other section is read-only through\n// `useShareSnapshot()` alone. This hook wraps the four dedicated\n// `shareAuth`-only routes `share.forms.{list,render,save,submit}`\n// (`kaafil-js/src/resources/share.ts`, verified this session).\n//\n// ── WHY THIS HOOK DOES NOT ALSO CALL `useShareSnapshot()` ──────────────────\n//\n// `02-forms.md`'s `Backed by` field says the section's own `/core` hook\n// \"composes both\" — the snapshot (for `forms` section presence) and the\n// dedicated routes (for the actual list/render/save/submit). This file\n// deliberately does NOT reproduce the snapshot fetch: `ShareFormsSection`\n// (future work, not this file) is only ever mounted once its own call to\n// `useShareSnapshot(token)` has already confirmed `sections.has('forms')`\n// (`01-share-sections.md`'s registry-driven mount rule) — duplicating that\n// fetch here would be a second, redundant read of the same snapshot for no\n// new information, and this hook has nothing to add to a presence check it\n// does not own. What this file DOES independently reproduce is\n// `useShareSnapshot()`'s own persona gate and its `share.expired`/\n// `share.revoked` subscriptions (`08-core-hooks.md §0`: \"every domain hook\n// is capability-gated internally\" — the share-surface's equivalent gate is\n// the persona check, applied the same way every other hook in this catalog\n// applies its own).\n//\n// ── SPEC TENSION FLAGGED: \"cache-first\" vs. \"the dedicated routes\" ─────────\n//\n// `02-forms.md`'s `Offline` field says the list \"rides the scoped share\n// snapshot cache-first, same as every other section\", but its own `Backed\n// by` field says in the same breath that \"the actual form list/render/\n// save/submit calls ride the dedicated forms-share routes\" — and\n// `ShareSnapshotResponse`'s per-section shape (verified,\n// `useShareSnapshot.ts`) carries no registered `forms` array with\n// `fillState`/`opensAt`/`closesAt` fields; only `ShareFormsListResponse`\n// (`GET /api/v1/share/{token}/forms`) does. This file follows the more\n// specific, SDK-verified statement — a LIVE `share.forms.list()` call,\n// refreshable on demand — the same \"own live-fetch sub-state, not a\n// `snapshot.updated` subscription\" pattern `useRooming.ts`'s\n// `unassignedPool` already uses for an analogous non-delta read. Flagged\n// for the doc owner to resolve; not silently picked one way with no trace.\n//\n// ── `clientToken` IS NOT A HOOK-MINTED IDEMPOTENCY KEY ──────────────────────\n//\n// `ShareSaveFormRequest`/`ShareSubmitFormRequest` (verified,\n// `kaafil-js/openapi/openapi.json`) require a body-level `clientToken`\n// (16-255 chars) — the SDK's own comment on `share.ts` calls it \"this\n// route's own de-dupe key, distinct from the automatic `Idempotency-Key`\n// header\", and `modules/forms/FRD.md §4.1/§8` calls it \"a fixed\n// `clientToken` generated once at enqueue and reused on every retry\" —\n// i.e. exactly the write-once, replay-unchanged lifecycle hard rule #4\n// reserves for `OfflineEngine.enqueue()`'s own internal idempotency-key\n// minting. This hook does NOT invent a value for it (that would be exactly\n// the \"hook mints its own idempotency key\" anti-pattern hard rule #4\n// forbids, even though `clientToken` is a different field from the\n// transport `Idempotency-Key` header `enqueue()` mints separately and\n// automatically for every op, share writes included). Instead\n// `ShareFormWriteInput.clientToken` is a REQUIRED field the CALLER\n// supplies — a future `ShareFormsSection`/`ShareFormFillScreen` generates\n// one value per form-fill session (e.g. once, the first time a field is\n// touched) and passes the SAME value to every `save()`/`submit()` call for\n// that session, which is what makes retries of the SAME logical write\n// dedupe wire-side. This hook only ever forwards it into the body verbatim.\n//\n// ── REVOCATION DROPS QUEUED WRITES — A REAL SDK GAP, WORKED AROUND HERE ────\n//\n// `02-forms.md`'s `Offline` field: \"Revocation is different and has no\n// grace: a `REVOKED` token drops queued writes unsent and purges the local\n// copy immediately.\" Verified against `kaafil-js/src/offline/share.ts`\n// this session: `ShareGuard.invalidate()` treats `'expired'` and\n// `'revoked'` IDENTICALLY — it purges the read snapshot in both cases and\n// only PRESERVES (never drops) the outbox either way; nothing in\n// `kaafil-js` currently distinguishes \"grace-covered\" from \"unsent, drop\n// it\" at the outbox level. This is a genuine SDK/spec disagreement — see\n// this file's final report note. Rather than leave the spec's hard\n// requirement unmet, this hook enforces it locally on `share.revoked`,\n// riding the outbox's own existing `drop()` primitive (the identical call\n// `useConflicts()`'s `'keep-current'` resolution already makes) — this is\n// composing an existing primitive in reaction to an event, not a second\n// sync engine (hard rule #3): no retry ladder, no cache, no idempotency\n// logic is reimplemented here, only \"remove this op from the outbox\".\n\nimport type { KaafilClient, OutboxOp } from 'kaafil-js/client';\nimport { SyncOpMethod } from 'kaafil-js/client';\nimport { useCallback, useEffect, useState } from 'react';\nimport { isDevelopment } from '../internal/isDevelopment';\nimport { useKaafilClient } from './useKaafilClient';\nimport { useOfflineEngine } from './useOfflineEngine';\nimport { useOfflineEvent } from './useOfflineEvent';\nimport { useOfflineMutation } from './useOfflineMutation';\nimport { usePersona } from './usePersona';\nimport { useServerTime } from './useServerTime';\n\ntype ShareFormsClient = Pick<KaafilClient, 'share'>;\n\n/** One row of `GET /api/v1/share/{token}/forms` — `ShareFormsListResponse`\n * (verified, `kaafil-js/openapi/openapi.json`). Metadata only: no prefill,\n * no field list, no answers (`FRD:traveller-share §4.8`) — that detail\n * arrives only from `renderForm()` below. */\nexport interface ShareFormListItem {\n readonly formId: string;\n readonly key: string;\n readonly title: string;\n readonly phase: string;\n readonly required: boolean;\n readonly fillState: string;\n readonly opensAt: string | null;\n readonly closesAt: string | null;\n readonly responseStatus: string | null;\n readonly submittedAt: string | null;\n}\n\n/** One answer in a `save`/`submit` body — `ShareSaveFormRequest.answers[]`\n * / `ShareSubmitFormRequest.answers[]` (verified). */\nexport interface ShareFormAnswer {\n readonly fieldKey: string;\n readonly value: unknown;\n}\n\nexport interface ShareFormWriteInput {\n readonly formId: string;\n readonly answers: readonly ShareFormAnswer[];\n /** This route's own de-dupe key — REQUIRED by the wire schema. See this\n * file's header (\"`clientToken` IS NOT A HOOK-MINTED IDEMPOTENCY KEY\") —\n * the caller mints this once per form-fill session and reuses it across\n * every save/submit/retry of that session; this hook never generates it. */\n readonly clientToken: string;\n /** Group fill within the same `TripTraveller.partyId` — omit when the\n * token itself already scopes to a single traveller. */\n readonly travellerRef?: string;\n readonly startNew?: boolean;\n readonly isAnonymous?: boolean;\n}\n\nexport type ShareFormsListStatus = 'loading' | 'list-empty' | 'list-populated' | 'not-found';\n\n/**\n * The write-side status a `save()`/`submit()` call's tracked `OutboxOp`\n * resolves to. Deliberately excludes `'filling'` (`02-forms.md`'s own\n * `States` list also names it): `'filling'` is \"the traveller is editing\n * fields, no request in flight yet\" — a pure local UI mode with no\n * server/outbox signal behind it, so it belongs to the composite that owns\n * the form's field state, never to this hook, which only ever reflects\n * something async.\n */\nexport type ShareFormsWriteStatus =\n | 'idle'\n | 'saving'\n | 'submitting'\n | 'submitted'\n | 'conflicted'\n | 'subject-required'\n | 'queued-offline'\n | 'dropped-on-revoke';\n\nexport interface ShareFormsResult {\n readonly status: ShareFormsListStatus;\n /** `[]` in both the `'loading'` and the `'list-empty'` states — a\n * consumer distinguishes them via `status`, never via array emptiness\n * alone (`02-forms.md`'s `Gating`: an empty list is a NORMAL steady\n * state, never an error, never a placeholder). */\n readonly forms: readonly ShareFormListItem[];\n readonly serverTime: string | undefined;\n /** Re-runs `share.forms.list()`. A composite calls this after a\n * `submit()` lands, since submitting can change another form's\n * `fillState` (e.g. an any-phase trigger opening a follow-up form). */\n readonly refresh: () => Promise<void>;\n /** `GET /api/v1/share/{token}/forms/{formId}` — the fully-resolved,\n * ready-to-paint form (definition merged with any in-progress answers).\n * An open shape (`ShareRenderResponse` has no closed schema yet,\n * verified) — a live call, not cached, matching `save`/`submit`'s own\n * un-cached write path. */\n readonly renderForm: (\n formId: string,\n options?: { readonly travellerRef?: string },\n ) => Promise<Record<string, unknown>>;\n /** An in-progress save — no required-field validation server-side. */\n readonly save: (input: ShareFormWriteInput) => Promise<OutboxOp>;\n /** Finalizes the response — full validation, one transaction. */\n readonly submit: (input: ShareFormWriteInput) => Promise<OutboxOp>;\n /** The combined save/submit write status — see `ShareFormsWriteStatus`. */\n readonly writeStatus: ShareFormsWriteStatus;\n /** The most recently tracked save/submit `OutboxOp`, or `undefined`\n * before either has ever been called. */\n readonly writeOp: OutboxOp | undefined;\n}\n\nfunction deriveListStatus(\n forms: readonly ShareFormListItem[] | undefined,\n listFailed: boolean,\n): ShareFormsListStatus {\n if (forms === undefined) {\n return listFailed ? 'not-found' : 'loading';\n }\n return forms.length === 0 ? 'list-empty' : 'list-populated';\n}\n\nfunction deriveWriteStatus(\n revoked: boolean,\n saveOp: OutboxOp | undefined,\n submitOp: OutboxOp | undefined,\n isOnline: boolean,\n): { readonly status: ShareFormsWriteStatus; readonly op: OutboxOp | undefined } {\n if (revoked) {\n return { status: 'dropped-on-revoke', op: submitOp ?? saveOp };\n }\n // `submit` always takes precedence when both are in play — finishing a\n // submission is the more advanced, more important-to-surface state of\n // the two for the same form.\n const active = submitOp !== undefined ? { op: submitOp, kind: 'submit' as const } : undefined;\n const fallback =\n active ?? (saveOp !== undefined ? { op: saveOp, kind: 'save' as const } : undefined);\n if (fallback === undefined) {\n return { status: 'idle', op: undefined };\n }\n const { op, kind } = fallback;\n if (op.status === 'parked') {\n if (op.parkReason?.code === 'CONFLICT_VERSION') {\n return { status: 'conflicted', op };\n }\n if (op.parkReason?.code === 'SUBJECT_REQUIRED') {\n return { status: 'subject-required', op };\n }\n // Any other park reason (e.g. `ShareWriteGraceExpired` —\n // `kaafil-js/src/offline/share.ts`, a grace window that closed before\n // this op ever synced) reports the same as a still-queued offline\n // write: the honest \"still catching up\" framing until it is provably\n // gone (`02-forms.md`'s `Offline` field). A distinct terminal wording\n // for that specific park reason is `ShareFormsSection`'s own\n // presentation concern, not this hook's.\n return { status: 'queued-offline', op };\n }\n if (op.status === 'done') {\n return { status: kind === 'submit' ? 'submitted' : 'idle', op };\n }\n // pending or inflight.\n if (!isOnline) {\n return { status: 'queued-offline', op };\n }\n return { status: kind === 'submit' ? 'submitting' : 'saving', op };\n}\n\nexport function useShareForms(token: string): ShareFormsResult {\n const client = useKaafilClient() as ShareFormsClient;\n const persona = usePersona();\n const engine = useOfflineEngine();\n const { now, sinceLastSync } = useServerTime();\n // `now()` throws before this session's first `snapshot.updated` event —\n // see `useServerTime.ts`'s own \"CALLERS: guard the call site\" note. This\n // hook's writes stay legal without a stamp (see the `enqueuedAt` call\n // sites below), so the guard is \"can I use it\", never \"must I have it\".\n const serverTimeKnown = sinceLastSync !== undefined;\n\n const [forms, setForms] = useState<readonly ShareFormListItem[] | undefined>(undefined);\n const [serverTime, setServerTime] = useState<string | undefined>(undefined);\n const [listFailed, setListFailed] = useState(false);\n const [revoked, setRevoked] = useState(false);\n const [isOnline, setIsOnline] = useState(\n () => typeof navigator === 'undefined' || navigator.onLine,\n );\n\n const fetchList = useCallback(async (): Promise<void> => {\n try {\n const response = await client.share.forms.list({ token });\n setForms(response.items);\n setServerTime(response.meta.serverTime);\n setListFailed(false);\n } catch {\n // `GET .../forms` only ever fails `RESOURCE_NOT_FOUND` (`FRD:\n // traveller-share §4.1`'s route table, verified) — the share 404\n // carve-out means dark/cross-scope/genuinely-gone collapse to one\n // shape, same reasoning `useShareSnapshot()` applies to its own read.\n setListFailed(true);\n }\n }, [client, token]);\n\n useEffect(() => {\n if (persona !== 'share') {\n if (isDevelopment()) {\n throw new Error(\n 'useShareForms() was called from a manager/agencyAdmin session — ' +\n 'this hook is `share`-only (families/traveller/02-forms.md, `ShareFormsSection`).',\n );\n }\n return;\n }\n void fetchList();\n }, [persona, fetchList]);\n\n // A browser-level connectivity signal, same source `useOutboxStatus()`\n // reads (`kaafil-js`'s `OfflineEngine` exposes no queryable connectivity\n // flag of its own — see that hook's own header, verified again here).\n useEffect(() => {\n if (typeof window === 'undefined') {\n return;\n }\n const handleOnline = (): void => setIsOnline(true);\n const handleOffline = (): void => setIsOnline(false);\n window.addEventListener('online', handleOnline);\n window.addEventListener('offline', handleOffline);\n return () => {\n window.removeEventListener('online', handleOnline);\n window.removeEventListener('offline', handleOffline);\n };\n }, []);\n\n useOfflineEvent('share.revoked', () => {\n setRevoked(true);\n // See this file's header (\"REVOCATION DROPS QUEUED WRITES\"). Only this\n // token's own lane, and only ops still in play (a `'done'` op already\n // landed and has nothing left to drop).\n for (const op of engine.outbox.all()) {\n if (op.tripRef === token && (op.status === 'pending' || op.status === 'parked')) {\n void engine.outbox.drop(op.id);\n }\n }\n });\n\n const saveMutation = useOfflineMutation<ShareFormWriteInput>({\n tripRef: token,\n enqueue: (mutationEngine, input) => {\n const query =\n input.travellerRef !== undefined\n ? `?travellerRef=${encodeURIComponent(input.travellerRef)}`\n : '';\n return mutationEngine.enqueue({\n tripRef: token,\n method: SyncOpMethod.Post,\n path: `/api/v1/share/${token}/forms/${input.formId}/save${query}`,\n // Hardcoded literal, not imported: `OperationId` is not exported\n // from `kaafil-js/client`'s public surface (same reasoning\n // `useRooming.ts` documents). Value verified against\n // `kaafil-js/src/generated/security.ts` this session:\n // `OperationId.ShareSaveForm === 'shareSaveForm'`.\n operationId: 'shareSaveForm' as never,\n body: {\n answers: input.answers,\n clientToken: input.clientToken,\n ...(input.startNew !== undefined ? { startNew: input.startNew } : {}),\n ...(input.isAnonymous !== undefined ? { isAnonymous: input.isAnonymous } : {}),\n },\n // The server-anchored \"now\" this write was created at — never\n // `Date.now()`/`new Date()` (hard rule #6) — `EnqueueWriteOptions\n // .enqueuedAt`'s own doc comment: \"client-attested and only ever\n // used by the server to REFUSE\" (the 7-day post-expiry grace\n // check). Optional on the wire, and genuinely omitted here on a\n // cold session: `useServerTime().now()` throws before this\n // session's very first `snapshot.updated` event has landed (its\n // own documented behaviour, guarded at the call site exactly as\n // its header instructs) — a share write attempted in that narrow\n // window still enqueues durably, just without a client-attested\n // stamp for the server's grace check to read.\n ...(serverTimeKnown ? { enqueuedAt: now() } : {}),\n });\n },\n });\n\n const submitMutation = useOfflineMutation<ShareFormWriteInput>({\n tripRef: token,\n enqueue: (mutationEngine, input) => {\n const query =\n input.travellerRef !== undefined\n ? `?travellerRef=${encodeURIComponent(input.travellerRef)}`\n : '';\n return mutationEngine.enqueue({\n tripRef: token,\n method: SyncOpMethod.Post,\n path: `/api/v1/share/${token}/forms/${input.formId}/submit${query}`,\n operationId: 'shareSubmitForm' as never,\n body: {\n answers: input.answers,\n clientToken: input.clientToken,\n ...(input.startNew !== undefined ? { startNew: input.startNew } : {}),\n ...(input.isAnonymous !== undefined ? { isAnonymous: input.isAnonymous } : {}),\n },\n // See the identical `save` enqueue above for why this is guarded.\n ...(serverTimeKnown ? { enqueuedAt: now() } : {}),\n });\n },\n });\n\n const renderForm = useCallback(\n async (\n formId: string,\n options?: { readonly travellerRef?: string },\n ): Promise<Record<string, unknown>> => {\n const response = await client.share.forms.render({\n token,\n formId,\n ...(options?.travellerRef !== undefined ? { travellerRef: options.travellerRef } : {}),\n });\n return response;\n },\n [client, token],\n );\n\n const { status: writeStatus, op: writeOp } = deriveWriteStatus(\n revoked,\n saveMutation.op,\n submitMutation.op,\n isOnline,\n );\n\n return {\n status: deriveListStatus(forms, listFailed),\n forms: forms ?? [],\n serverTime,\n refresh: fetchList,\n renderForm,\n save: saveMutation.mutate,\n submit: submitMutation.mutate,\n writeStatus,\n writeOp,\n };\n}\n","'use client';\n\n// `08-core-hooks.md §3.1`. The single assembled read behind the whole\n// traveller share surface. Wraps `share.snapshot()` (verified `shareAuth`\n// -only in `security.ts` — no `apiKeyAuth` alternative exists for any\n// `share.*` operation), read cache-first from the snapshot once\n// `OfflineEngine`'s `share` option is configured.\n//\n// VERIFIED SHAPE (`openapi/openapi.json`'s `ShareSnapshotResponse`, this\n// session): a flat object with one property PER section key, each present\n// only when the link exposes it and data exists — never `null`, never an\n// empty placeholder — plus a `trip` echo (`name`/`startDate`/`endDate`/\n// `timezone`/`phase`) that is NOT one of the thirteen section flags\n// (`09-registries.md §5`). This hook builds `sections` by taking every own\n// key off the response except `trip` and `meta` — additive-safe against a\n// future 14th section key without needing this file to enumerate all\n// thirteen by name.\n//\n// `trip` and the server clock are surfaced as their OWN top-level fields on\n// `ShareSnapshotResult`, never folded into `sections`: every consumer of\n// `sections` (starting with `KaafilShareView`, which walks the map and\n// renders one composite per key) treats \"is this key present\" as \"should I\n// render a section for it\" — letting `trip`/`meta` leak into that map would\n// make the view try to mount a `<ShareTripSection>`/`<ShareMetaSection>`\n// that has never existed. But every traveller composite still needs BOTH:\n// `trip.timezone` is the one zone `DateDisplay`/`TimeDisplay` may legally\n// anchor to on this surface (never the device zone, never a fabricated\n// `'UTC'`), `trip.phase` lets a composite react to PRE_DEPARTURE/ON_TRIP/\n// POST_TRIP, and `meta.serverTime` is the only trusted \"now\" a share\n// composite may read without going through `useServerTime()` (hard rule\n// #6 — no `Date.now()`/`new Date()` in `src/core`). Hence: two extra return\n// fields, kept structurally apart from the section map they must never\n// pollute.\n\nimport type { KaafilClient } from 'kaafil-js/client';\nimport { useContext, useEffect, useState } from 'react';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { isDevelopment } from '../internal/isDevelopment';\nimport { useKaafilClient } from './useKaafilClient';\nimport { usePersona } from './usePersona';\n\nexport interface ShareSnapshotOptions {\n readonly travellerRef?: string;\n}\n\n// Derived from the SDK's own return type rather than hand-copied — this\n// stays correct for free if `kaafil-js` grows another `trip` field, instead\n// of silently drifting the way the old `'UTC'` constants did.\ntype ShareSnapshotResponse = Awaited<ReturnType<KaafilClient['share']['snapshot']>>;\n\n/** The trip echo every snapshot response carries — `name`/`startDate`/\n * `endDate` plus the two fields this hook used to throw away:\n * `timezone` (the IANA zone every traveller-facing render must anchor to)\n * and `phase` (server-computed `PRE_DEPARTURE`/`ON_TRIP`/`POST_TRIP`). */\nexport type ShareSnapshotTrip = ShareSnapshotResponse['trip'];\n\nexport interface ShareSnapshotResult {\n readonly status: 'loading' | 'ready' | 'expired' | 'revoked' | 'not-found';\n readonly sections: ReadonlyMap<string, unknown>;\n /** The snapshot's `trip` echo, or `undefined` before any response has\n * landed (mirrors `sections`' own \"empty until ready\" behaviour). NEVER a\n * section key — see this file's header. */\n readonly trip: ShareSnapshotTrip | undefined;\n /** `meta.serverTime` off the most recently landed snapshot response — the\n * only trusted clock a share composite may read (hard rule #6). Kept\n * separate from `useServerTime()`'s own stream (which advances off\n * `OfflineEngine`'s `snapshot.updated` event, not this hook's own fetch)\n * so a composite that only ever calls `useShareSnapshot()` still has a\n * real server stamp to compare against without also wiring the offline\n * engine's event stream. `undefined` before any response has landed. */\n readonly serverTime: string | undefined;\n}\n\nconst NON_SECTION_KEYS = new Set(['trip', 'meta']);\n\nexport function useShareSnapshot(\n token: string,\n options?: ShareSnapshotOptions,\n): ShareSnapshotResult {\n void options; // `travellerRef` narrows which subject-token rows the server\n // itself returns for a `travellerRef`-scoped share link — this hook has no\n // client-side use for it beyond passing the token through; the server does\n // the scoping (`09-registries.md §5`, `families/traveller/01-share-sections.md`, cited).\n\n const client = useKaafilClient();\n const persona = usePersona();\n const engine = useContext(OfflineEngineContext);\n const [sections, setSections] = useState<ReadonlyMap<string, unknown> | undefined>(undefined);\n const [trip, setTrip] = useState<ShareSnapshotTrip | undefined>(undefined);\n const [serverTime, setServerTime] = useState<string | undefined>(undefined);\n const [terminal, setTerminal] = useState<'expired' | 'revoked' | 'not-found' | undefined>(\n undefined,\n );\n\n useEffect(() => {\n if (persona !== 'share') {\n if (isDevelopment()) {\n throw new Error(\n 'useShareSnapshot() was called from a manager/agencyAdmin session — ' +\n 'this hook is `share`-only (08-core-hooks.md §3.1).',\n );\n }\n return;\n }\n\n let cancelled = false;\n async function load(): Promise<void> {\n try {\n const response = await client.share.snapshot({ token });\n if (cancelled) {\n return;\n }\n const map = new Map<string, unknown>();\n for (const [key, value] of Object.entries(response)) {\n if (!NON_SECTION_KEYS.has(key)) {\n map.set(key, value);\n }\n }\n setSections(map);\n setTrip(response.trip);\n setServerTime(response.meta.serverTime);\n } catch {\n // `06-capability-and-personas.md §9`: dark, cross-scope, and\n // genuinely-gone all collapse to the identical shape here — this\n // hook cannot and must not try to distinguish them, so any failure\n // to read the snapshot at all reports the same `'not-found'`.\n if (!cancelled) {\n setTerminal('not-found');\n }\n }\n }\n void load();\n\n if (engine === null) {\n return () => {\n cancelled = true;\n };\n }\n const unsubscribeExpired = engine.events.on('share.expired', () => setTerminal('expired'));\n const unsubscribeRevoked = engine.events.on('share.revoked', () => setTerminal('revoked'));\n return () => {\n cancelled = true;\n unsubscribeExpired();\n unsubscribeRevoked();\n };\n }, [client, persona, token, engine]);\n\n if (terminal !== undefined) {\n return { status: terminal, sections: sections ?? new Map(), trip, serverTime };\n }\n if (sections === undefined) {\n return { status: 'loading', sections: new Map(), trip: undefined, serverTime: undefined };\n }\n return { status: 'ready', sections, trip, serverTime };\n}\n"]}
|
package/dist/core/index.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var
|
|
6
|
-
var
|
|
3
|
+
var chunkHACH2NUM_cjs = require('../chunk-HACH2NUM.cjs');
|
|
4
|
+
var chunkIU2UM5JP_cjs = require('../chunk-IU2UM5JP.cjs');
|
|
5
|
+
var chunk6TI6YQPE_cjs = require('../chunk-6TI6YQPE.cjs');
|
|
6
|
+
var chunkBBC5EX5O_cjs = require('../chunk-BBC5EX5O.cjs');
|
|
7
7
|
var chunk57SUK3GD_cjs = require('../chunk-57SUK3GD.cjs');
|
|
8
|
-
var
|
|
8
|
+
var chunkECCQW5LN_cjs = require('../chunk-ECCQW5LN.cjs');
|
|
9
9
|
var chunkUALMCHNW_cjs = require('../chunk-UALMCHNW.cjs');
|
|
10
10
|
var client = require('kaafil-js/client');
|
|
11
11
|
var react = require('react');
|
|
@@ -163,7 +163,7 @@ function useResolvedSetting(key) {
|
|
|
163
163
|
}
|
|
164
164
|
function useSnapshotEntity(tripRef, listName, id) {
|
|
165
165
|
const engine = react.useContext(chunkUALMCHNW_cjs.OfflineEngineContext);
|
|
166
|
-
const { rows } =
|
|
166
|
+
const { rows } = chunk6TI6YQPE_cjs.useSnapshotList(tripRef, listName);
|
|
167
167
|
const row = rows.find((candidate) => candidate.id === id);
|
|
168
168
|
const syncedAt = engine === null ? void 0 : engine.snapshot.syncedAt(tripRef, listName, id);
|
|
169
169
|
return { row, syncedAt };
|
|
@@ -171,8 +171,8 @@ function useSnapshotEntity(tripRef, listName, id) {
|
|
|
171
171
|
|
|
172
172
|
// src/core/hooks/useStaleness.ts
|
|
173
173
|
function useStaleness(tripRef, listName) {
|
|
174
|
-
const { syncedAt } =
|
|
175
|
-
const { now } =
|
|
174
|
+
const { syncedAt } = chunk6TI6YQPE_cjs.useSnapshotList(tripRef, listName);
|
|
175
|
+
const { now } = chunkECCQW5LN_cjs.useServerTime();
|
|
176
176
|
const thresholdSeconds = useResolvedSetting("stale.thresholdSeconds.default");
|
|
177
177
|
if (syncedAt === void 0) {
|
|
178
178
|
return { syncedAt: void 0, ageSeconds: void 0, isStale: false };
|
|
@@ -187,7 +187,7 @@ function useStaleness(tripRef, listName) {
|
|
|
187
187
|
return { syncedAt, ageSeconds, isStale };
|
|
188
188
|
}
|
|
189
189
|
var WALK_INS_PAGE_SIZE = 25;
|
|
190
|
-
var useTreksInternal =
|
|
190
|
+
var useTreksInternal = chunk6TI6YQPE_cjs.createDomainHook("treks", (tripRef) => {
|
|
191
191
|
const client$1 = chunkUALMCHNW_cjs.useKaafilClient();
|
|
192
192
|
const [boardData, setBoardData] = react.useState(void 0);
|
|
193
193
|
const [boardLoaded, setBoardLoaded] = react.useState(false);
|
|
@@ -498,7 +498,7 @@ function ConfigShell({ seedConfig = {}, children }) {
|
|
|
498
498
|
return /* @__PURE__ */ jsxRuntime.jsx(chunkUALMCHNW_cjs.ConfigContext.Provider, { value, children });
|
|
499
499
|
}
|
|
500
500
|
function classifyForFallback(error) {
|
|
501
|
-
const classification =
|
|
501
|
+
const classification = chunk6TI6YQPE_cjs.classifyError(error);
|
|
502
502
|
if (classification.code === "RESOURCE_NOT_FOUND") {
|
|
503
503
|
return { classification: "isolation", code: classification.code };
|
|
504
504
|
}
|
|
@@ -741,7 +741,7 @@ function emit(onEvent, event) {
|
|
|
741
741
|
}
|
|
742
742
|
function TelemetryShell({ onEvent, children }) {
|
|
743
743
|
const session = chunkUALMCHNW_cjs.useSession();
|
|
744
|
-
const serverTime =
|
|
744
|
+
const serverTime = chunkECCQW5LN_cjs.useServerTime();
|
|
745
745
|
const previousStatusRef = react.useRef(void 0);
|
|
746
746
|
react.useEffect(() => {
|
|
747
747
|
const previousStatus = previousStatusRef.current;
|
|
@@ -995,179 +995,179 @@ function KaafilSessionProbe({
|
|
|
995
995
|
|
|
996
996
|
Object.defineProperty(exports, "useConflicts", {
|
|
997
997
|
enumerable: true,
|
|
998
|
-
get: function () { return
|
|
998
|
+
get: function () { return chunkHACH2NUM_cjs.useConflicts; }
|
|
999
999
|
});
|
|
1000
1000
|
Object.defineProperty(exports, "useManagerMe", {
|
|
1001
1001
|
enumerable: true,
|
|
1002
|
-
get: function () { return
|
|
1002
|
+
get: function () { return chunkHACH2NUM_cjs.useManagerMe; }
|
|
1003
1003
|
});
|
|
1004
1004
|
Object.defineProperty(exports, "useNotifications", {
|
|
1005
1005
|
enumerable: true,
|
|
1006
|
-
get: function () { return
|
|
1006
|
+
get: function () { return chunkHACH2NUM_cjs.useNotifications; }
|
|
1007
1007
|
});
|
|
1008
1008
|
Object.defineProperty(exports, "CLOSEOUT_ACTION_TAB", {
|
|
1009
1009
|
enumerable: true,
|
|
1010
|
-
get: function () { return
|
|
1010
|
+
get: function () { return chunkIU2UM5JP_cjs.CLOSEOUT_ACTION_TAB; }
|
|
1011
1011
|
});
|
|
1012
1012
|
Object.defineProperty(exports, "fromSearchParams", {
|
|
1013
1013
|
enumerable: true,
|
|
1014
|
-
get: function () { return
|
|
1014
|
+
get: function () { return chunkIU2UM5JP_cjs.fromSearchParams; }
|
|
1015
1015
|
});
|
|
1016
1016
|
Object.defineProperty(exports, "isTripTabKey", {
|
|
1017
1017
|
enumerable: true,
|
|
1018
|
-
get: function () { return
|
|
1018
|
+
get: function () { return chunkIU2UM5JP_cjs.isTripTabKey; }
|
|
1019
1019
|
});
|
|
1020
1020
|
Object.defineProperty(exports, "resolveBlockerDeepLink", {
|
|
1021
1021
|
enumerable: true,
|
|
1022
|
-
get: function () { return
|
|
1022
|
+
get: function () { return chunkIU2UM5JP_cjs.resolveBlockerDeepLink; }
|
|
1023
1023
|
});
|
|
1024
1024
|
Object.defineProperty(exports, "toSearchParams", {
|
|
1025
1025
|
enumerable: true,
|
|
1026
|
-
get: function () { return
|
|
1026
|
+
get: function () { return chunkIU2UM5JP_cjs.toSearchParams; }
|
|
1027
1027
|
});
|
|
1028
1028
|
Object.defineProperty(exports, "useAgencyAdminMe", {
|
|
1029
1029
|
enumerable: true,
|
|
1030
|
-
get: function () { return
|
|
1030
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyAdminMe; }
|
|
1031
1031
|
});
|
|
1032
1032
|
Object.defineProperty(exports, "useAgencyChecklistTemplates", {
|
|
1033
1033
|
enumerable: true,
|
|
1034
|
-
get: function () { return
|
|
1034
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyChecklistTemplates; }
|
|
1035
1035
|
});
|
|
1036
1036
|
Object.defineProperty(exports, "useAgencyForms", {
|
|
1037
1037
|
enumerable: true,
|
|
1038
|
-
get: function () { return
|
|
1038
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyForms; }
|
|
1039
1039
|
});
|
|
1040
1040
|
Object.defineProperty(exports, "useAgencyJourneyTriggers", {
|
|
1041
1041
|
enumerable: true,
|
|
1042
|
-
get: function () { return
|
|
1042
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyJourneyTriggers; }
|
|
1043
1043
|
});
|
|
1044
1044
|
Object.defineProperty(exports, "useAgencyManagerProfile", {
|
|
1045
1045
|
enumerable: true,
|
|
1046
|
-
get: function () { return
|
|
1046
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyManagerProfile; }
|
|
1047
1047
|
});
|
|
1048
1048
|
Object.defineProperty(exports, "useAgencySettings", {
|
|
1049
1049
|
enumerable: true,
|
|
1050
|
-
get: function () { return
|
|
1050
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencySettings; }
|
|
1051
1051
|
});
|
|
1052
1052
|
Object.defineProperty(exports, "useAgencyTrip", {
|
|
1053
1053
|
enumerable: true,
|
|
1054
|
-
get: function () { return
|
|
1054
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyTrip; }
|
|
1055
1055
|
});
|
|
1056
1056
|
Object.defineProperty(exports, "useAgencyTripManifest", {
|
|
1057
1057
|
enumerable: true,
|
|
1058
|
-
get: function () { return
|
|
1058
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyTripManifest; }
|
|
1059
1059
|
});
|
|
1060
1060
|
Object.defineProperty(exports, "useAgencyTrips", {
|
|
1061
1061
|
enumerable: true,
|
|
1062
|
-
get: function () { return
|
|
1062
|
+
get: function () { return chunkIU2UM5JP_cjs.useAgencyTrips; }
|
|
1063
1063
|
});
|
|
1064
1064
|
Object.defineProperty(exports, "useBookings", {
|
|
1065
1065
|
enumerable: true,
|
|
1066
|
-
get: function () { return
|
|
1066
|
+
get: function () { return chunkIU2UM5JP_cjs.useBookings; }
|
|
1067
1067
|
});
|
|
1068
1068
|
Object.defineProperty(exports, "useCapabilityStatuses", {
|
|
1069
1069
|
enumerable: true,
|
|
1070
|
-
get: function () { return
|
|
1070
|
+
get: function () { return chunkIU2UM5JP_cjs.useCapabilityStatuses; }
|
|
1071
1071
|
});
|
|
1072
1072
|
Object.defineProperty(exports, "useDirectories", {
|
|
1073
1073
|
enumerable: true,
|
|
1074
|
-
get: function () { return
|
|
1074
|
+
get: function () { return chunkIU2UM5JP_cjs.useDirectories; }
|
|
1075
1075
|
});
|
|
1076
1076
|
Object.defineProperty(exports, "usePaginatedList", {
|
|
1077
1077
|
enumerable: true,
|
|
1078
|
-
get: function () { return
|
|
1078
|
+
get: function () { return chunkIU2UM5JP_cjs.usePaginatedList; }
|
|
1079
1079
|
});
|
|
1080
1080
|
Object.defineProperty(exports, "useShareLinks", {
|
|
1081
1081
|
enumerable: true,
|
|
1082
|
-
get: function () { return
|
|
1082
|
+
get: function () { return chunkIU2UM5JP_cjs.useShareLinks; }
|
|
1083
1083
|
});
|
|
1084
1084
|
Object.defineProperty(exports, "useTravellerFormResponses", {
|
|
1085
1085
|
enumerable: true,
|
|
1086
|
-
get: function () { return
|
|
1086
|
+
get: function () { return chunkIU2UM5JP_cjs.useTravellerFormResponses; }
|
|
1087
1087
|
});
|
|
1088
1088
|
Object.defineProperty(exports, "ERROR_HANDLING_PATH", {
|
|
1089
1089
|
enumerable: true,
|
|
1090
|
-
get: function () { return
|
|
1090
|
+
get: function () { return chunk6TI6YQPE_cjs.ERROR_HANDLING_PATH; }
|
|
1091
1091
|
});
|
|
1092
1092
|
Object.defineProperty(exports, "classifyError", {
|
|
1093
1093
|
enumerable: true,
|
|
1094
|
-
get: function () { return
|
|
1094
|
+
get: function () { return chunk6TI6YQPE_cjs.classifyError; }
|
|
1095
1095
|
});
|
|
1096
1096
|
Object.defineProperty(exports, "useChecklists", {
|
|
1097
1097
|
enumerable: true,
|
|
1098
|
-
get: function () { return
|
|
1098
|
+
get: function () { return chunk6TI6YQPE_cjs.useChecklists; }
|
|
1099
1099
|
});
|
|
1100
1100
|
Object.defineProperty(exports, "useCloseout", {
|
|
1101
1101
|
enumerable: true,
|
|
1102
|
-
get: function () { return
|
|
1102
|
+
get: function () { return chunk6TI6YQPE_cjs.useCloseout; }
|
|
1103
1103
|
});
|
|
1104
1104
|
Object.defineProperty(exports, "useCollections", {
|
|
1105
1105
|
enumerable: true,
|
|
1106
|
-
get: function () { return
|
|
1106
|
+
get: function () { return chunk6TI6YQPE_cjs.useCollections; }
|
|
1107
1107
|
});
|
|
1108
1108
|
Object.defineProperty(exports, "useExpenses", {
|
|
1109
1109
|
enumerable: true,
|
|
1110
|
-
get: function () { return
|
|
1110
|
+
get: function () { return chunk6TI6YQPE_cjs.useExpenses; }
|
|
1111
1111
|
});
|
|
1112
1112
|
Object.defineProperty(exports, "useFiles", {
|
|
1113
1113
|
enumerable: true,
|
|
1114
|
-
get: function () { return
|
|
1114
|
+
get: function () { return chunk6TI6YQPE_cjs.useFiles; }
|
|
1115
1115
|
});
|
|
1116
1116
|
Object.defineProperty(exports, "useFloat", {
|
|
1117
1117
|
enumerable: true,
|
|
1118
|
-
get: function () { return
|
|
1118
|
+
get: function () { return chunk6TI6YQPE_cjs.useFloat; }
|
|
1119
1119
|
});
|
|
1120
1120
|
Object.defineProperty(exports, "useForms", {
|
|
1121
1121
|
enumerable: true,
|
|
1122
|
-
get: function () { return
|
|
1122
|
+
get: function () { return chunk6TI6YQPE_cjs.useForms; }
|
|
1123
1123
|
});
|
|
1124
1124
|
Object.defineProperty(exports, "useItinerary", {
|
|
1125
1125
|
enumerable: true,
|
|
1126
|
-
get: function () { return
|
|
1126
|
+
get: function () { return chunk6TI6YQPE_cjs.useItinerary; }
|
|
1127
1127
|
});
|
|
1128
1128
|
Object.defineProperty(exports, "useManagerToday", {
|
|
1129
1129
|
enumerable: true,
|
|
1130
|
-
get: function () { return
|
|
1130
|
+
get: function () { return chunk6TI6YQPE_cjs.useManagerToday; }
|
|
1131
1131
|
});
|
|
1132
1132
|
Object.defineProperty(exports, "useManagers", {
|
|
1133
1133
|
enumerable: true,
|
|
1134
|
-
get: function () { return
|
|
1134
|
+
get: function () { return chunk6TI6YQPE_cjs.useManagers; }
|
|
1135
1135
|
});
|
|
1136
1136
|
Object.defineProperty(exports, "useParties", {
|
|
1137
1137
|
enumerable: true,
|
|
1138
|
-
get: function () { return
|
|
1138
|
+
get: function () { return chunk6TI6YQPE_cjs.useParties; }
|
|
1139
1139
|
});
|
|
1140
1140
|
Object.defineProperty(exports, "usePickups", {
|
|
1141
1141
|
enumerable: true,
|
|
1142
|
-
get: function () { return
|
|
1142
|
+
get: function () { return chunk6TI6YQPE_cjs.usePickups; }
|
|
1143
1143
|
});
|
|
1144
1144
|
Object.defineProperty(exports, "useRooming", {
|
|
1145
1145
|
enumerable: true,
|
|
1146
|
-
get: function () { return
|
|
1146
|
+
get: function () { return chunk6TI6YQPE_cjs.useRooming; }
|
|
1147
1147
|
});
|
|
1148
1148
|
Object.defineProperty(exports, "useSeating", {
|
|
1149
1149
|
enumerable: true,
|
|
1150
|
-
get: function () { return
|
|
1150
|
+
get: function () { return chunk6TI6YQPE_cjs.useSeating; }
|
|
1151
1151
|
});
|
|
1152
1152
|
Object.defineProperty(exports, "useSnapshotList", {
|
|
1153
1153
|
enumerable: true,
|
|
1154
|
-
get: function () { return
|
|
1154
|
+
get: function () { return chunk6TI6YQPE_cjs.useSnapshotList; }
|
|
1155
1155
|
});
|
|
1156
1156
|
Object.defineProperty(exports, "useTravellerProfile", {
|
|
1157
1157
|
enumerable: true,
|
|
1158
|
-
get: function () { return
|
|
1158
|
+
get: function () { return chunk6TI6YQPE_cjs.useTravellerProfile; }
|
|
1159
1159
|
});
|
|
1160
1160
|
Object.defineProperty(exports, "useVendors", {
|
|
1161
1161
|
enumerable: true,
|
|
1162
|
-
get: function () { return
|
|
1162
|
+
get: function () { return chunk6TI6YQPE_cjs.useVendors; }
|
|
1163
1163
|
});
|
|
1164
1164
|
Object.defineProperty(exports, "useShareForms", {
|
|
1165
1165
|
enumerable: true,
|
|
1166
|
-
get: function () { return
|
|
1166
|
+
get: function () { return chunkBBC5EX5O_cjs.useShareForms; }
|
|
1167
1167
|
});
|
|
1168
1168
|
Object.defineProperty(exports, "useShareSnapshot", {
|
|
1169
1169
|
enumerable: true,
|
|
1170
|
-
get: function () { return
|
|
1170
|
+
get: function () { return chunkBBC5EX5O_cjs.useShareSnapshot; }
|
|
1171
1171
|
});
|
|
1172
1172
|
Object.defineProperty(exports, "BrandShell", {
|
|
1173
1173
|
enumerable: true,
|
|
@@ -1187,7 +1187,7 @@ Object.defineProperty(exports, "useOfflineEngine", {
|
|
|
1187
1187
|
});
|
|
1188
1188
|
Object.defineProperty(exports, "useServerTime", {
|
|
1189
1189
|
enumerable: true,
|
|
1190
|
-
get: function () { return
|
|
1190
|
+
get: function () { return chunkECCQW5LN_cjs.useServerTime; }
|
|
1191
1191
|
});
|
|
1192
1192
|
Object.defineProperty(exports, "I18nShell", {
|
|
1193
1193
|
enumerable: true,
|