better-convex 0.6.4 → 0.7.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 (47) hide show
  1. package/dist/aggregate/index.d.ts +388 -0
  2. package/dist/aggregate/index.js +37 -0
  3. package/dist/{auth-client → auth/client}/index.js +1 -1
  4. package/dist/auth/http/index.d.ts +63 -0
  5. package/dist/auth/http/index.js +429 -0
  6. package/dist/auth/index.d.ts +18991 -175
  7. package/dist/auth/index.js +373 -686
  8. package/dist/{auth-nextjs → auth/nextjs}/index.d.ts +3 -5
  9. package/dist/{auth-nextjs → auth/nextjs}/index.js +3 -5
  10. package/dist/{caller-factory-B1FvYSKr.js → caller-factory-Dmgv8MLS.js} +15 -12
  11. package/dist/cli.mjs +2601 -13
  12. package/dist/codegen-Cz1idI3-.mjs +969 -0
  13. package/dist/{create-schema-orm-DplxTtYj.js → create-schema-orm-69VF4CFV.js} +4 -3
  14. package/dist/crpc/index.d.ts +2 -2
  15. package/dist/crpc/index.js +3 -3
  16. package/dist/{http-types-BRLY10NX.d.ts → http-types-BCf2wCgp.d.ts} +25 -25
  17. package/dist/meta-utils-DDVYp9Xf.js +117 -0
  18. package/dist/orm/index.d.ts +4 -3012
  19. package/dist/orm/index.js +9631 -2
  20. package/dist/{index-BQkhP2ny.d.ts → procedure-caller-CcjtUFvL.d.ts} +211 -74
  21. package/dist/query-context-BDSis9rT.js +1518 -0
  22. package/dist/query-context-DGExXZIV.d.ts +42 -0
  23. package/dist/react/index.d.ts +31 -35
  24. package/dist/react/index.js +145 -58
  25. package/dist/rsc/index.d.ts +4 -7
  26. package/dist/rsc/index.js +14 -10
  27. package/dist/runtime-B9xQFY8W.js +2280 -0
  28. package/dist/server/index.d.ts +3 -4
  29. package/dist/server/index.js +384 -10
  30. package/dist/{types-o-5rYcTr.d.ts → types-CIBGEYXq.d.ts} +4 -3
  31. package/dist/types-DgwvxKbT.d.ts +4 -0
  32. package/dist/watcher.mjs +8 -8
  33. package/dist/where-clause-compiler-CRP-i1Qa.d.ts +3463 -0
  34. package/package.json +14 -10
  35. package/dist/codegen-DkpPBVPn.mjs +0 -189
  36. package/dist/context-utils-DSuX99Da.d.ts +0 -17
  37. package/dist/meta-utils-DCpLSBWB.js +0 -41
  38. package/dist/orm-BKc-pwj_.js +0 -8821
  39. /package/dist/{auth-client → auth/client}/index.d.ts +0 -0
  40. /package/dist/{auth-config → auth/config}/index.d.ts +0 -0
  41. /package/dist/{auth-config → auth/config}/index.js +0 -0
  42. /package/dist/{create-schema-DhWXOhnU.js → create-schema-BdZOL6ns.js} +0 -0
  43. /package/dist/{customFunctions-C1okqCzL.js → customFunctions-CZnCwoR3.js} +0 -0
  44. /package/dist/{error-BZUhlhYz.js → error-Be4OcwwD.js} +0 -0
  45. /package/dist/{query-options-BL1Q0X7q.js → query-options-B0c1b6pZ.js} +0 -0
  46. /package/dist/{transformer-CTNSPjwp.js → transformer-Dh0w2py0.js} +0 -0
  47. /package/dist/{types-jftzhhuc.d.ts → types-DwGkkq2s.d.ts} +0 -0
