feat: add MessagingProvider and useAdapter

This commit is contained in:
2026-07-18 00:57:39 +05:30
parent 54f426e4f0
commit 256a5dcea0
2 changed files with 47 additions and 0 deletions
@@ -0,0 +1,25 @@
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { MessagingProvider, useAdapter } from './provider';
import { MockAdapter } from './adapters/mock';
function ShowActor() {
const adapter = useAdapter();
return <span>{adapter.currentActorId()}</span>;
}
describe('MessagingProvider', () => {
it('supplies the injected adapter to descendants', () => {
render(
<MessagingProvider adapter={new MockAdapter()}>
<ShowActor />
</MessagingProvider>,
);
expect(screen.getByText('me')).toBeDefined();
});
it('throws a helpful error when a hook is used outside the provider', () => {
// React logs the error boundary trace; that noise is expected.
expect(() => render(<ShowActor />)).toThrow(/useAdapter must be used within a <MessagingProvider>/);
});
});
@@ -0,0 +1,22 @@
import { createContext, useContext, type ReactNode } from 'react';
import type { MessagingAdapter } from './adapter';
const AdapterContext = createContext<MessagingAdapter | null>(null);
export function MessagingProvider({
adapter,
children,
}: {
adapter: MessagingAdapter;
children: ReactNode;
}) {
return <AdapterContext.Provider value={adapter}>{children}</AdapterContext.Provider>;
}
/** Access the host-injected adapter. Throws outside a provider — a missing provider is
* a wiring bug, and failing loudly beats a confusing null-deref three layers down. */
export function useAdapter(): MessagingAdapter {
const adapter = useContext(AdapterContext);
if (!adapter) throw new Error('useAdapter must be used within a <MessagingProvider>');
return adapter;
}