kaafil-react-uikit 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/admin/index.cjs +342 -342
  2. package/dist/admin/index.js +5 -5
  3. package/dist/{chunk-YHOQRKDJ.cjs → chunk-57SUK3GD.cjs} +7 -7
  4. package/dist/{chunk-YHOQRKDJ.cjs.map → chunk-57SUK3GD.cjs.map} +1 -1
  5. package/dist/{chunk-2SRBJ4H7.js → chunk-A4Z2YBEF.js} +19 -5
  6. package/dist/chunk-A4Z2YBEF.js.map +1 -0
  7. package/dist/{chunk-2MWTLYVP.cjs → chunk-BBC5EX5O.cjs} +17 -17
  8. package/dist/{chunk-2MWTLYVP.cjs.map → chunk-BBC5EX5O.cjs.map} +1 -1
  9. package/dist/{chunk-W5PG3IUJ.cjs → chunk-ECCQW5LN.cjs} +7 -4
  10. package/dist/chunk-ECCQW5LN.cjs.map +1 -0
  11. package/dist/{chunk-M2D6CZK2.cjs → chunk-FVK7HMQ5.cjs} +37 -37
  12. package/dist/{chunk-M2D6CZK2.cjs.map → chunk-FVK7HMQ5.cjs.map} +1 -1
  13. package/dist/{chunk-PYETPKTT.js → chunk-GJ2J3PYN.js} +3 -3
  14. package/dist/{chunk-PYETPKTT.js.map → chunk-GJ2J3PYN.js.map} +1 -1
  15. package/dist/{chunk-TF3GCIDK.cjs → chunk-HACH2NUM.cjs} +24 -13
  16. package/dist/chunk-HACH2NUM.cjs.map +1 -0
  17. package/dist/{chunk-PDQVVJCS.js → chunk-KW5LH6KV.js} +3 -3
  18. package/dist/{chunk-PDQVVJCS.js.map → chunk-KW5LH6KV.js.map} +1 -1
  19. package/dist/{chunk-WS2DKREI.cjs → chunk-MNUCVVIE.cjs} +168 -97
  20. package/dist/chunk-MNUCVVIE.cjs.map +1 -0
  21. package/dist/{chunk-CURTZGHY.js → chunk-RWLO6IFX.js} +19 -8
  22. package/dist/chunk-RWLO6IFX.js.map +1 -0
  23. package/dist/{chunk-V36WWMTF.cjs → chunk-UALMCHNW.cjs} +19 -5
  24. package/dist/chunk-UALMCHNW.cjs.map +1 -0
  25. package/dist/{chunk-JMWXQTE3.js → chunk-VLP323AD.js} +6 -3
  26. package/dist/chunk-VLP323AD.js.map +1 -0
  27. package/dist/{chunk-7WXE5SUS.js → chunk-WTTGPWMR.js} +92 -21
  28. package/dist/chunk-WTTGPWMR.js.map +1 -0
  29. package/dist/{chunk-PCDEJHWL.cjs → chunk-YNHOPYBK.cjs} +12 -12
  30. package/dist/{chunk-PCDEJHWL.cjs.map → chunk-YNHOPYBK.cjs.map} +1 -1
  31. package/dist/{chunk-FFXGZZGJ.js → chunk-YTSYRLGS.js} +5 -5
  32. package/dist/{chunk-FFXGZZGJ.js.map → chunk-YTSYRLGS.js.map} +1 -1
  33. package/dist/{chunk-E42K6UMM.js → chunk-YU2242AR.js} +5 -5
  34. package/dist/{chunk-E42K6UMM.js.map → chunk-YU2242AR.js.map} +1 -1
  35. package/dist/core/index.cjs +113 -113
  36. package/dist/core/index.js +11 -11
  37. package/dist/manager/index.cjs +239 -239
  38. package/dist/manager/index.js +6 -6
  39. package/dist/traveller/index.cjs +35 -35
  40. package/dist/traveller/index.js +5 -5
  41. package/package.json +2 -2
  42. package/dist/chunk-2SRBJ4H7.js.map +0 -1
  43. package/dist/chunk-7WXE5SUS.js.map +0 -1
  44. package/dist/chunk-CURTZGHY.js.map +0 -1
  45. package/dist/chunk-JMWXQTE3.js.map +0 -1
  46. package/dist/chunk-TF3GCIDK.cjs.map +0 -1
  47. package/dist/chunk-V36WWMTF.cjs.map +0 -1
  48. package/dist/chunk-W5PG3IUJ.cjs.map +0 -1
  49. package/dist/chunk-WS2DKREI.cjs.map +0 -1