@@ -0,0 +1,42 @@
1
+ import { DocumentByName, GenericQueryCtx, TableNamesInDataModel } from "convex/server";
2
+
3
+ //#region src/orm/query-context.d.ts
4
+ type InferCtxDataModel<TCtx extends GenericQueryCtx<any>> = TCtx extends GenericQueryCtx<infer DataModel> ? DataModel : never;
5
+ type DocByCtx<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = DocumentByName<InferCtxDataModel<TCtx>, TableName>;
6
+ type QueryCtxWithOptionalOrmQueryTable<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = TCtx & {
7
+ orm?: {
8
+ query?: { [K in TableName]?: {
9
+ findFirst?: (...args: any[]) => unknown;
10
+ } };
11
+ };
12
+ };
13
+ type QueryCtxWithOrmQueryTable<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = TCtx & {
14
+ orm: {
15
+ query: { [K in TableName]-?: {
16
+ findFirst: (...args: any[]) => unknown;
17
+ } };
18
+ };
19
+ };
20
+ type OrmQueryByCtx<TCtx extends GenericQueryCtx<any>> = TCtx extends {
21
+ orm: {
22
+ query: infer TQuery;
23
+ };
24
+ } ? TQuery : never;
25
+ type OrmQueryEntryByCtx<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = TableName extends keyof OrmQueryByCtx<TCtx> ? NonNullable<OrmQueryByCtx<TCtx>[TableName]> : never;
26
+ type HasOrmFindFirstByCtx<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = [OrmQueryEntryByCtx<TCtx, TableName>] extends [never] ? false : OrmQueryEntryByCtx<TCtx, TableName> extends {
27
+ findFirst: (...args: any[]) => unknown;
28
+ } ? true : false;
29
+ type QueryCtxWithPreferredOrmQueryTable<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = TCtx extends {
30
+ orm: unknown;
31
+ } ? HasOrmFindFirstByCtx<TCtx, TableName> extends true ? TCtx : never : TCtx;
32
+ type OrmQueryRowByCtx<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = OrmQueryEntryByCtx<TCtx, TableName> extends {
33
+ _: {
34
+ baseResult: infer TResult;
35
+ };
36
+ } ? TResult : never;
37
+ type LookupByIdResultByCtx<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>> = (TCtx extends {
38
+ orm: unknown;
39
+ } ? OrmQueryRowByCtx<TCtx, TableName> : DocByCtx<TCtx, TableName>) | null;
40
+ declare function getByIdWithOrmQueryFallback<TCtx extends GenericQueryCtx<any>, TableName extends TableNamesInDataModel<InferCtxDataModel<TCtx>>>(ctx: QueryCtxWithPreferredOrmQueryTable<TCtx, TableName>, tableName: TableName, id: DocByCtx<TCtx, TableName>['_id']): Promise<LookupByIdResultByCtx<TCtx, TableName>>;
41
+ //#endregion
42
+ export { QueryCtxWithPreferredOrmQueryTable as a, QueryCtxWithOrmQueryTable as i, LookupByIdResultByCtx as n, getByIdWithOrmQueryFallback as o, QueryCtxWithOptionalOrmQueryTable as r, DocByCtx as t };
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { ConvexProvider, ConvexProviderWithAuth as ConvexProviderWithAuth$1, ConvexReactClient, ConvexReactClient as ConvexReactClient$1, ConvexReactClientOptions, Watch, WatchQueryOptions, useConvex } from "convex/react";
3
- import * as react0 from "react";
3
+ import * as react from "react";
4
4
  import { ReactNode } from "react";
5
5
  import * as jotai_x0 from "jotai-x";
6
6
  import * as react_jsx_runtime0 from "react/jsx-runtime";
@@ -80,7 +80,7 @@ declare function createAuthMutations<T extends AuthClient>(authClient: T): AuthM
80
80
  type FetchAccessTokenFn = (args: {
81
81
  forceRefreshToken: boolean;
82
82
  }) => Promise<string | null>;
83
- declare const FetchAccessTokenContext: react0.Context<FetchAccessTokenFn | null>;
83
+ declare const FetchAccessTokenContext: react.Context<FetchAccessTokenFn | null>;
84
84
  /** Get fetchAccessToken from context (available immediately, no race condition) */
85
85
  declare const useFetchAccessToken: () => FetchAccessTokenFn | null;
86
86
  type ConvexAuthResult = {
@@ -102,7 +102,7 @@ type AuthStoreState = {
102
102
  };
103
103
  /** Decode JWT expiration (ms timestamp) from token */
104
104
  declare function decodeJwtExp(token: string): number | null;
105
- declare const AuthProvider: react0.FC<jotai_x0.ProviderProps<{
105
+ declare const AuthProvider: react.FC<jotai_x0.ProviderProps<{
106
106
  onMutationUnauthorized: () => void;
107
107
  onQueryUnauthorized: (info: {
108
108
  queryName: string;
@@ -197,33 +197,33 @@ declare function MaybeAuthenticated({
197
197
  children
198
198
  }: {
199
199
  children: React.ReactNode;
200
- }): react0.ReactNode;
200
+ }): react.ReactNode;
201
201
  /** Render children only when authenticated (server-verified) */
202
202
  declare function Authenticated({
203
203
  children
204
204
  }: {
205
205
  children: React.ReactNode;
206
- }): react0.ReactNode;
206
+ }): react.ReactNode;
207
207
  /** Render children only when maybe not auth (optimistic) */
208
208
  declare function MaybeUnauthenticated({
209
209
  children
210
210
  }: {
211
211
  children: React.ReactNode;
212
- }): react0.ReactNode;
212
+ }): react.ReactNode;
213
213
  /** Render children only when not authenticated (server-verified) */
214
214
  declare function Unauthenticated({
215
215
  children
216
216
  }: {
217
217
  children: React.ReactNode;
218
- }): react0.ReactNode;
218
+ }): react.ReactNode;
219
219
  //#endregion
220
220
  //#region src/crpc/transformer.d.ts
221
221
  /**
222
222
  * Generic transformer contract (mirrors tRPC shape).
223
223
  */
224
224
  interface DataTransformer {
225
- serialize(object: any): any;
226
225
  deserialize(object: any): any;
226
+ serialize(object: any): any;
227
227
  }
228
228
  /**
229
229
  * Separate input/output transformers.
@@ -241,15 +241,17 @@ type DataTransformerOptions = CombinedDataTransformer | DataTransformer;
241
241
  interface ConvexQueryClientOptions extends ConvexReactClientOptions {
242
242
  /** Auth store for checking auth state in queryFn */
