kitcn 0.25.7 → 0.26.1
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/CHANGELOG.md +87 -0
- package/dist/aggregate/index.d.ts +1 -1
- package/dist/aggregate/index.js +1 -1
- package/dist/auth/generated/index.d.ts +1 -1
- package/dist/auth/index.d.ts +12 -12
- package/dist/auth/nextjs/index.js +1 -1
- package/dist/auth/start/server/index.d.ts +57 -3
- package/dist/auth/start/server/index.js +118 -15
- package/dist/{caller-factory-Dd3H7j3V.js → caller-factory-D4pz5GcZ.js} +2 -0
- package/dist/cli.mjs +7 -35
- package/dist/{generated-contract-disabled-D_-_iJXw.d.ts → generated-contract-disabled-BEc4d98x.d.ts} +29 -29
- package/dist/orm/aggregate-index/index.js +1 -1
- package/dist/orm/index.d.ts +1 -1
- package/dist/orm/migrations/index.d.ts +1 -1
- package/dist/{runtime-BdqTbgKh.js → runtime-CcOvOf4K.js} +1 -1
- package/dist/server/index.js +1 -1
- package/dist/{where-clause-compiler-CwSrhq51.d.ts → where-clause-compiler-3fKontPx.d.ts} +16 -16
- package/package.json +1 -1
- package/skills/kitcn/references/features/auth-organizations.md +24 -10
- package/skills/kitcn/references/setup/start.md +20 -34
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,92 @@
|
|
|
1
1
|
# kitcn
|
|
2
2
|
|
|
3
|
+
## 0.26.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#392](https://github.com/udecode/kitcn/pull/392) [`72d3270`](https://github.com/udecode/kitcn/commit/72d327003547b1f4097aa72db0d35128ed57b04d) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Patches
|
|
8
|
+
|
|
9
|
+
- Fix a crash when writing an object key that cannot be converted to a string,
|
|
10
|
+
such as one created with `Object.create(null)`, into an `aggregateIndex` or
|
|
11
|
+
`rankIndex`. Once enough keys accumulated to rebalance the index, the write
|
|
12
|
+
failed with `TypeError: Cannot convert object to primitive value` instead of
|
|
13
|
+
succeeding.
|
|
14
|
+
|
|
15
|
+
## 0.26.0
|
|
16
|
+
|
|
17
|
+
### Minor Changes
|
|
18
|
+
|
|
19
|
+
- [#401](https://github.com/udecode/kitcn/pull/401) [`947cd11`](https://github.com/udecode/kitcn/commit/947cd11fe4e461caca9d7cc934ef34d62599e136) Thanks [@MikeyZhang75](https://github.com/MikeyZhang75)! - ## Breaking changes
|
|
20
|
+
|
|
21
|
+
- Require `api` on `convexBetterAuthReactStart`, which now returns `createCaller`
|
|
22
|
+
and `createContext` alongside the auth helpers.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// Before
|
|
26
|
+
export const { handler, getToken } = convexBetterAuthReactStart({
|
|
27
|
+
convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
28
|
+
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// After
|
|
32
|
+
export const { handler, getToken, createCaller, createContext } =
|
|
33
|
+
convexBetterAuthReactStart({
|
|
34
|
+
api,
|
|
35
|
+
convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
36
|
+
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
- Drop `runServerCall` from the TanStack Start scaffold. Call procedures on a
|
|
41
|
+
caller bound once with `createCaller()`.
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// Before
|
|
45
|
+
export function runServerCall<T>(
|
|
46
|
+
fn: (caller: ServerCaller) => Promise<T> | T
|
|
47
|
+
) {
|
|
48
|
+
const caller = createServerCaller();
|
|
49
|
+
return fn(caller);
|
|
50
|
+
}
|
|
51
|
+
await runServerCall((caller) => caller.user.getSessionUser({}));
|
|
52
|
+
|
|
53
|
+
// After
|
|
54
|
+
export const caller = createCaller();
|
|
55
|
+
await caller.user.getSessionUser({});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
- Move TanStack Start JWT caching under `auth.jwtCache`, a boolean.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
// Before
|
|
62
|
+
convexBetterAuthReactStart({
|
|
63
|
+
jwtCache: { enabled: true, isAuthError },
|
|
64
|
+
// ...
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// After
|
|
68
|
+
convexBetterAuthReactStart({
|
|
69
|
+
auth: { jwtCache: true, isUnauthorized: isAuthError },
|
|
70
|
+
// ...
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Patches
|
|
75
|
+
|
|
76
|
+
- Fetch the Convex auth token once per request on TanStack Start. Every
|
|
77
|
+
procedure call, `getToken()`, and `fetchAuthQuery`/`fetchAuthMutation`/
|
|
78
|
+
`fetchAuthAction` in a request now share one token, instead of each paying its
|
|
79
|
+
own round trip.
|
|
80
|
+
- Stop replaying a rejected auth token for the rest of a request. After a
|
|
81
|
+
refresh, the remaining calls sharing that context use the new token instead of
|
|
82
|
+
re-failing and re-running non-idempotent mutations and actions.
|
|
83
|
+
- Refresh expired TanStack Start tokens instead of failing. Forced refresh and
|
|
84
|
+
token freshness now reach the token layer, so a stale token retries once and a
|
|
85
|
+
fresh one is no longer replayed on an authorization error.
|
|
86
|
+
|
|
87
|
+
Existing TanStack Start apps: re-run `kitcn add auth --overwrite` to update
|
|
88
|
+
`src/lib/convex/auth-server.ts` and `src/lib/convex/server.ts`.
|
|
89
|
+
|
|
3
90
|
## 0.25.7
|
|
4
91
|
|
|
5
92
|
### Patch Changes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Bn as ConvexTextBuilderInitial, Xt as ConvexTableWithColumns } from "../capabilities-DtDfpdcH.js";
|
|
2
|
-
import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-
|
|
2
|
+
import { C as ConvexNumberBuilderInitial, E as ConvexIdBuilderInitial, N as ConvexCustomBuilderInitial } from "../where-clause-compiler-3fKontPx.js";
|
|
3
3
|
import * as convex_values0 from "convex/values";
|
|
4
4
|
import { GenericId, Infer, Value } from "convex/values";
|
|
5
5
|
import { DocumentByName, GenericDataModel, GenericDatabaseReader, GenericDatabaseWriter, TableNamesInDataModel } from "convex/server";
|
package/dist/aggregate/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as TableAggregate$1, r as aggregateStorageTables, t as DirectAggregate$1 } from "../runtime-
|
|
1
|
+
import { n as TableAggregate$1, r as aggregateStorageTables, t as DirectAggregate$1 } from "../runtime-CcOvOf4K.js";
|
|
2
2
|
|
|
3
3
|
//#region src/aggregate/index.ts
|
|
4
4
|
const wrapTriggerFactory = (methodName, factory) => ((...args) => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { S as defineAuth, _ as GenericAuthBeforeResult, b as GenericAuthTriggerHandlers, g as BetterAuthOptionsWithoutDatabase, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../../generated-contract-disabled-
|
|
1
|
+
import { S as defineAuth, _ as GenericAuthBeforeResult, b as GenericAuthTriggerHandlers, g as BetterAuthOptionsWithoutDatabase, i as getGeneratedAuthDisabledReason, n as GeneratedAuthDisabledReasonKind, r as createDisabledAuthRuntime, t as AuthRuntime, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../../generated-contract-disabled-BEc4d98x.js";
|
|
2
2
|
export { type AuthRuntime, BetterAuthOptionsWithoutDatabase, type GeneratedAuthDisabledReasonKind, GenericAuthBeforeResult, GenericAuthDefinition, GenericAuthTriggerChange, GenericAuthTriggerHandlers, GenericAuthTriggers, createDisabledAuthRuntime, defineAuth, getGeneratedAuthDisabledReason };
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { a as QueryCtxWithPreferredOrmQueryTable, n as LookupByIdResultByCtx, t as DocByCtx } from "../query-context-DJONf8X5.js";
|
|
2
2
|
import { t as GetAuth } from "../types-Bf3XQex5.js";
|
|
3
3
|
import { t as GenericCtx } from "../context-utils-DwZ3Cam1.js";
|
|
4
|
-
import { S as defineAuth, _ as GenericAuthBeforeResult, a as AuthFunctions, b as GenericAuthTriggerHandlers, c as createApi, d as deleteOneHandler, f as findManyHandler, g as BetterAuthOptionsWithoutDatabase, h as updateOneHandler, i as getGeneratedAuthDisabledReason, l as createHandler, m as updateManyHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findOneHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as deleteManyHandler, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../generated-contract-disabled-
|
|
4
|
+
import { S as defineAuth, _ as GenericAuthBeforeResult, a as AuthFunctions, b as GenericAuthTriggerHandlers, c as createApi, d as deleteOneHandler, f as findManyHandler, g as BetterAuthOptionsWithoutDatabase, h as updateOneHandler, i as getGeneratedAuthDisabledReason, l as createHandler, m as updateManyHandler, n as GeneratedAuthDisabledReasonKind, o as Triggers, p as findOneHandler, r as createDisabledAuthRuntime, s as createClient, t as AuthRuntime, u as deleteManyHandler, v as GenericAuthDefinition, x as GenericAuthTriggers, y as GenericAuthTriggerChange } from "../generated-contract-disabled-BEc4d98x.js";
|
|
5
5
|
import * as convex_values0 from "convex/values";
|
|
6
6
|
import { Infer } from "convex/values";
|
|
7
7
|
import { AuthConfig, DocumentByName, GenericDataModel, GenericMutationCtx, GenericQueryCtx, GenericSchema, PaginationOptions, PaginationResult, SchemaDefinition, TableNamesInDataModel } from "convex/server";
|
|
@@ -111,27 +111,27 @@ type AdapterPaginationOptions = PaginationOptions & {
|
|
|
111
111
|
};
|
|
112
112
|
declare const adapterWhereValidator: convex_values0.VObject<{
|
|
113
113
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
114
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
115
114
|
connector?: "AND" | "OR" | undefined;
|
|
115
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
116
116
|
value: string | number | boolean | string[] | number[] | null;
|
|
117
117
|
field: string;
|
|
118
118
|
}, {
|
|
119
119
|
connector: convex_values0.VUnion<"AND" | "OR" | undefined, [convex_values0.VLiteral<"AND", "required">, convex_values0.VLiteral<"OR", "required">], "optional", never>;
|
|
120
120
|
field: convex_values0.VString<string, "required">;
|
|
121
121
|
mode: convex_values0.VUnion<"sensitive" | "insensitive" | undefined, [convex_values0.VLiteral<"sensitive", "required">, convex_values0.VLiteral<"insensitive", "required">], "optional", never>;
|
|
122
|
-
operator: convex_values0.VUnion<"
|
|
122
|
+
operator: convex_values0.VUnion<"lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined, [convex_values0.VLiteral<"lt", "required">, convex_values0.VLiteral<"lte", "required">, convex_values0.VLiteral<"gt", "required">, convex_values0.VLiteral<"gte", "required">, convex_values0.VLiteral<"eq", "required">, convex_values0.VLiteral<"in", "required">, convex_values0.VLiteral<"not_in", "required">, convex_values0.VLiteral<"ne", "required">, convex_values0.VLiteral<"contains", "required">, convex_values0.VLiteral<"starts_with", "required">, convex_values0.VLiteral<"ends_with", "required">], "optional", never>;
|
|
123
123
|
value: convex_values0.VUnion<string | number | boolean | string[] | number[] | null, [convex_values0.VString<string, "required">, convex_values0.VFloat64<number, "required">, convex_values0.VBoolean<boolean, "required">, convex_values0.VArray<string[], convex_values0.VString<string, "required">, "required">, convex_values0.VArray<number[], convex_values0.VFloat64<number, "required">, "required">, convex_values0.VNull<null, "required">], "required", never>;
|
|
124
|
-
}, "required", "mode" | "
|
|
124
|
+
}, "required", "mode" | "value" | "connector" | "field" | "operator">;
|
|
125
125
|
declare const adapterArgsValidator: convex_values0.VObject<{
|
|
126
|
-
|
|
126
|
+
select?: string[] | undefined;
|
|
127
127
|
where?: {
|
|
128
128
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
129
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
130
129
|
connector?: "AND" | "OR" | undefined;
|
|
130
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
131
131
|
value: string | number | boolean | string[] | number[] | null;
|
|
132
132
|
field: string;
|
|
133
133
|
}[] | undefined;
|
|
134
|
-
|
|
134
|
+
limit?: number | undefined;
|
|
135
135
|
offset?: number | undefined;
|
|
136
136
|
sortBy?: {
|
|
137
137
|
field: string;
|
|
@@ -152,24 +152,24 @@ declare const adapterArgsValidator: convex_values0.VObject<{
|
|
|
152
152
|
}, "optional", "field" | "direction">;
|
|
153
153
|
where: convex_values0.VArray<{
|
|
154
154
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
155
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
156
155
|
connector?: "AND" | "OR" | undefined;
|
|
156
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
157
157
|
value: string | number | boolean | string[] | number[] | null;
|
|
158
158
|
field: string;
|
|
159
159
|
}[] | undefined, convex_values0.VObject<{
|
|
160
160
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
161
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
162
161
|
connector?: "AND" | "OR" | undefined;
|
|
162
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
163
163
|
value: string | number | boolean | string[] | number[] | null;
|
|
164
164
|
field: string;
|
|
165
165
|
}, {
|
|
166
166
|
connector: convex_values0.VUnion<"AND" | "OR" | undefined, [convex_values0.VLiteral<"AND", "required">, convex_values0.VLiteral<"OR", "required">], "optional", never>;
|
|
167
167
|
field: convex_values0.VString<string, "required">;
|
|
168
168
|
mode: convex_values0.VUnion<"sensitive" | "insensitive" | undefined, [convex_values0.VLiteral<"sensitive", "required">, convex_values0.VLiteral<"insensitive", "required">], "optional", never>;
|
|
169
|
-
operator: convex_values0.VUnion<"
|
|
169
|
+
operator: convex_values0.VUnion<"lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined, [convex_values0.VLiteral<"lt", "required">, convex_values0.VLiteral<"lte", "required">, convex_values0.VLiteral<"gt", "required">, convex_values0.VLiteral<"gte", "required">, convex_values0.VLiteral<"eq", "required">, convex_values0.VLiteral<"in", "required">, convex_values0.VLiteral<"not_in", "required">, convex_values0.VLiteral<"ne", "required">, convex_values0.VLiteral<"contains", "required">, convex_values0.VLiteral<"starts_with", "required">, convex_values0.VLiteral<"ends_with", "required">], "optional", never>;
|
|
170
170
|
value: convex_values0.VUnion<string | number | boolean | string[] | number[] | null, [convex_values0.VString<string, "required">, convex_values0.VFloat64<number, "required">, convex_values0.VBoolean<boolean, "required">, convex_values0.VArray<string[], convex_values0.VString<string, "required">, "required">, convex_values0.VArray<number[], convex_values0.VFloat64<number, "required">, "required">, convex_values0.VNull<null, "required">], "required", never>;
|
|
171
|
-
}, "required", "mode" | "
|
|
172
|
-
}, "required", "
|
|
171
|
+
}, "required", "mode" | "value" | "connector" | "field" | "operator">, "optional">;
|
|
172
|
+
}, "required", "model" | "select" | "where" | "limit" | "offset" | "sortBy" | "sortBy.field" | "sortBy.direction">;
|
|
173
173
|
declare const hasUniqueFields: (betterAuthSchema: BetterAuthDBSchema, model: string, input: Record<string, any>) => boolean;
|
|
174
174
|
declare const checkUniqueFields: <Schema extends SchemaDefinition<any, any>>(ctx: GenericQueryCtx<GenericDataModel>, schema: Schema, betterAuthSchema: BetterAuthDBSchema, table: string, input: Record<string, any>, doc?: Record<string, any>) => Promise<void>;
|
|
175
175
|
declare const selectFields: <T extends TableNamesInDataModel<GenericDataModel>, D extends DocumentByName<GenericDataModel, T>>(doc: D | null, select?: string[]) => D | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { t as getToken } from "../../token-DcV_0fkF.js";
|
|
2
2
|
import { n as defaultIsUnauthorized } from "../../error-CMLeCadS.js";
|
|
3
|
-
import { t as createCallerFactory } from "../../caller-factory-
|
|
3
|
+
import { t as createCallerFactory } from "../../caller-factory-D4pz5GcZ.js";
|
|
4
4
|
|
|
5
5
|
//#region src/auth-nextjs/index.ts
|
|
6
6
|
/** biome-ignore-all lint/suspicious/noExplicitAny: lib */
|
|
@@ -1,12 +1,66 @@
|
|
|
1
|
+
import { H as ConvexContext, W as LazyCaller } from "../../../procedure-name-l2YusEZI.js";
|
|
1
2
|
import { t as GetTokenOptions } from "../../../token-kQaqFby4.js";
|
|
2
3
|
import { FunctionReference, FunctionReturnType, OptionalRestArgs } from "convex/server";
|
|
3
4
|
|
|
4
5
|
//#region src/auth-start/server.d.ts
|
|
5
|
-
|
|
6
|
+
/** Auth options for server-side calls. */
|
|
7
|
+
type AuthOptions = {
|
|
8
|
+
/** Better Auth auth route base path. Defaults to `/api/auth`. */basePath?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Read the Convex JWT from the session cookie instead of fetching it.
|
|
11
|
+
* Default: false.
|
|
12
|
+
*
|
|
13
|
+
* The token this saves a round trip on is also the token
|
|
14
|
+
* `syncConvexAuthForStartLoader` hands the browser Convex client, which
|
|
15
|
+
* captures it for the lifetime of the socket. A cookie JWT can be within
|
|
16
|
+
* seconds of expiry and cannot be renewed from that callback, so enable this
|
|
17
|
+
* only for apps that do not prime the browser client from `getToken()`.
|
|
18
|
+
*/
|
|
19
|
+
jwtCache?: boolean; /** Custom function to detect UNAUTHORIZED errors. Default checks code property. */
|
|
20
|
+
isUnauthorized?: (error: unknown) => boolean; /** Expiration tolerance in seconds. */
|
|
21
|
+
expirationToleranceSeconds?: number;
|
|
22
|
+
};
|
|
23
|
+
type ConvexBetterAuthReactStartOptions<TApi> = Omit<GetTokenOptions, 'forceRefresh' | 'jwtCache'> & {
|
|
24
|
+
/** Your Convex API object. */api: TApi;
|
|
6
25
|
convexSiteUrl: string;
|
|
7
|
-
convexUrl: string;
|
|
26
|
+
convexUrl: string; /** Auth options. */
|
|
27
|
+
auth?: AuthOptions;
|
|
8
28
|
};
|
|
9
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Create Convex caller factory with Better Auth integration for TanStack Start.
|
|
31
|
+
*
|
|
32
|
+
* Every request resolves its Convex token once. TanStack Start runs each request
|
|
33
|
+
* inside an `AsyncLocalStorage` scope, so `getRequest()` returns an object whose
|
|
34
|
+
* identity is stable for that request and distinct across requests. Keying the
|
|
35
|
+
* memos on it makes them request-scoped by construction: nothing auth-related is
|
|
36
|
+
* ever held at module scope, and entries are collected with the request.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* // auth-server.ts
|
|
41
|
+
* export const { createCaller, handler, getToken } = convexBetterAuthReactStart({
|
|
42
|
+
* api,
|
|
43
|
+
* convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
44
|
+
* convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
45
|
+
* });
|
|
46
|
+
*
|
|
47
|
+
* // server.ts
|
|
48
|
+
* export const caller = createCaller();
|
|
49
|
+
*
|
|
50
|
+
* // any server function or server route - single token fetch per request
|
|
51
|
+
* const user = await caller.user.getSessionUser();
|
|
52
|
+
* const posts = await caller.posts.list();
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
declare const convexBetterAuthReactStart: <TApi extends Record<string, unknown>>(opts: ConvexBetterAuthReactStartOptions<TApi>) => {
|
|
56
|
+
/**
|
|
57
|
+
* Bind a cRPC caller. Defaults to the request-scoped context, so every
|
|
58
|
+
* procedure call in a request shares one token fetch.
|
|
59
|
+
*/
|
|
60
|
+
createCaller: (ctxFn?: () => Promise<ConvexContext<TApi>>) => LazyCaller<TApi>;
|
|
61
|
+
createContext: (reqOpts: {
|
|
62
|
+
headers: Headers;
|
|
63
|
+
}) => Promise<ConvexContext<TApi>>;
|
|
10
64
|
getToken: () => Promise<string | undefined>;
|
|
11
65
|
handler: (request: Request) => Promise<Response>;
|
|
12
66
|
fetchAuthQuery: <Query extends FunctionReference<"query">>(query: Query, ...args: OptionalRestArgs<Query>) => Promise<FunctionReturnType<Query>>;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { t as getToken } from "../../../token-DcV_0fkF.js";
|
|
2
|
+
import { n as defaultIsUnauthorized } from "../../../error-CMLeCadS.js";
|
|
3
|
+
import { t as createCallerFactory } from "../../../caller-factory-D4pz5GcZ.js";
|
|
2
4
|
import { stripIndent } from "common-tags";
|
|
3
|
-
import {
|
|
5
|
+
import { getRequest } from "@tanstack/react-start/server";
|
|
4
6
|
import { ConvexHttpClient } from "convex/browser";
|
|
5
|
-
import React from "react";
|
|
6
7
|
|
|
7
8
|
//#region src/auth-start/server.ts
|
|
8
|
-
const fallbackCache = (fn) => fn;
|
|
9
|
-
const cache = React.cache ?? fallbackCache;
|
|
10
9
|
const TRAILING_COLON_RE = /:$/;
|
|
11
10
|
const requestCanHaveBody = (method) => method !== "GET" && method !== "HEAD" && method !== "OPTIONS";
|
|
12
11
|
const stripHopByHopHeaders = (headers) => {
|
|
@@ -79,30 +78,134 @@ const handler = async (request, opts) => {
|
|
|
79
78
|
redirect: "manual"
|
|
80
79
|
});
|
|
81
80
|
};
|
|
81
|
+
/**
|
|
82
|
+
* Create Convex caller factory with Better Auth integration for TanStack Start.
|
|
83
|
+
*
|
|
84
|
+
* Every request resolves its Convex token once. TanStack Start runs each request
|
|
85
|
+
* inside an `AsyncLocalStorage` scope, so `getRequest()` returns an object whose
|
|
86
|
+
* identity is stable for that request and distinct across requests. Keying the
|
|
87
|
+
* memos on it makes them request-scoped by construction: nothing auth-related is
|
|
88
|
+
* ever held at module scope, and entries are collected with the request.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* // auth-server.ts
|
|
93
|
+
* export const { createCaller, handler, getToken } = convexBetterAuthReactStart({
|
|
94
|
+
* api,
|
|
95
|
+
* convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
96
|
+
* convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* // server.ts
|
|
100
|
+
* export const caller = createCaller();
|
|
101
|
+
*
|
|
102
|
+
* // any server function or server route - single token fetch per request
|
|
103
|
+
* const user = await caller.user.getSessionUser();
|
|
104
|
+
* const posts = await caller.posts.list();
|
|
105
|
+
* ```
|
|
106
|
+
*/
|
|
82
107
|
const convexBetterAuthReactStart = (opts) => {
|
|
83
108
|
const siteUrl = parseConvexSiteUrl(opts.convexSiteUrl);
|
|
84
|
-
const
|
|
85
|
-
|
|
109
|
+
const auth = opts.auth ?? {};
|
|
110
|
+
const jwtCacheEnabled = auth.jwtCache === true;
|
|
111
|
+
const fetchTokenFor = (headers, forceRefresh) => {
|
|
86
112
|
const mutableHeaders = new Headers(headers);
|
|
87
113
|
stripHopByHopHeaders(mutableHeaders);
|
|
88
114
|
mutableHeaders.set("accept-encoding", "identity");
|
|
89
|
-
return getToken(siteUrl, mutableHeaders,
|
|
115
|
+
return getToken(siteUrl, mutableHeaders, {
|
|
116
|
+
basePath: auth.basePath ?? opts.basePath,
|
|
117
|
+
cookiePrefix: opts.cookiePrefix,
|
|
118
|
+
forceRefresh,
|
|
119
|
+
jwtCache: {
|
|
120
|
+
enabled: jwtCacheEnabled,
|
|
121
|
+
expirationToleranceSeconds: auth.expirationToleranceSeconds,
|
|
122
|
+
isAuthError: auth.isUnauthorized ?? defaultIsUnauthorized
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
const headersByRequest = /* @__PURE__ */ new WeakMap();
|
|
127
|
+
const tokenByRequest = /* @__PURE__ */ new WeakMap();
|
|
128
|
+
const contextByRequest = /* @__PURE__ */ new WeakMap();
|
|
129
|
+
/**
|
|
130
|
+
* Snapshot the current request's headers once.
|
|
131
|
+
*
|
|
132
|
+
* `getRequestHeaders()` is not identity-stable within a request: srvx serves a
|
|
133
|
+
* lazy header view until anything materializes the native Request (a server
|
|
134
|
+
* function reading `formData()`, for example), then swaps in that Request's
|
|
135
|
+
* own `Headers` and drops the old one. Header *values* survive the swap, so a
|
|
136
|
+
* snapshot taken at any point is correct, but comparing or keying on the live
|
|
137
|
+
* accessor would silently stop matching mid-request.
|
|
138
|
+
*/
|
|
139
|
+
const requestHeaders = (request) => {
|
|
140
|
+
const cached = headersByRequest.get(request);
|
|
141
|
+
if (cached) return cached;
|
|
142
|
+
const snapshot = new Headers(request.headers);
|
|
143
|
+
headersByRequest.set(request, snapshot);
|
|
144
|
+
return snapshot;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Memoize `create` for the lifetime of the current request. The pending
|
|
148
|
+
* promise is stored before it settles so concurrent callers share one
|
|
149
|
+
* in-flight fetch, and a rejection is evicted so the next caller can retry.
|
|
150
|
+
*/
|
|
151
|
+
const perRequest = (store, create) => {
|
|
152
|
+
const request = getRequest();
|
|
153
|
+
const cached = store.get(request);
|
|
154
|
+
if (cached) return cached;
|
|
155
|
+
const pending = create(request).catch((error) => {
|
|
156
|
+
if (store.get(request) === pending) store.delete(request);
|
|
157
|
+
throw error;
|
|
158
|
+
});
|
|
159
|
+
store.set(request, pending);
|
|
160
|
+
return pending;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* The current request, or `undefined` outside a Start request scope.
|
|
164
|
+
* `getRequest()` throws there, and an explicit `createContext({ headers })`
|
|
165
|
+
* is allowed to run with no ambient request at all.
|
|
166
|
+
*/
|
|
167
|
+
const currentRequest = () => {
|
|
168
|
+
try {
|
|
169
|
+
return getRequest();
|
|
170
|
+
} catch {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
/** Ambient token for the current request, resolved at most once. */
|
|
175
|
+
const requestToken = () => perRequest(tokenByRequest, (request) => fetchTokenFor(requestHeaders(request)));
|
|
176
|
+
const { createContext, createCaller } = createCallerFactory({
|
|
177
|
+
api: opts.api,
|
|
178
|
+
auth: {
|
|
179
|
+
getToken: (_tokenSiteUrl, headers, getTokenOpts) => {
|
|
180
|
+
const forceRefresh = getTokenOpts?.forceRefresh;
|
|
181
|
+
const request = currentRequest();
|
|
182
|
+
if (!forceRefresh && request && headers === headersByRequest.get(request)) return requestToken();
|
|
183
|
+
return fetchTokenFor(headers, forceRefresh);
|
|
184
|
+
},
|
|
185
|
+
isUnauthorized: auth.isUnauthorized
|
|
186
|
+
},
|
|
187
|
+
convexSiteUrl: opts.convexSiteUrl,
|
|
188
|
+
convexUrl: opts.convexUrl
|
|
90
189
|
});
|
|
190
|
+
/** Request-scoped context. One context, one token, per request. */
|
|
191
|
+
const createRequestContext = () => perRequest(contextByRequest, (request) => createContext({ headers: requestHeaders(request) }));
|
|
91
192
|
const callWithToken = async (fn) => {
|
|
92
|
-
const token = await
|
|
193
|
+
const token = await requestToken();
|
|
93
194
|
try {
|
|
94
|
-
return await fn(token
|
|
195
|
+
return await fn(token.token);
|
|
95
196
|
} catch (error) {
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
197
|
+
if (token.isFresh || !(auth.isUnauthorized ?? defaultIsUnauthorized)(error)) throw error;
|
|
198
|
+
const refreshed = await fetchTokenFor(requestHeaders(getRequest()), true);
|
|
199
|
+
token.token = refreshed.token;
|
|
200
|
+
token.isFresh = refreshed.isFresh;
|
|
201
|
+
return await fn(refreshed.token);
|
|
101
202
|
}
|
|
102
203
|
};
|
|
103
204
|
return {
|
|
205
|
+
createCaller: (ctxFn = createRequestContext) => createCaller(ctxFn),
|
|
206
|
+
createContext,
|
|
104
207
|
getToken: async () => {
|
|
105
|
-
return (await
|
|
208
|
+
return (await requestToken()).token;
|
|
106
209
|
},
|
|
107
210
|
handler: async (request) => cloneAuthHandlerResponse(await handler(request, opts)),
|
|
108
211
|
fetchAuthQuery: async (query, ...args) => {
|
package/dist/cli.mjs
CHANGED
|
@@ -5636,15 +5636,19 @@ export const Route = createFileRoute('/api/auth/$')({
|
|
|
5636
5636
|
|
|
5637
5637
|
//#endregion
|
|
5638
5638
|
//#region src/cli/registry/items/auth/auth-start-server.template.ts
|
|
5639
|
-
const AUTH_START_SERVER_TEMPLATE = `import {
|
|
5639
|
+
const AUTH_START_SERVER_TEMPLATE = `import { api } from '@convex/api';
|
|
5640
|
+
import { convexBetterAuthReactStart } from 'kitcn/auth/start/server';
|
|
5640
5641
|
|
|
5641
5642
|
export const {
|
|
5642
5643
|
handler,
|
|
5643
5644
|
getToken,
|
|
5645
|
+
createCaller,
|
|
5646
|
+
createContext,
|
|
5644
5647
|
fetchAuthQuery,
|
|
5645
5648
|
fetchAuthMutation,
|
|
5646
5649
|
fetchAuthAction,
|
|
5647
5650
|
} = convexBetterAuthReactStart({
|
|
5651
|
+
api,
|
|
5648
5652
|
convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
5649
5653
|
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
5650
5654
|
});
|
|
@@ -5652,41 +5656,9 @@ export const {
|
|
|
5652
5656
|
|
|
5653
5657
|
//#endregion
|
|
5654
5658
|
//#region src/cli/registry/items/auth/auth-start-server-call.template.ts
|
|
5655
|
-
const AUTH_START_SERVER_CALL_TEMPLATE = `import {
|
|
5656
|
-
import { getRequestHeaders } from '@tanstack/react-start/server';
|
|
5657
|
-
import { createCallerFactory } from 'kitcn/server';
|
|
5658
|
-
|
|
5659
|
-
import { getToken } from '@/lib/convex/auth-server';
|
|
5660
|
-
|
|
5661
|
-
const { createContext, createCaller } = createCallerFactory({
|
|
5662
|
-
api,
|
|
5663
|
-
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
5664
|
-
auth: {
|
|
5665
|
-
getToken: async () => {
|
|
5666
|
-
return {
|
|
5667
|
-
token: await getToken(),
|
|
5668
|
-
};
|
|
5669
|
-
},
|
|
5670
|
-
},
|
|
5671
|
-
});
|
|
5672
|
-
|
|
5673
|
-
type ServerCaller = ReturnType<typeof createCaller>;
|
|
5674
|
-
|
|
5675
|
-
async function makeContext() {
|
|
5676
|
-
const headers = await getRequestHeaders();
|
|
5677
|
-
return createContext({ headers });
|
|
5678
|
-
}
|
|
5659
|
+
const AUTH_START_SERVER_CALL_TEMPLATE = `import { createCaller } from '@/lib/convex/auth-server';
|
|
5679
5660
|
|
|
5680
|
-
|
|
5681
|
-
return createCaller(async () => {
|
|
5682
|
-
return await makeContext();
|
|
5683
|
-
});
|
|
5684
|
-
}
|
|
5685
|
-
|
|
5686
|
-
export function runServerCall<T>(fn: (caller: ServerCaller) => Promise<T> | T) {
|
|
5687
|
-
const caller = createServerCaller();
|
|
5688
|
-
return fn(caller);
|
|
5689
|
-
}
|
|
5661
|
+
export const caller = createCaller();
|
|
5690
5662
|
`;
|
|
5691
5663
|
|
|
5692
5664
|
//#endregion
|
package/dist/{generated-contract-disabled-D_-_iJXw.d.ts → generated-contract-disabled-BEc4d98x.d.ts}
RENAMED
|
@@ -181,18 +181,10 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
181
181
|
};
|
|
182
182
|
}, Promise<any>>;
|
|
183
183
|
deleteMany: convex_server0.RegisteredMutation<"internal", {
|
|
184
|
-
paginationOpts: {
|
|
185
|
-
id?: number;
|
|
186
|
-
endCursor?: string | null;
|
|
187
|
-
maximumRowsRead?: number;
|
|
188
|
-
maximumBytesRead?: number;
|
|
189
|
-
numItems: number;
|
|
190
|
-
cursor: string | null;
|
|
191
|
-
};
|
|
192
184
|
input: {
|
|
193
185
|
where?: {
|
|
194
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
195
186
|
connector?: "AND" | "OR" | undefined;
|
|
187
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
196
188
|
value: string | number | boolean | string[] | number[] | null;
|
|
197
189
|
field: string;
|
|
198
190
|
}[] | undefined;
|
|
@@ -201,6 +193,14 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
201
193
|
where?: any[] | undefined;
|
|
202
194
|
model: string;
|
|
203
195
|
};
|
|
196
|
+
paginationOpts: {
|
|
197
|
+
id?: number;
|
|
198
|
+
endCursor?: string | null;
|
|
199
|
+
maximumRowsRead?: number;
|
|
200
|
+
maximumBytesRead?: number;
|
|
201
|
+
numItems: number;
|
|
202
|
+
cursor: string | null;
|
|
203
|
+
};
|
|
204
204
|
}, Promise<{
|
|
205
205
|
count: number;
|
|
206
206
|
ids: any[];
|
|
@@ -212,8 +212,8 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
212
212
|
deleteOne: convex_server0.RegisteredMutation<"internal", {
|
|
213
213
|
input: {
|
|
214
214
|
where?: {
|
|
215
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
216
215
|
connector?: "AND" | "OR" | undefined;
|
|
216
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
217
217
|
value: string | number | boolean | string[] | number[] | null;
|
|
218
218
|
field: string;
|
|
219
219
|
}[] | undefined;
|
|
@@ -224,20 +224,21 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
224
224
|
};
|
|
225
225
|
}, Promise<Record<string, unknown> | undefined>>;
|
|
226
226
|
findMany: convex_server0.RegisteredQuery<"internal", {
|
|
227
|
-
limit?: number | undefined;
|
|
228
227
|
join?: any;
|
|
229
228
|
where?: {
|
|
230
229
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
231
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
232
230
|
connector?: "AND" | "OR" | undefined;
|
|
231
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
233
232
|
value: string | number | boolean | string[] | number[] | null;
|
|
234
233
|
field: string;
|
|
235
234
|
}[] | undefined;
|
|
235
|
+
limit?: number | undefined;
|
|
236
236
|
offset?: number | undefined;
|
|
237
237
|
sortBy?: {
|
|
238
238
|
field: string;
|
|
239
239
|
direction: "asc" | "desc";
|
|
240
240
|
} | undefined;
|
|
241
|
+
model: string;
|
|
241
242
|
paginationOpts: {
|
|
242
243
|
id?: number;
|
|
243
244
|
endCursor?: string | null;
|
|
@@ -246,48 +247,47 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
246
247
|
numItems: number;
|
|
247
248
|
cursor: string | null;
|
|
248
249
|
};
|
|
249
|
-
model: string;
|
|
250
250
|
}, Promise<PaginationResult<convex_server0.GenericDocument>>>;
|
|
251
251
|
findOne: convex_server0.RegisteredQuery<"internal", {
|
|
252
252
|
join?: any;
|
|
253
|
+
select?: string[] | undefined;
|
|
253
254
|
where?: {
|
|
254
255
|
mode?: "sensitive" | "insensitive" | undefined;
|
|
255
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
256
256
|
connector?: "AND" | "OR" | undefined;
|
|
257
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
257
258
|
value: string | number | boolean | string[] | number[] | null;
|
|
258
259
|
field: string;
|
|
259
260
|
}[] | undefined;
|
|
260
|
-
select?: string[] | undefined;
|
|
261
261
|
model: string;
|
|
262
262
|
}, Promise<convex_server0.GenericDocument | null>>;
|
|
263
263
|
getLatestJwks: convex_server0.RegisteredAction<"internal", {}, Promise<unknown>>;
|
|
264
264
|
rotateKeys: convex_server0.RegisteredAction<"internal", {}, Promise<unknown>>;
|
|
265
265
|
updateMany: convex_server0.RegisteredMutation<"internal", {
|
|
266
|
-
paginationOpts: {
|
|
267
|
-
id?: number;
|
|
268
|
-
endCursor?: string | null;
|
|
269
|
-
maximumRowsRead?: number;
|
|
270
|
-
maximumBytesRead?: number;
|
|
271
|
-
numItems: number;
|
|
272
|
-
cursor: string | null;
|
|
273
|
-
};
|
|
274
266
|
input: {
|
|
275
267
|
where?: {
|
|
276
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
277
268
|
connector?: "AND" | "OR" | undefined;
|
|
269
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
278
270
|
value: string | number | boolean | string[] | number[] | null;
|
|
279
271
|
field: string;
|
|
280
272
|
}[] | undefined;
|
|
273
|
+
model: string;
|
|
281
274
|
update: {
|
|
282
275
|
[x: string]: unknown;
|
|
283
276
|
[x: number]: unknown;
|
|
284
277
|
[x: symbol]: unknown;
|
|
285
278
|
};
|
|
286
|
-
model: string;
|
|
287
279
|
} | {
|
|
288
280
|
where?: any[] | undefined;
|
|
289
|
-
update: any;
|
|
290
281
|
model: string;
|
|
282
|
+
update: any;
|
|
283
|
+
};
|
|
284
|
+
paginationOpts: {
|
|
285
|
+
id?: number;
|
|
286
|
+
endCursor?: string | null;
|
|
287
|
+
maximumRowsRead?: number;
|
|
288
|
+
maximumBytesRead?: number;
|
|
289
|
+
numItems: number;
|
|
290
|
+
cursor: string | null;
|
|
291
291
|
};
|
|
292
292
|
}, Promise<{
|
|
293
293
|
count: number;
|
|
@@ -300,21 +300,21 @@ declare const createApi: <Schema extends SchemaDefinition<any, any>, DataModel e
|
|
|
300
300
|
updateOne: convex_server0.RegisteredMutation<"internal", {
|
|
301
301
|
input: {
|
|
302
302
|
where?: {
|
|
303
|
-
operator?: "eq" | "ne" | "lt" | "lte" | "gt" | "gte" | "in" | "not_in" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
304
303
|
connector?: "AND" | "OR" | undefined;
|
|
304
|
+
operator?: "lt" | "lte" | "gt" | "gte" | "eq" | "in" | "not_in" | "ne" | "contains" | "starts_with" | "ends_with" | undefined;
|
|
305
305
|
value: string | number | boolean | string[] | number[] | null;
|
|
306
306
|
field: string;
|
|
307
307
|
}[] | undefined;
|
|
308
|
+
model: string;
|
|
308
309
|
update: {
|
|
309
310
|
[x: string]: unknown;
|
|
310
311
|
[x: number]: unknown;
|
|
311
312
|
[x: symbol]: unknown;
|
|
312
313
|
};
|
|
313
|
-
model: string;
|
|
314
314
|
} | {
|
|
315
315
|
where?: any[] | undefined;
|
|
316
|
-
update: any;
|
|
317
316
|
model: string;
|
|
317
|
+
update: any;
|
|
318
318
|
};
|
|
319
319
|
}, Promise<any>>;
|
|
320
320
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as DirectAggregate } from "../../runtime-
|
|
1
|
+
import { t as DirectAggregate } from "../../runtime-CcOvOf4K.js";
|
|
2
2
|
import { a as Columns } from "../../table-CX2lnX7e.js";
|
|
3
3
|
import { Y as normalizeTemporalComparableValue, bt as PUBLIC_CREATED_AT_FIELD, c as AGGREGATE_ERROR, f as createError, i as AGGREGATE_STATE_TABLE, l as COUNT_ERROR, lt as mapWithConcurrency, n as AGGREGATE_EXTREMA_TABLE, o as getAggregateIndexDefinitions, r as AGGREGATE_MEMBER_TABLE, s as getRankIndexDefinitions, t as AGGREGATE_BUCKET_TABLE, xt as usesSystemCreatedAtAlias, yt as INTERNAL_CREATION_TIME_FIELD } from "../../schema-e0wbZ_Ax.js";
|
|
4
4
|
|
package/dist/orm/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { $n as BinaryExpression, $t as OrmLifecycleOperation, A as DatabaseWithMutations, An as ConvexCheckConfig, Ar as AnyColumn, At as VectorQueryConfig, B as RlsContext, Bn as ConvexTextBuilderInitial, Br as IsUnique, Bt as RelationsBuilderColumnConfig, C as MigrationTableName, Cn as aggregateIndex, Cr as notBetween, Ct as OrderDirection, D as defineMigrationSet, Dn as uniqueIndex, Dt as ReturningResult, E as defineMigration, En as searchIndex, Er as startsWith, Et as ReturningAll, Fn as ConvexUniqueConstraintConfig, Fr as ColumnBuilderWithTableName, Ft as ExtractTablesWithRelations, Gt as defineRelations, H as EdgeMetadata, In as check, Ir as ColumnDataType, It as ManyConfig, Jt as ConvexDeletionConfig, Kt as defineRelationsPart, Ln as foreignKey, Lr as DrizzleEntity, Lt as OneConfig, M as OrmReader$1, Mn as ConvexForeignKeyConfig, Mr as ColumnBuilderBaseConfig, Mt as unsetToken, N as OrmWriter$1, Nn as ConvexUniqueConstraintBuilder, Nr as ColumnBuilderRuntimeConfig, O as detectMigrationDrift, On as vectorIndex, Or as SystemFields, Ot as ReturningSelection, Pn as ConvexUniqueConstraintBuilderOn, Pr as ColumnBuilderTypeConfig, Pt as ExtractTablesFromSchema, Qn as TableName, Qt as OrmLifecycleChange, Rn as unique, Rr as HasDefault, Rt as RelationsBuilder, S as MigrationStep, Sn as ConvexVectorIndexConfig, Sr as not, St as OrderByClause, T as buildMigrationPlan, Tn as rankIndex, Tr as or, Tt as PredicateWhereIndexConfig, U as extractRelationsConfig, Un as Brand, Ut as TableRelationalConfig, V as RlsMode, Vn as text, Vr as NotNull, Wn as Columns, Wt as TablesRelationalConfig, Xn as OrmSchemaRelations, Xt as ConvexTableWithColumns, Yn as OrmSchemaExtensions, Yt as ConvexTable, Zn as OrmSchemaTriggers, Zt as DiscriminatorBuilderConfig, _ as MigrationMigrateOne, _n as ConvexSearchIndexBuilder, _r as isNull, _t as MutationPaginateConfig, an as RlsPolicyConfig, ar as and, at as CountConfig, b as MigrationSet, bn as ConvexVectorIndexBuilder, br as lte, bt as MutationReturning, cn as RlsRole, cr as endsWith, ct as FilterOperators, d as MigrationDefinition, dn as ConvexAggregateIndexBuilder, dr as gt, dt as InferModelFromColumns, en as TableConfig, er as ExpressionVisitor, et as AggregateConfig, f as MigrationDirection, fn as ConvexAggregateIndexBuilderOn, fr as gte, ft as InferSelectModel, g as MigrationManifestEntry, gn as ConvexRankIndexBuilderOn, gr as isNotNull, gt as MutationExecutionMode, h as MigrationDriftIssue, hn as ConvexRankIndexBuilder, hr as isFieldReference, ht as MutationExecuteResult, i as OrmMigrationCapability, in as RlsPolicy, ir as UnaryExpression, it as BuildRelationResult, j as DatabaseWithQuery, jn as ConvexForeignKeyBuilder, jr as ColumnBuilder, jt as VectorSearchProvider, kn as ConvexCheckBuilder, kt as UpdateSet, ln as RlsRoleConfig, lr as eq, lt as GetColumnData, m as MigrationDocContext, mn as ConvexIndexBuilderOn, mr as inArray, mt as MutationExecuteConfig, n as OrmCapabilities, nn as deletion, nr as FilterExpression, nt as AggregateResult, on as RlsPolicyToOption, or as between, ot as CountResult, p as MigrationDoc, pn as ConvexIndexBuilder, pr as ilike, pt as InsertValue, qn as OrmSchemaExtensionTables, qt as ConvexDeletionBuilder, r as OrmCapability, rn as discriminator, rr as LogicalExpression, rt as BuildQueryResult, sn as rlsPolicy, sr as contains, st as DBQueryConfig, t as OrmAggregateCapability, tn as convexTable, tr as FieldReference, tt as AggregateFieldValue, u as MigrationAppliedState, un as rlsRole, ur as fieldRef, ut as InferInsertModel, v as MigrationPlan, vn as ConvexSearchIndexBuilderOn, vr as like, vt as MutationPaginatedResult, w as MigrationWriteMode, wn as index, wr as notInArray, wt as PaginatedResult, x as MigrationStateMap, xn as ConvexVectorIndexBuilderOn, xr as ne, xt as MutationRunMode, y as MigrationRunStatus, yn as ConvexSearchIndexConfig, yr as lt, yt as MutationResult, zn as ConvexTextBuilder, zr as IsPrimaryKey, zt as RelationsBuilderColumnBase } from "../capabilities-DtDfpdcH.js";
|
|
2
|
-
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-
|
|
2
|
+
import { $ as OrmClientWithApi$1, A as ConvexDateMode, B as ConvexBytesBuilderInitial, C as ConvexNumberBuilderInitial, D as id, E as ConvexIdBuilderInitial, F as custom, G as ConvexBigIntBuilder, H as ConvexBooleanBuilder, I as json, J as CreateOrmOptions, K as ConvexBigIntBuilderInitial, L as objectOf, M as ConvexCustomBuilder, N as ConvexCustomBuilderInitial, O as ConvexDateBuilder, P as arrayOf, Q as OrmClientBase$1, R as unionOf, S as ConvexNumberBuilder, St as defineTriggers, T as ConvexIdBuilder, U as ConvexBooleanBuilderInitial, V as bytes, W as boolean, X as GenericOrmCtx$1, Y as GenericOrm$1, Z as OrmApiResult, _ as ConvexTimestampMode, _t as OrmBeforeResult, a as requireSchemaRelations, at as ScheduledMutationBatchArgs, b as ConvexTextEnumBuilderInitial, bt as OrmTriggerContext, c as TableConfigResult, ct as scheduledDeleteFactory, d as OrmNotFoundError, et as OrmFunctions, f as ConvexVectorBuilder, g as ConvexTimestampBuilderInitial, gt as defineSchemaExtension, h as ConvexTimestampBuilder, ht as SchemaExtension, i as getSchemaTriggers, it as createOrm, j as date, k as ConvexDateBuilderInitial, l as getTableColumns, m as vector, n as defineSchema, nt as OrmWriterCtx, o as asc, ot as scheduledMutationBatchFactory, p as ConvexVectorBuilderInitial, q as bigint, r as getSchemaRelations, rt as ResolveOrmSchema, s as desc, st as ScheduledDeleteArgs, t as WhereClauseResult, tt as OrmReaderCtx, u as getTableConfig, v as timestamp, vt as OrmTableTriggers, w as integer, x as textEnum, xt as OrmTriggers, y as ConvexTextEnumBuilder, yt as OrmTriggerChange, z as ConvexBytesBuilder } from "../where-clause-compiler-3fKontPx.js";
|
|
3
3
|
import { i as pretendRequired, n as deprecated, r as pretend } from "../validators-wOIjhkfN.js";
|
|
4
4
|
import { a as QueryCtxWithPreferredOrmQueryTable, i as QueryCtxWithOrmQueryTable, n as LookupByIdResultByCtx, o as getByIdWithOrmQueryFallback, r as QueryCtxWithOptionalOrmQueryTable, t as DocByCtx } from "../query-context-DJONf8X5.js";
|
|
5
5
|
import { DefineSchemaOptions, GenericDatabaseReader, GenericDatabaseWriter, GenericSchema, SchemaDefinition } from "convex/server";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { C as MigrationTableName, D as defineMigrationSet, E as defineMigration, O as detectMigrationDrift, S as MigrationStep, T as buildMigrationPlan, _ as MigrationMigrateOne, a as MigrationCancelArgs, b as MigrationSet, c as MigrationStatusArgs, d as MigrationDefinition, f as MigrationDirection, g as MigrationManifestEntry, h as MigrationDriftIssue, l as createMigrationHandlers, m as MigrationDocContext, o as MigrationRunArgs, p as MigrationDoc, s as MigrationRunChunkArgs, u as MigrationAppliedState, v as MigrationPlan, w as MigrationWriteMode, x as MigrationStateMap, y as MigrationRunStatus } from "../../capabilities-DtDfpdcH.js";
|
|
2
|
-
import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-
|
|
2
|
+
import { Ct as migrationCapability, dt as MIGRATION_STORAGE_TABLE_NAMES, ft as injectMigrationStorageTables, lt as MIGRATION_RUN_TABLE, mt as migrationStorageTables, pt as migrationExtension, ut as MIGRATION_STATE_TABLE } from "../../where-clause-compiler-3fKontPx.js";
|
|
3
3
|
export { MIGRATION_RUN_TABLE, MIGRATION_STATE_TABLE, MIGRATION_STORAGE_TABLE_NAMES, type MigrationAppliedState, type MigrationCancelArgs, type MigrationDefinition, type MigrationDirection, type MigrationDoc, type MigrationDocContext, type MigrationDriftIssue, type MigrationManifestEntry, type MigrationMigrateOne, type MigrationPlan, type MigrationRunArgs, type MigrationRunChunkArgs, type MigrationRunStatus, type MigrationSet, type MigrationStateMap, type MigrationStatusArgs, type MigrationStep, type MigrationTableName, type MigrationWriteMode, buildMigrationPlan, createMigrationHandlers, defineMigration, defineMigrationSet, detectMigrationDrift, injectMigrationStorageTables, migrationCapability, migrationExtension, migrationStorageTables };
|
|
@@ -439,7 +439,7 @@ async function insertIntoNode(ctx, maxNodeSize, node, item) {
|
|
|
439
439
|
const minNodeSize = minNodeSizeFor(maxNodeSize);
|
|
440
440
|
if (newN.items.length > maxNodeSize) {
|
|
441
441
|
if (newN.items.length !== maxNodeSize + 1 || newN.items.length !== 2 * minNodeSize + 1) throw new Error(`bad ${newN.items.length}`);
|
|
442
|
-
log(`splitting node ${newN._id} at ${newN.items[minNodeSize].k}`);
|
|
442
|
+
log(`splitting node ${newN._id} at ${p(newN.items[minNodeSize].k)}`);
|
|
443
443
|
const topLevel = nodeCounts(newN);
|
|
444
444
|
const subCounts = await subtreeCounts(ctx.db, newN);
|
|
445
445
|
const leftCount = add(accumulate(topLevel.slice(0, minNodeSize)), accumulate(subCounts.length ? subCounts.slice(0, minNodeSize + 1) : []));
|
package/dist/server/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as isMutationCtx, c as isSchedulerCtx, d as requireQueryCtx, f as requireRunMutationCtx, i as isActionCtx, l as requireActionCtx, n as createGeneratedFunctionReference, o as isQueryCtx, p as requireSchedulerCtx, r as getGeneratedValue, s as isRunMutationCtx, t as createApiLeaf, u as requireMutationCtx } from "../api-entry-CkDpGYVg.js";
|
|
2
|
-
import { n as createLazyCaller, r as createServerCaller, t as createCallerFactory } from "../caller-factory-
|
|
2
|
+
import { n as createLazyCaller, r as createServerCaller, t as createCallerFactory } from "../caller-factory-D4pz5GcZ.js";
|
|
3
3
|
import { A as zid, C as toCRPCError, D as zCustomAction, E as withSystemFields, M as zodOutputToConvexFields, N as zodToConvex, O as zCustomMutation, P as zodToConvexFields, S as isCRPCError, T as convexToZodFields, _ as CRPCError, a as createMiddlewareFactory, b as getCRPCErrorFromUnknown, c as registerProcedureNameLookup, d as createHttpRouterFactory, f as extractRouteMap, g as matchPathParams, h as handleHttpError, i as QueryProcedureBuilder, j as zodOutputToConvex, k as zCustomQuery, l as HttpRouterWithHono, m as extractPathParams, n as MutationProcedureBuilder, o as initCRPC, p as createHttpProcedureBuilder, r as ProcedureBuilder, s as inferProcedureNameFromCallsite, t as ActionProcedureBuilder, u as createHttpRouter, v as CRPC_ERROR_CODES_BY_KEY, w as convexToZod, x as getHTTPStatusCodeFromError, y as CRPC_ERROR_CODE_TO_HTTP } from "../builder-CsAw-DK8.js";
|
|
4
4
|
import { a as createProcedureHandlerFactory, c as typedProcedureResolver, i as createProcedureCallerFactory, l as createEnv, n as createGenericCallerFactory, o as defineProcedure, r as createGenericHandlerFactory, s as getGeneratedFunctionReference, t as createGeneratedRegistryRuntime } from "../procedure-caller-BR-Wb0si.js";
|
|
5
5
|
|
|
@@ -102,22 +102,22 @@ declare const migrationStorageTables: {
|
|
|
102
102
|
fieldName: "status";
|
|
103
103
|
};
|
|
104
104
|
};
|
|
105
|
-
|
|
105
|
+
cursor: ConvexTextBuilderInitial<""> & {
|
|
106
106
|
_: {
|
|
107
107
|
tableName: "migration_state";
|
|
108
108
|
};
|
|
109
109
|
} & {
|
|
110
110
|
_: {
|
|
111
|
-
fieldName: "
|
|
111
|
+
fieldName: "cursor";
|
|
112
112
|
};
|
|
113
113
|
};
|
|
114
|
-
|
|
114
|
+
direction: ConvexTextBuilderInitial<""> & {
|
|
115
115
|
_: {
|
|
116
116
|
tableName: "migration_state";
|
|
117
117
|
};
|
|
118
118
|
} & {
|
|
119
119
|
_: {
|
|
120
|
-
fieldName: "
|
|
120
|
+
fieldName: "direction";
|
|
121
121
|
};
|
|
122
122
|
};
|
|
123
123
|
updatedAt: ConvexNumberBuilderInitial<""> & {
|
|
@@ -1323,7 +1323,11 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
|
|
|
1323
1323
|
readonly aggregate_extrema: ConvexTableWithColumns<{
|
|
1324
1324
|
name: "aggregate_extrema";
|
|
1325
1325
|
columns: {
|
|
1326
|
-
|
|
1326
|
+
value: ConvexCustomBuilderInitial<"", convex_values0.VAny<any, "required", string>> & {
|
|
1327
|
+
_: {
|
|
1328
|
+
$type: convex_values0.Value;
|
|
1329
|
+
};
|
|
1330
|
+
} & {
|
|
1327
1331
|
_: {
|
|
1328
1332
|
notNull: true;
|
|
1329
1333
|
};
|
|
@@ -1333,14 +1337,10 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
|
|
|
1333
1337
|
};
|
|
1334
1338
|
} & {
|
|
1335
1339
|
_: {
|
|
1336
|
-
fieldName: "
|
|
1340
|
+
fieldName: "value";
|
|
1337
1341
|
};
|
|
1338
1342
|
};
|
|
1339
|
-
|
|
1340
|
-
_: {
|
|
1341
|
-
$type: convex_values0.Value;
|
|
1342
|
-
};
|
|
1343
|
-
} & {
|
|
1343
|
+
count: ConvexNumberBuilderInitial<""> & {
|
|
1344
1344
|
_: {
|
|
1345
1345
|
notNull: true;
|
|
1346
1346
|
};
|
|
@@ -1350,7 +1350,7 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
|
|
|
1350
1350
|
};
|
|
1351
1351
|
} & {
|
|
1352
1352
|
_: {
|
|
1353
|
-
fieldName: "
|
|
1353
|
+
fieldName: "count";
|
|
1354
1354
|
};
|
|
1355
1355
|
};
|
|
1356
1356
|
updatedAt: ConvexNumberBuilderInitial<""> & {
|
|
@@ -1744,22 +1744,22 @@ declare const BUILTIN_SCHEMA_EXTENSIONS: readonly [SchemaExtension<{
|
|
|
1744
1744
|
fieldName: "status";
|
|
1745
1745
|
};
|
|
1746
1746
|
};
|
|
1747
|
-
|
|
1747
|
+
cursor: ConvexTextBuilderInitial<""> & {
|
|
1748
1748
|
_: {
|
|
1749
1749
|
tableName: "migration_state";
|
|
1750
1750
|
};
|
|
1751
1751
|
} & {
|
|
1752
1752
|
_: {
|
|
1753
|
-
fieldName: "
|
|
1753
|
+
fieldName: "cursor";
|
|
1754
1754
|
};
|
|
1755
1755
|
};
|
|
1756
|
-
|
|
1756
|
+
direction: ConvexTextBuilderInitial<""> & {
|
|
1757
1757
|
_: {
|
|
1758
1758
|
tableName: "migration_state";
|
|
1759
1759
|
};
|
|
1760
1760
|
} & {
|
|
1761
1761
|
_: {
|
|
1762
|
-
fieldName: "
|
|
1762
|
+
fieldName: "direction";
|
|
1763
1763
|
};
|
|
1764
1764
|
};
|
|
1765
1765
|
updatedAt: ConvexNumberBuilderInitial<""> & {
|
package/package.json
CHANGED
|
@@ -77,6 +77,7 @@ export const authClient = createAuthClient({
|
|
|
77
77
|
```ts
|
|
78
78
|
// convex/functions/schema.ts
|
|
79
79
|
import {
|
|
80
|
+
aggregateIndex,
|
|
80
81
|
convexTable,
|
|
81
82
|
defineSchema,
|
|
82
83
|
id,
|
|
@@ -111,6 +112,8 @@ export const member = convexTable(
|
|
|
111
112
|
index("userId").on(t.userId),
|
|
112
113
|
index("organizationId_userId").on(t.organizationId, t.userId),
|
|
113
114
|
index("organizationId_role").on(t.organizationId, t.role),
|
|
115
|
+
// Backs `member.count({ where: { organizationId } })` for seat limits.
|
|
116
|
+
aggregateIndex("by_organization").on(t.organizationId),
|
|
114
117
|
]
|
|
115
118
|
);
|
|
116
119
|
|
|
@@ -134,6 +137,10 @@ export const invitation = convexTable(
|
|
|
134
137
|
t.status
|
|
135
138
|
),
|
|
136
139
|
index("organizationId_status").on(t.organizationId, t.status),
|
|
140
|
+
// Backs `invitation.count({ where: { organizationId, status } })`.
|
|
141
|
+
// `count()` index matching is exact-set, so the aggregate key must list
|
|
142
|
+
// every field the filter constrains.
|
|
143
|
+
aggregateIndex("by_organization_status").on(t.organizationId, t.status),
|
|
137
144
|
]
|
|
138
145
|
);
|
|
139
146
|
|
|
@@ -145,6 +152,11 @@ export const session = convexTable("session", {
|
|
|
145
152
|
});
|
|
146
153
|
```
|
|
147
154
|
|
|
155
|
+
`count()` requires its aggregate index to be `READY`. Backfill these indexes
|
|
156
|
+
before routing live traffic to the count path. When schema and count code ship
|
|
157
|
+
together, catch only `COUNT_INDEX_BUILDING` and read the exact count from the
|
|
158
|
+
matching native organization index until backfill completes.
|
|
159
|
+
|
|
148
160
|
### Teams (Optional)
|
|
149
161
|
|
|
150
162
|
```ts
|
|
@@ -506,16 +518,18 @@ export const inviteMember = authMutation
|
|
|
506
518
|
permissions: { invitation: ["create"] },
|
|
507
519
|
});
|
|
508
520
|
|
|
509
|
-
// Check member limit
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
521
|
+
// Check member limit. Count off `aggregateIndex`, never by collecting rows
|
|
522
|
+
// to read `.length` -- that puts every member and pending invitation into
|
|
523
|
+
// the transaction's read set to produce two integers.
|
|
524
|
+
const [members, pending] = await Promise.all([
|
|
525
|
+
ctx.orm.query.member.count({
|
|
526
|
+
where: { organizationId: input.organizationId },
|
|
527
|
+
}),
|
|
528
|
+
ctx.orm.query.invitation.count({
|
|
529
|
+
where: { organizationId: input.organizationId, status: "pending" },
|
|
530
|
+
}),
|
|
531
|
+
]);
|
|
532
|
+
if (members + pending >= MEMBER_LIMIT) {
|
|
519
533
|
throw new CRPCError({
|
|
520
534
|
code: "FORBIDDEN",
|
|
521
535
|
message: `Organization member limit reached. Maximum ${MEMBER_LIMIT} members allowed.`,
|
|
@@ -34,20 +34,28 @@ export const {
|
|
|
34
34
|
**Create:** `src/lib/convex/auth-server.ts`
|
|
35
35
|
|
|
36
36
|
```ts
|
|
37
|
+
import { api } from "@convex/api";
|
|
37
38
|
import { convexBetterAuthReactStart } from "kitcn/auth/start/server";
|
|
38
39
|
|
|
39
40
|
export const {
|
|
40
41
|
handler,
|
|
41
42
|
getToken,
|
|
43
|
+
createCaller,
|
|
44
|
+
createContext,
|
|
42
45
|
fetchAuthQuery,
|
|
43
46
|
fetchAuthMutation,
|
|
44
47
|
fetchAuthAction,
|
|
45
48
|
} = convexBetterAuthReactStart({
|
|
49
|
+
api,
|
|
46
50
|
convexUrl: import.meta.env.VITE_CONVEX_URL!,
|
|
47
51
|
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
48
52
|
});
|
|
49
53
|
```
|
|
50
54
|
|
|
55
|
+
`getToken` fetches the Convex token from the auth route. `auth.jwtCache: true`
|
|
56
|
+
reads it from the session cookie instead. Leave it off when the browser Convex
|
|
57
|
+
client is primed from `getToken()`.
|
|
58
|
+
|
|
51
59
|
For client-side route loaders that fetch protected Convex queries through the
|
|
52
60
|
router `queryClient`, prime the shared Convex client in the root `beforeLoad`
|
|
53
61
|
before child loaders run:
|
|
@@ -78,7 +86,7 @@ export const Route = createRootRouteWithContext<{
|
|
|
78
86
|
});
|
|
79
87
|
```
|
|
80
88
|
|
|
81
|
-
Use `
|
|
89
|
+
Use the request-scoped `caller` or `fetchAuthQuery` for server-side loaders. Use
|
|
82
90
|
`syncConvexAuthForStartLoader` only for client/router loaders that execute
|
|
83
91
|
shared `ConvexQueryClient` queries before `ConvexAuthProvider` mounts.
|
|
84
92
|
|
|
@@ -105,42 +113,20 @@ export const Route = createFileRoute("/api/auth/$" as never)({
|
|
|
105
113
|
**Create:** `src/lib/convex/server.ts`
|
|
106
114
|
|
|
107
115
|
```ts
|
|
108
|
-
import {
|
|
109
|
-
import { getRequestHeaders } from "@tanstack/react-start/server";
|
|
110
|
-
import { createCallerFactory } from "kitcn/server";
|
|
116
|
+
import { createCaller } from "@/lib/convex/auth-server";
|
|
111
117
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const { createContext, createCaller } = createCallerFactory({
|
|
115
|
-
api,
|
|
116
|
-
convexSiteUrl: import.meta.env.VITE_CONVEX_SITE_URL!,
|
|
117
|
-
auth: {
|
|
118
|
-
getToken: async () => {
|
|
119
|
-
return {
|
|
120
|
-
token: await getToken(),
|
|
121
|
-
};
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
type ServerCaller = ReturnType<typeof createCaller>;
|
|
127
|
-
|
|
128
|
-
async function makeContext() {
|
|
129
|
-
const headers = await getRequestHeaders();
|
|
130
|
-
return createContext({ headers });
|
|
131
|
-
}
|
|
118
|
+
export const caller = createCaller();
|
|
119
|
+
```
|
|
132
120
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
121
|
+
`createCaller()` binds to the current request, so every procedure call in a
|
|
122
|
+
request shares one Convex auth token fetch. The module-scope `caller` holds no
|
|
123
|
+
request state; it resolves the current request on each call. Pass a context
|
|
124
|
+
factory (`createCaller(() => createContext({ headers }))`) only to call Convex
|
|
125
|
+
with headers other than the current request's.
|
|
138
126
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
```
|
|
127
|
+
Reach `caller` from a `createServerFn` handler or a server route. A route
|
|
128
|
+
`loader` also runs in the browser on client-side navigation, where there is no
|
|
129
|
+
request scope.
|
|
144
130
|
|
|
145
131
|
Use the docs pattern from `tanstack-start.mdx` for:
|
|
146
132
|
|