@@ -1,8 +1,8 @@
1
- import { useAgencySettings, useAgencyChecklistTemplates, useAgencyForms, useAgencyManagerProfile, useAgencyJourneyTriggers, useBookings, useDirectories, useCapabilityStatuses, useAgencyTrip, useAgencyAdminMe, useTravellerFormResponses, familySafeSections, useShareLinks, usePaginatedList, useAgencyTrips, useAgencyTripManifest, resolveBlockerDeepLink } from '../chunk-FFXGZZGJ.js';
2
- import { useChecklists, useFiles, useExpenses, useVendors, useFloat, useManagers, useForms, useItinerary, useCollections, useParties, usePickups, useRooming, useSeating, classifyError, useTravellerProfile, roomingHeuristicSeverity, useManagerToday, useCloseout, parseRoomingTone, TONE_FAMILIES, SHADES_PER_FAMILY, FALLBACK_GLYPH } from '../chunk-7WXE5SUS.js';
3
- import '../chunk-JMWXQTE3.js';
4
- export { BootErrorScreen, LockedTripScreen, NotFoundScreen, OfflineFallbackScreen, PlanLockedScreen, SessionExpiredScreen } from '../chunk-PYETPKTT.js';
5
- import { createRegistry, useKaafilChrome, tokenStyle, useSession, useKaafilClient } from '../chunk-2SRBJ4H7.js';
1
+ import { useAgencySettings, useAgencyChecklistTemplates, useAgencyForms, useAgencyManagerProfile, useAgencyJourneyTriggers, useBookings, useDirectories, useCapabilityStatuses, useAgencyTrip, useAgencyAdminMe, useTravellerFormResponses, familySafeSections, useShareLinks, usePaginatedList, useAgencyTrips, useAgencyTripManifest, resolveBlockerDeepLink } from '../chunk-YTSYRLGS.js';
2
+ import { useChecklists, useFiles, useExpenses, useVendors, useFloat, useManagers, useForms, useItinerary, useCollections, useParties, usePickups, useRooming, useSeating, classifyError, useTravellerProfile, roomingHeuristicSeverity, useManagerToday, useCloseout, parseRoomingTone, TONE_FAMILIES, SHADES_PER_FAMILY, FALLBACK_GLYPH } from '../chunk-WTTGPWMR.js';
3
+ import '../chunk-VLP323AD.js';
4
+ export { BootErrorScreen, LockedTripScreen, NotFoundScreen, OfflineFallbackScreen, PlanLockedScreen, SessionExpiredScreen } from '../chunk-GJ2J3PYN.js';
5
+ import { createRegistry, useKaafilChrome, tokenStyle, useSession, useKaafilClient } from '../chunk-A4Z2YBEF.js';
6
6
  import { useState, useEffect, useCallback, useMemo, useId, useRef, Children } from 'react';
7
7
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
 
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkV36WWMTF_cjs = require('./chunk-V36WWMTF.cjs');
3
+ var chunkUALMCHNW_cjs = require('./chunk-UALMCHNW.cjs');
4
4
  var react = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
7
  // src/core/hooks/useOfflineEngine.ts
8
8
  function useOfflineEngine() {
9
- return chunkV36WWMTF_cjs.useRequiredContext(chunkV36WWMTF_cjs.OfflineEngineContext, "useOfflineEngine", "OfflineShell");
9
+ return chunkUALMCHNW_cjs.useRequiredContext(chunkUALMCHNW_cjs.OfflineEngineContext, "useOfflineEngine", "OfflineShell");
10
10
  }
11
11
  var BrandAssetsContext = react.createContext(null);