243
243
  authStore?: AuthStore;
244
- /** TanStack QueryClient. Can also be set later via .connect(queryClient) */
245
- queryClient?: QueryClient;
246
- /** Custom fetch for SSR. Avoid bundling on client. */
247
- serverFetch?: typeof globalThis.fetch;
248
244
  /**
249
245
  * Opt out of consistent SSR queries for faster performance.
250
246
  * Trade-off: queries may return results from different timestamps.
251
247
  */
252
248
  dangerouslyUseInconsistentQueriesDuringSSR?: boolean;
249
+ /** TanStack QueryClient. Can also be set later via .connect(queryClient) */
250
+ queryClient?: QueryClient;
251
+ /** Custom fetch for SSR. Avoid bundling on client. */
252
+ serverFetch?: typeof globalThis.fetch;
253
+ /** Optional payload transformer (always composed with built-in Date support). */
254
+ transformer?: DataTransformerOptions;
253
255
  /**
254
256
  * Delay in ms before unsubscribing when a query has no observers.
255
257
  * Prevents wasteful unsubscribe/subscribe cycles from React StrictMode
@@ -257,8 +259,6 @@ interface ConvexQueryClientOptions extends ConvexReactClientOptions {
257
259
  * @default 3000
258
260
  */
259
261
  unsubscribeDelay?: number;
260
- /** Optional payload transformer (always composed with built-in Date support). */
261
- transformer?: DataTransformerOptions;
262
262
  }
263
263
  /**
264
264
  * Bridges TanStack Query with Convex real-time subscriptions.
@@ -466,8 +466,8 @@ type UnsetMarker = {
466
466
  //#region src/server/http-types.d.ts
467
467
  type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
468
468
  interface HttpRouteDefinition<TMethod extends HttpMethod = HttpMethod> {
469
- path: string;
470
469
  method: TMethod;
470
+ path: string;
471
471
  pathParamNames: string[];
472
472
  usePathPrefix: boolean;
473
473
  }
@@ -497,11 +497,11 @@ interface HttpRouterRecord {
497
497
  * Router definition - stores both flat procedures and hierarchical record
498
498
  */
499
499
  interface HttpRouterDef<TRecord extends HttpRouterRecord> {
500
- router: true;
501
500
  /** Flat map with dot-notation keys (e.g., "todos.get") for lookup */
502
501
  procedures: Record<string, HttpProcedure>;
503
502
  /** Hierarchical structure for type inference */
504
503
  record: TRecord;
504
+ router: true;
505
505
  }
506
506
  /**
507
507
  * HTTP Router - like tRPC's BuiltRouter
@@ -541,6 +541,7 @@ type FnMeta$1 = {
541
541
  rateLimit?: string;
542
542
  type?: 'query' | 'mutation' | 'action';
543
543
  limit?: number;
544
+ [key: string]: unknown;
544
545
  };
545
546
  /** Metadata for paginated functions (limit is required) */
