@lunora/react 1.0.0-alpha.71 → 1.0.0-alpha.73

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/README.md CHANGED
@@ -94,24 +94,31 @@ function MessageList({ room }: { room: string }) {
94
94
 
95
95
  ## Hooks
96
96
 
97
- | Hook | Returns | Notes |
98
- | ---------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------------ |
99
- | `useQuery(fn, args, options?)` | `T \| undefined` | Live query; shares one WS subscription across consumers of the same key. |
100
- | `useMutation(fn)` | `{ mutate, pending, data, error, reset, withOptimisticUpdate }` | Per-call `optimistic` / `optimisticUpdate` options pass through to the client. |
101
- | `useSubscription(fn, args, options?)` | `{ data, error }` | No initial fetch — only server-pushed values. |
102
- | `usePaginatedQuery(fn, args, { initialNumItems })` | `{ results, status, isLoading, loadMore }` | Cursor-paginated feed that stays consistent under live edits. |
103
- | `useInfiniteQuery(fn, args, { initialNumItems })` | `{ pages, status, hasNextPage, fetchNextPage, … }` | Page-array variant of the same paginator. |
104
- | `usePreloadedQuery(preloaded)` | `T` | Reads a server `Preloaded` token, then goes live. |
105
- | `usePresence({ heartbeat, listPresent, roomId, … })` | present members | Drives the `definePresence` heartbeat + list functions. |
106
- | `useFlag(key, default, context?)` | flag value (live) | Live OpenFeature flag over the WS; reads `default` until the server answers. |
107
- | `useFlags(defaults, context?)` | `{ [key]: value }` | Batch variant — one live value per key in the `defaults` map. |
108
- | `useStream(fn, args, options?)` | `{ chunks, status, error, cancel }` | Consumes a streamed action response chunk by chunk. |
109
- | `useRateLimit(config, options?)` | `{ ok, disabled, retryAfter, check, consume, reset }` | Client-side mirror of a `@lunora/ratelimit` budget for instant UX. |
110
- | `useConnectionStatus()` | `ConnectionStatus` | `idle` / `connecting` / `connected` / `offline`. |
111
- | `useAuth()` | `{ user, token, setToken }` | Call `setToken(jwt)` after sign-in; RPC then carries the token. |
112
- | `useAuthState()` | `{ isAuthenticated, isLoading }` | Hydration-safe three-state gate. |
113
-
114
- `Authenticated`, `Unauthenticated`, and `AuthLoading` are gate components built on `useAuthState`. `CheckoutButton`, `CustomerPortalButton`, and `useCheckout` wrap `@lunora/payment` flows.
97
+ | Hook | Returns | Notes |
98
+ | -------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
99
+ | `useQuery(fn, args, options?)` | `T \| undefined` | Live query; shares one WS subscription across consumers of the same key. |
100
+ | `useMutation(fn)` | `{ mutate, pending, data, error, reset, withOptimisticUpdate }` | Per-call `optimistic` / `optimisticUpdate` options pass through to the client. |
101
+ | `useSubscription(fn, args, options?)` | `{ data, error }` | No initial fetch — only server-pushed values. |
102
+ | `usePaginatedQuery(fn, args, { initialNumItems })` | `{ results, status, isLoading, loadMore }` | Cursor-paginated feed that stays consistent under live edits. |
103
+ | `useInfiniteQuery(fn, args, { initialNumItems })` | `{ pages, status, hasNextPage, fetchNextPage, … }` | Page-array variant of the same paginator. |
104
+ | `usePreloadedQuery(preloaded)` | `T` | Reads a server `Preloaded` token, then goes live. |
105
+ | `usePresence({ heartbeat, listPresent, roomId, … })` | present members | Drives the `definePresence` heartbeat + list functions. |
106
+ | `useFlag(key, default)` | flag value (live) | Live OpenFeature flag over the WS; reads `default` until the server answers. Evaluated under the socket's server-verified identity. |
107
+ | `useFlags(defaults)` | `{ [key]: value }` | Batch variant — one live value per key in the `defaults` map. |
108
+ | `useStream(fn, args, options?)` | `{ chunks, status, error, cancel }` | Consumes a streamed action response chunk by chunk. |
109
+ | `useRateLimit(config, options?)` | `{ ok, disabled, retryAfter, check, consume, reset }` | Client-side mirror of a `@lunora/ratelimit` budget for instant UX. |
110
+ | `useConnectionStatus()` | `ConnectionStatus` | `idle` / `connecting` / `connected` / `offline`. |
111
+ | `useAuth()` | `{ user, token, setToken }` | Call `setToken(jwt)` after sign-in; RPC then carries the token. |
112
+ | `useAuthState()` | `{ isAuthenticated, isLoading }` | Hydration-safe three-state gate. |
113
+ | `useAgentToolEvents({ api, threadKey, … })` | `{ events }` | One agent thread's tool lifecycle: call / result / awaiting-approval / progress. |
114
+ | `useVoiceAgent({ voice, threadKey, … })` | `{ status, transcript, startCall, endCall, … }` | Full-duplex voice call: mic capture, playback, live transcripts, barge-in. |
115
+ | `useAuthUsers` / `useAuthSessions` / `useOrganizations` / `useImpersonate` | `{ data, error, loading, hasMore, total, loadMore, refetch }` (`useImpersonate`: `{ data, error, pending, impersonate, reset }`) | Admin-plane auth reads for a console UI; each needs an admin-capable token. HTTP-only, so `refetch()` rather than a live subscription. |
116
+
117
+ `Authenticated`, `Unauthenticated`, and `AuthLoading` are gate components built on `useAuthState`.
118
+
119
+ The payment kit — `CheckoutButton`, `CustomerPortalButton`, and `useCheckout`, which wrap `@lunora/payment` flows — ships from the `@lunora/react/payment` subpath, not the package root: it renders a DOM `<button>` and navigates via `globalThis.location`, so it is the one part of this package that is browser-only (the root barrel stays renderer-agnostic, which is what lets `@lunora/react-native` re-export it wholesale).
120
+
121
+ `useVoiceAgent` opens nothing until you call `startCall()` — that is what requests the microphone, so it has to run from a user gesture; `endCall()` releases the socket, the mic tracks and the Web Audio graph, and also runs on unmount. See the [voice-agent docs](https://lunora.sh/docs/packages/react#voice-agents--usevoiceagentoptions) for the silence/barge-in thresholds.
115
122
 
116
123
  ## Server Components
117
124
 
package/dist/index.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode, ReactElement } from 'react';
2
- import { LunoraClient, OptimisticUpdate, User, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, AuthImpersonation, AuthSession, AuthUser, ClientQueryRef, ConnectionStatus, HttpStreamRef, HttpStreamArgsOf, HttpStreamChunkOf, MutatorHandle, Preloaded } from '@lunora/client';
3
- export { type ArgsOf, type ClientQueryRef, type FunctionReference, type HttpStreamArgsOf, type HttpStreamChunkOf, type HttpStreamRef, type LunoraClient, type LunoraErrorCode, type MutatorHandle, type MutatorTransaction, type OptimisticLocalStore, type OptimisticUpdate, type Preloaded, type ReturnOf, type User, createClientQuery, getErrorCode, getRetryAfterMs, isConflictError, isForbiddenError, isRateLimitedError, isUnauthorizedError } from '@lunora/client';
2
+ import { LunoraClient, OptimisticUpdate, User, SubscriptionErrorCallback, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, AuthImpersonation, AuthSession, AuthUser, ClientQueryRef, ConnectionStatus, HttpStreamRef, HttpStreamArgsOf, HttpStreamChunkOf, MutatorHandle, Preloaded } from '@lunora/client';
3
+ export { type ArgsOf, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type ClientQueryRef, type FunctionReference, type HttpStreamArgsOf, type HttpStreamChunkOf, type HttpStreamRef, type LunoraClient, type LunoraErrorCode, type MutatorHandle, type MutatorTransaction, type OptimisticLocalStore, type OptimisticUpdate, type Preloaded, type ReturnOf, type SubscriptionError, type SubscriptionErrorCallback, type User, createClientQuery, getErrorCode, getRetryAfterMs, isConflictError, isForbiddenError, isRateLimitedError, isUnauthorizedError } from '@lunora/client';
4
4
  import { QueryClient } from '@tanstack/react-query';
5
5
  export { type L as LunoraQueryOptions, l as lunoraQueryOptions } from "./packem_shared/query-options.d-CdgGQ9s4.mjs";
6
6
  import { PaginationStatus } from '@lunora/client/pagination';
@@ -63,89 +63,13 @@ declare const LunoraProvider: ({ children, client, queryClient }: LunoraProvider
63
63
  * colocated with the provider for back-compat.
64
64
  */
65
65
  declare const useLunora: () => LunoraClient;
66
- /**
67
- * Client-safe mirror of `@lunora/payment`'s `Subscription`. Re-declared here
68
- * (rather than imported) so this React entry never pulls in the server-only
69
- * `@lunora/payment` module graph — the kit stays React + DOM only. Keep this in
70
- * sync with `packages/payment/src/types.ts`.
71
- */
72
- interface Subscription {
73
- readonly cancelAtPeriodEnd: boolean;
74
- readonly createdAt: number;
75
- readonly currentPeriodEnd?: number;
76
- readonly id: string;
77
- readonly priceId: string;
78
- readonly provider: "polar" | "stripe";
79
- readonly quantity: number;
80
- readonly referenceId: string;
81
- readonly state: "active" | "canceled" | "past_due" | "paused" | "trialing";
82
- readonly updatedAt: number;
83
- }
84
- /** The `{ url }` shape every checkout/portal trigger resolves to. */
85
- interface RedirectTarget {
86
- readonly url: string;
87
- }
88
- /** A thunk the app supplies that calls its own Lunora action and resolves a redirect URL. */
89
- type RedirectTrigger = () => Promise<RedirectTarget>;
90
- interface UseCheckoutResult {
91
- /** Run the trigger and redirect the browser to the resolved URL. Resolves once the redirect is issued; rejects on failure. */
92
- checkout: () => Promise<void>;
93
- /** The most recent failure, or `undefined`. */
94
- error: Error | undefined;
95
- /** `true` while the trigger is in flight (before the redirect is issued). */
96
- pending: boolean;
97
- }
98
- /**
99
- * Decoupled redirect-on-resolve primitive shared by `CheckoutButton` and
100
- * `CustomerPortalButton`. The app passes a `trigger` thunk that calls its own
101
- * Lunora action (the one wrapping `LunoraPayment.createCheckout` /
102
- * `createPortalSession`) and resolves `{ url }`; this hook awaits it, flips
103
- * `pending`, surfaces any `error`, and on success navigates via
104
- * `location.assign(url)`.
105
- *
106
- * Mirrors Convex's `CheckoutLink` / `CustomerPortalLink` flow (trigger an action
107
- * that returns a URL, then redirect) while staying agnostic of the app's
108
- * function names.
109
- */
110
- declare const useCheckout: (trigger: RedirectTrigger) => UseCheckoutResult;
111
- /**
112
- * Presentational props shared by the redirect buttons. Kept to a curated set
113
- * (rather than spreading arbitrary button attributes) so the component stays
114
- * within the repo's `react/jsx-props-no-spreading` rule while covering the
115
- * common styling / accessibility hooks.
116
- */
117
- interface RedirectButtonOwnProps {
118
- /** Accessible label when the visible `children` are icon-only. */
119
- "aria-label"?: string;
120
- children?: ReactNode;
121
- className?: string;
122
- /** Force-disable the control regardless of pending state. */
123
- disabled?: boolean;
124
- /** Called with the failure when the trigger rejects. The error is also surfaced via `useCheckout`. */
125
- onError?: (error: Error) => void;
126
- title?: string;
127
- }
128
- interface CheckoutButtonProps extends RedirectButtonOwnProps {
129
- /** Calls the app's checkout action and resolves the hosted-checkout `{ url }`. */
130
- onCheckout: RedirectTrigger;
131
- }
132
- interface CustomerPortalButtonProps extends RedirectButtonOwnProps {
133
- /** Calls the app's portal action and resolves the customer-portal `{ url }`. */
134
- onPortal: RedirectTrigger;
135
- }
136
- /**
137
- * Button that starts a hosted checkout. On click it awaits `onCheckout` (a thunk
138
- * that calls the app's checkout action) and redirects to the returned URL,
139
- * disabling itself while the request is in flight.
140
- */
141
- declare const CheckoutButton: ({ onCheckout, ...rest }: CheckoutButtonProps) => ReactNode;
142
- /**
143
- * Button that opens the provider's customer portal. On click it awaits
144
- * `onPortal` (a thunk that calls the app's portal action) and redirects to the
145
- * returned URL, disabling itself while the request is in flight.
146
- */
147
- declare const CustomerPortalButton: ({ onPortal, ...rest }: CustomerPortalButtonProps) => ReactNode;
148
66
  interface UseQueryOptions {
67
+ /**
68
+ * Called when the server pushes a subscription-scoped error (an RLS denial, a
69
+ * query that starts failing server-side). Without a handler such an error has
70
+ * nowhere to go and the hook's value simply freezes at its last good result.
71
+ */
72
+ onError?: SubscriptionErrorCallback;
149
73
  shardKey?: string;
150
74
  }
151
75
  interface UseMutationCallOptions<TCurrent = unknown, TValue = unknown, TArgs = unknown> {
@@ -825,8 +749,6 @@ declare const useClientQuery: <T extends unknown>(ref: ClientQueryRef<T>) => [T,
825
749
  * operator can tell a healthy live channel from a silently-dropped socket.
826
750
  */
827
751
  declare const useConnectionStatus: () => ConnectionStatus;
828
- /** A targeting context merged on top of the app's default (`defineFlags({ identify })`). */
829
- type FlagContext = Record<string, unknown>;
830
752
  /** The value kinds a flag resolves to — OpenFeature's boolean / number / string / structured (JSON) flags. */
831
753
  type FlagValue = boolean | number | string | {
832
754
  [key: string]: unknown;
@@ -838,25 +760,30 @@ type FlagValue = boolean | number | string | {
838
760
  * resolved value — re-pushed whenever the provider re-evaluates (e.g. a flag is
839
761
  * toggled in Cloudflare Flagship). The flag's kind is inferred from
840
762
  * `defaultValue`'s runtime type, so `useFlag("dark", false)` reads a boolean and
841
- * `useFlag("hero", "control")` a string. `context` supplies a per-call targeting
842
- * context merged on top of the app's default `identify` targeting key.
763
+ * `useFlag("hero", "control")` a string.
764
+ *
765
+ * The reactive channel is public, so the server evaluates every flag under the
766
+ * socket's own verified identity — the targeting key your `defineFlags({
767
+ * identify })` derives — and accepts no client-supplied targeting context. For
768
+ * evaluation under a context you compute, call `ctx.flags.*` inside a query,
769
+ * mutation, or action and return the resolved value.
843
770
  *
844
771
  * Evaluation runs through whatever OpenFeature provider the app wired in
845
772
  * `lunora/flags.ts`; the read never throws — a provider error resolves the
846
773
  * default (the same fail-open contract as server-side `ctx.flags`).
847
774
  */
848
- declare const useFlag: <T extends FlagValue>(key: string, defaultValue: T, context?: FlagContext) => T;
775
+ declare const useFlag: <T extends FlagValue>(key: string, defaultValue: T) => T;
849
776
  /**
850
777
  * Subscribe to several feature flags at once, live over Lunora's WebSocket.
851
778
  *
852
779
  * Pass a record of `key → defaultValue`; each flag's kind is inferred from its
853
780
  * default, and the result is the same-shaped record with resolved values (the
854
- * defaults until each evaluation lands). A single `context` applies to every
855
- * flag. This is the batched form of {@link useFlag} — one effect manages one
856
- * subscription per key, so it stays rules-of-hooks-safe even as the flag set
857
- * changes between renders.
781
+ * defaults until each evaluation lands). This is the batched form of
782
+ * {@link useFlag} — one effect manages one subscription per key, so it stays
783
+ * rules-of-hooks-safe even as the flag set changes between renders. Like
784
+ * {@link useFlag} it evaluates under the socket's server-verified identity only.
858
785
  */
859
- declare const useFlags: <T extends Record<string, FlagValue>>(flags: T, context?: FlagContext) => T;
786
+ declare const useFlags: <T extends Record<string, FlagValue>>(flags: T) => T;
860
787
  /** The lifecycle of a stream the hook is observing. */
861
788
  type UseStreamStatus = "complete" | "error" | "idle" | "streaming";
862
789
  /**
@@ -1121,6 +1048,10 @@ declare const usePresence: <H extends HeartbeatReference, L extends ListPresentR
1121
1048
  * so an args object built in a different key order still dedupes). The
1122
1049
  * subscription registry shares a single WS subscription across every consumer
1123
1050
  * of the same queryKey; pushes call `queryClient.setQueryData(...)`.
1051
+ *
1052
+ * Pass `onError` to surface a subscription-scoped error the server pushes (an RLS
1053
+ * denial, a query that starts failing server-side). Without it such an error is
1054
+ * dropped and the returned value just freezes at its last good result.
1124
1055
  */
1125
1056
  declare const useQuery: <F extends FunctionReference>(function_: F, args: ArgsOf<F> | "skip", options?: UseQueryOptions) => ReturnOf<F> | undefined;
1126
1057
  interface UseRateLimitOptions {
@@ -1334,4 +1265,4 @@ interface UseVoiceAgentResult {
1334
1265
  * `createSocket`) so the hook is drivable outside a browser.
1335
1266
  */
1336
1267
  declare const useVoiceAgent: (options: UseVoiceAgentOptions) => UseVoiceAgentResult;
1337
- export { type ActionHook, type AdminAuthListResult, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, type AuthState, Authenticated, CheckoutButton, type CheckoutButtonProps, CustomerPortalButton, type CustomerPortalButtonProps, type FlagContext, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraProvider, type LunoraProviderProps, type MutationHook, type MutatorHook, type PageItemOf, type PaginatedArgs, type RedirectTarget, type RedirectTrigger, type Subscription, Unauthenticated, type UseAgentApi, type UseAgentChatApi, type UseAgentChatOptions, type UseAgentChatResult, type UseAgentOptions, type UseAgentResult, type UseAgentStateApi, type UseAgentStateOptions, type UseAgentStateResult, type UseAgentToolEventsApi, type UseAgentToolEventsOptions, type UseAgentToolEventsResult, type UseAuthResult, type UseAuthSessionsOptions, type UseAuthUsersOptions, type UseCheckoutResult, type UseHttpStreamOptions, type UseHttpStreamResult, type UseImpersonateResult, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMutationCallOptions, type UseOrganizationsOptions, type UsePaginatedQueryOptions, type UsePaginatedQueryResult, type UsePresenceOptions, type UsePresenceResult, type UseQueryOptions, type UseRateLimitOptions, type UseRateLimitResult, type UseStreamOptions, type UseStreamResult, type UseStreamStatus, type UseSubscriptionResult, type UseVoiceAgentOptions, type UseVoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, hydratePreloaded, useAction, useAgent, useAgentChat, useAgentState, useAgentToolEvents, useAuth, useAuthSessions, useAuthState, useAuthUsers, useCheckout, useClientQuery, useConnectionStatus, useFlag, useFlags, useHttpStream, useImpersonate, useInfiniteQuery, useLunora, useMutation, useMutator, useOrganizations, usePaginatedQuery, usePreloadedQuery, usePresence, useQuery, useRateLimit, useStream, useSubscription, useVoiceAgent };
1268
+ export { type ActionHook, type AdminAuthListResult, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, type AuthState, Authenticated, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraProvider, type LunoraProviderProps, type MutationHook, type MutatorHook, type PageItemOf, type PaginatedArgs, Unauthenticated, type UseAgentApi, type UseAgentChatApi, type UseAgentChatOptions, type UseAgentChatResult, type UseAgentOptions, type UseAgentResult, type UseAgentStateApi, type UseAgentStateOptions, type UseAgentStateResult, type UseAgentToolEventsApi, type UseAgentToolEventsOptions, type UseAgentToolEventsResult, type UseAuthResult, type UseAuthSessionsOptions, type UseAuthUsersOptions, type UseHttpStreamOptions, type UseHttpStreamResult, type UseImpersonateResult, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMutationCallOptions, type UseOrganizationsOptions, type UsePaginatedQueryOptions, type UsePaginatedQueryResult, type UsePresenceOptions, type UsePresenceResult, type UseQueryOptions, type UseRateLimitOptions, type UseRateLimitResult, type UseStreamOptions, type UseStreamResult, type UseStreamStatus, type UseSubscriptionResult, type UseVoiceAgentOptions, type UseVoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, hydratePreloaded, useAction, useAgent, useAgentChat, useAgentState, useAgentToolEvents, useAuth, useAuthSessions, useAuthState, useAuthUsers, useClientQuery, useConnectionStatus, useFlag, useFlags, useHttpStream, useImpersonate, useInfiniteQuery, useLunora, useMutation, useMutator, useOrganizations, usePaginatedQuery, usePreloadedQuery, usePresence, useQuery, useRateLimit, useStream, useSubscription, useVoiceAgent };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ReactNode, ReactElement } from 'react';
2
- import { LunoraClient, OptimisticUpdate, User, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, AuthImpersonation, AuthSession, AuthUser, ClientQueryRef, ConnectionStatus, HttpStreamRef, HttpStreamArgsOf, HttpStreamChunkOf, MutatorHandle, Preloaded } from '@lunora/client';
3
- export { type ArgsOf, type ClientQueryRef, type FunctionReference, type HttpStreamArgsOf, type HttpStreamChunkOf, type HttpStreamRef, type LunoraClient, type LunoraErrorCode, type MutatorHandle, type MutatorTransaction, type OptimisticLocalStore, type OptimisticUpdate, type Preloaded, type ReturnOf, type User, createClientQuery, getErrorCode, getRetryAfterMs, isConflictError, isForbiddenError, isRateLimitedError, isUnauthorizedError } from '@lunora/client';
2
+ import { LunoraClient, OptimisticUpdate, User, SubscriptionErrorCallback, FunctionReference, ArgsOf, ActionCallOptions, ReturnOf, AuthImpersonation, AuthSession, AuthUser, ClientQueryRef, ConnectionStatus, HttpStreamRef, HttpStreamArgsOf, HttpStreamChunkOf, MutatorHandle, Preloaded } from '@lunora/client';
3
+ export { type ArgsOf, type AuthImpersonation, type AuthPage, type AuthSession, type AuthUser, type ClientQueryRef, type FunctionReference, type HttpStreamArgsOf, type HttpStreamChunkOf, type HttpStreamRef, type LunoraClient, type LunoraErrorCode, type MutatorHandle, type MutatorTransaction, type OptimisticLocalStore, type OptimisticUpdate, type Preloaded, type ReturnOf, type SubscriptionError, type SubscriptionErrorCallback, type User, createClientQuery, getErrorCode, getRetryAfterMs, isConflictError, isForbiddenError, isRateLimitedError, isUnauthorizedError } from '@lunora/client';
4
4
  import { QueryClient } from '@tanstack/react-query';
5
5
  export { type L as LunoraQueryOptions, l as lunoraQueryOptions } from "./packem_shared/query-options.d-CdgGQ9s4.js";
6
6
  import { PaginationStatus } from '@lunora/client/pagination';
@@ -63,89 +63,13 @@ declare const LunoraProvider: ({ children, client, queryClient }: LunoraProvider
63
63
  * colocated with the provider for back-compat.
64
64
  */
65
65
  declare const useLunora: () => LunoraClient;
66
- /**
67
- * Client-safe mirror of `@lunora/payment`'s `Subscription`. Re-declared here
68
- * (rather than imported) so this React entry never pulls in the server-only
69
- * `@lunora/payment` module graph — the kit stays React + DOM only. Keep this in
70
- * sync with `packages/payment/src/types.ts`.
71
- */
72
- interface Subscription {
73
- readonly cancelAtPeriodEnd: boolean;
74
- readonly createdAt: number;
75
- readonly currentPeriodEnd?: number;
76
- readonly id: string;
77
- readonly priceId: string;
78
- readonly provider: "polar" | "stripe";
79
- readonly quantity: number;
80
- readonly referenceId: string;
81
- readonly state: "active" | "canceled" | "past_due" | "paused" | "trialing";
82
- readonly updatedAt: number;
83
- }
84
- /** The `{ url }` shape every checkout/portal trigger resolves to. */
85
- interface RedirectTarget {
86
- readonly url: string;
87
- }
88
- /** A thunk the app supplies that calls its own Lunora action and resolves a redirect URL. */
89
- type RedirectTrigger = () => Promise<RedirectTarget>;
90
- interface UseCheckoutResult {
91
- /** Run the trigger and redirect the browser to the resolved URL. Resolves once the redirect is issued; rejects on failure. */
92
- checkout: () => Promise<void>;
93
- /** The most recent failure, or `undefined`. */
94
- error: Error | undefined;
95
- /** `true` while the trigger is in flight (before the redirect is issued). */
96
- pending: boolean;
97
- }
98
- /**
99
- * Decoupled redirect-on-resolve primitive shared by `CheckoutButton` and
100
- * `CustomerPortalButton`. The app passes a `trigger` thunk that calls its own
101
- * Lunora action (the one wrapping `LunoraPayment.createCheckout` /
102
- * `createPortalSession`) and resolves `{ url }`; this hook awaits it, flips
103
- * `pending`, surfaces any `error`, and on success navigates via
104
- * `location.assign(url)`.
105
- *
106
- * Mirrors Convex's `CheckoutLink` / `CustomerPortalLink` flow (trigger an action
107
- * that returns a URL, then redirect) while staying agnostic of the app's
108
- * function names.
109
- */
110
- declare const useCheckout: (trigger: RedirectTrigger) => UseCheckoutResult;
111
- /**
112
- * Presentational props shared by the redirect buttons. Kept to a curated set
113
- * (rather than spreading arbitrary button attributes) so the component stays
114
- * within the repo's `react/jsx-props-no-spreading` rule while covering the
115
- * common styling / accessibility hooks.
116
- */
117
- interface RedirectButtonOwnProps {
118
- /** Accessible label when the visible `children` are icon-only. */
119
- "aria-label"?: string;
120
- children?: ReactNode;
121
- className?: string;
122
- /** Force-disable the control regardless of pending state. */
123
- disabled?: boolean;
124
- /** Called with the failure when the trigger rejects. The error is also surfaced via `useCheckout`. */
125
- onError?: (error: Error) => void;
126
- title?: string;
127
- }
128
- interface CheckoutButtonProps extends RedirectButtonOwnProps {
129
- /** Calls the app's checkout action and resolves the hosted-checkout `{ url }`. */
130
- onCheckout: RedirectTrigger;
131
- }
132
- interface CustomerPortalButtonProps extends RedirectButtonOwnProps {
133
- /** Calls the app's portal action and resolves the customer-portal `{ url }`. */
134
- onPortal: RedirectTrigger;
135
- }
136
- /**
137
- * Button that starts a hosted checkout. On click it awaits `onCheckout` (a thunk
138
- * that calls the app's checkout action) and redirects to the returned URL,
139
- * disabling itself while the request is in flight.
140
- */
141
- declare const CheckoutButton: ({ onCheckout, ...rest }: CheckoutButtonProps) => ReactNode;
142
- /**
143
- * Button that opens the provider's customer portal. On click it awaits
144
- * `onPortal` (a thunk that calls the app's portal action) and redirects to the
145
- * returned URL, disabling itself while the request is in flight.
146
- */
147
- declare const CustomerPortalButton: ({ onPortal, ...rest }: CustomerPortalButtonProps) => ReactNode;
148
66
  interface UseQueryOptions {
67
+ /**
68
+ * Called when the server pushes a subscription-scoped error (an RLS denial, a
69
+ * query that starts failing server-side). Without a handler such an error has
70
+ * nowhere to go and the hook's value simply freezes at its last good result.
71
+ */
72
+ onError?: SubscriptionErrorCallback;
149
73
  shardKey?: string;
150
74
  }
151
75
  interface UseMutationCallOptions<TCurrent = unknown, TValue = unknown, TArgs = unknown> {
@@ -825,8 +749,6 @@ declare const useClientQuery: <T extends unknown>(ref: ClientQueryRef<T>) => [T,
825
749
  * operator can tell a healthy live channel from a silently-dropped socket.
826
750
  */
827
751
  declare const useConnectionStatus: () => ConnectionStatus;
828
- /** A targeting context merged on top of the app's default (`defineFlags({ identify })`). */
829
- type FlagContext = Record<string, unknown>;
830
752
  /** The value kinds a flag resolves to — OpenFeature's boolean / number / string / structured (JSON) flags. */
831
753
  type FlagValue = boolean | number | string | {
832
754
  [key: string]: unknown;
@@ -838,25 +760,30 @@ type FlagValue = boolean | number | string | {
838
760
  * resolved value — re-pushed whenever the provider re-evaluates (e.g. a flag is
839
761
  * toggled in Cloudflare Flagship). The flag's kind is inferred from
840
762
  * `defaultValue`'s runtime type, so `useFlag("dark", false)` reads a boolean and
841
- * `useFlag("hero", "control")` a string. `context` supplies a per-call targeting
842
- * context merged on top of the app's default `identify` targeting key.
763
+ * `useFlag("hero", "control")` a string.
764
+ *
765
+ * The reactive channel is public, so the server evaluates every flag under the
766
+ * socket's own verified identity — the targeting key your `defineFlags({
767
+ * identify })` derives — and accepts no client-supplied targeting context. For
768
+ * evaluation under a context you compute, call `ctx.flags.*` inside a query,
769
+ * mutation, or action and return the resolved value.
843
770
  *
844
771
  * Evaluation runs through whatever OpenFeature provider the app wired in
845
772
  * `lunora/flags.ts`; the read never throws — a provider error resolves the
846
773
  * default (the same fail-open contract as server-side `ctx.flags`).
847
774
  */
848
- declare const useFlag: <T extends FlagValue>(key: string, defaultValue: T, context?: FlagContext) => T;
775
+ declare const useFlag: <T extends FlagValue>(key: string, defaultValue: T) => T;
849
776
  /**
850
777
  * Subscribe to several feature flags at once, live over Lunora's WebSocket.
851
778
  *
852
779
  * Pass a record of `key → defaultValue`; each flag's kind is inferred from its
853
780
  * default, and the result is the same-shaped record with resolved values (the
854
- * defaults until each evaluation lands). A single `context` applies to every
855
- * flag. This is the batched form of {@link useFlag} — one effect manages one
856
- * subscription per key, so it stays rules-of-hooks-safe even as the flag set
857
- * changes between renders.
781
+ * defaults until each evaluation lands). This is the batched form of
782
+ * {@link useFlag} — one effect manages one subscription per key, so it stays
783
+ * rules-of-hooks-safe even as the flag set changes between renders. Like
784
+ * {@link useFlag} it evaluates under the socket's server-verified identity only.
858
785
  */
859
- declare const useFlags: <T extends Record<string, FlagValue>>(flags: T, context?: FlagContext) => T;
786
+ declare const useFlags: <T extends Record<string, FlagValue>>(flags: T) => T;
860
787
  /** The lifecycle of a stream the hook is observing. */
861
788
  type UseStreamStatus = "complete" | "error" | "idle" | "streaming";
862
789
  /**
@@ -1121,6 +1048,10 @@ declare const usePresence: <H extends HeartbeatReference, L extends ListPresentR
1121
1048
  * so an args object built in a different key order still dedupes). The
1122
1049
  * subscription registry shares a single WS subscription across every consumer
1123
1050
  * of the same queryKey; pushes call `queryClient.setQueryData(...)`.
1051
+ *
1052
+ * Pass `onError` to surface a subscription-scoped error the server pushes (an RLS
1053
+ * denial, a query that starts failing server-side). Without it such an error is
1054
+ * dropped and the returned value just freezes at its last good result.
1124
1055
  */
1125
1056
  declare const useQuery: <F extends FunctionReference>(function_: F, args: ArgsOf<F> | "skip", options?: UseQueryOptions) => ReturnOf<F> | undefined;
1126
1057
  interface UseRateLimitOptions {
@@ -1334,4 +1265,4 @@ interface UseVoiceAgentResult {
1334
1265
  * `createSocket`) so the hook is drivable outside a browser.
1335
1266
  */
1336
1267
  declare const useVoiceAgent: (options: UseVoiceAgentOptions) => UseVoiceAgentResult;
1337
- export { type ActionHook, type AdminAuthListResult, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, type AuthState, Authenticated, CheckoutButton, type CheckoutButtonProps, CustomerPortalButton, type CustomerPortalButtonProps, type FlagContext, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraProvider, type LunoraProviderProps, type MutationHook, type MutatorHook, type PageItemOf, type PaginatedArgs, type RedirectTarget, type RedirectTrigger, type Subscription, Unauthenticated, type UseAgentApi, type UseAgentChatApi, type UseAgentChatOptions, type UseAgentChatResult, type UseAgentOptions, type UseAgentResult, type UseAgentStateApi, type UseAgentStateOptions, type UseAgentStateResult, type UseAgentToolEventsApi, type UseAgentToolEventsOptions, type UseAgentToolEventsResult, type UseAuthResult, type UseAuthSessionsOptions, type UseAuthUsersOptions, type UseCheckoutResult, type UseHttpStreamOptions, type UseHttpStreamResult, type UseImpersonateResult, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMutationCallOptions, type UseOrganizationsOptions, type UsePaginatedQueryOptions, type UsePaginatedQueryResult, type UsePresenceOptions, type UsePresenceResult, type UseQueryOptions, type UseRateLimitOptions, type UseRateLimitResult, type UseStreamOptions, type UseStreamResult, type UseStreamStatus, type UseSubscriptionResult, type UseVoiceAgentOptions, type UseVoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, hydratePreloaded, useAction, useAgent, useAgentChat, useAgentState, useAgentToolEvents, useAuth, useAuthSessions, useAuthState, useAuthUsers, useCheckout, useClientQuery, useConnectionStatus, useFlag, useFlags, useHttpStream, useImpersonate, useInfiniteQuery, useLunora, useMutation, useMutator, useOrganizations, usePaginatedQuery, usePreloadedQuery, usePresence, useQuery, useRateLimit, useStream, useSubscription, useVoiceAgent };
1268
+ export { type ActionHook, type AdminAuthListResult, type AgentChatMessage, type AgentLiveEvent, type AgentProgressEvent, type AgentThreadRecord, type AgentThreadStatus, type AgentTokenDelta, type AgentToolEvent, AuthLoading, type AuthState, Authenticated, type FlagValue, type HeartbeatReference, type ListPresentReference, LunoraProvider, type LunoraProviderProps, type MutationHook, type MutatorHook, type PageItemOf, type PaginatedArgs, Unauthenticated, type UseAgentApi, type UseAgentChatApi, type UseAgentChatOptions, type UseAgentChatResult, type UseAgentOptions, type UseAgentResult, type UseAgentStateApi, type UseAgentStateOptions, type UseAgentStateResult, type UseAgentToolEventsApi, type UseAgentToolEventsOptions, type UseAgentToolEventsResult, type UseAuthResult, type UseAuthSessionsOptions, type UseAuthUsersOptions, type UseHttpStreamOptions, type UseHttpStreamResult, type UseImpersonateResult, type UseInfiniteQueryOptions, type UseInfiniteQueryResult, type UseMutationCallOptions, type UseOrganizationsOptions, type UsePaginatedQueryOptions, type UsePaginatedQueryResult, type UsePresenceOptions, type UsePresenceResult, type UseQueryOptions, type UseRateLimitOptions, type UseRateLimitResult, type UseStreamOptions, type UseStreamResult, type UseStreamStatus, type UseSubscriptionResult, type UseVoiceAgentOptions, type UseVoiceAgentResult, type VoiceAudioFormat, type VoiceReference, type VoiceStatus, hydratePreloaded, useAction, useAgent, useAgentChat, useAgentState, useAgentToolEvents, useAuth, useAuthSessions, useAuthState, useAuthUsers, useClientQuery, useConnectionStatus, useFlag, useFlags, useHttpStream, useImpersonate, useInfiniteQuery, useLunora, useMutation, useMutator, useOrganizations, usePaginatedQuery, usePreloadedQuery, usePresence, useQuery, useRateLimit, useStream, useSubscription, useVoiceAgent };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{AuthLoading as o,Authenticated as t,Unauthenticated as u}from"./packem_shared/AuthLoading-dC08yqew.mjs";import{useAuthState as a}from"./packem_shared/useAuthState-CoOG9XdT.mjs";import{LunoraProvider as f,useLunora as n}from"./packem_shared/LunoraProvider-DC06S-p1.mjs";import{CheckoutButton as i,CustomerPortalButton as d,useCheckout as x}from"./packem_shared/CheckoutButton-D8MutXhg.mjs";import{lunoraQueryOptions as h}from"./packem_shared/lunoraQueryOptions-B5PEocLy.mjs";import{useAction as c}from"./packem_shared/useAction-CUSJu4yq.mjs";import{useAuthSessions as C,useAuthUsers as U,useImpersonate as y,useOrganizations as E}from"./packem_shared/useAuthSessions-Bq4-f3g-.mjs";import{useAgent as Q}from"./packem_shared/useAgent-BtmvbOfx.mjs";import{useAgentChat as L}from"./packem_shared/useAgentChat-CYdAxCn5.mjs";import{useAgentState as F}from"./packem_shared/useAgentState-CxeO0Nzo.mjs";import{useAgentToolEvents as k}from"./packem_shared/useAgentToolEvents-MfR_4MA_.mjs";import{default as b}from"./packem_shared/useAuth-x4boOoAR.mjs";import{default as z}from"./packem_shared/useClientQuery-DFs7trEf.mjs";import{default as O}from"./packem_shared/useConnectionStatus-XYsYGiT6.mjs";import{useFlag as H,useFlags as V}from"./packem_shared/useFlag-HLt4Xzmd.mjs";import{useHttpStream as q}from"./packem_shared/useHttpStream-D9vum8Qx.mjs";import{default as D}from"./packem_shared/useInfiniteQuery-DDYp2Df1.mjs";import{useMutation as J}from"./packem_shared/useMutation-BnKec7bE.mjs";import{useMutator as N}from"./packem_shared/useMutator-BtUd-xEA.mjs";import{usePaginatedQuery as X}from"./packem_shared/usePaginatedQuery-B3Q7mppN.mjs";import{hydratePreloaded as Z,default as _}from"./packem_shared/hydratePreloaded-D6ZG10Q7.mjs";import{usePresence as ee}from"./packem_shared/usePresence-DsYEO_XX.mjs";import{default as oe}from"./packem_shared/useQuery-BIkNc_t1.mjs";import{useRateLimit as ue}from"./packem_shared/useRateLimit-Cckxi8m9.mjs";import{useStream as ae}from"./packem_shared/useStream-CmGOT0qj.mjs";import{default as fe}from"./packem_shared/useSubscription-BXhI6J-f.mjs";import{useVoiceAgent as me}from"./packem_shared/useVoiceAgent-BziH3D-1.mjs";import{createClientQuery as de,getErrorCode as xe,getRetryAfterMs as le,isConflictError as he,isForbiddenError as Ae,isRateLimitedError as ce,isUnauthorizedError as ge}from"@lunora/client";import{RestrictionError as Ue,UploadControl as ye,UploadError as Ee}from"@visulima/storage-client";import{useChunkedRestUpload as Qe,useFileInput as Se,useMultipartUpload as Le,usePasteUpload as Re,useTusUpload as Fe,useUpload as Me}from"@visulima/storage-client/react";export{o as AuthLoading,t as Authenticated,i as CheckoutButton,d as CustomerPortalButton,f as LunoraProvider,Ue as RestrictionError,u as Unauthenticated,ye as UploadControl,Ee as UploadError,de as createClientQuery,xe as getErrorCode,le as getRetryAfterMs,Z as hydratePreloaded,he as isConflictError,Ae as isForbiddenError,ce as isRateLimitedError,ge as isUnauthorizedError,h as lunoraQueryOptions,c as useAction,Q as useAgent,L as useAgentChat,F as useAgentState,k as useAgentToolEvents,b as useAuth,C as useAuthSessions,a as useAuthState,U as useAuthUsers,x as useCheckout,Qe as useChunkedRestUpload,z as useClientQuery,O as useConnectionStatus,Se as useFileInput,H as useFlag,V as useFlags,q as useHttpStream,y as useImpersonate,D as useInfiniteQuery,n as useLunora,Le as useMultipartUpload,J as useMutation,N as useMutator,E as useOrganizations,X as usePaginatedQuery,Re as usePasteUpload,_ as usePreloadedQuery,ee as usePresence,oe as useQuery,ue as useRateLimit,ae as useStream,fe as useSubscription,Fe as useTusUpload,Me as useUpload,me as useVoiceAgent};
2
+ import{AuthLoading as o,Authenticated as t,Unauthenticated as u}from"./packem_shared/AuthLoading-dC08yqew.mjs";import{useAuthState as a}from"./packem_shared/useAuthState-CoOG9XdT.mjs";import{LunoraProvider as f,useLunora as n}from"./packem_shared/LunoraProvider-DC06S-p1.mjs";import{lunoraQueryOptions as m}from"./packem_shared/lunoraQueryOptions-B5PEocLy.mjs";import{useAction as x}from"./packem_shared/useAction-CUSJu4yq.mjs";import{useAuthSessions as A,useAuthUsers as g,useImpersonate as h,useOrganizations as c}from"./packem_shared/useAuthSessions-Bq4-f3g-.mjs";import{useAgent as y}from"./packem_shared/useAgent-BtmvbOfx.mjs";import{useAgentChat as E}from"./packem_shared/useAgentChat-PSWHsc8L.mjs";import{useAgentState as S}from"./packem_shared/useAgentState-CxeO0Nzo.mjs";import{useAgentToolEvents as L}from"./packem_shared/useAgentToolEvents-MfR_4MA_.mjs";import{default as F}from"./packem_shared/useAuth-x4boOoAR.mjs";import{default as I}from"./packem_shared/useClientQuery-DFs7trEf.mjs";import{default as v}from"./packem_shared/useConnectionStatus-XYsYGiT6.mjs";import{useFlag as O,useFlags as T}from"./packem_shared/useFlag-BDM923ke.mjs";import{useHttpStream as H}from"./packem_shared/useHttpStream-D9vum8Qx.mjs";import{default as j}from"./packem_shared/useInfiniteQuery-JrM8Gv4A.mjs";import{useMutation as w}from"./packem_shared/useMutation-BnKec7bE.mjs";import{useMutator as D}from"./packem_shared/useMutator-BtUd-xEA.mjs";import{usePaginatedQuery as J}from"./packem_shared/usePaginatedQuery-f-GjDA-g.mjs";import{hydratePreloaded as N,default as W}from"./packem_shared/hydratePreloaded-D_NlgGV_.mjs";import{usePresence as Y}from"./packem_shared/usePresence-DsYEO_XX.mjs";import{default as _}from"./packem_shared/useQuery-HeFPuRVz.mjs";import{useRateLimit as ee}from"./packem_shared/useRateLimit-Cckxi8m9.mjs";import{useStream as oe}from"./packem_shared/useStream-CmGOT0qj.mjs";import{default as ue}from"./packem_shared/useSubscription-BXhI6J-f.mjs";import{useVoiceAgent as ae}from"./packem_shared/useVoiceAgent-BziH3D-1.mjs";import{createClientQuery as fe,getErrorCode as ne,getRetryAfterMs as ie,isConflictError as me,isForbiddenError as de,isRateLimitedError as xe,isUnauthorizedError as le}from"@lunora/client";import{RestrictionError as ge,UploadControl as he,UploadError as ce}from"@visulima/storage-client";import{useChunkedRestUpload as ye,useFileInput as Ce,useMultipartUpload as Ee,usePasteUpload as Qe,useTusUpload as Se,useUpload as Pe}from"@visulima/storage-client/react";export{o as AuthLoading,t as Authenticated,f as LunoraProvider,ge as RestrictionError,u as Unauthenticated,he as UploadControl,ce as UploadError,fe as createClientQuery,ne as getErrorCode,ie as getRetryAfterMs,N as hydratePreloaded,me as isConflictError,de as isForbiddenError,xe as isRateLimitedError,le as isUnauthorizedError,m as lunoraQueryOptions,x as useAction,y as useAgent,E as useAgentChat,S as useAgentState,L as useAgentToolEvents,F as useAuth,A as useAuthSessions,a as useAuthState,g as useAuthUsers,ye as useChunkedRestUpload,I as useClientQuery,v as useConnectionStatus,Ce as useFileInput,O as useFlag,T as useFlags,H as useHttpStream,h as useImpersonate,j as useInfiniteQuery,n as useLunora,Ee as useMultipartUpload,w as useMutation,D as useMutator,c as useOrganizations,J as usePaginatedQuery,Qe as usePasteUpload,W as usePreloadedQuery,Y as usePresence,_ as useQuery,ee as useRateLimit,oe as useStream,ue as useSubscription,Se as useTusUpload,Pe as useUpload,ae as useVoiceAgent};
@@ -0,0 +1 @@
1
+ import{k as u}from"./query-key-C6iUhRuD.mjs";class k{constructor(e){this.client=e}client;entries=new Map;keyOf(e){return u(e)}attach(e,o,b,h,p,l={}){const i=u(o);let t=this.entries.get(i);if(!t){t={errorCallbacks:new Set,pollTimer:void 0,refCount:0,unsubscribe:void 0},this.entries.set(i,t);const r=t;try{t.unsubscribe=this.client.subscribe(b,h,a=>{e.setQueryData(o,a)},{onError:a=>{for(const d of r.errorCallbacks)d(a)},shardKey:p})}catch{t.pollTimer=setInterval(()=>{e.invalidateQueries({queryKey:o}).catch(()=>{})},l.pollIntervalMs??5e3)}}t.refCount+=1;const{onError:n}=l;n&&t.errorCallbacks.add(n);let c=!1;return()=>{if(c)return;c=!0;const r=this.entries.get(i);r&&(r.refCount-=1,n&&r.errorCallbacks.delete(n),r.refCount<=0&&(r.unsubscribe?.(),r.pollTimer&&clearInterval(r.pollTimer),this.entries.delete(i)))}}}const f=new WeakMap,C=s=>{let e=f.get(s);return e||(e=new k(s),f.set(s,e)),e};export{C as g};
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{c as m}from"react/compiler-runtime";import{useQueryClient as d,useQuery as p}from"@tanstack/react-query";import{useEffect as g}from"react";import{g as I}from"./cache-I4w1R5RF.mjs";import{useLunora as Q}from"./LunoraProvider-DC06S-p1.mjs";import{l as h,s as q}from"./query-key-C6iUhRuD.mjs";const K=function(n){const e=m(4),t=Q(),r=d(),{args:s,functionPath:l,shardKey:u,value:y}=n,i={__lunoraRef:l},a=h(i,s,u),{data:f}=p({initialData:y,queryFn:()=>t.query(i,s,{shardKey:u}),queryKey:a,staleTime:Number.POSITIVE_INFINITY}),c=q(a);let o;return e[0]!==t||e[1]!==r||e[2]!==c?(o=[t,r,c],e[0]=t,e[1]=r,e[2]=c,e[3]=o):o=e[3],g(()=>I(t).attach(r,a,i,s,u),o),f===void 0?y:f},C=function(n){return K(n)};export{K as default,C as hydratePreloaded};
2
+ import{c as m}from"react/compiler-runtime";import{useQueryClient as d,useQuery as p}from"@tanstack/react-query";import{useEffect as g}from"react";import{g as I}from"./cache-BuILe2dy.mjs";import{useLunora as Q}from"./LunoraProvider-DC06S-p1.mjs";import{l as h,s as q}from"./query-key-C6iUhRuD.mjs";const K=function(n){const e=m(4),t=Q(),r=d(),{args:s,functionPath:l,shardKey:u,value:y}=n,i={__lunoraRef:l},a=h(i,s,u),{data:f}=p({initialData:y,queryFn:()=>t.query(i,s,{shardKey:u}),queryKey:a,staleTime:Number.POSITIVE_INFINITY}),c=q(a);let o;return e[0]!==t||e[1]!==r||e[2]!==c?(o=[t,r,c],e[0]=t,e[1]=r,e[2]=c,e[3]=o):o=e[3],g(()=>I(t).attach(r,a,i,s,u),o),f===void 0?y:f},C=function(n){return K(n)};export{K as default,C as hydratePreloaded};
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{initialPages as M,rebalance as D,derivePaginationStatus as A,applyLoadMore as E}from"@lunora/client/pagination";import{useQueryClient as O}from"@tanstack/react-query";import{useRef as m,useReducer as _,useState as $,useEffect as d,useCallback as j}from"react";import{g as H}from"./cache-I4w1R5RF.mjs";import{useLunora as N}from"./LunoraProvider-DC06S-p1.mjs";import{s as i,l as q}from"./query-key-C6iUhRuD.mjs";const T=function(o){const f=m(void 0);return f.current??=o(),f},Y=function(o,f,L){const a=N(),n=O(),{initialNumItems:g,shardKey:l}=L,c=f==="skip",p=c?{}:f,[,P]=_(e=>e+1,0),[v,K]=$(()=>M(g)),b=`${i(q(o,p,l))}::${String(g)}`,S=m(b);S.current!==b&&(S.current=b,K(M(g)));const h=v.map(e=>{const s={...p,paginationOpts:{cursor:e.lower,endCursor:e.upper,numItems:e.numItems}},r=q(o,s,l);return{args:s,key:r}}),w=h.map(({key:e})=>i(e)).join("|"),k=m({baseArgs:p,entries:[],fn:o,shardKey:l});d(()=>{k.current={baseArgs:p,entries:h,fn:o,shardKey:l}});const C=T(()=>new Map),I=m(a);d(()=>{const e=C.current;if(I.current!==a){for(const t of e.values())t();e.clear(),I.current=a}if(c){for(const t of e.values())t();e.clear();return}const s=k.current,r=H(a),y=new Set(s.entries.map(({key:t})=>i(t)));for(const[t,u]of e)y.has(t)||(u(),e.delete(t));for(const t of s.entries){const u=i(t.key);if(e.has(u))continue;n.fetchQuery({queryFn:()=>a.query(s.fn,t.args,{shardKey:s.shardKey}),queryKey:t.key,staleTime:0}).catch(()=>{}),e.set(u,r.attach(n,t.key,s.fn,t.args,s.shardKey))}},[a,n,w,c]),d(()=>()=>{for(const e of C.current.values())e();C.current.clear()},[]),d(()=>n.getQueryCache().subscribe(r=>{if(r.type!=="updated")return;const y=i(r.query.queryKey);h.some(({key:t})=>i(t)===y)&&P()}),[n,w]);const R=c?[]:h.map(({key:e})=>n.getQueryData(e));d(()=>{if(c)return;const e=D(v,R);e&&K(e)});const{status:x}=A(c,R);return{loadMore:j(e=>{K(s=>{const r=k.current,y=s.map(Q=>{const z={...r.baseArgs,paginationOpts:{cursor:Q.lower,endCursor:Q.upper,numItems:Q.numItems}};return n.getQueryData(q(r.fn,z,r.shardKey))}),{nextCursor:t,status:u}=A(!1,y);return E(s,u==="CanLoadMore"?t:void 0,e)??s})},[n]),pageResults:R,status:x}};export{Y as u};
2
+ import{initialPages as M,rebalance as D,derivePaginationStatus as A,applyLoadMore as E}from"@lunora/client/pagination";import{useQueryClient as O}from"@tanstack/react-query";import{useRef as m,useReducer as _,useState as $,useEffect as d,useCallback as j}from"react";import{g as H}from"./cache-BuILe2dy.mjs";import{useLunora as N}from"./LunoraProvider-DC06S-p1.mjs";import{s as i,l as q}from"./query-key-C6iUhRuD.mjs";const T=function(o){const f=m(void 0);return f.current??=o(),f},Y=function(o,f,L){const a=N(),n=O(),{initialNumItems:g,shardKey:l}=L,c=f==="skip",p=c?{}:f,[,P]=_(e=>e+1,0),[v,K]=$(()=>M(g)),b=`${i(q(o,p,l))}::${String(g)}`,S=m(b);S.current!==b&&(S.current=b,K(M(g)));const h=v.map(e=>{const s={...p,paginationOpts:{cursor:e.lower,endCursor:e.upper,numItems:e.numItems}},r=q(o,s,l);return{args:s,key:r}}),w=h.map(({key:e})=>i(e)).join("|"),k=m({baseArgs:p,entries:[],fn:o,shardKey:l});d(()=>{k.current={baseArgs:p,entries:h,fn:o,shardKey:l}});const C=T(()=>new Map),I=m(a);d(()=>{const e=C.current;if(I.current!==a){for(const t of e.values())t();e.clear(),I.current=a}if(c){for(const t of e.values())t();e.clear();return}const s=k.current,r=H(a),y=new Set(s.entries.map(({key:t})=>i(t)));for(const[t,u]of e)y.has(t)||(u(),e.delete(t));for(const t of s.entries){const u=i(t.key);if(e.has(u))continue;n.fetchQuery({queryFn:()=>a.query(s.fn,t.args,{shardKey:s.shardKey}),queryKey:t.key,staleTime:0}).catch(()=>{}),e.set(u,r.attach(n,t.key,s.fn,t.args,s.shardKey))}},[a,n,w,c]),d(()=>()=>{for(const e of C.current.values())e();C.current.clear()},[]),d(()=>n.getQueryCache().subscribe(r=>{if(r.type!=="updated")return;const y=i(r.query.queryKey);h.some(({key:t})=>i(t)===y)&&P()}),[n,w]);const R=c?[]:h.map(({key:e})=>n.getQueryData(e));d(()=>{if(c)return;const e=D(v,R);e&&K(e)});const{status:x}=A(c,R);return{loadMore:j(e=>{K(s=>{const r=k.current,y=s.map(Q=>{const z={...r.baseArgs,paginationOpts:{cursor:Q.lower,endCursor:Q.upper,numItems:Q.numItems}};return n.getQueryData(q(r.fn,z,r.shardKey))}),{nextCursor:t,status:u}=A(!1,y);return E(s,u==="CanLoadMore"?t:void 0,e)??s})},[n]),pageResults:R,status:x}};export{Y as u};
@@ -0,0 +1,2 @@
1
+ 'use client';
2
+ import{reconcileOptimistic as y,maxSeq as M}from"@lunora/client";import{useState as H,useRef as R}from"react";import{useMutation as u}from"./useMutation-BnKec7bE.mjs";import{useStream as J}from"./useStream-CmGOT0qj.mjs";import S from"./useSubscription-BXhI6J-f.mjs";const L={__lunoraRef:""},Q={__lunoraRef:""},V=[],ot=A=>{const{api:r,cancel:m,limit:d,send:_,sendArgs:k,stream:l,threadKey:e}=A,x=d===void 0?{key:e}:{key:e,limit:d},{data:E}=S(r.agents.agentMessages,x),{data:w}=S(r.agents.agentThread,{key:e}),O=l===void 0?"skip":{key:e},{chunks:T}=J(l??Q,O),b=u(_),I=u(m??L),j=u(r.agents.agentResolveApproval),[q,c]=H([]),p=R(0),f=R(e);f.current!==e&&(f.current=e,c([]));const g=w,C=g?.status,o=g?.instanceId,s=E??V,h=y(q,s),D=M(s),K=h.length===0?s:[...s,...h.map((t,n)=>({content:t.content,optimistic:!0,role:"user",seq:D+1+n}))],N=s.filter(t=>t.role==="assistant").length,F=T.filter(t=>t.kind!=="progress"&&t.threadKey===e&&t.turn>=N).map(t=>t.text).join(""),{mutate:G}=b,{mutate:P}=I,{mutate:U}=j,Y=async(t,n)=>{const a=p.current;p.current+=1;const $=M(s);c(i=>[...y(i,s),{content:t,id:a,maxDurableSeqAtSend:$}]);try{await G({input:t,threadKey:e,...k,...n})}catch(i){throw c(z=>z.filter(B=>B.id!==a)),i}},v=async(t,n,a)=>{if(o===void 0)throw new Error(`useAgentChat: cannot ${t} — no in-flight run (thread has no instanceId)`);await U({decision:t,instanceId:o,threadKey:e,toolCallId:n,...a===void 0?{}:{note:a}})};return{approve:(t,n)=>v("approve",t,n),cancel:async()=>{m===void 0||o===void 0||await P({instanceId:o,threadKey:e})},messages:K,reject:(t,n)=>v("reject",t,n),send:Y,status:C,streamingText:F}};export{ot as useAgentChat};
@@ -0,0 +1,2 @@
1
+ 'use client';
2
+ import{useState as _,useRef as i,useEffect as b}from"react";import{useLunora as d}from"./LunoraProvider-DC06S-p1.mjs";import{s as K}from"./stable-key-B_BlboiY.mjs";const g="__lunora_flags__:eval",m=t=>{const e=typeof t;return e==="boolean"||e==="number"||e==="string"?e:"object"},v={__lunoraRef:g},F=(t,e,n)=>{try{return t.subscribe(v,{default:e.default,key:e.key,type:m(e.default)},s=>{n(s)},{onError:()=>{n(e.default)}})}catch{return()=>{}}},S=(t,e)=>{const n=d(),[s,r]=_(e),o=m(e),u=`${t}::${o}`,f=i(u);f.current!==u&&(f.current=u,r(e));const l=i(e);return b(()=>{l.current=e}),b(()=>{let a=!1;const c=l.current;r(c);const p=F(n,{default:c,key:t},y=>{a||r(y)});return()=>{a=!0,p()}},[n,t,o]),s},h=t=>{const e=d(),[n,s]=_(t),r=K(t),o=i(r);o.current!==r&&(o.current=r,s(t));const u=i(t);return b(()=>{u.current=t}),b(()=>{let f=!1;const l=u.current;s(l);const a=[];for(const[c,p]of Object.entries(l))a.push(F(e,{default:p,key:c},y=>{f||s(R=>({...R,[c]:y}))}));return()=>{f=!0;for(const c of a)c()}},[e,r]),n};export{S as useFlag,h as useFlags};
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{c as L}from"react/compiler-runtime";import{useRef as M,useEffect as R}from"react";import{u as y}from"./use-paginated-core-D7U-wwgW.mjs";const b=(h,c,g)=>{const e=L(15),{initialNumItems:s}=g,{loadMore:o,pageResults:u,status:a}=y(h,c==="skip"?"skip":c,g),N=c==="skip";let t;if(e[0]!==u){t=[];for(const f of u)f&&t.push(f.page);e[0]=u,e[1]=t}else t=e[1];let i;e[2]!==s||e[3]!==o?(i={defaultNumItems:s,loadMore:o},e[2]=s,e[3]=o,e[4]=i):i=e[4];const P=M(i);let n;e[5]!==s||e[6]!==o?(n=()=>{P.current={defaultNumItems:s,loadMore:o}},e[5]=s,e[6]=o,e[7]=n):n=e[7],R(n);let l;e[8]===Symbol.for("react.memo_cache_sentinel")?(l=f=>{const{defaultNumItems:I,loadMore:k}=P.current;k(f??I)},e[8]=l):l=e[8];const x=l,m=a==="CanLoadMore",d=!N&&a==="LoadingMore",p=!N&&a==="LoadingFirstPage";let r;return e[9]!==t||e[10]!==a||e[11]!==m||e[12]!==d||e[13]!==p?(r={fetchNextPage:x,hasNextPage:m,isFetchingNextPage:d,isLoading:p,pages:t,status:a},e[9]=t,e[10]=a,e[11]=m,e[12]=d,e[13]=p,e[14]=r):r=e[14],r};export{b as default};
2
+ import{c as L}from"react/compiler-runtime";import{useRef as M,useEffect as R}from"react";import{u as y}from"./use-paginated-core-Lu50LpUb.mjs";const b=(h,c,g)=>{const e=L(15),{initialNumItems:s}=g,{loadMore:o,pageResults:u,status:a}=y(h,c==="skip"?"skip":c,g),N=c==="skip";let t;if(e[0]!==u){t=[];for(const f of u)f&&t.push(f.page);e[0]=u,e[1]=t}else t=e[1];let i;e[2]!==s||e[3]!==o?(i={defaultNumItems:s,loadMore:o},e[2]=s,e[3]=o,e[4]=i):i=e[4];const P=M(i);let n;e[5]!==s||e[6]!==o?(n=()=>{P.current={defaultNumItems:s,loadMore:o}},e[5]=s,e[6]=o,e[7]=n):n=e[7],R(n);let l;e[8]===Symbol.for("react.memo_cache_sentinel")?(l=f=>{const{defaultNumItems:I,loadMore:k}=P.current;k(f??I)},e[8]=l):l=e[8];const x=l,m=a==="CanLoadMore",d=!N&&a==="LoadingMore",p=!N&&a==="LoadingFirstPage";let r;return e[9]!==t||e[10]!==a||e[11]!==m||e[12]!==d||e[13]!==p?(r={fetchNextPage:x,hasNextPage:m,isFetchingNextPage:d,isLoading:p,pages:t,status:a},e[9]=t,e[10]=a,e[11]=m,e[12]=d,e[13]=p,e[14]=r):r=e[14],r};export{b as default};
@@ -1,2 +1,2 @@
1
1
  'use client';
2
- import{c as l}from"react/compiler-runtime";import{u as c}from"./use-paginated-core-D7U-wwgW.mjs";const m=(u,i,d)=>{const e=l(7),{loadMore:p,pageResults:r,status:t}=c(u,i==="skip"?"skip":i,d);let s;if(e[0]!==r){s=[];for(const a of r)a&&s.push(...a.page);e[0]=r,e[1]=s}else s=e[1];const n=!(i==="skip")&&(t==="LoadingFirstPage"||t==="LoadingMore");let o;return e[2]!==p||e[3]!==s||e[4]!==t||e[5]!==n?(o={isLoading:n,loadMore:p,results:s,status:t},e[2]=p,e[3]=s,e[4]=t,e[5]=n,e[6]=o):o=e[6],o};export{m as usePaginatedQuery};
2
+ import{c as l}from"react/compiler-runtime";import{u as c}from"./use-paginated-core-Lu50LpUb.mjs";const m=(u,i,d)=>{const e=l(7),{loadMore:p,pageResults:r,status:t}=c(u,i==="skip"?"skip":i,d);let s;if(e[0]!==r){s=[];for(const a of r)a&&s.push(...a.page);e[0]=r,e[1]=s}else s=e[1];const n=!(i==="skip")&&(t==="LoadingFirstPage"||t==="LoadingMore");let o;return e[2]!==p||e[3]!==s||e[4]!==t||e[5]!==n?(o={isLoading:n,loadMore:p,results:s,status:t},e[2]=p,e[3]=s,e[4]=t,e[5]=n,e[6]=o):o=e[6],o};export{m as usePaginatedQuery};
@@ -0,0 +1,2 @@
1
+ 'use client';
2
+ import{useQueryClient as h,useQuery as E}from"@tanstack/react-query";import{useRef as b,useEffect as n,useCallback as g,useState as I}from"react";import{g as k}from"./cache-BuILe2dy.mjs";import{useLunora as q}from"./LunoraProvider-DC06S-p1.mjs";import{l as K,s as C}from"./query-key-C6iUhRuD.mjs";const F=(t,i,p={})=>{const e=q(),y=h(),{onError:c,shardKey:s}=p,d=b(c);n(()=>{d.current=c});const l=g(m=>{d.current?.(m)},[]),r=i==="skip",o=r?{}:i,a=K(t,o,s),[u,f]=I(e.isReady);n(()=>{u||e.whenReady().then(()=>{f(!0)})},[e,u]);const Q=r?void 0:e.peekHydratedQuery(t.__lunoraRef,o,s),{data:R}=E({enabled:!r&&u,initialData:Q,queryFn:()=>e.query(t,o,{shardKey:s}),queryKey:a,staleTime:Number.POSITIVE_INFINITY});return n(()=>r?()=>{}:k(e).attach(y,a,t,o,s,{onError:l}),[e,y,C(a),r,l]),r?void 0:R};export{F as default};
@@ -0,0 +1,84 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * Client-safe mirror of `@lunora/payment`'s `Subscription`. Re-declared here
4
+ * (rather than imported) so this React entry never pulls in the server-only
5
+ * `@lunora/payment` module graph — the kit stays React + DOM only. Keep this in
6
+ * sync with `packages/payment/src/types.ts`.
7
+ */
8
+ interface Subscription {
9
+ readonly cancelAtPeriodEnd: boolean;
10
+ readonly createdAt: number;
11
+ readonly currentPeriodEnd?: number;
12
+ readonly id: string;
13
+ readonly priceId: string;
14
+ readonly provider: "polar" | "stripe";
15
+ readonly quantity: number;
16
+ readonly referenceId: string;
17
+ readonly state: "active" | "canceled" | "past_due" | "paused" | "trialing";
18
+ readonly updatedAt: number;
19
+ }
20
+ /** The `{ url }` shape every checkout/portal trigger resolves to. */
21
+ interface RedirectTarget {
22
+ readonly url: string;
23
+ }
24
+ /** A thunk the app supplies that calls its own Lunora action and resolves a redirect URL. */
25
+ type RedirectTrigger = () => Promise<RedirectTarget>;
26
+ interface UseCheckoutResult {
27
+ /** Run the trigger and redirect the browser to the resolved URL. Resolves once the redirect is issued; rejects on failure. */
28
+ checkout: () => Promise<void>;
29
+ /** The most recent failure, or `undefined`. */
30
+ error: Error | undefined;
31
+ /** `true` while the trigger is in flight (before the redirect is issued). */
32
+ pending: boolean;
33
+ }
34
+ /**
35
+ * Decoupled redirect-on-resolve primitive shared by `CheckoutButton` and
36
+ * `CustomerPortalButton`. The app passes a `trigger` thunk that calls its own
37
+ * Lunora action (the one wrapping `LunoraPayment.createCheckout` /
38
+ * `createPortalSession`) and resolves `{ url }`; this hook awaits it, flips
39
+ * `pending`, surfaces any `error`, and on success navigates via
40
+ * `location.assign(url)`.
41
+ *
42
+ * Mirrors Convex's `CheckoutLink` / `CustomerPortalLink` flow (trigger an action
43
+ * that returns a URL, then redirect) while staying agnostic of the app's
44
+ * function names.
45
+ */
46
+ declare const useCheckout: (trigger: RedirectTrigger) => UseCheckoutResult;
47
+ /**
48
+ * Presentational props shared by the redirect buttons. Kept to a curated set
49
+ * (rather than spreading arbitrary button attributes) so the component stays
50
+ * within the repo's `react/jsx-props-no-spreading` rule while covering the
51
+ * common styling / accessibility hooks.
52
+ */
53
+ interface RedirectButtonOwnProps {
54
+ /** Accessible label when the visible `children` are icon-only. */
55
+ "aria-label"?: string;
56
+ children?: ReactNode;
57
+ className?: string;
58
+ /** Force-disable the control regardless of pending state. */
59
+ disabled?: boolean;
60
+ /** Called with the failure when the trigger rejects. The error is also surfaced via `useCheckout`. */
61
+ onError?: (error: Error) => void;
62
+ title?: string;
63
+ }
64
+ interface CheckoutButtonProps extends RedirectButtonOwnProps {
65
+ /** Calls the app's checkout action and resolves the hosted-checkout `{ url }`. */
66
+ onCheckout: RedirectTrigger;
67
+ }
68
+ interface CustomerPortalButtonProps extends RedirectButtonOwnProps {
69
+ /** Calls the app's portal action and resolves the customer-portal `{ url }`. */
70
+ onPortal: RedirectTrigger;
71
+ }
72
+ /**
73
+ * Button that starts a hosted checkout. On click it awaits `onCheckout` (a thunk
74
+ * that calls the app's checkout action) and redirects to the returned URL,
75
+ * disabling itself while the request is in flight.
76
+ */
77
+ declare const CheckoutButton: ({ onCheckout, ...rest }: CheckoutButtonProps) => ReactNode;
78
+ /**
79
+ * Button that opens the provider's customer portal. On click it awaits
80
+ * `onPortal` (a thunk that calls the app's portal action) and redirects to the
81
+ * returned URL, disabling itself while the request is in flight.
82
+ */
83
+ declare const CustomerPortalButton: ({ onPortal, ...rest }: CustomerPortalButtonProps) => ReactNode;
84
+ export { CheckoutButton, type CheckoutButtonProps, CustomerPortalButton, type CustomerPortalButtonProps, type RedirectTarget, type RedirectTrigger, type Subscription, type UseCheckoutResult, useCheckout };
@@ -0,0 +1,84 @@
1
+ import { ReactNode } from 'react';
2
+ /**
3
+ * Client-safe mirror of `@lunora/payment`'s `Subscription`. Re-declared here
4
+ * (rather than imported) so this React entry never pulls in the server-only
5
+ * `@lunora/payment` module graph — the kit stays React + DOM only. Keep this in
6
+ * sync with `packages/payment/src/types.ts`.
7
+ */
8
+ interface Subscription {
9
+ readonly cancelAtPeriodEnd: boolean;
10
+ readonly createdAt: number;
11
+ readonly currentPeriodEnd?: number;
12
+ readonly id: string;
13
+ readonly priceId: string;
14
+ readonly provider: "polar" | "stripe";
15
+ readonly quantity: number;
16
+ readonly referenceId: string;
17
+ readonly state: "active" | "canceled" | "past_due" | "paused" | "trialing";
18
+ readonly updatedAt: number;
19
+ }
20
+ /** The `{ url }` shape every checkout/portal trigger resolves to. */
21
+ interface RedirectTarget {
22
+ readonly url: string;
23
+ }
24
+ /** A thunk the app supplies that calls its own Lunora action and resolves a redirect URL. */
25
+ type RedirectTrigger = () => Promise<RedirectTarget>;
26
+ interface UseCheckoutResult {
27
+ /** Run the trigger and redirect the browser to the resolved URL. Resolves once the redirect is issued; rejects on failure. */
28
+ checkout: () => Promise<void>;
29
+ /** The most recent failure, or `undefined`. */
30
+ error: Error | undefined;
31
+ /** `true` while the trigger is in flight (before the redirect is issued). */
32
+ pending: boolean;
33
+ }
34
+ /**
35
+ * Decoupled redirect-on-resolve primitive shared by `CheckoutButton` and
36
+ * `CustomerPortalButton`. The app passes a `trigger` thunk that calls its own
37
+ * Lunora action (the one wrapping `LunoraPayment.createCheckout` /
38
+ * `createPortalSession`) and resolves `{ url }`; this hook awaits it, flips
39
+ * `pending`, surfaces any `error`, and on success navigates via
40
+ * `location.assign(url)`.
41
+ *
42
+ * Mirrors Convex's `CheckoutLink` / `CustomerPortalLink` flow (trigger an action
43
+ * that returns a URL, then redirect) while staying agnostic of the app's
44
+ * function names.
45
+ */
46
+ declare const useCheckout: (trigger: RedirectTrigger) => UseCheckoutResult;
47
+ /**
48
+ * Presentational props shared by the redirect buttons. Kept to a curated set
49
+ * (rather than spreading arbitrary button attributes) so the component stays
50
+ * within the repo's `react/jsx-props-no-spreading` rule while covering the
51
+ * common styling / accessibility hooks.
52
+ */
53
+ interface RedirectButtonOwnProps {
54
+ /** Accessible label when the visible `children` are icon-only. */
55
+ "aria-label"?: string;
56
+ children?: ReactNode;
57
+ className?: string;
58
+ /** Force-disable the control regardless of pending state. */
59
+ disabled?: boolean;
60
+ /** Called with the failure when the trigger rejects. The error is also surfaced via `useCheckout`. */
61
+ onError?: (error: Error) => void;
62
+ title?: string;
63
+ }
64
+ interface CheckoutButtonProps extends RedirectButtonOwnProps {
65
+ /** Calls the app's checkout action and resolves the hosted-checkout `{ url }`. */
66
+ onCheckout: RedirectTrigger;
67
+ }
68
+ interface CustomerPortalButtonProps extends RedirectButtonOwnProps {
69
+ /** Calls the app's portal action and resolves the customer-portal `{ url }`. */
70
+ onPortal: RedirectTrigger;
71
+ }
72
+ /**
73
+ * Button that starts a hosted checkout. On click it awaits `onCheckout` (a thunk
74
+ * that calls the app's checkout action) and redirects to the returned URL,
75
+ * disabling itself while the request is in flight.
76
+ */
77
+ declare const CheckoutButton: ({ onCheckout, ...rest }: CheckoutButtonProps) => ReactNode;
78
+ /**
79
+ * Button that opens the provider's customer portal. On click it awaits
80
+ * `onPortal` (a thunk that calls the app's portal action) and redirects to the
81
+ * returned URL, disabling itself while the request is in flight.
82
+ */
83
+ declare const CustomerPortalButton: ({ onPortal, ...rest }: CustomerPortalButtonProps) => ReactNode;
84
+ export { CheckoutButton, type CheckoutButtonProps, CustomerPortalButton, type CustomerPortalButtonProps, type RedirectTarget, type RedirectTrigger, type Subscription, type UseCheckoutResult, useCheckout };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/react",
3
- "version": "1.0.0-alpha.71",
3
+ "version": "1.0.0-alpha.73",
4
4
  "description": "React hooks for Lunora: useQuery, useMutation, useSubscription, and useAuth",
5
5
  "keywords": [
6
6
  "cloudflare",
@@ -39,6 +39,10 @@
39
39
  "types": "./dist/index.d.ts",
40
40
  "import": "./dist/index.mjs"
41
41
  },
42
+ "./payment": {
43
+ "types": "./dist/payment.d.ts",
44
+ "import": "./dist/payment.mjs"
45
+ },
42
46
  "./server": {
43
47
  "types": "./dist/server.d.ts",
44
48
  "import": "./dist/server.mjs"
@@ -53,9 +57,9 @@
53
57
  "access": "public"
54
58
  },
55
59
  "dependencies": {
56
- "@lunora/client": "1.0.0-alpha.66",
57
- "@lunora/errors": "1.0.0-alpha.26",
58
- "@lunora/ratelimit": "1.0.0-alpha.30",
60
+ "@lunora/client": "1.0.0-alpha.68",
61
+ "@lunora/errors": "1.0.0-alpha.27",
62
+ "@lunora/ratelimit": "1.0.0-alpha.32",
59
63
  "@visulima/storage-client": "1.0.2"
60
64
  },
61
65
  "peerDependencies": {
@@ -1 +0,0 @@
1
- import{k as a}from"./query-key-C6iUhRuD.mjs";class p{constructor(e){this.client=e}client;entries=new Map;keyOf(e){return a(e)}attach(e,n,l,u,f,h={}){const i=a(n);let r=this.entries.get(i);if(!r){r={pollTimer:void 0,refCount:0,unsubscribe:void 0},this.entries.set(i,r);try{r.unsubscribe=this.client.subscribe(l,u,t=>{e.setQueryData(n,t)},{shardKey:f})}catch{r.pollTimer=setInterval(()=>{e.invalidateQueries({queryKey:n}).catch(()=>{})},h.pollIntervalMs??5e3)}}r.refCount+=1;let o=!1;return()=>{if(o)return;o=!0;const t=this.entries.get(i);t&&(t.refCount-=1,t.refCount<=0&&(t.unsubscribe?.(),t.pollTimer&&clearInterval(t.pollTimer),this.entries.delete(i)))}}}const c=new WeakMap,g=s=>{let e=c.get(s);return e||(e=new p(s),c.set(s,e)),e};export{g};
@@ -1,2 +0,0 @@
1
- 'use client';
2
- import{c as rt}from"react/compiler-runtime";import{reconcileOptimistic as H,maxSeq as J}from"@lunora/client";import{useState as ct,useRef as it}from"react";import{useMutation as Y}from"./useMutation-BnKec7bE.mjs";import{useStream as lt}from"./useStream-CmGOT0qj.mjs";import L from"./useSubscription-BXhI6J-f.mjs";const ut={__lunoraRef:""},mt={__lunoraRef:""},ft=[],St=i=>{const t=rt(47),{api:E,cancel:u,limit:m,send:Q,sendArgs:b,stream:f,threadKey:e}=i;let d;t[0]!==m||t[1]!==e?(d=m===void 0?{key:e}:{key:e,limit:m},t[0]=m,t[1]=e,t[2]=d):d=t[2];const V=d,{data:W}=L(E.agents.agentMessages,V);let p;t[3]!==e?(p={key:e},t[3]=e,t[4]=p):p=t[4];const{data:X}=L(E.agents.agentThread,p);let g;t[5]!==f||t[6]!==e?(g=f===void 0?"skip":{key:e},t[5]=f,t[6]=e,t[7]=g):g=t[7];const Z=g,{chunks:w}=lt(f??mt,Z),tt=Y(Q),et=Y(u??ut),st=Y(E.agents.agentResolveApproval);let h;t[8]===Symbol.for("react.memo_cache_sentinel")?(h=[],t[8]=h):h=t[8];const[O,z]=ct(h),T=it(0),B=X,I=B?.status,a=B?.instanceId,n=W??ft;let _;if(t[9]!==n||t[10]!==O){const s=H(O,n),o=J(n);_=s.length===0?n:[...n,...s.map((r,P)=>({content:r.content,optimistic:!0,role:"user",seq:o+1+P}))],t[9]=n,t[10]=O,t[11]=_}else _=t[11];const q=_;let v;t[12]!==n?(v=n.filter(dt),t[12]=n,t[13]=v):v=t[13];const l=v.length;let y;if(t[14]!==l||t[15]!==w||t[16]!==e){let s;t[18]!==l||t[19]!==e?(s=o=>o.kind!=="progress"&&o.threadKey===e&&o.turn>=l,t[18]=l,t[19]=e,t[20]=s):s=t[20],y=w.filter(s).map(pt).join(""),t[14]=l,t[15]=w,t[16]=e,t[17]=y}else y=t[17];const j=y,{mutate:C}=tt,{mutate:D}=et,{mutate:N}=st;let M;t[21]!==n||t[22]!==b||t[23]!==C||t[24]!==e?(M=async(s,o)=>{const r=T.current;T.current=T.current+1;const P=J(n);z(U=>[...H(U,n),{content:s,id:r,maxDurableSeqAtSend:P}]);try{await C({input:s,threadKey:e,...b,...o})}catch(U){const nt=U;throw z(ot=>ot.filter(at=>at.id!==r)),nt}},t[21]=n,t[22]=b,t[23]=C,t[24]=e,t[25]=M):M=t[25];const F=M;let S;t[26]!==a||t[27]!==N||t[28]!==e?(S=async(s,o,r)=>{if(a===void 0)throw new Error(`useAgentChat: cannot ${s} — no in-flight run (thread has no instanceId)`);await N({decision:s,instanceId:a,threadKey:e,toolCallId:o,...r===void 0?{}:{note:r}})},t[26]=a,t[27]=N,t[28]=e,t[29]=S):S=t[29];const c=S;let R;t[30]!==c?(R=(s,o)=>c("approve",s,o),t[30]=c,t[31]=R):R=t[31];const K=R;let A;t[32]!==c?(A=(s,o)=>c("reject",s,o),t[32]=c,t[33]=A):A=t[33];const $=A;let k;t[34]!==D||t[35]!==u||t[36]!==a||t[37]!==e?(k=async()=>{u===void 0||a===void 0||await D({instanceId:a,threadKey:e})},t[34]=D,t[35]=u,t[36]=a,t[37]=e,t[38]=k):k=t[38];const G=k;let x;return t[39]!==K||t[40]!==G||t[41]!==q||t[42]!==$||t[43]!==F||t[44]!==I||t[45]!==j?(x={approve:K,cancel:G,messages:q,reject:$,send:F,status:I,streamingText:j},t[39]=K,t[40]=G,t[41]=q,t[42]=$,t[43]=F,t[44]=I,t[45]=j,t[46]=x):x=t[46],x};function dt(i){return i.role==="assistant"}function pt(i){return i.text}export{St as useAgentChat};
@@ -1,2 +0,0 @@
1
- 'use client';
2
- import{useState as v,useRef as d,useEffect as m}from"react";import{useLunora as K}from"./LunoraProvider-DC06S-p1.mjs";import{s as g}from"./stable-key-B_BlboiY.mjs";const h="__lunora_flags__:eval",R=t=>{const e=typeof t;return e==="boolean"||e==="number"||e==="string"?e:"object"},$={__lunoraRef:h},S=(t,e,r)=>{const p=K(),[i,s]=v(e),c=R(e),o=r===void 0?"":g(r),u=`${t}::${c}::${o}`,l=d(u);l.current!==u&&(l.current=u,s(e));const a=d({context:r,defaultValue:e});return m(()=>{a.current={context:r,defaultValue:e}}),m(()=>{let f=!1;const{context:y,defaultValue:b}=a.current;s(b);let n;try{n=p.subscribe($,{context:y,default:b,key:t,type:c},_=>{f||s(_)})}catch{return()=>{f=!0}}return()=>{f=!0,n()}},[p,t,c,o]),i},j=(t,e)=>{const r=K(),[p,i]=v(t),s=g(t),c=e===void 0?"":g(e),o=`${s}::${c}`,u=d(o);u.current!==o&&(u.current=o,i(t));const l=d({context:e,flags:t});return m(()=>{l.current={context:e,flags:t}}),m(()=>{let a=!1;const{context:f,flags:y}=l.current;i(y);const b=[];for(const[n,_]of Object.entries(y))try{b.push(r.subscribe($,{context:f,default:_,key:n,type:R(_)},C=>{a||i(F=>({...F,[n]:C}))}))}catch{}return()=>{a=!0;for(const n of b)n()}},[r,s,c]),p};export{S as useFlag,j as useFlags};
@@ -1,2 +0,0 @@
1
- 'use client';
2
- import{c as R}from"react/compiler-runtime";import{useQueryClient as q,useQuery as K}from"@tanstack/react-query";import{useState as b,useEffect as f}from"react";import{g as k}from"./cache-I4w1R5RF.mjs";import{useLunora as v}from"./LunoraProvider-DC06S-p1.mjs";import{l as N,s as S}from"./query-key-C6iUhRuD.mjs";const x=(o,m,p)=>{const e=R(9),Q=p===void 0?{}:p,t=v(),a=q(),{shardKey:i}=Q,r=m==="skip",n=r?{}:m,d=N(o,n,i),[s,h]=b(t.isReady);let u,y;e[0]!==t||e[1]!==s?(u=()=>{s||t.whenReady().then(()=>{h(!0)})},y=[t,s],e[0]=t,e[1]=s,e[2]=u,e[3]=y):(u=e[2],y=e[3]),f(u,y);const g=r?void 0:t.peekHydratedQuery(o.__lunoraRef,n,i),{data:I}=K({enabled:!r&&s,initialData:g,queryFn:()=>t.query(o,n,{shardKey:i}),queryKey:d,staleTime:Number.POSITIVE_INFINITY}),l=S(d);let c;return e[4]!==t||e[5]!==a||e[6]!==r||e[7]!==l?(c=[t,a,l,r],e[4]=t,e[5]=a,e[6]=r,e[7]=l,e[8]=c):c=e[8],f(()=>r?T:k(t).attach(a,d,o,n,i),c),r?void 0:I};function T(){}export{x as default};