12
12
  function useKaafilBrand() {
@@ -68,14 +68,14 @@ function BrandShell({
68
68
  headStrategy = "none",
69
69
  children
70
70
  }) {
71
- const persona = chunkV36WWMTF_cjs.usePersona();
71
+ const persona = chunkUALMCHNW_cjs.usePersona();
72
72
  const assets = react.useMemo(
73
73
  () => ({ appName, logo, logoMark, favicon }),
74
74
  [appName, logo, logoMark, favicon]
75
75
  );
76
76
  const rejectedOwnPage = headStrategy === "own-page" && persona !== "share";
77
77
  react.useEffect(() => {
78
- if (headStrategy === "own-page" && persona !== "share" && chunkV36WWMTF_cjs.isDevelopment()) {
78
+ if (headStrategy === "own-page" && persona !== "share" && chunkUALMCHNW_cjs.isDevelopment()) {
79
79
  throw new Error(
80
80
  `BrandShell: headStrategy="own-page" was requested under a non-share persona ("${persona}") \u2014 only the traveller/share surface may own document.head (00-decisions.md U-005). Falls back to "none" in production.`
81
81
  );
@@ -86,7 +86,7 @@ function BrandShell({
86
86
  // work under every `headStrategy` and warning about it told integrators
87
87
  // their correct code was wrong. `favicon` has no in-page use at all, so
88
88
  // passing one under `'none'` genuinely is a no-op worth flagging.
89
- favicon !== void 0 && chunkV36WWMTF_cjs.isDevelopment()) {
89
+ favicon !== void 0 && chunkUALMCHNW_cjs.isDevelopment()) {
90
90
  console.warn(
91
91
  'BrandShell: headStrategy="none" (the default) is a hard no-op \u2014 "favicon" was passed but document.head is never touched under "none" (00-decisions.md U-005). "appName" is unaffected: it still feeds the in-page brand fallback.'
92
92
  );
@@ -106,5 +106,5 @@ exports.BrandShell = BrandShell;
106
106
  exports.useKaafilBrand = useKaafilBrand;
107
107
  exports.useKaafilShareMeta = useKaafilShareMeta;
108
108
  exports.useOfflineEngine = useOfflineEngine;
109
- //# sourceMappingURL=chunk-YHOQRKDJ.cjs.map
110
- //# sourceMappingURL=chunk-YHOQRKDJ.cjs.map
109
+ //# sourceMappingURL=chunk-57SUK3GD.cjs.map
110
+ //# sourceMappingURL=chunk-57SUK3GD.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/hooks/useOfflineEngine.ts","../src/core/shells/BrandShell.tsx"],"names":["useRequiredContext","OfflineEngineContext","createContext","useContext","useEffect","usePersona","useMemo","isDevelopment","jsxs"],"mappings":"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","file":"chunk-YHOQRKDJ.cjs","sourcesContent":["'use client';\n\n// `08-core-hooks.md §2.1`. The escape hatch underneath every hook in §2 — a\n// composite should reach for a narrower hook before this one.\n\nimport type { OfflineEngine, OutboxOp } from 'kaafil-js/client';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { useRequiredContext } from '../internal/useRequiredContext';\n\n// Re-exported so a composite (`ManagerSyncCenterSection.types.ts`) can name\n// one outbox op's shape without importing `kaafil-js/client` directly —\n// hard rule #1.\nexport type { OutboxOp };\n\n/** Returns the engine instance `OfflineShell` opened via\n * `client.openOffline(options)`. Throws outside the provider tree. */\nexport function useOfflineEngine(): OfflineEngine {\n return useRequiredContext(OfflineEngineContext, 'useOfflineEngine', 'OfflineShell');\n}\n","'use client';\n\n// `shells/06-brand-shell.md`. Eighth in the locked mount order\n// (`shells/README.md §2` row 8) — supplies host-side brand assets\n// (fallback chain: partner logo → neutral mark → text-only appName,\n// `05-theming-and-branding.md §8`) and, opt-in and persona-gated, controls\n// `document.head` for the traveller/share surface only. Fetches nothing\n// from the engine (`00-decisions.md` U-007 — per-agency brand assets are a\n// named non-goal for the backend).\n\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useMemo } from 'react';\nimport { usePersona } from '../hooks/usePersona';\nimport { isDevelopment } from '../internal/isDevelopment';\n\nexport interface KaafilBrandAssets {\n readonly appName?: string;\n readonly logo?: string | ReactNode;\n readonly logoMark?: string | ReactNode;\n readonly favicon?: string;\n}\n\nexport interface BrandShellProps extends KaafilBrandAssets {\n readonly headStrategy?: 'none' | 'own-page';\n readonly children?: ReactNode;\n}\n\n/** Shell-owned, not a `08-core-hooks.md` catalog entry (component authoring\n * — this context's eventual consumer, a logo/header component reading the\n * fallback chain — is out of scope for this phase). */\nconst BrandAssetsContext = createContext<KaafilBrandAssets | null>(null);\n\n/** Reads the brand assets `BrandShell` forwarded, or `{}` when mounted\n * without one (never throws — brand is presentational, not load-bearing the\n * way a session read is). */\nexport function useKaafilBrand(): KaafilBrandAssets {\n return useContext(BrandAssetsContext) ?? {};\n}\n\nexport interface ShareMeta {\n readonly title: string | undefined;\n readonly favicon: string | undefined;\n readonly ogTitle: string | undefined;\n readonly ogDescription: string | undefined;\n readonly ogImage: string | undefined;\n readonly robots: 'noindex' | 'index';\n}\n\nfunction resolveShareMeta(assets: KaafilBrandAssets): ShareMeta {\n return {\n title: assets.appName,\n favicon: assets.favicon,\n ogTitle: assets.appName,\n ogDescription: undefined,\n ogImage: undefined,\n // Share meta defaults to noindex — a share link is private-by-obscurity;\n // indexing it is a disclosure bug, never the shipped default\n // (`00-decisions.md` U-005).\n robots: 'noindex',\n };\n}\n\n/** Only the traveller/share surface may write `document.head` — mounted\n * exclusively by `BrandShell` under a persona-permitted `'own-page'`\n * request. Renders nothing into the page body: title/meta writes are not\n * \"visual output\" in the sense `shells/README.md §1` means the phrase. */\nfunction KaafilDocumentHead({ meta }: { readonly meta: ShareMeta }): null {\n useEffect(() => {\n if (meta.title !== undefined) {\n document.title = meta.title;\n }\n if (meta.favicon !== undefined) {\n let link = document.querySelector<HTMLLinkElement>('link[rel=\"icon\"][data-kf-brand]');\n if (link === null) {\n link = document.createElement('link');\n link.rel = 'icon';\n link.setAttribute('data-kf-brand', '');\n document.head.appendChild(link);\n }\n link.href = meta.favicon;\n }\n const setMeta = (\n name: string,\n content: string | undefined,\n attr: 'name' | 'property' = 'name',\n ): void => {\n if (content === undefined) {\n return;\n }\n let tag = document.querySelector<HTMLMetaElement>(`meta[${attr}=\"${name}\"][data-kf-brand]`);\n if (tag === null) {\n tag = document.createElement('meta');\n tag.setAttribute(attr, name);\n tag.setAttribute('data-kf-brand', '');\n document.head.appendChild(tag);\n }\n tag.content = content;\n };\n setMeta('og:title', meta.ogTitle, 'property');\n setMeta('og:description', meta.ogDescription, 'property');\n setMeta('og:image', meta.ogImage, 'property');\n setMeta('robots', meta.robots);\n }, [meta]);\n\n return null;\n}\n\n/**\n * Forwards brand assets unconditionally; enforces `headStrategy` before\n * ever mounting `<KaafilDocumentHead>`. `'none'` is a HARD no-op — no\n * branch below it ever touches `document.head`, even when `favicon`/\n * `appName` are supplied. `'own-page'` is runtime-rejected under\n * `agencyAdmin`/`manager` (dev throw, prod warning + silent `'none'`\n * fallback — the same shape `useCapability()` uses for a wrong-persona call,\n * `08-core-hooks.md §1.4`).\n */\nexport function BrandShell({\n appName,\n logo,\n logoMark,\n favicon,\n headStrategy = 'none',\n children,\n}: BrandShellProps): ReactNode {\n const persona = usePersona();\n const assets = useMemo(\n () => ({ appName, logo, logoMark, favicon }),\n [appName, logo, logoMark, favicon],\n );\n\n const rejectedOwnPage = headStrategy === 'own-page' && persona !== 'share';\n\n useEffect(() => {\n if (headStrategy === 'own-page' && persona !== 'share' && isDevelopment()) {\n throw new Error(\n 'BrandShell: headStrategy=\"own-page\" was requested under a non-share persona ' +\n `(\"${persona}\") — only the traveller/share surface may own document.head ` +\n '(00-decisions.md U-005). Falls back to \"none\" in production.',\n );\n }\n if (\n headStrategy === 'none' &&\n // `favicon` ONLY. `appName` is not a head-only prop: it is the last rung\n // of the in-page brand fallback chain (partner logo -> neutral mark ->\n // text-only appName, 05-theming-and-branding.md §8), so it does real\n // work under every `headStrategy` and warning about it told integrators\n // their correct code was wrong. `favicon` has no in-page use at all, so\n // passing one under `'none'` genuinely is a no-op worth flagging.\n favicon !== undefined &&\n isDevelopment()\n ) {\n // biome-ignore lint/suspicious/noConsole: dev-only, gated above by isDevelopment()\n console.warn(\n 'BrandShell: headStrategy=\"none\" (the default) is a hard no-op — \"favicon\" was passed ' +\n 'but document.head is never touched under \"none\" (00-decisions.md U-005). ' +\n '\"appName\" is unaffected: it still feeds the in-page brand fallback.',\n );\n }\n }, [headStrategy, persona, favicon]);\n\n const shouldOwnPage = headStrategy === 'own-page' && persona === 'share' && !rejectedOwnPage;\n\n return (\n <BrandAssetsContext.Provider value={assets}>\n {shouldOwnPage ? <KaafilDocumentHead meta={resolveShareMeta(assets)} /> : null}\n {children}\n </BrandAssetsContext.Provider>\n );\n}\n\n/**\n * Shell-owned read-only alternative to `<KaafilDocumentHead>` — for a host\n * (e.g. Next.js App Router) that already owns `<head>` via its own\n * `metadata`/`generateMetadata` export and must keep `headStrategy=\"none\"`\n * here. Never writes the head itself; exactly one of the two paths is\n * active per mount (`shells/06-brand-shell.md`).\n */\nexport function useKaafilShareMeta(assets: KaafilBrandAssets): ShareMeta {\n return useMemo(() => resolveShareMeta(assets), [assets]);\n}\n"]}
1
+ {"version":3,"sources":["../src/core/hooks/useOfflineEngine.ts","../src/core/shells/BrandShell.tsx"],"names":["useRequiredContext","OfflineEngineContext","createContext","useContext","useEffect","usePersona","useMemo","isDevelopment","jsxs"],"mappings":"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","file":"chunk-57SUK3GD.cjs","sourcesContent":["'use client';\n\n// `08-core-hooks.md §2.1`. The escape hatch underneath every hook in §2 — a\n// composite should reach for a narrower hook before this one.\n\nimport type { OfflineEngine, OutboxOp } from 'kaafil-js/client';\nimport { OfflineEngineContext } from '../internal/contexts';\nimport { useRequiredContext } from '../internal/useRequiredContext';\n\n// Re-exported so a composite (`ManagerSyncCenterSection.types.ts`) can name\n// one outbox op's shape without importing `kaafil-js/client` directly —\n// hard rule #1.\nexport type { OutboxOp };\n\n/** Returns the engine instance `OfflineShell` opened via\n * `client.openOffline(options)`. Throws outside the provider tree. */\nexport function useOfflineEngine(): OfflineEngine {\n return useRequiredContext(OfflineEngineContext, 'useOfflineEngine', 'OfflineShell');\n}\n","'use client';\n\n// `shells/06-brand-shell.md`. Eighth in the locked mount order\n// (`shells/README.md §2` row 8) — supplies host-side brand assets\n// (fallback chain: partner logo → neutral mark → text-only appName,\n// `05-theming-and-branding.md §8`) and, opt-in and persona-gated, controls\n// `document.head` for the traveller/share surface only. Fetches nothing\n// from the engine (`00-decisions.md` U-007 — per-agency brand assets are a\n// named non-goal for the backend).\n\nimport type { ReactNode } from 'react';\nimport { createContext, useContext, useEffect, useMemo } from 'react';\nimport { usePersona } from '../hooks/usePersona';\nimport { isDevelopment } from '../internal/isDevelopment';\n\nexport interface KaafilBrandAssets {\n readonly appName?: string;\n readonly logo?: string | ReactNode;\n readonly logoMark?: string | ReactNode;\n readonly favicon?: string;\n}\n\nexport interface BrandShellProps extends KaafilBrandAssets {\n readonly headStrategy?: 'none' | 'own-page';\n readonly children?: ReactNode;\n}\n\n/** Shell-owned, not a `08-core-hooks.md` catalog entry (component authoring\n * — this context's eventual consumer, a logo/header component reading the\n * fallback chain — is out of scope for this phase). */\nconst BrandAssetsContext = createContext<KaafilBrandAssets | null>(null);\n\n/** Reads the brand assets `BrandShell` forwarded, or `{}` when mounted\n * without one (never throws — brand is presentational, not load-bearing the\n * way a session read is). */\nexport function useKaafilBrand(): KaafilBrandAssets {\n return useContext(BrandAssetsContext) ?? {};\n}\n\nexport interface ShareMeta {\n readonly title: string | undefined;\n readonly favicon: string | undefined;\n readonly ogTitle: string | undefined;\n readonly ogDescription: string | undefined;\n readonly ogImage: string | undefined;\n readonly robots: 'noindex' | 'index';\n}\n\nfunction resolveShareMeta(assets: KaafilBrandAssets): ShareMeta {\n return {\n title: assets.appName,\n favicon: assets.favicon,\n ogTitle: assets.appName,\n ogDescription: undefined,\n ogImage: undefined,\n // Share meta defaults to noindex — a share link is private-by-obscurity;\n // indexing it is a disclosure bug, never the shipped default\n // (`00-decisions.md` U-005).\n robots: 'noindex',\n };\n}\n\n/** Only the traveller/share surface may write `document.head` — mounted\n * exclusively by `BrandShell` under a persona-permitted `'own-page'`\n * request. Renders nothing into the page body: title/meta writes are not\n * \"visual output\" in the sense `shells/README.md §1` means the phrase. */\nfunction KaafilDocumentHead({ meta }: { readonly meta: ShareMeta }): null {\n useEffect(() => {\n if (meta.title !== undefined) {\n document.title = meta.title;\n }\n if (meta.favicon !== undefined) {\n let link = document.querySelector<HTMLLinkElement>('link[rel=\"icon\"][data-kf-brand]');\n if (link === null) {\n link = document.createElement('link');\n link.rel = 'icon';\n link.setAttribute('data-kf-brand', '');\n document.head.appendChild(link);\n }\n link.href = meta.favicon;\n }\n const setMeta = (\n name: string,\n content: string | undefined,\n attr: 'name' | 'property' = 'name',\n ): void => {\n if (content === undefined) {\n return;\n }\n let tag = document.querySelector<HTMLMetaElement>(`meta[${attr}=\"${name}\"][data-kf-brand]`);\n if (tag === null) {\n tag = document.createElement('meta');\n tag.setAttribute(attr, name);\n tag.setAttribute('data-kf-brand', '');\n document.head.appendChild(tag);\n }\n tag.content = content;\n };\n setMeta('og:title', meta.ogTitle, 'property');\n setMeta('og:description', meta.ogDescription, 'property');\n setMeta('og:image', meta.ogImage, 'property');\n setMeta('robots', meta.robots);\n }, [meta]);\n\n return null;\n}\n\n/**\n * Forwards brand assets unconditionally; enforces `headStrategy` before\n * ever mounting `<KaafilDocumentHead>`. `'none'` is a HARD no-op — no\n * branch below it ever touches `document.head`, even when `favicon`/\n * `appName` are supplied. `'own-page'` is runtime-rejected under\n * `agencyAdmin`/`manager` (dev throw, prod warning + silent `'none'`\n * fallback — the same shape `useCapability()` uses for a wrong-persona call,\n * `08-core-hooks.md §1.4`).\n */\nexport function BrandShell({\n appName,\n logo,\n logoMark,\n favicon,\n headStrategy = 'none',\n children,\n}: BrandShellProps): ReactNode {\n const persona = usePersona();\n const assets = useMemo(\n () => ({ appName, logo, logoMark, favicon }),\n [appName, logo, logoMark, favicon],\n );\n\n const rejectedOwnPage = headStrategy === 'own-page' && persona !== 'share';\n\n useEffect(() => {\n if (headStrategy === 'own-page' && persona !== 'share' && isDevelopment()) {\n throw new Error(\n 'BrandShell: headStrategy=\"own-page\" was requested under a non-share persona ' +\n `(\"${persona}\") — only the traveller/share surface may own document.head ` +\n '(00-decisions.md U-005). Falls back to \"none\" in production.',\n );\n }\n if (\n headStrategy === 'none' &&\n // `favicon` ONLY. `appName` is not a head-only prop: it is the last rung\n // of the in-page brand fallback chain (partner logo -> neutral mark ->\n // text-only appName, 05-theming-and-branding.md §8), so it does real\n // work under every `headStrategy` and warning about it told integrators\n // their correct code was wrong. `favicon` has no in-page use at all, so\n // passing one under `'none'` genuinely is a no-op worth flagging.\n favicon !== undefined &&\n isDevelopment()\n ) {\n // biome-ignore lint/suspicious/noConsole: dev-only, gated above by isDevelopment()\n console.warn(\n 'BrandShell: headStrategy=\"none\" (the default) is a hard no-op — \"favicon\" was passed ' +\n 'but document.head is never touched under \"none\" (00-decisions.md U-005). ' +\n '\"appName\" is unaffected: it still feeds the in-page brand fallback.',\n );\n }\n }, [headStrategy, persona, favicon]);\n\n const shouldOwnPage = headStrategy === 'own-page' && persona === 'share' && !rejectedOwnPage;\n\n return (\n <BrandAssetsContext.Provider value={assets}>\n {shouldOwnPage ? <KaafilDocumentHead meta={resolveShareMeta(assets)} /> : null}\n {children}\n </BrandAssetsContext.Provider>\n );\n}\n\n/**\n * Shell-owned read-only alternative to `<KaafilDocumentHead>` — for a host\n * (e.g. Next.js App Router) that already owns `<head>` via its own\n * `metadata`/`generateMetadata` export and must keep `headStrategy=\"none\"`\n * here. Never writes the head itself; exactly one of the two paths is\n * active per mount (`shells/06-brand-shell.md`).\n */\nexport function useKaafilShareMeta(assets: KaafilBrandAssets): ShareMeta {\n return useMemo(() => resolveShareMeta(assets), [assets]);\n}\n"]}
@@ -174,12 +174,16 @@ function isDevelopment() {
174
174
  }
175
175
 
176
176
  // src/core/internal/useCapabilityRows.ts
177
+ var CAPABILITY_CACHE_PREFIX = "journey.capabilities:";
177
178
  function useCapabilityRows(tripRef) {
178
179
  const client = useContext(KaafilClientContext);
179
180
  const persona = usePersona();
180
181
  const engine = useContext(OfflineEngineContext);
181
- const [rows, setRows] = useState([]);
182
- const [loaded, setLoaded] = useState(false);
182
+ const cachedRows = engine?.reads.get(
183
+ `${CAPABILITY_CACHE_PREFIX}${tripRef}`
184
+ )?.value;
185
+ const [rows, setRows] = useState(() => cachedRows ?? []);
186
+ const [loaded, setLoaded] = useState(cachedRows !== void 0);
183
187
  useEffect(() => {
184
188
  if (persona === "share") {
185
189
  if (isDevelopment()) {
@@ -195,17 +199,27 @@ function useCapabilityRows(tripRef) {
195
199
  return;
196
200
  }
197
201
  const openClient = client;
202
+ const cacheKey = `${CAPABILITY_CACHE_PREFIX}${tripRef}`;
203
+ const openEngine = engine;
204
+ const copy = openEngine?.reads.get(cacheKey);
205
+ if (copy !== void 0) {
206
+ setRows(copy.value);
207
+ setLoaded(true);
208
+ }
198
209
  let cancelled = false;
199
210
  async function load() {
200
211
  try {
201
212
  const response = await openClient.journey.capabilities({ tripRef });
213
+ void openEngine?.reads.set(cacheKey, [...response], response.meta.serverTime).catch(() => {
214
+ });
202
215
  if (!cancelled) {
203
216
  setRows(response);
204
217
  setLoaded(true);
205
218
  }
206
219
  } catch {
220
+ const cached = openEngine?.reads.get(cacheKey);
207
221
  if (!cancelled) {
208
- setRows([]);
222
+ setRows(cached?.value ?? []);
209
223
  setLoaded(true);
210
224
  }
211
225
  }
@@ -6031,5 +6045,5 @@ function tokenStyle(overrides, own) {
6031
6045
  }
6032
6046
 
6033
6047
  export { ConfigContext, I18nShell, KaafilClientContext, OfflineEngineContext, SessionContext, UNKNOWN_CAPABILITY_TRIPLE, createRegistry, darkReasonFor, deriveCapabilityTriple, isDevelopment, tokenStyle, useCapabilities, useCapability, useCapabilityRows, useKaafilChrome, useKaafilClient, useOfflineEvent, useOfflineMutation, useOutboxStatus, usePersona, useRequiredContext, useSession };
6034
- //# sourceMappingURL=chunk-2SRBJ4H7.js.map
6035
- //# sourceMappingURL=chunk-2SRBJ4H7.js.map
6048
+ //# sourceMappingURL=chunk-A4Z2YBEF.js.map
6049
+ //# sourceMappingURL=chunk-A4Z2YBEF.js.map