546
547
  type PaginatedFnMeta = Omit<FnMeta$1, 'limit'> & {
@@ -708,7 +709,7 @@ type VanillaAction<T extends FunctionReference<'action'>> = {
708
709
  * await client.user.update.mutate({ id, name: 'test' });
709
710
  * ```
710
711
  */
711
- type VanillaCRPCClient<TApi> = { [K in keyof TApi]: TApi[K] extends FunctionReference<'query'> ? VanillaQuery<TApi[K]> : TApi[K] extends FunctionReference<'mutation'> ? VanillaMutation<TApi[K]> : TApi[K] extends FunctionReference<'action'> ? VanillaAction<TApi[K]> : TApi[K] extends Record<string, unknown> ? VanillaCRPCClient<TApi[K]> : never };
712
+ type VanillaCRPCClient<TApi> = { [K in keyof TApi as K extends string ? K extends `_${string}` ? never : K : K]: TApi[K] extends FunctionReference<'query'> ? VanillaQuery<TApi[K]> : TApi[K] extends FunctionReference<'mutation'> ? VanillaMutation<TApi[K]> : TApi[K] extends FunctionReference<'action'> ? VanillaAction<TApi[K]> : TApi[K] extends Record<string, unknown> ? VanillaCRPCClient<TApi[K]> : never };
712
713
  /**
713
714
  * Recursively decorates all procedures in a Convex API object.
714
715
  *
@@ -728,7 +729,7 @@ type VanillaCRPCClient<TApi> = { [K in keyof TApi]: TApi[K] extends FunctionRefe
728
729
  */
729
730
  /** Check if a type has cursor key (pagination detection) */
730
731
  type IsPaginated<T> = 'cursor' extends keyof T ? true : false;
731
- type CRPCClient<TApi> = { [K in keyof TApi]: TApi[K] extends FunctionReference<'query'> ? IsPaginated<FunctionArgs<TApi[K]>> extends true ? DecorateQuery<TApi[K]> & DecorateInfiniteQuery<TApi[K]> : DecorateQuery<TApi[K]> : TApi[K] extends FunctionReference<'mutation'> ? DecorateMutation<TApi[K]> : TApi[K] extends FunctionReference<'action'> ? DecorateAction<TApi[K]> : TApi[K] extends Record<string, unknown> ? CRPCClient<TApi[K]> : never };
732
+ type CRPCClient<TApi> = { [K in keyof TApi as K extends string ? K extends `_${string}` ? never : K : K]: TApi[K] extends FunctionReference<'query'> ? IsPaginated<FunctionArgs<TApi[K]>> extends true ? DecorateQuery<TApi[K]> & DecorateInfiniteQuery<TApi[K]> : DecorateQuery<TApi[K]> : TApi[K] extends FunctionReference<'mutation'> ? DecorateMutation<TApi[K]> : TApi[K] extends FunctionReference<'action'> ? DecorateAction<TApi[K]> : TApi[K] extends Record<string, unknown> ? CRPCClient<TApi[K]> : never };
732
733
  //#endregion
733
734
  //#region src/react/http-proxy.d.ts
734
735
  type HttpRouteInfo = {
@@ -865,8 +866,8 @@ type HttpCRPCClientFromRouter<TRouter extends CRPCHttpRouter<any>> = HttpCRPCCli
865
866
  interface HttpProxyOptions<TRoutes extends HttpRouteMap> {
866
867
  /** Base URL for the Convex HTTP API (e.g., https://your-site.convex.site) */
867
868
  convexSiteUrl: string;
868
- /** Runtime route definitions (from codegen httpRoutes) */
869
- routes: TRoutes;
869
+ /** Custom fetch function (defaults to global fetch) */
870
+ fetch?: typeof fetch;
870
871
  /** Default headers or async function returning headers (for auth tokens) */
871
872
  headers?: {
872
873
  [key: string]: string | undefined;
@@ -875,10 +876,10 @@ interface HttpProxyOptions<TRoutes extends HttpRouteMap> {
875
876
  } | Promise<{
876
877
  [key: string]: string | undefined;
877
878
  }>);
878
- /** Custom fetch function (defaults to global fetch) */
879
- fetch?: typeof fetch;
880
879
  /** Error handler called on HTTP errors */
881
880
  onError?: (error: HttpClientError) => void;
881
+ /** Runtime route definitions (from codegen httpRoutes) */
882
+ routes: TRoutes;
882
883
  /** Optional payload transformer (always composed with built-in Date support). */
883
884
  transformer?: DataTransformerOptions;
884
885
  }
@@ -930,8 +931,7 @@ type CRPCHttpOptions = {
930
931
  onError?: (error: HttpClientError) => void;
931
932
  };
932
933
  type CreateCRPCContextOptions<TApi> = {
933
- api: TApi;
934
- meta: Meta; /** Optional payload transformer (always composed with built-in Date support). */
934
+ api: TApi; /** Optional payload transformer (always composed with built-in Date support). */
935
935
  transformer?: DataTransformerOptions;
936
936
  } & Partial<CRPCHttpOptions>;
937
937
  /**
@@ -944,23 +944,18 @@ type ExtractHttpRouter<TApi> = TApi extends {
944
944
  /**
945
945
  * Create CRPC context, provider, and hooks for a Convex API.
946
946
  *
947
- * @param options - Configuration object containing api, meta, and optional HTTP settings
947
+ * @param options - Configuration object containing api and optional HTTP settings
948
948
  * @returns Object with CRPCProvider, useCRPC, and useCRPCClient
949
949
  *
950
950
  * @example
951
951
  * ```tsx
952
952
  * // lib/crpc.ts
953
953
  * import { api } from '@convex/api';
954
- * import { meta } from '@convex/meta';
955
954
  * import { createCRPCContext } from 'better-convex/react';
956
955
  *
957
- * // Without HTTP endpoints
958
- * export const { useCRPC } = createCRPCContext({ api, meta });
959
- *
960
- * // With HTTP endpoints (Api = Api & { http?: typeof appRouter })
961
- * export const { useCRPC } = createCRPCContext<Api>({
956
+ * // Works for both regular Convex functions and generated HTTP router types
957
+ * export const { useCRPC } = createCRPCContext({
962
958
  * api,
963
- * meta,
964
959
  * convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_URL!,
965
960
  * });
966
961
  *
@@ -1000,7 +995,7 @@ type FnMeta = {
1000
995
  };
1001
996
  /** Metadata for all functions in a module */
1002
997
  type ModuleMeta = Record<string, FnMeta>;
1003
- /** Metadata for all modules - from generated `@convex/meta` */
998
+ /** Metadata for all modules - from generated `@convex/api` */
1004
999
  type CallerMeta = Record<string, ModuleMeta>;
1005
1000
  //#endregion
1006
1001
  //#region src/react/proxy.d.ts
@@ -1017,9 +1012,10 @@ type CallerMeta = Record<string, ModuleMeta>;
1017
1012
  * @example
1018
1013
  * ```tsx
1019
1014
  * import { api } from '@convex/api';
1020
- * import { meta } from '@convex/meta';
1021
1015
  *
1022
- * const crpc = createCRPCOptionsProxy(api, meta);
1016
+ * // Usually you should use createCRPCContext({ api }) instead.
1017
+ * // createCRPCOptionsProxy is a low-level helper.
1018
+ * const crpc = createCRPCOptionsProxy(api, {} as any);
1023
1019
  *
1024
1020
  * function MyComponent() {
1025
1021
  * const { data } = useQuery(crpc.user.get.queryOptions({ id }));
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { S as isCRPCClientError, _ as useIsAuth, a as FetchAccessTokenContext, b as CRPCClientError, c as Unauthenticated, d as useAuthGuard, f as useAuthState, g as useFetchAccessToken, h as useConvexAuthBridge, i as ConvexProviderWithAuth, l as decodeJwtExp, m as useAuthValue, n as Authenticated, o as MaybeAuthenticated, p as useAuthStore, r as ConvexAuthBridge, s as MaybeUnauthenticated, t as AuthProvider, u as useAuth, v as useMaybeAuth, y as useSafeConvexAuth } from "../auth-store-DHapqI5u.js";
2
+ import { S as isCRPCClientError, _ as useIsAuth, a as FetchAccessTokenContext, b as CRPCClientError, c as Unauthenticated, d as useAuthGuard, f as useAuthState, g as useFetchAccessToken, h as useConvexAuthBridge, i as ConvexProviderWithAuth, l as decodeJwtExp, m as useAuthValue, n as Authenticated, o as MaybeAuthenticated, p as useAuthStore, r as ConvexAuthBridge, s as MaybeUnauthenticated, t as AuthProvider, u as useAuth, v as useMaybeAuth, x as defaultIsUnauthorized, y as useSafeConvexAuth } from "../auth-store-DHapqI5u.js";
3
3
  import { c } from "react/compiler-runtime";
4
4
  import { ConvexProvider, ConvexReactClient, ConvexReactClient as ConvexReactClient$1, useAction, useConvex, useMutation } from "convex/react";
5
5
  import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
@@ -9,6 +9,122 @@ import { getFunctionName } from "convex/server";
9
9
  import { ConvexHttpClient } from "convex/browser";
10
10
  import { convexToJson } from "convex/values";
11
11
 
12
+ //#region src/shared/meta-utils.ts
13
+ const metaCache = /* @__PURE__ */ new WeakMap();
14
+ const nonMetaLeafKeys = new Set(["functionRef", "ref"]);
15
+ function isRecord(value) {
16
+ return typeof value === "object" && value !== null;
17
+ }
18
+ function isFunctionType(value) {
19
+ return value === "query" || value === "mutation" || value === "action";
20
+ }
21
+ function isMetaScalar(value) {
22
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
23
+ }
24
+ function extractLeafMeta(value) {
25
+ const type = value.type;
26
+ if (!isFunctionType(type)) return;
27
+ const result = { type };
28
+ for (const [key, entry] of Object.entries(value)) {
29
+ if (key === "type" || nonMetaLeafKeys.has(key) || key.startsWith("_")) continue;
30
+ if (entry === void 0) continue;
31
+ if (isMetaScalar(entry)) result[key] = entry;
32
+ }
33
+ return result;
34
+ }
35
+ function getHttpRoutes(api) {
36
+ const routes = api._http;
37
+ if (!isRecord(routes)) return;
38
+ const normalized = {};
39
+ for (const [routeKey, routeValue] of Object.entries(routes)) {
40
+ if (!isRecord(routeValue)) continue;
41
+ const routePath = routeValue.path;
42
+ const routeMethod = routeValue.method;
43
+ if (typeof routePath === "string" && typeof routeMethod === "string") normalized[routeKey] = {
44
+ path: routePath,
45
+ method: routeMethod
46
+ };
47
+ }
48
+ return normalized;
49
+ }
50
+ /**
51
+ * Build a metadata index from merged API leaves.
52
+ * Supports both generated `api` objects and plain metadata fixtures.
53
+ */
54
+ function buildMetaIndex(api) {
55
+ const cached = metaCache.get(api);
56
+ if (cached) return cached;
57
+ const meta = {};
58
+ const httpRoutes = getHttpRoutes(api);
59
+ if (httpRoutes) meta._http = httpRoutes;
60
+ const walk = (node, path) => {
61
+ for (const [key, value] of Object.entries(node)) {
62
+ if (key.startsWith("_")) continue;
63
+ if (!isRecord(value)) continue;
64
+ const leafMeta = extractLeafMeta(value);
65
+ if (leafMeta) {
66
+ if (path.length === 0) continue;
67
+ const namespace = path.join("/");
68
+ meta[namespace] ??= {};
69
+ meta[namespace][key] = leafMeta;
70
+ continue;
71
+ }
72
+ walk(value, [...path, key]);
73
+ }
74
+ };
75
+ walk(api, []);
76
+ metaCache.set(api, meta);
77
+ return meta;
78
+ }
79
+ /**
80
+ * Get a function reference from the API object by traversing the path.
81
+ */
82
+ function getFuncRef(api, path) {
83
+ let current = api;
84
+ for (const key of path) if (current && typeof current === "object") {
85
+ const next = current[key];
86
+ if (next === void 0) throw new Error(`Invalid path: ${path.join(".")}`);
87
+ current = next;
88
+ } else throw new Error(`Invalid path: ${path.join(".")}`);
89
+ if (current && typeof current === "object") {
90
+ const maybeFunctionRef = current.functionRef;
91
+ if (maybeFunctionRef && typeof maybeFunctionRef === "object") return maybeFunctionRef;
92
+ }
93
+ if (!current || typeof current !== "object") throw new Error(`Invalid function reference at path: ${path.join(".")}`);
94
+ return current;
95
+ }
96
+ /**
97
+ * Get function type from meta using path.
98
+ * Supports nested paths like ['items', 'queries', 'list'] → namespace='items/queries', fn='list'
99
+ *
100
+ * @param path - Path segments like ['todos', 'create'] or ['items', 'queries', 'list']
101
+ * @param meta - The meta object from codegen
102
+ * @returns Function type or 'query' as default
103
+ */
104
+ function getFunctionType(path, source) {
105
+ if (path.length < 2) return "query";
106
+ const meta = buildMetaIndex(source);
107
+ const fnName = path.at(-1);
108
+ const fnType = meta[path.slice(0, -1).join("/")]?.[fnName]?.type;
109
+ if (fnType === "query" || fnType === "mutation" || fnType === "action") return fnType;
110
+ return "query";
111
+ }
112
+ /**
113
+ * Get function metadata from meta using path.
114
+ * Supports nested paths like ['items', 'queries', 'list'] → namespace='items/queries', fn='list'
115
+ *
116
+ * @param path - Path segments like ['todos', 'create'] or ['items', 'queries', 'list']
117
+ * @param meta - The meta object from codegen
118
+ * @returns Function metadata or undefined
119
+ */
120
+ function getFunctionMeta(path, source) {
121
+ if (path.length < 2) return;
122
+ const meta = buildMetaIndex(source);
123
+ const fnName = path.at(-1);
124
+ return meta[path.slice(0, -1).join("/")]?.[fnName];
125
+ }
126
+
127
+ //#endregion
12
128
  //#region src/crpc/http-types.ts
13
129
  /** HTTP client error */
14
130
  var HttpClientError = class extends Error {
@@ -578,46 +694,6 @@ function convexInfiniteQueryOptions(funcRef, args, opts = {}, meta) {
578
694
  /** Symbol key for attaching FunctionReference to options (non-serializable) */
579
695
  const FUNC_REF_SYMBOL = Symbol.for("convex.funcRef");
580
696
 
581
- //#endregion
582
- //#region src/shared/meta-utils.ts
583
- /**
584
- * Get a function reference from the API object by traversing the path.
585
- */
586
- function getFuncRef(api, path) {
587
- let current = api;
588
- for (const key of path) if (current && typeof current === "object") current = current[key];
589
- else throw new Error(`Invalid path: ${path.join(".")}`);
590
- return current;
591
- }
592
- /**
593
- * Get function type from meta using path.
594
- * Supports nested paths like ['items', 'queries', 'list'] → namespace='items/queries', fn='list'
595
- *
596
- * @param path - Path segments like ['todos', 'create'] or ['items', 'queries', 'list']
597
- * @param meta - The meta object from codegen
598
- * @returns Function type or 'query' as default
599
- */
600
- function getFunctionType(path, meta) {
601
- if (path.length < 2) return "query";
602
- const fnName = path.at(-1);
603
- const fnType = meta[path.slice(0, -1).join("/")]?.[fnName]?.type;
604
- if (fnType === "query" || fnType === "mutation" || fnType === "action") return fnType;
605
- return "query";
606
- }
607
- /**
608
- * Get function metadata from meta using path.
609
- * Supports nested paths like ['items', 'queries', 'list'] → namespace='items/queries', fn='list'
610
- *
611
- * @param path - Path segments like ['todos', 'create'] or ['items', 'queries', 'list']
612
- * @param meta - The meta object from codegen
613
- * @returns Function metadata or undefined
614
- */
615
- function getFunctionMeta(path, meta) {
616
- if (path.length < 2) return;
617
- const fnName = path.at(-1);
618
- return meta[path.slice(0, -1).join("/")]?.[fnName];
619
- }
620
-
621
697
  //#endregion
622
698
  //#region src/internal/auth.ts
623
699
  /** Get auth type from meta for a function */
@@ -1221,9 +1297,10 @@ function createRecursiveProxy(api, path, meta, transformer) {
1221
1297
  * @example
1222
1298
  * ```tsx
1223
1299
  * import { api } from '@convex/api';
1224
- * import { meta } from '@convex/meta';
1225
1300
  *
1226
- * const crpc = createCRPCOptionsProxy(api, meta);
1301
+ * // Usually you should use createCRPCContext({ api }) instead.
1302
+ * // createCRPCOptionsProxy is a low-level helper.
1303
+ * const crpc = createCRPCOptionsProxy(api, {} as any);
1227
1304
  *
1228
1305
  * function MyComponent() {
1229
1306
  * const { data } = useQuery(crpc.user.get.queryOptions({ id }));
@@ -1325,23 +1402,18 @@ function useFnMeta() {
1325
1402
  /**
1326
1403
  * Create CRPC context, provider, and hooks for a Convex API.
1327
1404
  *
1328
- * @param options - Configuration object containing api, meta, and optional HTTP settings
1405
+ * @param options - Configuration object containing api and optional HTTP settings
1329
1406
  * @returns Object with CRPCProvider, useCRPC, and useCRPCClient
1330
1407
  *
1331
1408
  * @example
1332
1409
  * ```tsx
1333
1410
  * // lib/crpc.ts
1334
1411
  * import { api } from '@convex/api';
1335
- * import { meta } from '@convex/meta';
1336
1412
  * import { createCRPCContext } from 'better-convex/react';
1337
1413
  *
1338
- * // Without HTTP endpoints
1339
- * export const { useCRPC } = createCRPCContext({ api, meta });
1340
- *
1341
- * // With HTTP endpoints (Api = Api & { http?: typeof appRouter })
1342
- * export const { useCRPC } = createCRPCContext<Api>({
1414
+ * // Works for both regular Convex functions and generated HTTP router types
1415
+ * export const { useCRPC } = createCRPCContext({
1343
1416
  * api,
1344
- * meta,
1345
1417
  * convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_URL!,
1346
1418
  * });
1347
1419
  *
@@ -1356,7 +1428,8 @@ function useFnMeta() {
1356
1428
  * ```
1357
1429
  */
1358
1430
  function createCRPCContext(options) {
1359
- const { api, meta, ...httpOptions } = options;
1431
+ const { api, ...httpOptions } = options;
1432
+ const meta = buildMetaIndex(api);
1360
1433
  const CRPCProxyContext = createContext(null);
1361
1434
  const VanillaClientContext = createContext(null);
1362
1435
  const HttpProxyContext = createContext(void 0);
@@ -2171,9 +2244,11 @@ var ConvexQueryClient = class {
2171
2244
  if (isConvexQuery(queryKey)) {
2172
2245
  const [, funcName, args] = queryKey;
2173
2246
  const wireArgs = this.transformer.input.serialize(args);
2247
+ const skipUnauth = meta?.skipUnauth ?? false;
2174
2248
  if (meta?.authType === "required" && !isServer && this.authStore) {
2175
2249
  const authState = this.getAuthState();
2176
2250
  if (authState && !authState.isLoading && !authState.isAuthenticated) {
2251
+ if (skipUnauth) return null;
2177
2252
  authState.onUnauthorized({ queryName: funcName });
2178
2253
  throw new CRPCClientError({
2179
2254
  code: "UNAUTHORIZED",
@@ -2181,18 +2256,25 @@ var ConvexQueryClient = class {
2181
2256
  });
2182
2257
  }
2183
2258
  }
2184
- if (isServer) {
2185
- if (this.ssrQueryMode === "consistent") return this.transformer.output.deserialize(await this.serverHttpClient.consistentQuery(funcName, wireArgs));
2186
- return this.transformer.output.deserialize(await this.serverHttpClient.query(funcName, wireArgs));
2259
+ try {
2260
+ if (isServer) {
2261
+ if (this.ssrQueryMode === "consistent") return this.transformer.output.deserialize(await this.serverHttpClient.consistentQuery(funcName, wireArgs));
2262
+ return this.transformer.output.deserialize(await this.serverHttpClient.query(funcName, wireArgs));
2263
+ }
2264
+ return this.transformer.output.deserialize(await this.convexClient.query(funcName, wireArgs));
2265
+ } catch (error) {
2266
+ if (skipUnauth && defaultIsUnauthorized(error)) return null;
2267
+ throw error;
2187
2268
  }
2188
- return this.transformer.output.deserialize(await this.convexClient.query(funcName, wireArgs));
2189
2269
  }
2190
2270
  if (isConvexAction(queryKey)) {
2191
2271
  const [, funcName, args] = queryKey;
2192
2272
  const wireArgs = this.transformer.input.serialize(args);
2273
+ const skipUnauth = meta?.skipUnauth ?? false;
2193
2274
  if (meta?.authType === "required" && !isServer && this.authStore) {
2194
2275
  const authState = this.getAuthState();
2195
2276
  if (authState && !authState.isLoading && !authState.isAuthenticated) {
2277
+ if (skipUnauth) return null;
2196
2278
  authState.onUnauthorized({ queryName: funcName });
2197
2279
  throw new CRPCClientError({
2198
2280
  code: "UNAUTHORIZED",
@@ -2200,8 +2282,13 @@ var ConvexQueryClient = class {
2200
2282
  });
2201
2283
  }
2202
2284
  }
2203
- if (isServer) return this.transformer.output.deserialize(await this.serverHttpClient.action(funcName, wireArgs));
2204
- return this.transformer.output.deserialize(await this.convexClient.action(funcName, wireArgs));
2285
+ try {
2286
+ if (isServer) return this.transformer.output.deserialize(await this.serverHttpClient.action(funcName, wireArgs));
2287
+ return this.transformer.output.deserialize(await this.convexClient.action(funcName, wireArgs));
2288
+ } catch (error) {
2289
+ if (skipUnauth && defaultIsUnauthorized(error)) return null;
2290
+ throw error;
2291
+ }
2205
2292
  }
2206
2293
  return otherFetch(context);
2207
2294
  };
@@ -1,6 +1,6 @@
1
- import { C as HttpProcedure, G as DataTransformerOptions, V as UnsetMarker, d as CRPCHttpRouter, p as HttpRouterRecord } from "../http-types-BRLY10NX.js";
2
- import { o as Simplify, r as DistributiveOmit } from "../types-jftzhhuc.js";
3
- import { S as Meta, n as CRPCClient } from "../types-o-5rYcTr.js";
1
+ import { o as Simplify, r as DistributiveOmit } from "../types-DwGkkq2s.js";
2
+ import { C as HttpProcedure, G as DataTransformerOptions, V as UnsetMarker, d as CRPCHttpRouter, p as HttpRouterRecord } from "../http-types-BCf2wCgp.js";
3
+ import { n as CRPCClient } from "../types-CIBGEYXq.js";
4
4
  import { DefaultError, QueryFilters, UseMutationOptions, UseQueryOptions } from "@tanstack/react-query";
5
5
  import { z } from "zod";
6
6
 
@@ -110,7 +110,6 @@ type HttpCRPCClientFromRouter<TRouter extends CRPCHttpRouter<any>> = HttpCRPCCli
110
110
  //#region src/rsc/proxy-server.d.ts
111
111
  type CreateServerCRPCProxyOptions<TApi> = {
112
112
  api: TApi;
113
- meta: Meta;
114
113
  };
115
114
  /**
116
115
  * Extract HTTP router from TApi['http'] if present (optional).
@@ -137,11 +136,9 @@ type ServerCRPCClient<TApi extends Record<string, unknown>> = ExtractHttpRouter<
137
136
  * ```tsx
138
137
  * // src/lib/convex/rsc.tsx
139
138
  * import { api } from '@convex/api';
140
- * import { meta } from '@convex/meta';
141
- * import type { Api } from '@convex/types';
142
139
  *
143
140
  * // Proxy just builds query options - no auth config here
144
- * export const crpc = createServerCRPCProxy<Api>({ api, meta });
141
+ * export const crpc = createServerCRPCProxy({ api });
145
142
  *
146
143
  * // Auth + execution config in QueryClient
147
144
  * const queryClient = new QueryClient({
package/dist/rsc/index.js CHANGED
@@ -1,8 +1,9 @@
1
- import { i as decodeWire, s as getTransformer } from "../transformer-CTNSPjwp.js";
2
- import { n as getFunctionMeta, t as getFuncRef } from "../meta-utils-DCpLSBWB.js";
3
- import { n as convexInfiniteQueryOptions, r as convexQuery } from "../query-options-BL1Q0X7q.js";
4
- import { getFunctionName } from "convex/server";
1
+ import { n as defaultIsUnauthorized } from "../error-Be4OcwwD.js";
2
+ import { n as getFuncRef, r as getFunctionMeta, t as buildMetaIndex } from "../meta-utils-DDVYp9Xf.js";
3
+ import { i as decodeWire, s as getTransformer } from "../transformer-Dh0w2py0.js";
4
+ import { n as convexInfiniteQueryOptions, r as convexQuery } from "../query-options-B0c1b6pZ.js";
5
5
  import { convexToJson } from "convex/values";
6
+ import { getFunctionName } from "convex/server";
6
7
  import { fetchAction, fetchQuery } from "convex/nextjs";
7
8
  import { hashKey } from "@tanstack/react-query";
8
9
 
@@ -105,11 +106,9 @@ function createRecursiveProxy(api, path, meta) {
105
106
  * ```tsx
106
107
  * // src/lib/convex/rsc.tsx
107
108
  * import { api } from '@convex/api';
108
- * import { meta } from '@convex/meta';
109
- * import type { Api } from '@convex/types';
110
109
  *
111
110
  * // Proxy just builds query options - no auth config here
112
- * export const crpc = createServerCRPCProxy<Api>({ api, meta });
111
+ * export const crpc = createServerCRPCProxy({ api });
113
112
  *
114
113
  * // Auth + execution config in QueryClient
115
114
  * const queryClient = new QueryClient({
@@ -125,8 +124,8 @@ function createRecursiveProxy(api, path, meta) {
125
124
  * ```
126
125
  */
127
126
  function createServerCRPCProxy(options) {
128
- const { api, meta } = options;
129
- return createRecursiveProxy(api, [], meta);
127
+ const { api } = options;
128
+ return createRecursiveProxy(api, [], buildMetaIndex(api));
130
129
  }
131
130
 
132
131
  //#endregion
@@ -219,7 +218,12 @@ function getServerQueryClientOptions({ getToken, convexSiteUrl, transformer: tra
219
218
  const authRequired = queryMeta?.authType === "required";
220
219
  if (!token && (skipUnauth || authRequired)) return null;
221
220
  const opts = token ? { token } : void 0;
222
- return transformer.output.deserialize(type === "convexQuery" ? await fetchQuery(funcRef, wireArgs, opts) : await fetchAction(funcRef, wireArgs, opts));
221
+ try {
222
+ return transformer.output.deserialize(type === "convexQuery" ? await fetchQuery(funcRef, wireArgs, opts) : await fetchAction(funcRef, wireArgs, opts));
223
+ } catch (error) {
224
+ if ((skipUnauth || authRequired) && defaultIsUnauthorized(error)) return null;
225
+ throw error;
226
+ }
223
227
  },
224
228
  queryKeyHashFn: createHashFn()
225
229
  } };