@convex-dev/better-auth 0.7.0-alpha.9 → 0.7.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/dist/commonjs/client/adapter.d.ts +10 -1
- package/dist/commonjs/client/adapter.d.ts.map +1 -1
- package/dist/commonjs/client/adapter.js +195 -193
- package/dist/commonjs/client/adapter.js.map +1 -1
- package/dist/commonjs/client/index.d.ts +283 -179
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +46 -58
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/component/adapterTest.d.ts +19 -0
- package/dist/commonjs/component/adapterTest.d.ts.map +1 -0
- package/dist/commonjs/component/adapterTest.js +82 -0
- package/dist/commonjs/component/adapterTest.js.map +1 -0
- package/dist/commonjs/component/lib.d.ts +308 -536
- package/dist/commonjs/component/lib.d.ts.map +1 -1
- package/dist/commonjs/component/lib.js +469 -292
- package/dist/commonjs/component/lib.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +465 -26
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +334 -18
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/util.d.ts +944 -68
- package/dist/commonjs/component/util.d.ts.map +1 -1
- package/dist/commonjs/nextjs/index.d.ts.map +1 -1
- package/dist/commonjs/nextjs/index.js +3 -9
- package/dist/commonjs/nextjs/index.js.map +1 -1
- package/dist/commonjs/plugins/convex/index.d.ts +14 -11
- package/dist/commonjs/plugins/convex/index.d.ts.map +1 -1
- package/dist/commonjs/plugins/convex/index.js +3 -2
- package/dist/commonjs/plugins/convex/index.js.map +1 -1
- package/dist/commonjs/plugins/cross-domain/client.d.ts +1 -1
- package/dist/commonjs/plugins/cross-domain/index.d.ts +5 -3
- package/dist/commonjs/plugins/cross-domain/index.d.ts.map +1 -1
- package/dist/commonjs/plugins/cross-domain/index.js +19 -5
- package/dist/commonjs/plugins/cross-domain/index.js.map +1 -1
- package/dist/commonjs/react/client.d.ts +1 -1
- package/dist/commonjs/react/client.d.ts.map +1 -1
- package/dist/commonjs/react/client.js +3 -9
- package/dist/commonjs/react/client.js.map +1 -1
- package/dist/commonjs/react-start/index.d.ts +4 -4
- package/dist/commonjs/react-start/index.d.ts.map +1 -1
- package/dist/commonjs/react-start/index.js +3 -0
- package/dist/commonjs/react-start/index.js.map +1 -1
- package/dist/commonjs/utils/index.d.ts +2 -0
- package/dist/commonjs/utils/index.d.ts.map +1 -0
- package/dist/commonjs/utils/index.js +8 -0
- package/dist/commonjs/utils/index.js.map +1 -0
- package/dist/esm/client/adapter.d.ts +10 -1
- package/dist/esm/client/adapter.d.ts.map +1 -1
- package/dist/esm/client/adapter.js +195 -193
- package/dist/esm/client/adapter.js.map +1 -1
- package/dist/esm/client/index.d.ts +283 -179
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +46 -58
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/component/adapterTest.d.ts +19 -0
- package/dist/esm/component/adapterTest.d.ts.map +1 -0
- package/dist/esm/component/adapterTest.js +82 -0
- package/dist/esm/component/adapterTest.js.map +1 -0
- package/dist/esm/component/lib.d.ts +308 -536
- package/dist/esm/component/lib.d.ts.map +1 -1
- package/dist/esm/component/lib.js +469 -292
- package/dist/esm/component/lib.js.map +1 -1
- package/dist/esm/component/schema.d.ts +465 -26
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +334 -18
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/util.d.ts +944 -68
- package/dist/esm/component/util.d.ts.map +1 -1
- package/dist/esm/nextjs/index.d.ts.map +1 -1
- package/dist/esm/nextjs/index.js +3 -9
- package/dist/esm/nextjs/index.js.map +1 -1
- package/dist/esm/plugins/convex/index.d.ts +14 -11
- package/dist/esm/plugins/convex/index.d.ts.map +1 -1
- package/dist/esm/plugins/convex/index.js +3 -2
- package/dist/esm/plugins/convex/index.js.map +1 -1
- package/dist/esm/plugins/cross-domain/client.d.ts +1 -1
- package/dist/esm/plugins/cross-domain/index.d.ts +5 -3
- package/dist/esm/plugins/cross-domain/index.d.ts.map +1 -1
- package/dist/esm/plugins/cross-domain/index.js +19 -5
- package/dist/esm/plugins/cross-domain/index.js.map +1 -1
- package/dist/esm/react/client.d.ts +1 -1
- package/dist/esm/react/client.d.ts.map +1 -1
- package/dist/esm/react/client.js +3 -9
- package/dist/esm/react/client.js.map +1 -1
- package/dist/esm/react-start/index.d.ts +4 -4
- package/dist/esm/react-start/index.d.ts.map +1 -1
- package/dist/esm/react-start/index.js +3 -0
- package/dist/esm/react-start/index.js.map +1 -1
- package/dist/esm/utils/index.d.ts +2 -0
- package/dist/esm/utils/index.d.ts.map +1 -0
- package/dist/esm/utils/index.js +8 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/package.json +24 -7
- package/src/client/adapter.test.ts +378 -0
- package/src/client/adapter.ts +210 -198
- package/src/client/index.ts +46 -71
- package/src/component/_generated/api.d.ts +2189 -171
- package/src/component/adapterTest.ts +141 -0
- package/src/component/lib.ts +648 -342
- package/src/component/schema.ts +349 -18
- package/src/nextjs/index.ts +3 -14
- package/src/plugins/convex/index.ts +5 -2
- package/src/plugins/cross-domain/index.ts +19 -5
- package/src/react/client.tsx +5 -11
- package/src/react-start/index.ts +4 -1
- package/src/client/cors.ts +0 -425
- /package/src/{util.ts → utils/index.ts} +0 -0
package/src/client/adapter.ts
CHANGED
|
@@ -1,34 +1,144 @@
|
|
|
1
1
|
import { BetterAuth } from "./index";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
AdapterDebugLogs,
|
|
4
|
+
CleanedWhere,
|
|
5
|
+
createAdapter,
|
|
6
|
+
} from "better-auth/adapters";
|
|
4
7
|
import {
|
|
5
8
|
GenericActionCtx,
|
|
6
9
|
GenericMutationCtx,
|
|
7
10
|
GenericQueryCtx,
|
|
11
|
+
PaginationOptions,
|
|
12
|
+
PaginationResult,
|
|
8
13
|
} from "convex/server";
|
|
14
|
+
import { SetOptional } from "type-fest";
|
|
15
|
+
|
|
16
|
+
const handlePagination = async (
|
|
17
|
+
next: ({
|
|
18
|
+
paginationOpts,
|
|
19
|
+
}: {
|
|
20
|
+
paginationOpts: PaginationOptions;
|
|
21
|
+
}) => Promise<
|
|
22
|
+
SetOptional<PaginationResult<any>, "page"> & { count?: number }
|
|
23
|
+
>,
|
|
24
|
+
{ limit, numItems }: { limit?: number; numItems?: number } = {}
|
|
25
|
+
) => {
|
|
26
|
+
const state: {
|
|
27
|
+
isDone: boolean;
|
|
28
|
+
cursor: string | null;
|
|
29
|
+
docs: any[];
|
|
30
|
+
count: number;
|
|
31
|
+
} = {
|
|
32
|
+
isDone: false,
|
|
33
|
+
cursor: null,
|
|
34
|
+
docs: [],
|
|
35
|
+
count: 0,
|
|
36
|
+
};
|
|
37
|
+
const onResult = (
|
|
38
|
+
result: SetOptional<PaginationResult<any>, "page"> & { count?: number }
|
|
39
|
+
) => {
|
|
40
|
+
state.cursor =
|
|
41
|
+
result.pageStatus === "SplitRecommended" ||
|
|
42
|
+
result.pageStatus === "SplitRequired"
|
|
43
|
+
? result.splitCursor ?? result.continueCursor
|
|
44
|
+
: result.continueCursor;
|
|
45
|
+
if (result.page) {
|
|
46
|
+
state.docs.push(...result.page);
|
|
47
|
+
state.isDone = (limit && state.docs.length >= limit) || result.isDone;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// Update and delete only return a count
|
|
51
|
+
if (result.count) {
|
|
52
|
+
state.count += result.count;
|
|
53
|
+
state.isDone = (limit && state.count >= limit) || result.isDone;
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
state.isDone = result.isDone;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
do {
|
|
60
|
+
const result = await next({
|
|
61
|
+
paginationOpts: {
|
|
62
|
+
numItems: Math.min(
|
|
63
|
+
numItems ?? 200,
|
|
64
|
+
(limit ?? 200) - state.docs.length,
|
|
65
|
+
200
|
|
66
|
+
),
|
|
67
|
+
cursor: state.cursor,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
onResult(result);
|
|
71
|
+
} while (!state.isDone);
|
|
72
|
+
return state;
|
|
73
|
+
};
|
|
9
74
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
75
|
+
type ConvexCleanedWhere = CleanedWhere & {
|
|
76
|
+
value: string | number | boolean | string[] | number[] | null;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const parseWhere = (where?: CleanedWhere[]): ConvexCleanedWhere[] => {
|
|
80
|
+
return where?.map((where) => {
|
|
81
|
+
if (where.value instanceof Date) {
|
|
82
|
+
return {
|
|
83
|
+
...where,
|
|
84
|
+
value: where.value.getTime(),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return where;
|
|
88
|
+
}) as ConvexCleanedWhere[];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
type GenericCtx =
|
|
92
|
+
| GenericQueryCtx<any>
|
|
93
|
+
| GenericMutationCtx<any>
|
|
94
|
+
| GenericActionCtx<any>;
|
|
95
|
+
|
|
96
|
+
interface ConvexAdapterConfig {
|
|
97
|
+
/**
|
|
98
|
+
* Helps you debug issues with the adapter.
|
|
99
|
+
*/
|
|
100
|
+
debugLogs?: AdapterDebugLogs;
|
|
101
|
+
}
|
|
102
|
+
export const convexAdapter = (
|
|
103
|
+
ctx: GenericCtx,
|
|
104
|
+
component: BetterAuth,
|
|
105
|
+
config: ConvexAdapterConfig = {}
|
|
106
|
+
) => {
|
|
107
|
+
const { debugLogs } = config;
|
|
108
|
+
return createAdapter({
|
|
20
109
|
config: {
|
|
21
110
|
adapterId: "convex",
|
|
22
111
|
adapterName: "Convex Adapter",
|
|
23
|
-
debugLogs: component.config.verbose ?? false,
|
|
112
|
+
debugLogs: component.config.verbose ?? debugLogs ?? false,
|
|
24
113
|
disableIdGeneration: true,
|
|
114
|
+
supportsNumericIds: false,
|
|
115
|
+
usePlural: false,
|
|
116
|
+
mapKeysTransformOutput: {
|
|
117
|
+
_id: "id",
|
|
118
|
+
},
|
|
119
|
+
// With supportsDates: false, dates are stored as strings,
|
|
120
|
+
// we convert them to numbers here. This aligns with how
|
|
121
|
+
// Convex stores _creationTime, and avoids a breaking change.
|
|
122
|
+
supportsDates: false,
|
|
123
|
+
customTransformInput: ({ data, fieldAttributes }) => {
|
|
124
|
+
if (data && fieldAttributes.type === "date") {
|
|
125
|
+
return new Date(data).getTime();
|
|
126
|
+
}
|
|
127
|
+
return data;
|
|
128
|
+
},
|
|
129
|
+
customTransformOutput: ({ data, fieldAttributes }) => {
|
|
130
|
+
if (data && fieldAttributes.type === "date") {
|
|
131
|
+
return new Date(data).getTime();
|
|
132
|
+
}
|
|
133
|
+
return data;
|
|
134
|
+
},
|
|
25
135
|
},
|
|
26
|
-
adapter: (
|
|
136
|
+
adapter: () => {
|
|
27
137
|
return {
|
|
28
138
|
id: "convex",
|
|
29
139
|
create: async ({ model, data, select }): Promise<any> => {
|
|
30
140
|
if (!("runMutation" in ctx)) {
|
|
31
|
-
throw new Error("ctx is not
|
|
141
|
+
throw new Error("ctx is not a mutation ctx");
|
|
32
142
|
}
|
|
33
143
|
if (select) {
|
|
34
144
|
throw new Error("select is not supported");
|
|
@@ -39,223 +149,125 @@ export const convexAdapter = <
|
|
|
39
149
|
: model === "session"
|
|
40
150
|
? component.config.authFunctions.createSession
|
|
41
151
|
: component.component.lib.create;
|
|
42
|
-
return ctx.runMutation(createFn, {
|
|
43
|
-
input: {
|
|
152
|
+
return await ctx.runMutation(createFn, {
|
|
153
|
+
input: { model, data },
|
|
44
154
|
});
|
|
45
155
|
},
|
|
46
|
-
findOne: async (
|
|
47
|
-
if (where
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (
|
|
59
|
-
model === "account" &&
|
|
60
|
-
where.length === 2 &&
|
|
61
|
-
where[0].field === "accountId" &&
|
|
62
|
-
where[1].field === "providerId" &&
|
|
63
|
-
where[0].connector === "AND"
|
|
64
|
-
) {
|
|
65
|
-
return ctx.runQuery(
|
|
66
|
-
component.component.lib.getAccountByAccountIdAndProviderId,
|
|
67
|
-
{
|
|
68
|
-
accountId: where[0].value as string,
|
|
69
|
-
providerId: where[1].value as string,
|
|
156
|
+
findOne: async (data): Promise<any> => {
|
|
157
|
+
if (data.where?.every((w) => w.connector === "OR")) {
|
|
158
|
+
for (const w of data.where) {
|
|
159
|
+
const result = await ctx.runQuery(
|
|
160
|
+
component.component.lib.findOne,
|
|
161
|
+
{
|
|
162
|
+
...data,
|
|
163
|
+
where: parseWhere([w]),
|
|
164
|
+
}
|
|
165
|
+
);
|
|
166
|
+
if (result) {
|
|
167
|
+
return result;
|
|
70
168
|
}
|
|
71
|
-
|
|
169
|
+
}
|
|
72
170
|
}
|
|
73
|
-
|
|
171
|
+
return await ctx.runQuery(component.component.lib.findOne, {
|
|
172
|
+
...data,
|
|
173
|
+
where: parseWhere(data.where),
|
|
174
|
+
});
|
|
74
175
|
},
|
|
75
|
-
findMany: async ({
|
|
76
|
-
|
|
77
|
-
where,
|
|
78
|
-
sortBy,
|
|
79
|
-
offset,
|
|
80
|
-
limit,
|
|
81
|
-
}): Promise<any[]> => {
|
|
82
|
-
if (offset) {
|
|
176
|
+
findMany: async (data): Promise<any[]> => {
|
|
177
|
+
if (data.offset) {
|
|
83
178
|
throw new Error("offset not supported");
|
|
84
179
|
}
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
!where &&
|
|
88
|
-
(!sortBy ||
|
|
89
|
-
(sortBy?.field === "createdAt" && sortBy?.direction === "desc"))
|
|
90
|
-
) {
|
|
91
|
-
return ctx.runQuery(component.component.lib.getJwks, { limit });
|
|
92
|
-
}
|
|
93
|
-
if (
|
|
94
|
-
where?.length !== 1 ||
|
|
95
|
-
(where[0].operator && where[0].operator !== "eq")
|
|
96
|
-
) {
|
|
97
|
-
throw new Error("where clause not supported");
|
|
98
|
-
}
|
|
99
|
-
if (model === "verification" && where[0].field === "identifier") {
|
|
100
|
-
return ctx.runQuery(
|
|
101
|
-
component.component.lib.listVerificationsByIdentifier,
|
|
102
|
-
{
|
|
103
|
-
identifier: where[0].value as string,
|
|
104
|
-
sortBy,
|
|
105
|
-
limit,
|
|
106
|
-
}
|
|
107
|
-
);
|
|
180
|
+
if (data.where?.some((w) => w.connector === "OR")) {
|
|
181
|
+
throw new Error("OR connector not supported in findMany");
|
|
108
182
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
183
|
+
const result = await handlePagination(
|
|
184
|
+
async ({ paginationOpts }) => {
|
|
185
|
+
return await ctx.runQuery(component.component.lib.findMany, {
|
|
186
|
+
...data,
|
|
187
|
+
where: parseWhere(data.where),
|
|
188
|
+
paginationOpts,
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
{ limit: data.limit }
|
|
192
|
+
);
|
|
193
|
+
return result.docs;
|
|
194
|
+
},
|
|
195
|
+
count: async (data) => {
|
|
196
|
+
// Yes, count is just findMany returning a number.
|
|
197
|
+
if (data.where?.some((w) => w.connector === "OR")) {
|
|
198
|
+
throw new Error("OR connector not supported in findMany");
|
|
114
199
|
}
|
|
115
|
-
|
|
116
|
-
return ctx.runQuery(component.component.lib.
|
|
117
|
-
|
|
118
|
-
|
|
200
|
+
const result = await handlePagination(async ({ paginationOpts }) => {
|
|
201
|
+
return await ctx.runQuery(component.component.lib.findMany, {
|
|
202
|
+
...data,
|
|
203
|
+
where: parseWhere(data.where),
|
|
204
|
+
paginationOpts,
|
|
119
205
|
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
count: async ({ where }) => {
|
|
124
|
-
throw new Error("count not implemented");
|
|
125
|
-
// return 0;
|
|
206
|
+
});
|
|
207
|
+
return result.docs?.length ?? 0;
|
|
126
208
|
},
|
|
127
|
-
update: async (
|
|
209
|
+
update: async (data): Promise<any> => {
|
|
128
210
|
if (!("runMutation" in ctx)) {
|
|
129
|
-
throw new Error("ctx is not
|
|
211
|
+
throw new Error("ctx is not a mutation ctx");
|
|
130
212
|
}
|
|
131
|
-
if (where?.length === 1 && where[0].operator === "eq") {
|
|
132
|
-
const { value, field } = where[0];
|
|
213
|
+
if (data.where?.length === 1 && data.where[0].operator === "eq") {
|
|
133
214
|
const updateFn =
|
|
134
|
-
model === "user"
|
|
215
|
+
data.model === "user"
|
|
135
216
|
? component.config.authFunctions.updateUser
|
|
136
|
-
: component.component.lib.
|
|
217
|
+
: component.component.lib.updateOne;
|
|
137
218
|
return ctx.runMutation(updateFn, {
|
|
138
219
|
input: {
|
|
139
|
-
|
|
140
|
-
where:
|
|
141
|
-
|
|
142
|
-
value: value instanceof Date ? value.getTime() : value,
|
|
143
|
-
},
|
|
144
|
-
value: transformInput(model, update as any),
|
|
220
|
+
model: data.model,
|
|
221
|
+
where: parseWhere(data.where),
|
|
222
|
+
update: data.update as any,
|
|
145
223
|
},
|
|
146
224
|
});
|
|
147
225
|
}
|
|
148
226
|
throw new Error("where clause not supported");
|
|
149
227
|
},
|
|
150
|
-
delete: async (
|
|
228
|
+
delete: async (data) => {
|
|
151
229
|
if (!("runMutation" in ctx)) {
|
|
152
|
-
throw new Error("ctx is not
|
|
230
|
+
throw new Error("ctx is not a mutation ctx");
|
|
153
231
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
value: value instanceof Date ? value.getTime() : value,
|
|
164
|
-
});
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
throw new Error("where clause not supported");
|
|
168
|
-
// return null
|
|
232
|
+
const deleteFn =
|
|
233
|
+
data.model === "user"
|
|
234
|
+
? component.config.authFunctions.deleteUser
|
|
235
|
+
: component.component.lib.deleteOne;
|
|
236
|
+
await ctx.runMutation(deleteFn, {
|
|
237
|
+
model: data.model,
|
|
238
|
+
where: parseWhere(data.where),
|
|
239
|
+
});
|
|
240
|
+
return;
|
|
169
241
|
},
|
|
170
|
-
deleteMany: async (
|
|
171
|
-
if (!("
|
|
172
|
-
throw new Error("ctx is not
|
|
173
|
-
}
|
|
174
|
-
if (
|
|
175
|
-
model === "verification" &&
|
|
176
|
-
where?.length === 1 &&
|
|
177
|
-
where[0].operator === "lt" &&
|
|
178
|
-
where[0].field === "expiresAt"
|
|
179
|
-
) {
|
|
180
|
-
return ctx.runAction(
|
|
181
|
-
component.component.lib.deleteOldVerifications,
|
|
182
|
-
{
|
|
183
|
-
currentTimestamp: Date.now(),
|
|
184
|
-
}
|
|
185
|
-
);
|
|
242
|
+
deleteMany: async (data) => {
|
|
243
|
+
if (!("runMutation" in ctx)) {
|
|
244
|
+
throw new Error("ctx is not a mutation ctx");
|
|
186
245
|
}
|
|
187
|
-
|
|
188
|
-
return ctx.
|
|
189
|
-
|
|
190
|
-
|
|
246
|
+
const result = await handlePagination(async ({ paginationOpts }) => {
|
|
247
|
+
return await ctx.runMutation(component.component.lib.deleteMany, {
|
|
248
|
+
...data,
|
|
249
|
+
where: parseWhere(data.where),
|
|
250
|
+
paginationOpts,
|
|
191
251
|
});
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
model === "session" &&
|
|
195
|
-
where?.length === 2 &&
|
|
196
|
-
where[0].operator === "eq" &&
|
|
197
|
-
where[0].connector === "AND" &&
|
|
198
|
-
where[0].field === "userId" &&
|
|
199
|
-
where[1].operator === "lte" &&
|
|
200
|
-
where[1].field === "expiresAt" &&
|
|
201
|
-
typeof where[1].value === "number"
|
|
202
|
-
) {
|
|
203
|
-
return ctx.runMutation(
|
|
204
|
-
component.component.lib.deleteExpiredSessions,
|
|
205
|
-
{
|
|
206
|
-
userId: where[0].value as string,
|
|
207
|
-
expiresAt: where[1].value as number,
|
|
208
|
-
}
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
throw new Error("where clause not supported");
|
|
212
|
-
// return count;
|
|
252
|
+
});
|
|
253
|
+
return result.count;
|
|
213
254
|
},
|
|
214
|
-
updateMany: async (
|
|
255
|
+
updateMany: async (data) => {
|
|
215
256
|
if (!("runMutation" in ctx)) {
|
|
216
257
|
throw new Error("ctx is not an action ctx");
|
|
217
258
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
userId: where[0].value as string,
|
|
226
|
-
update: transformInput(model, update as any),
|
|
259
|
+
const result = await handlePagination(async ({ paginationOpts }) => {
|
|
260
|
+
return await ctx.runMutation(component.component.lib.updateMany, {
|
|
261
|
+
input: {
|
|
262
|
+
...data,
|
|
263
|
+
where: parseWhere(data.where),
|
|
264
|
+
paginationOpts,
|
|
265
|
+
},
|
|
227
266
|
});
|
|
228
|
-
}
|
|
229
|
-
if (
|
|
230
|
-
model === "account" &&
|
|
231
|
-
where?.length === 2 &&
|
|
232
|
-
where[0].operator === "eq" &&
|
|
233
|
-
where[0].connector === "AND" &&
|
|
234
|
-
where[0].field === "userId" &&
|
|
235
|
-
where[1].operator === "eq" &&
|
|
236
|
-
where[1].field === "providerId"
|
|
237
|
-
) {
|
|
238
|
-
return ctx.runMutation(
|
|
239
|
-
component.component.lib.updateUserProviderAccounts,
|
|
240
|
-
{
|
|
241
|
-
userId: where[0].value as string,
|
|
242
|
-
providerId: where[1].value as string,
|
|
243
|
-
update: transformInput(model, update as any),
|
|
244
|
-
}
|
|
245
|
-
);
|
|
246
|
-
}
|
|
247
|
-
throw new Error("updateMany not implemented");
|
|
248
|
-
//return 0;
|
|
249
|
-
/*
|
|
250
|
-
const { model, where, update } = data;
|
|
251
|
-
const table = db[model];
|
|
252
|
-
const res = convertWhereClause(where, table, model);
|
|
253
|
-
res.forEach((record) => {
|
|
254
|
-
Object.assign(record, update);
|
|
255
267
|
});
|
|
256
|
-
return
|
|
257
|
-
*/
|
|
268
|
+
return result.count;
|
|
258
269
|
},
|
|
259
270
|
};
|
|
260
271
|
},
|
|
261
272
|
});
|
|
273
|
+
};
|
package/src/client/index.ts
CHANGED
|
@@ -16,33 +16,36 @@ import { type GenericId, Infer, v } from "convex/values";
|
|
|
16
16
|
import type { api } from "../component/_generated/api";
|
|
17
17
|
import schema from "../component/schema";
|
|
18
18
|
import { convexAdapter } from "./adapter";
|
|
19
|
-
import corsRouter from "./cors";
|
|
20
|
-
import { getByArgsValidator, updateArgsInputValidator } from "../component/lib";
|
|
21
19
|
import { betterAuth } from "better-auth";
|
|
22
20
|
import { omit } from "convex-helpers";
|
|
23
21
|
import { createCookieGetter } from "better-auth/cookies";
|
|
24
22
|
import { fetchQuery } from "convex/nextjs";
|
|
25
23
|
import { JWT_COOKIE_NAME } from "../plugins/convex";
|
|
26
|
-
import { requireEnv } from "../
|
|
24
|
+
import { requireEnv } from "../utils";
|
|
25
|
+
import { partial } from "convex-helpers/validators";
|
|
26
|
+
import { adapterArgsValidator, adapterWhereValidator } from "../component/lib";
|
|
27
|
+
import { corsRouter } from "convex-helpers/server/cors";
|
|
27
28
|
export { convexAdapter };
|
|
28
29
|
|
|
29
30
|
const createUserFields = omit(schema.tables.user.validator.fields, ["userId"]);
|
|
30
31
|
const createUserValidator = v.object(createUserFields);
|
|
31
32
|
const createUserArgsValidator = v.object({
|
|
32
33
|
input: v.object({
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
model: v.literal("user"),
|
|
35
|
+
data: v.object(createUserFields),
|
|
35
36
|
}),
|
|
36
37
|
});
|
|
37
38
|
const updateUserArgsValidator = v.object({
|
|
38
|
-
input:
|
|
39
|
+
input: v.object({
|
|
40
|
+
model: v.literal("user"),
|
|
41
|
+
where: v.optional(v.array(adapterWhereValidator)),
|
|
42
|
+
update: v.object(partial(createUserFields)),
|
|
43
|
+
}),
|
|
39
44
|
});
|
|
40
|
-
const deleteUserArgsValidator = v.object(getByArgsValidator);
|
|
41
|
-
|
|
42
45
|
const createSessionArgsValidator = v.object({
|
|
43
46
|
input: v.object({
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
model: v.literal("session"),
|
|
48
|
+
data: v.object(schema.tables.session.validator.fields),
|
|
46
49
|
}),
|
|
47
50
|
});
|
|
48
51
|
|
|
@@ -61,7 +64,7 @@ export type AuthFunctions = {
|
|
|
61
64
|
deleteUser: FunctionReference<
|
|
62
65
|
"mutation",
|
|
63
66
|
"internal",
|
|
64
|
-
Infer<typeof
|
|
67
|
+
Infer<typeof adapterArgsValidator>
|
|
65
68
|
>;
|
|
66
69
|
updateUser: FunctionReference<
|
|
67
70
|
"mutation",
|
|
@@ -128,10 +131,14 @@ export class BetterAuth<UserId extends string = string> {
|
|
|
128
131
|
if (!identity) {
|
|
129
132
|
return null;
|
|
130
133
|
}
|
|
131
|
-
const doc = await ctx.runQuery(this.component.lib.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
134
|
+
const doc = await ctx.runQuery(this.component.lib.findOne, {
|
|
135
|
+
model: "user",
|
|
136
|
+
where: [
|
|
137
|
+
{
|
|
138
|
+
field: "userId",
|
|
139
|
+
value: identity.subject,
|
|
140
|
+
},
|
|
141
|
+
],
|
|
135
142
|
});
|
|
136
143
|
if (!doc) {
|
|
137
144
|
return null;
|
|
@@ -182,35 +189,38 @@ export class BetterAuth<UserId extends string = string> {
|
|
|
182
189
|
createUser: internalMutationGeneric({
|
|
183
190
|
args: createUserArgsValidator,
|
|
184
191
|
handler: async (ctx, args) => {
|
|
185
|
-
const userId = await opts.onCreateUser(ctx, args.input);
|
|
186
|
-
const input = { ...args.input, table: "user", userId };
|
|
192
|
+
const userId = await opts.onCreateUser(ctx, args.input.data);
|
|
187
193
|
return ctx.runMutation(this.component.lib.create, {
|
|
188
|
-
input
|
|
194
|
+
input: {
|
|
195
|
+
...args.input,
|
|
196
|
+
data: { ...args.input.data, userId },
|
|
197
|
+
},
|
|
189
198
|
});
|
|
190
199
|
},
|
|
191
200
|
}),
|
|
192
201
|
deleteUser: internalMutationGeneric({
|
|
193
|
-
args:
|
|
202
|
+
args: adapterArgsValidator,
|
|
194
203
|
handler: async (ctx, args) => {
|
|
195
|
-
const doc = await ctx.runMutation(this.component.lib.
|
|
196
|
-
if (opts.onDeleteUser) {
|
|
204
|
+
const doc = await ctx.runMutation(this.component.lib.deleteOne, args);
|
|
205
|
+
if (doc && opts.onDeleteUser) {
|
|
197
206
|
await opts.onDeleteUser(ctx, doc.userId as UserId);
|
|
198
207
|
}
|
|
208
|
+
return doc;
|
|
199
209
|
},
|
|
200
210
|
}),
|
|
201
211
|
updateUser: internalMutationGeneric({
|
|
202
212
|
args: updateUserArgsValidator,
|
|
203
213
|
handler: async (ctx, args) => {
|
|
204
214
|
const updatedUser = await ctx.runMutation(
|
|
205
|
-
this.component.lib.
|
|
206
|
-
args
|
|
215
|
+
this.component.lib.updateOne,
|
|
216
|
+
{ input: args.input }
|
|
207
217
|
);
|
|
208
218
|
// Type narrowing
|
|
209
219
|
if (!("emailVerified" in updatedUser)) {
|
|
210
220
|
throw new Error("invalid user");
|
|
211
221
|
}
|
|
212
222
|
if (opts.onUpdateUser) {
|
|
213
|
-
await opts.onUpdateUser(ctx, omit(updatedUser, ["
|
|
223
|
+
await opts.onUpdateUser(ctx, omit(updatedUser, ["_id"]));
|
|
214
224
|
}
|
|
215
225
|
return updatedUser;
|
|
216
226
|
},
|
|
@@ -218,14 +228,9 @@ export class BetterAuth<UserId extends string = string> {
|
|
|
218
228
|
createSession: internalMutationGeneric({
|
|
219
229
|
args: createSessionArgsValidator,
|
|
220
230
|
handler: async (ctx, args) => {
|
|
221
|
-
const session = await ctx.runMutation(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
);
|
|
225
|
-
// Type narrowing
|
|
226
|
-
if (!("ipAddress" in session)) {
|
|
227
|
-
throw new Error("invalid session");
|
|
228
|
-
}
|
|
231
|
+
const session = await ctx.runMutation(this.component.lib.create, {
|
|
232
|
+
input: args.input,
|
|
233
|
+
});
|
|
229
234
|
await opts.onCreateSession?.(ctx, session);
|
|
230
235
|
return session;
|
|
231
236
|
},
|
|
@@ -283,50 +288,20 @@ export class BetterAuth<UserId extends string = string> {
|
|
|
283
288
|
|
|
284
289
|
return;
|
|
285
290
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
const trustedOriginsFromPlugins =
|
|
295
|
-
betterAuthOptions.plugins?.reduce((acc, plugin) => {
|
|
296
|
-
if (plugin.options?.trustedOrigins) {
|
|
297
|
-
acc.push(...plugin.options.trustedOrigins);
|
|
298
|
-
}
|
|
299
|
-
return acc;
|
|
300
|
-
}, [] as string[]) ?? [];
|
|
301
|
-
|
|
302
|
-
// Reuse trustedOrigins as default for allowedOrigins
|
|
303
|
-
const allowedOrigins = async (request: Request) => {
|
|
304
|
-
return (
|
|
305
|
-
await Promise.all(
|
|
306
|
-
[...trustedOrigins, ...trustedOriginsFromPlugins].map(
|
|
307
|
-
async (origin) => {
|
|
308
|
-
if (!origin) {
|
|
309
|
-
return [];
|
|
310
|
-
}
|
|
311
|
-
if (typeof origin === "function") {
|
|
312
|
-
return origin(request);
|
|
313
|
-
}
|
|
314
|
-
return [origin];
|
|
315
|
-
}
|
|
316
|
-
)
|
|
317
|
-
)
|
|
318
|
-
)
|
|
319
|
-
.flat()
|
|
320
|
-
.map((origin) =>
|
|
291
|
+
const cors = corsRouter(http, {
|
|
292
|
+
allowedOrigins: async (request) => {
|
|
293
|
+
const trustedOriginsOption =
|
|
294
|
+
(await createAuth({} as any).$context).options.trustedOrigins ?? [];
|
|
295
|
+
const trustedOrigins = Array.isArray(trustedOriginsOption)
|
|
296
|
+
? trustedOriginsOption
|
|
297
|
+
: await trustedOriginsOption(request);
|
|
298
|
+
return trustedOrigins.map((origin) =>
|
|
321
299
|
// Strip trailing wildcards, unsupported for allowedOrigins
|
|
322
300
|
origin.endsWith("*") && origin.length > 1
|
|
323
301
|
? origin.slice(0, -1)
|
|
324
302
|
: origin
|
|
325
303
|
);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const cors = corsRouter(http, {
|
|
329
|
-
allowedOrigins,
|
|
304
|
+
},
|
|
330
305
|
allowCredentials: true,
|
|
331
306
|
allowedHeaders: ["Content-Type", "Better-Auth-Cookie"],
|
|
332
307
|
exposedHeaders: ["Set-Better-Auth-Cookie"],
|