{"version":3,"sources":["../../../src/react-provider/index.ts","../../../src/react/context.tsx","../../../src/react/sharedContext.ts","../../../src/react/lazyPorts.tsx"],"sourcesContent":["\"use client\";\n\n// @ai-matrx/associations/react/provider — the binding a host mounts at the top of its tree, and\n// nothing else.\n//\n// `/react` is the whole faces bundle: importing `AssociationsProvider` from it ships every card,\n// picker and hook, and through them the entity-type metadata table, on every route the provider\n// sits above. A host mounts the provider at load, so it imports it from HERE: the context, the\n// three binding hooks and the two lazy port wrappers. These are the same objects `/react`\n// exports (one shared context, `sharedContext.ts`), so a face from `/react` or `/react/lazy` finds\n// this provider. Budget: `entryBudgets[\"./react/provider\"]` forbids the metadata module up front.\n\nexport {\n  AssociationsProvider,\n  useAssociationsStore,\n  useAssociationsUiPorts,\n  useNotifier,\n  type AssociationsProviderProps,\n  type AssociationsUiPorts,\n} from \"../react/context\";\nexport { lazyPickerOverride, lazyWindowShell, type WindowShellComponentProps } from \"../react/lazyPorts\";\n","// react/context.tsx — @ai-matrx/associations/react\n//\n// The ONE React binding point (design Decision 2): a host constructs the\n// /core store once (`createAssociationsStore(cfg)`) in its binding module and\n// mounts `<AssociationsProvider store={store} …>` at the top of the tree. The\n// UI ports (notifier / windowShell / capture / pickerOverrides / entityDoors\n// / authorDisplay) are /react concerns and bind HERE — the headless store\n// never sees them.\n//\n// Required-port failures stay loud: every hook/face reaches the store through\n// `useAssociationsStore()`, which THROWS with a precise message when no\n// provider is mounted — never a silently-empty surface.\n//\n// MOUNTING IS INERT (0.9.0). This provider issues NO network call of its own.\n// The demanded-schema boot probe it carried from 0.6.0 asked whether each of\n// the 26 demanded RPCs existed by CALLING it with sentinel arguments —\n// fourteen of them WRITES — so every consumer fired ~25 POSTs that answered\n// 400 on every page load. Worse, its `process.env.NODE_ENV === \"development\"`\n// gate is BAKED TO TRUE by our own build (esbuild substitutes that expression\n// under `platform: \"browser\"`), so \"dev-only\" ran in production too. The probe\n// is deleted; PGRST202 at any real call site still screams\n// `demanded_schema_violation` with a remedy.\n//\n// 🚨 NEVER gate runtime behavior in this package on `process.env.NODE_ENV`.\n// The build inlines it. `src/__tests__/no-node-env-gating.test.ts` holds it.\n//\n// Notifier degradation (design Decision 2 table): when the host binds no\n// notifier, /react warns ONCE through the store's errorSink and every\n// user-facing failure still reaches the errorSink — the create-then-associate\n// loud-outcome law is satisfied structurally, not by toast availability.\n\nimport { useContext, useRef, type ComponentType, type ReactNode } from \"react\";\n\nimport { sharedContext } from \"./sharedContext\";\n\nimport type {\n  AssociationsNotifier,\n  AuthorDisplayPort,\n  CapturePort,\n  EntityDoorsPort,\n  PickerOverrideMap,\n  WindowShellPort,\n} from \"../ports\";\nimport type { AssociationsStore } from \"../core/store\";\n\nexport interface AssociationsUiPorts {\n  notifier?: AssociationsNotifier;\n  windowShell?: WindowShellPort;\n  capture?: CapturePort;\n  pickerOverrides?: PickerOverrideMap;\n  entityDoors?: EntityDoorsPort;\n  authorDisplay?: AuthorDisplayPort;\n  /**\n   * The host's compact markdown renderer for a comment body (an edit thread's\n   * quoted \"Was:/Now:\" blocks). Absent → the package's built-in renderer.\n   */\n  commentBody?: ComponentType<{ body: string; className?: string | undefined }>;\n  /**\n   * Sign in again (a signed-out tab). Shown as the action beside a signed-out\n   * failure; absent → the sentence alone, with Retry. The host opens its login\n   * in a NEW tab so the words typed here stay for Retry.\n   */\n  signIn?: () => void;\n}\n\ninterface AssociationsReactBinding extends AssociationsUiPorts {\n  store: AssociationsStore;\n  /** ONE warn-once latch per provider instance (never module state). */\n  notifierWarned: { current: boolean };\n}\n\n// Shared across copies of this package (`sharedContext.ts`): two installed copies must not mean two contexts.\nconst AssociationsReactContext = sharedContext<AssociationsReactBinding | null>(\n  \"AssociationsReactContext\",\n  null,\n);\n\nexport interface AssociationsProviderProps extends AssociationsUiPorts {\n  /** The /core store the host constructed with `createAssociationsStore`. */\n  store: AssociationsStore;\n  children: ReactNode;\n}\n\nexport function AssociationsProvider({\n  store,\n  notifier,\n  windowShell,\n  capture,\n  pickerOverrides,\n  entityDoors,\n  authorDisplay,\n  commentBody,\n  signIn,\n  children,\n}: AssociationsProviderProps) {\n  const notifierWarned = useRef(false);\n\n  return (\n    <AssociationsReactContext.Provider\n      value={{\n        store,\n        notifierWarned,\n        ...(notifier !== undefined ? { notifier } : {}),\n        ...(windowShell !== undefined ? { windowShell } : {}),\n        ...(capture !== undefined ? { capture } : {}),\n        ...(pickerOverrides !== undefined ? { pickerOverrides } : {}),\n        ...(entityDoors !== undefined ? { entityDoors } : {}),\n        ...(authorDisplay !== undefined ? { authorDisplay } : {}),\n        ...(commentBody !== undefined ? { commentBody } : {}),\n        ...(signIn !== undefined ? { signIn } : {}),\n      }}\n    >\n      {children}\n    </AssociationsReactContext.Provider>\n  );\n}\n\nfunction requireBinding(): AssociationsReactBinding {\n  const binding = useContext(AssociationsReactContext);\n  if (!binding) {\n    throw new Error(\n      \"@ai-matrx/associations/react: no <AssociationsProvider> above this \" +\n        \"component. Construct the store once with createAssociationsStore(cfg) \" +\n        \"in your host binding and mount <AssociationsProvider store={store}> \" +\n        \"at the top of the tree.\",\n    );\n  }\n  return binding;\n}\n\n/** The /core store bound by the nearest provider. Throws when unmounted. */\nexport function useAssociationsStore(): AssociationsStore {\n  return requireBinding().store;\n}\n\n/** The UI ports the host bound (each optional, each degradable). */\nexport function useAssociationsUiPorts(): AssociationsUiPorts {\n  const { store: _store, notifierWarned: _warned, ...ports } = requireBinding();\n  return ports;\n}\n\n/**\n * The notifier, degraded per contract: absent → warn once via errorSink,\n * then route every user-facing failure to the errorSink so no outcome is\n * silent. Success messages without a notifier are dropped (the surface's own\n * state change is the confirmation); failures always scream.\n */\nexport function useNotifier(): AssociationsNotifier {\n  const binding = requireBinding();\n  if (binding.notifier) return binding.notifier;\n  const { store, notifierWarned } = binding;\n  const warnOnce = () => {\n    if (notifierWarned.current) return;\n    notifierWarned.current = true;\n    store.errorSink({\n      code: \"notifier_missing\",\n      message:\n        \"@ai-matrx/associations/react: no notifier port bound — user-facing \" +\n        \"failures are routed to the errorSink only. Bind `notifier` on \" +\n        \"AssociationsProvider for toasts.\",\n    });\n  };\n  return {\n    success() {\n      warnOnce();\n    },\n    error(msg, opts) {\n      warnOnce();\n      store.errorSink({\n        code: \"user_facing_error\",\n        message: msg,\n        ...(opts?.description !== undefined\n          ? { context: { description: opts.description } }\n          : {}),\n      });\n    },\n  };\n}\n","// react/sharedContext.ts — a React context that survives TWO COPIES of this package.\n//\n// This package republishes a patch version many times a day, and a host's `node_modules` can briefly hold two\n// (the app's own copy, and the one a sibling package such as @ai-matrx/chat resolved after a partial install).\n// A plain module-level `createContext` then makes TWO contexts: the host mounts <AssociationsProvider> through\n// copy A while a chat tile reads through copy B, and B throws \"no <AssociationsProvider> above this component\"\n// — a defect no code in either place can see. Registering the context on `globalThis` under a `Symbol.for` key\n// makes every copy read and write the SAME one (the pattern @ai-matrx/records uses for its registries).\n// Precondition: the copies agree on the value's shape (a minor bump that changes it must change the key).\n\nimport { createContext, type Context } from \"react\";\n\nexport function sharedContext<T>(name: string, initial: T): Context<T> {\n  const key = Symbol.for(`@ai-matrx/associations/react/${name}`);\n  const registry = globalThis as unknown as Record<symbol, Context<T> | undefined>;\n  return (registry[key] ??= createContext<T>(initial));\n}\n","// react/lazyPorts.tsx — @ai-matrx/associations/react\n//\n// THE package-owned bundle-split seam (0.6.0, C23 § framework differences).\n//\n// Before this module every host hand-wrote the same `next/dynamic({ssr:false})`\n// glue to keep a heavy port binding (a window manager, a canonical file\n// browser) out of its boot bundle — mechanical seam code, rebuilt per app,\n// each one a chance to get `ssr`, the `loading` fallback or the `.then(m =>\n// m.X)` unwrap wrong. The split is a PACKAGE concern; these two helpers own\n// it once, for every framework we ship on.\n//\n// They are deliberately framework-AGNOSTIC — `React.lazy` + `Suspense`, no\n// `next/dynamic`, no `next` peer dependency. `ssr: false` is not needed and\n// never was: both ports are only ever RENDERED after a user gesture opens a\n// window, so the loader fires client-side and the module never enters a\n// server render. Next.js, Vite, the Tauri shell and Jest all handle it the\n// same way, and the consumer's own bundler creates the real chunk.\n//\n// Usage in a host binding (the whole of it):\n//\n//   windowShell: {\n//     Window: lazyWindowShell(() =>\n//       import(\"./hostWindows\").then((m) => m.AssociationsWindowShellImpl)),\n//   },\n//   pickerOverrides: {\n//     file: lazyPickerOverride(() =>\n//       import(\"./hostPickers\").then((m) => m.FileAssociationPickerImpl)),\n//   },\n\nimport { Suspense, lazy, type ComponentType, type ReactNode } from \"react\";\n\nimport type { AssociationPickerProps, WindowShellPort } from \"../ports\";\n\n/** What a `windowShell.Window` component receives. */\nexport interface WindowShellComponentProps {\n  id: string;\n  title: string;\n  onClose(): void;\n  children: ReactNode;\n}\n\n/**\n * Wrap `React.lazy` so the loader may resolve EITHER a bare component or a\n * `{ default }` module — hosts reach for `.then(m => m.Named)` reflexively\n * and both spellings must work, not one of them silently.\n */\nfunction lazyComponent<P>(\n  load: () => Promise<ComponentType<P> | { default: ComponentType<P> }>,\n): ComponentType<P> {\n  return lazy(async () => {\n    const loaded = await load();\n    return typeof loaded === \"function\" ? { default: loaded } : loaded;\n  });\n}\n\n/**\n * Split a host window component off the boot bundle. The returned component\n * satisfies `WindowShellPort[\"Window\"]` exactly; the chunk fetches the first\n * time an association window opens.\n */\nexport function lazyWindowShell(\n  load: () => Promise<\n    | ComponentType<WindowShellComponentProps>\n    | { default: ComponentType<WindowShellComponentProps> }\n  >,\n): WindowShellPort[\"Window\"] {\n  const Loaded = lazyComponent<WindowShellComponentProps>(load);\n  return function LazyWindowShell(props: WindowShellComponentProps) {\n    // `null` while the chunk arrives: a window opens on a click and the\n    // chunk lands in a frame or two — a skeleton window would flash worse\n    // than nothing. Failure is NOT silent: a rejected chunk throws into the\n    // host's error boundary rather than leaving a dead surface.\n    return (\n      <Suspense fallback={null}>\n        <Loaded {...props} />\n      </Suspense>\n    );\n  };\n}\n\n/**\n * Split a host per-token picker override off the boot bundle. The returned\n * component satisfies the `pickerOverrides` map's value type exactly.\n */\nexport function lazyPickerOverride(\n  load: () => Promise<\n    | ComponentType<AssociationPickerProps>\n    | { default: ComponentType<AssociationPickerProps> }\n  >,\n): ComponentType<AssociationPickerProps> {\n  const Loaded = lazyComponent<AssociationPickerProps>(load);\n  return function LazyPickerOverride(props: AssociationPickerProps) {\n    // Gated on `open` as well as Suspense: an override registered for a\n    // token must not fetch its chunk until that picker is actually opened.\n    if (!props.open) return null;\n    return (\n      <Suspense fallback={null}>\n        <Loaded {...props} />\n      </Suspense>\n    );\n  };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime"]}