@convex-dev/better-auth 0.7.0-alpha.12 → 0.7.0-alpha.3
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 +1 -10
- package/dist/commonjs/client/adapter.d.ts.map +1 -1
- package/dist/commonjs/client/adapter.js +192 -183
- package/dist/commonjs/client/adapter.js.map +1 -1
- package/dist/commonjs/client/index.d.ts +179 -238
- package/dist/commonjs/client/index.d.ts.map +1 -1
- package/dist/commonjs/client/index.js +67 -60
- package/dist/commonjs/client/index.js.map +1 -1
- package/dist/commonjs/component/lib.d.ts +548 -218
- package/dist/commonjs/component/lib.d.ts.map +1 -1
- package/dist/commonjs/component/lib.js +286 -315
- package/dist/commonjs/component/lib.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +28 -90
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +18 -76
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/util.d.ts +86 -148
- 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 +0 -3
- package/dist/commonjs/nextjs/index.js.map +1 -1
- package/dist/commonjs/plugins/convex/index.d.ts +11 -14
- package/dist/commonjs/plugins/convex/index.d.ts.map +1 -1
- package/dist/commonjs/plugins/convex/index.js +4 -10
- 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 +3 -5
- package/dist/commonjs/plugins/cross-domain/index.d.ts.map +1 -1
- package/dist/commonjs/plugins/cross-domain/index.js +5 -19
- 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 +9 -3
- package/dist/commonjs/react/client.js.map +1 -1
- package/dist/commonjs/react-start/index.d.ts +3 -37
- package/dist/commonjs/react-start/index.d.ts.map +1 -1
- package/dist/commonjs/react-start/index.js +4 -20
- package/dist/commonjs/react-start/index.js.map +1 -1
- package/dist/esm/client/adapter.d.ts +1 -10
- package/dist/esm/client/adapter.d.ts.map +1 -1
- package/dist/esm/client/adapter.js +192 -183
- package/dist/esm/client/adapter.js.map +1 -1
- package/dist/esm/client/index.d.ts +179 -238
- package/dist/esm/client/index.d.ts.map +1 -1
- package/dist/esm/client/index.js +67 -60
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/component/lib.d.ts +548 -218
- package/dist/esm/component/lib.d.ts.map +1 -1
- package/dist/esm/component/lib.js +286 -315
- package/dist/esm/component/lib.js.map +1 -1
- package/dist/esm/component/schema.d.ts +28 -90
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +18 -76
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/util.d.ts +86 -148
- 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 +0 -3
- package/dist/esm/nextjs/index.js.map +1 -1
- package/dist/esm/plugins/convex/index.d.ts +11 -14
- package/dist/esm/plugins/convex/index.d.ts.map +1 -1
- package/dist/esm/plugins/convex/index.js +4 -10
- 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 +3 -5
- package/dist/esm/plugins/cross-domain/index.d.ts.map +1 -1
- package/dist/esm/plugins/cross-domain/index.js +5 -19
- 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 +9 -3
- package/dist/esm/react/client.js.map +1 -1
- package/dist/esm/react-start/index.d.ts +3 -37
- package/dist/esm/react-start/index.d.ts.map +1 -1
- package/dist/esm/react-start/index.js +4 -20
- package/dist/esm/react-start/index.js.map +1 -1
- package/package.json +5 -20
- package/src/client/adapter.ts +195 -191
- package/src/client/cors.ts +425 -0
- package/src/client/index.ts +80 -61
- package/src/component/_generated/api.d.ts +149 -605
- package/src/component/lib.ts +335 -444
- package/src/component/schema.ts +19 -81
- package/src/nextjs/index.ts +0 -3
- package/src/plugins/convex/index.ts +4 -12
- package/src/plugins/cross-domain/index.ts +5 -19
- package/src/react/client.tsx +11 -5
- package/src/react-start/index.ts +6 -33
- package/dist/commonjs/component/adapterTest.d.ts +0 -19
- package/dist/commonjs/component/adapterTest.d.ts.map +0 -1
- package/dist/commonjs/component/adapterTest.js +0 -82
- package/dist/commonjs/component/adapterTest.js.map +0 -1
- package/dist/commonjs/utils/index.d.ts +0 -2
- package/dist/commonjs/utils/index.d.ts.map +0 -1
- package/dist/commonjs/utils/index.js +0 -8
- package/dist/commonjs/utils/index.js.map +0 -1
- package/dist/esm/component/adapterTest.d.ts +0 -19
- package/dist/esm/component/adapterTest.d.ts.map +0 -1
- package/dist/esm/component/adapterTest.js +0 -82
- package/dist/esm/component/adapterTest.js.map +0 -1
- package/dist/esm/utils/index.d.ts +0 -2
- package/dist/esm/utils/index.d.ts.map +0 -1
- package/dist/esm/utils/index.js +0 -8
- package/dist/esm/utils/index.js.map +0 -1
- package/src/client/adapter.test.ts +0 -144
- package/src/component/adapterTest.ts +0 -141
- package/src/react-start/vite-env.d.ts +0 -2
- /package/src/{utils/index.ts → util.ts} +0 -0
package/src/component/lib.ts
CHANGED
|
@@ -1,532 +1,423 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
action,
|
|
3
|
+
mutation,
|
|
4
|
+
query,
|
|
5
|
+
QueryCtx,
|
|
6
|
+
} from "../component/_generated/server";
|
|
2
7
|
import { asyncMap } from "convex-helpers";
|
|
3
|
-
import {
|
|
8
|
+
import { v } from "convex/values";
|
|
9
|
+
import { api } from "../component/_generated/api";
|
|
4
10
|
import { Doc, Id, TableNames } from "../component/_generated/dataModel";
|
|
5
|
-
import schema
|
|
6
|
-
import {
|
|
7
|
-
PaginationOptions,
|
|
8
|
-
paginationOptsValidator,
|
|
9
|
-
PaginationResult,
|
|
10
|
-
} from "convex/server";
|
|
11
|
+
import schema from "../component/schema";
|
|
12
|
+
import { paginationOptsValidator, PaginationResult } from "convex/server";
|
|
11
13
|
import { paginator } from "convex-helpers/server/pagination";
|
|
12
14
|
import { partial } from "convex-helpers/validators";
|
|
13
15
|
|
|
14
|
-
export const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
v.literal("contains"),
|
|
26
|
-
v.literal("starts_with"),
|
|
27
|
-
v.literal("ends_with")
|
|
28
|
-
)
|
|
29
|
-
),
|
|
30
|
-
value: v.union(
|
|
31
|
-
v.string(),
|
|
32
|
-
v.number(),
|
|
33
|
-
v.boolean(),
|
|
34
|
-
v.array(v.string()),
|
|
35
|
-
v.array(v.number()),
|
|
36
|
-
v.null()
|
|
37
|
-
),
|
|
38
|
-
connector: v.optional(v.union(v.literal("AND"), v.literal("OR"))),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
export const adapterArgsValidator = v.object({
|
|
42
|
-
model: v.string(),
|
|
43
|
-
where: v.optional(v.array(adapterWhereValidator)),
|
|
44
|
-
sortBy: v.optional(
|
|
45
|
-
v.object({
|
|
46
|
-
field: v.string(),
|
|
47
|
-
direction: v.union(v.literal("asc"), v.literal("desc")),
|
|
48
|
-
})
|
|
49
|
-
),
|
|
50
|
-
select: v.optional(v.array(v.string())),
|
|
51
|
-
limit: v.optional(v.number()),
|
|
52
|
-
unique: v.optional(v.boolean()),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const getUniqueFields = (table: TableNames, input: Record<string, any>) => {
|
|
56
|
-
const fields = specialFields[table as keyof typeof specialFields];
|
|
57
|
-
if (!fields) {
|
|
58
|
-
return [];
|
|
59
|
-
}
|
|
60
|
-
return Object.entries(fields)
|
|
61
|
-
.filter(
|
|
62
|
-
([key, value]) =>
|
|
63
|
-
value.unique && Object.keys(input).includes(key as keyof typeof input)
|
|
64
|
-
)
|
|
65
|
-
.map(([key]) => key);
|
|
16
|
+
export const transformInput = (model: string, data: Record<string, any>) => {
|
|
17
|
+
return {
|
|
18
|
+
...Object.fromEntries(
|
|
19
|
+
Object.entries(data).map(([key, value]) => {
|
|
20
|
+
if (value instanceof Date) {
|
|
21
|
+
return [key, value.getTime()];
|
|
22
|
+
}
|
|
23
|
+
return [key, value];
|
|
24
|
+
})
|
|
25
|
+
),
|
|
26
|
+
};
|
|
66
27
|
};
|
|
67
28
|
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
input: Record<string, any>,
|
|
72
|
-
doc?: Doc<any>
|
|
29
|
+
export const transformOutput = (
|
|
30
|
+
{ _id, _creationTime, ...data }: Doc<TableNames>,
|
|
31
|
+
_model: string
|
|
73
32
|
) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
for (const field of uniqueFields) {
|
|
79
|
-
const existingDoc = await ctx.db
|
|
80
|
-
.query(table as any)
|
|
81
|
-
.withIndex(field as any, (q) =>
|
|
82
|
-
q.eq(field, input[field as keyof typeof input])
|
|
83
|
-
)
|
|
84
|
-
.unique();
|
|
85
|
-
if (existingDoc && existingDoc._id !== doc?._id) {
|
|
86
|
-
throw new Error(`${table} ${field} already exists`);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
33
|
+
// Provide the expected id field, but it can be overwritten if
|
|
34
|
+
// the model has an id field
|
|
35
|
+
return { id: _id, ...data };
|
|
89
36
|
};
|
|
90
37
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
38
|
+
// Get the session via sessionId in jwt claims
|
|
39
|
+
export const getCurrentSession = query({
|
|
40
|
+
args: {},
|
|
41
|
+
handler: async (ctx) => {
|
|
42
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
43
|
+
if (!identity) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return ctx.db.get(identity.sessionId as Id<"session">);
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
export const getByHelper = async (
|
|
51
|
+
ctx: QueryCtx,
|
|
52
|
+
args: {
|
|
53
|
+
table: string;
|
|
94
54
|
field: string;
|
|
95
|
-
operator?: string;
|
|
96
55
|
value: any;
|
|
97
|
-
|
|
98
|
-
}[];
|
|
99
|
-
sortBy?: {
|
|
100
|
-
field: string;
|
|
101
|
-
direction: "asc" | "desc";
|
|
102
|
-
};
|
|
103
|
-
}) => {
|
|
104
|
-
if (!args.where && !args.sortBy) {
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
if (args.where?.some((w) => w.field === "id")) {
|
|
108
|
-
throw new Error("id is not a valid index field");
|
|
56
|
+
unique?: boolean;
|
|
109
57
|
}
|
|
110
|
-
if (args.where?.some((w) => w.connector && w.connector !== "AND")) {
|
|
111
|
-
throw new Error(
|
|
112
|
-
`OR connector not supported: ${JSON.stringify(args.where)}`
|
|
113
|
-
);
|
|
114
|
-
}
|
|
115
|
-
if (
|
|
116
|
-
args.where?.some(
|
|
117
|
-
(w) =>
|
|
118
|
-
w.operator &&
|
|
119
|
-
!["lt", "lte", "gt", "gte", "eq", "in"].includes(w.operator)
|
|
120
|
-
)
|
|
121
|
-
) {
|
|
122
|
-
throw new Error(
|
|
123
|
-
`where clause not supported: ${JSON.stringify(args.where)}`
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
const lowerBounds =
|
|
127
|
-
args.where?.filter((w) => w.operator === "lt" || w.operator === "lte") ??
|
|
128
|
-
[];
|
|
129
|
-
if (lowerBounds.length > 1) {
|
|
130
|
-
throw new Error(
|
|
131
|
-
`cannot have more than one lower bound where clause: ${JSON.stringify(args.where)}`
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
const upperBounds =
|
|
135
|
-
args.where?.filter((w) => w.operator === "gt" || w.operator === "gte") ??
|
|
136
|
-
[];
|
|
137
|
-
if (upperBounds.length > 1) {
|
|
138
|
-
throw new Error(
|
|
139
|
-
`cannot have more than one upper bound where clause: ${JSON.stringify(args.where)}`
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
const lowerBound = lowerBounds[0];
|
|
143
|
-
const upperBound = upperBounds[0];
|
|
144
|
-
if (lowerBound && upperBound && lowerBound.field !== upperBound.field) {
|
|
145
|
-
throw new Error(
|
|
146
|
-
`lower bound and upper bound must have the same field: ${JSON.stringify(args.where)}`
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
const boundField = lowerBound?.field || upperBound?.field;
|
|
150
|
-
if (
|
|
151
|
-
boundField &&
|
|
152
|
-
args.where?.some(
|
|
153
|
-
(w) => w.field === boundField && w !== lowerBound && w !== upperBound
|
|
154
|
-
)
|
|
155
|
-
) {
|
|
156
|
-
throw new Error(
|
|
157
|
-
`too many where clauses on the bound field: ${JSON.stringify(args.where)}`
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
const indexFields =
|
|
161
|
-
args.where
|
|
162
|
-
?.filter((w) => !w.operator || w.operator === "eq")
|
|
163
|
-
.sort((a, b) => {
|
|
164
|
-
return a.field.localeCompare(b.field);
|
|
165
|
-
})
|
|
166
|
-
.map((w) => [w.field, w.value]) ?? [];
|
|
167
|
-
if (!indexFields?.length && !boundField && !args.sortBy) {
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
const indexes =
|
|
171
|
-
schema.tables[args.model as keyof typeof schema.tables][" indexes"]();
|
|
172
|
-
const sortField = args.sortBy?.field;
|
|
173
|
-
|
|
174
|
-
// We internally use _creationTime in place of Better Auth's createdAt
|
|
175
|
-
const indexName = indexFields
|
|
176
|
-
.map(([field]) => field)
|
|
177
|
-
.join("_")
|
|
178
|
-
.concat(
|
|
179
|
-
boundField && boundField !== "createdAt"
|
|
180
|
-
? `${indexFields.length ? "_" : ""}${boundField}`
|
|
181
|
-
: ""
|
|
182
|
-
)
|
|
183
|
-
.concat(
|
|
184
|
-
sortField && sortField !== "createdAt" && boundField !== sortField
|
|
185
|
-
? `${indexFields.length || boundField ? "_" : ""}${sortField}`
|
|
186
|
-
: ""
|
|
187
|
-
);
|
|
188
|
-
if (!indexName && !boundField && !sortField) {
|
|
189
|
-
return;
|
|
190
|
-
}
|
|
191
|
-
// Use the built in creationTime index if bounding or sorting by createdAt
|
|
192
|
-
// with no other fields
|
|
193
|
-
const index = !indexName
|
|
194
|
-
? {
|
|
195
|
-
indexDescriptor: "by_creation_time",
|
|
196
|
-
fields: [],
|
|
197
|
-
}
|
|
198
|
-
: indexes.find(({ indexDescriptor }) => {
|
|
199
|
-
return boundField === "createdAt" || sortField === "createdAt"
|
|
200
|
-
? indexDescriptor === indexName
|
|
201
|
-
: indexDescriptor.startsWith(indexName);
|
|
202
|
-
});
|
|
203
|
-
if (!index) {
|
|
204
|
-
throw new Error(`Index ${indexName} not found for table ${args.model}`);
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
index: {
|
|
208
|
-
indexDescriptor: index.indexDescriptor,
|
|
209
|
-
fields: [...index.fields, "_creationTime"],
|
|
210
|
-
},
|
|
211
|
-
boundField,
|
|
212
|
-
sortField,
|
|
213
|
-
values: {
|
|
214
|
-
eq: indexFields.map(([, value]) => value),
|
|
215
|
-
lt: lowerBound?.operator === "lt" ? lowerBound.value : undefined,
|
|
216
|
-
lte: lowerBound?.operator === "lte" ? lowerBound.value : undefined,
|
|
217
|
-
gt: upperBound?.operator === "gt" ? upperBound.value : undefined,
|
|
218
|
-
gte: upperBound?.operator === "gte" ? upperBound.value : undefined,
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
};
|
|
222
|
-
|
|
223
|
-
const selectFields = <T extends TableNames, D extends Doc<T>>(
|
|
224
|
-
doc: D | null,
|
|
225
|
-
select?: string[]
|
|
226
58
|
) => {
|
|
227
|
-
if (
|
|
228
|
-
return
|
|
229
|
-
}
|
|
230
|
-
if (!select?.length) {
|
|
231
|
-
return doc;
|
|
59
|
+
if (args.field === "id") {
|
|
60
|
+
return ctx.db.get(args.value);
|
|
232
61
|
}
|
|
233
|
-
|
|
234
|
-
(
|
|
235
|
-
|
|
236
|
-
|
|
62
|
+
const query = ctx.db
|
|
63
|
+
.query(args.table as any)
|
|
64
|
+
.withIndex(args.field as any, (q) => q.eq(args.field, args.value));
|
|
65
|
+
return args.unique ? await query.unique() : await query.first();
|
|
237
66
|
};
|
|
238
67
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const doc = await ctx.db.get(idWhere.value as Id<TableNames>);
|
|
252
|
-
return {
|
|
253
|
-
page: [selectFields(doc, args.select)].filter(Boolean),
|
|
254
|
-
isDone: true,
|
|
255
|
-
continueCursor: "",
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
const { index, values, boundField } = (await findIndex(args)) ?? {};
|
|
259
|
-
const query = paginator(ctx.db, schema).query(args.model as any);
|
|
260
|
-
const hasValues =
|
|
261
|
-
values?.eq?.length ||
|
|
262
|
-
values?.lt ||
|
|
263
|
-
values?.lte ||
|
|
264
|
-
values?.gt ||
|
|
265
|
-
values?.gte;
|
|
266
|
-
const indexedQuery =
|
|
267
|
-
index && index.indexDescriptor !== "by_creation_time"
|
|
268
|
-
? query.withIndex(
|
|
269
|
-
index.indexDescriptor,
|
|
270
|
-
hasValues
|
|
271
|
-
? (q: any) => {
|
|
272
|
-
for (const [idx, value] of (values?.eq ?? []).entries()) {
|
|
273
|
-
q = q.eq(index.fields[idx], value);
|
|
274
|
-
}
|
|
275
|
-
if (values?.lt) {
|
|
276
|
-
q = q.lt(boundField, values.lt);
|
|
277
|
-
}
|
|
278
|
-
if (values?.lte) {
|
|
279
|
-
q = q.lte(boundField, values.lte);
|
|
280
|
-
}
|
|
281
|
-
if (values?.gt) {
|
|
282
|
-
q = q.gt(boundField, values.gt);
|
|
283
|
-
}
|
|
284
|
-
if (values?.gte) {
|
|
285
|
-
q = q.gte(boundField, values.gte);
|
|
286
|
-
}
|
|
287
|
-
return q;
|
|
288
|
-
}
|
|
289
|
-
: undefined
|
|
290
|
-
)
|
|
291
|
-
: query;
|
|
292
|
-
|
|
293
|
-
const orderedQuery = args.sortBy
|
|
294
|
-
? indexedQuery.order(args.sortBy.direction === "asc" ? "asc" : "desc")
|
|
295
|
-
: indexedQuery;
|
|
296
|
-
const result = await orderedQuery.paginate(args.paginationOpts);
|
|
297
|
-
return {
|
|
298
|
-
...result,
|
|
299
|
-
page: result.page.map((doc) => selectFields(doc, args.select)),
|
|
300
|
-
};
|
|
68
|
+
export const getByArgsValidator = {
|
|
69
|
+
table: v.string(),
|
|
70
|
+
field: v.string(),
|
|
71
|
+
unique: v.optional(v.boolean()),
|
|
72
|
+
value: v.union(
|
|
73
|
+
v.string(),
|
|
74
|
+
v.number(),
|
|
75
|
+
v.boolean(),
|
|
76
|
+
v.array(v.string()),
|
|
77
|
+
v.array(v.number()),
|
|
78
|
+
v.null()
|
|
79
|
+
),
|
|
301
80
|
};
|
|
302
81
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
args:
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
).page[0];
|
|
316
|
-
};
|
|
82
|
+
// Generic functions
|
|
83
|
+
export const getByQuery = query({
|
|
84
|
+
args: getByArgsValidator,
|
|
85
|
+
handler: async (ctx, args) => {
|
|
86
|
+
const doc = await getByHelper(ctx, args);
|
|
87
|
+
if (!doc) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
return transformOutput(doc, args.table);
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
export { getByQuery as getBy };
|
|
317
94
|
|
|
318
95
|
export const create = mutation({
|
|
319
|
-
args: {
|
|
96
|
+
args: v.object({
|
|
320
97
|
input: v.union(
|
|
321
|
-
...Object.
|
|
98
|
+
...Object.values(schema.tables).map((table) =>
|
|
322
99
|
v.object({
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
data: v.object(table.validator.fields),
|
|
100
|
+
table: v.string(),
|
|
101
|
+
...table.validator.fields,
|
|
326
102
|
})
|
|
327
103
|
)
|
|
328
104
|
),
|
|
105
|
+
}),
|
|
106
|
+
handler: async (ctx, args) => {
|
|
107
|
+
const { table, ...input } = args.input;
|
|
108
|
+
const id = await ctx.db.insert(table as any, {
|
|
109
|
+
...input,
|
|
110
|
+
});
|
|
111
|
+
const doc = await ctx.db.get(id);
|
|
112
|
+
if (!doc) {
|
|
113
|
+
throw new Error(`Failed to create ${table}`);
|
|
114
|
+
}
|
|
115
|
+
return transformOutput(doc, table);
|
|
329
116
|
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
export const updateArgsInputValidator = <T extends TableNames>(table: T) => {
|
|
120
|
+
return v.object({
|
|
121
|
+
table: v.literal(table),
|
|
122
|
+
where: v.object({ field: v.string(), value: getByArgsValidator.value }),
|
|
123
|
+
value: v.record(v.string(), v.any()),
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const updateArgsValidator = {
|
|
128
|
+
input: v.union(
|
|
129
|
+
updateArgsInputValidator("account"),
|
|
130
|
+
updateArgsInputValidator("session"),
|
|
131
|
+
updateArgsInputValidator("verification"),
|
|
132
|
+
updateArgsInputValidator("user")
|
|
133
|
+
),
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
export const update = mutation({
|
|
137
|
+
args: updateArgsValidator,
|
|
330
138
|
handler: async (ctx, args) => {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
139
|
+
const { table, where, value } = args.input;
|
|
140
|
+
const doc =
|
|
141
|
+
where.field === "id"
|
|
142
|
+
? await ctx.db.get(where.value as Id<any>)
|
|
143
|
+
: await getByHelper(ctx, { table, ...where });
|
|
144
|
+
if (!doc) {
|
|
145
|
+
throw new Error(`Failed to update ${table}`);
|
|
146
|
+
}
|
|
147
|
+
await ctx.db.patch(doc._id, value as any);
|
|
148
|
+
const updatedDoc = await ctx.db.get(doc._id);
|
|
149
|
+
if (!updatedDoc) {
|
|
150
|
+
throw new Error(`Failed to update ${table}`);
|
|
151
|
+
}
|
|
152
|
+
return transformOutput(updatedDoc, table);
|
|
153
|
+
},
|
|
154
|
+
});
|
|
336
155
|
|
|
337
|
-
|
|
338
|
-
|
|
156
|
+
export const deleteBy = mutation({
|
|
157
|
+
args: getByArgsValidator,
|
|
158
|
+
handler: async (ctx, args) => {
|
|
159
|
+
const doc = await getByHelper(ctx, args);
|
|
339
160
|
if (!doc) {
|
|
340
|
-
|
|
161
|
+
return;
|
|
341
162
|
}
|
|
163
|
+
await ctx.db.delete(doc._id);
|
|
164
|
+
// onDeleteUser requires userId from the doc,
|
|
165
|
+
// so just return the whole thing
|
|
342
166
|
return doc;
|
|
343
167
|
},
|
|
344
168
|
});
|
|
345
169
|
|
|
346
|
-
|
|
347
|
-
|
|
170
|
+
// Single purpose functions
|
|
171
|
+
export const getAccountsByUserId = query({
|
|
172
|
+
args: { userId: v.string(), limit: v.optional(v.number()) },
|
|
173
|
+
handler: async (ctx, args) => {
|
|
174
|
+
const query = ctx.db
|
|
175
|
+
.query("account")
|
|
176
|
+
.withIndex("userId", (q) => q.eq("userId", args.userId));
|
|
177
|
+
const docs = args.limit
|
|
178
|
+
? await query.take(args.limit)
|
|
179
|
+
: await query.collect();
|
|
180
|
+
return docs.map((doc) => transformOutput(doc, "account"));
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
export const getSessionsByUserId = query({
|
|
185
|
+
args: { userId: v.string(), limit: v.optional(v.number()) },
|
|
348
186
|
handler: async (ctx, args) => {
|
|
349
|
-
|
|
187
|
+
const query = ctx.db
|
|
188
|
+
.query("session")
|
|
189
|
+
.withIndex("userId", (q) => q.eq("userId", args.userId));
|
|
190
|
+
const docs = args.limit
|
|
191
|
+
? await query.take(args.limit)
|
|
192
|
+
: await query.collect();
|
|
193
|
+
return docs.map((doc) => transformOutput(doc, "session"));
|
|
350
194
|
},
|
|
351
195
|
});
|
|
352
196
|
|
|
353
|
-
export const
|
|
197
|
+
export const getJwks = query({
|
|
354
198
|
args: {
|
|
355
|
-
|
|
356
|
-
paginationOpts: paginationOptsValidator,
|
|
199
|
+
limit: v.optional(v.number()),
|
|
357
200
|
},
|
|
358
201
|
handler: async (ctx, args) => {
|
|
359
|
-
|
|
202
|
+
const query = ctx.db.query("jwks");
|
|
203
|
+
const docs = args.limit
|
|
204
|
+
? await query.take(args.limit)
|
|
205
|
+
: await query.collect();
|
|
206
|
+
return docs.map((doc) => transformOutput(doc, "jwks"));
|
|
360
207
|
},
|
|
361
208
|
});
|
|
362
209
|
|
|
363
|
-
export const
|
|
210
|
+
export const listVerificationsByIdentifier = query({
|
|
364
211
|
args: {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
Object.fromEntries(
|
|
372
|
-
Object.entries(table.validator.fields).map(([key, value]) => [
|
|
373
|
-
key,
|
|
374
|
-
value.isOptional === "required" ? v.optional(value) : value,
|
|
375
|
-
])
|
|
376
|
-
)
|
|
377
|
-
),
|
|
378
|
-
})
|
|
379
|
-
)
|
|
212
|
+
identifier: v.string(),
|
|
213
|
+
sortBy: v.optional(
|
|
214
|
+
v.object({
|
|
215
|
+
field: v.string(),
|
|
216
|
+
direction: v.union(v.literal("asc"), v.literal("desc")),
|
|
217
|
+
})
|
|
380
218
|
),
|
|
219
|
+
limit: v.optional(v.number()),
|
|
381
220
|
},
|
|
382
221
|
handler: async (ctx, args) => {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
throw new Error(`Failed to update ${args.input.model}`);
|
|
386
|
-
}
|
|
387
|
-
await checkUniqueFields(
|
|
388
|
-
ctx,
|
|
389
|
-
args.input.model as TableNames,
|
|
390
|
-
args.input.update,
|
|
391
|
-
doc
|
|
392
|
-
);
|
|
393
|
-
await ctx.db.patch(doc._id, args.input.update as any);
|
|
394
|
-
const updatedDoc = await ctx.db.get(doc._id);
|
|
395
|
-
if (!updatedDoc) {
|
|
396
|
-
throw new Error(`Failed to update ${args.input.model}`);
|
|
222
|
+
if (args.sortBy && args.sortBy.field !== "createdAt") {
|
|
223
|
+
throw new Error(`Unsupported sortBy field: ${args.sortBy.field}`);
|
|
397
224
|
}
|
|
398
|
-
|
|
225
|
+
const query = ctx.db
|
|
226
|
+
.query("verification")
|
|
227
|
+
.withIndex("identifier", (q) => q.eq("identifier", args.identifier))
|
|
228
|
+
.order(
|
|
229
|
+
args.sortBy?.field === "createdAt" && args.sortBy?.direction
|
|
230
|
+
? args.sortBy.direction
|
|
231
|
+
: "asc"
|
|
232
|
+
);
|
|
233
|
+
const docs = args.limit
|
|
234
|
+
? await query.take(args.limit)
|
|
235
|
+
: await query.collect();
|
|
236
|
+
return docs.map((doc) => transformOutput(doc, "verification"));
|
|
399
237
|
},
|
|
400
238
|
});
|
|
401
239
|
|
|
402
|
-
export const
|
|
240
|
+
export const deleteOldVerificationsPage = mutation({
|
|
403
241
|
args: {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
paginationOpts: paginationOptsValidator,
|
|
242
|
+
currentTimestamp: v.number(),
|
|
243
|
+
paginationOpts: v.optional(paginationOptsValidator),
|
|
407
244
|
},
|
|
408
245
|
handler: async (ctx, args) => {
|
|
409
|
-
const
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
args.model as TableNames,
|
|
413
|
-
args.update ?? {}
|
|
414
|
-
);
|
|
415
|
-
if (uniqueFields.length && page.length > 1) {
|
|
416
|
-
throw new Error(
|
|
417
|
-
`Attempted to set unique fields in multiple documents in ${args.model} with the same value. Fields: ${uniqueFields.join(", ")}`
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
await asyncMap(page, async (doc) => {
|
|
421
|
-
await checkUniqueFields(
|
|
422
|
-
ctx,
|
|
423
|
-
args.model as TableNames,
|
|
424
|
-
args.update ?? {},
|
|
425
|
-
doc
|
|
426
|
-
);
|
|
427
|
-
await ctx.db.patch(doc._id, args.update as any);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
return {
|
|
431
|
-
...result,
|
|
432
|
-
count: page.length,
|
|
246
|
+
const paginationOpts = args.paginationOpts ?? {
|
|
247
|
+
numItems: 500,
|
|
248
|
+
cursor: null,
|
|
433
249
|
};
|
|
250
|
+
const { page, ...result } = await paginator(ctx.db, schema)
|
|
251
|
+
.query("verification")
|
|
252
|
+
.withIndex("expiresAt", (q) => q.lt("expiresAt", args.currentTimestamp))
|
|
253
|
+
.paginate(paginationOpts);
|
|
254
|
+
await asyncMap(page, async (doc) => {
|
|
255
|
+
await ctx.db.delete(doc._id);
|
|
256
|
+
});
|
|
257
|
+
return { ...result, count: page.length };
|
|
434
258
|
},
|
|
435
259
|
});
|
|
436
260
|
|
|
437
|
-
export const
|
|
438
|
-
args:
|
|
261
|
+
export const deleteOldVerifications = action({
|
|
262
|
+
args: {
|
|
263
|
+
currentTimestamp: v.number(),
|
|
264
|
+
},
|
|
439
265
|
handler: async (ctx, args) => {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
266
|
+
let count = 0;
|
|
267
|
+
let cursor = null;
|
|
268
|
+
let isDone = false;
|
|
269
|
+
do {
|
|
270
|
+
const result: Omit<PaginationResult<Doc<"verification">>, "page"> & {
|
|
271
|
+
count: number;
|
|
272
|
+
} = await ctx.runMutation(api.lib.deleteOldVerificationsPage, {
|
|
273
|
+
currentTimestamp: args.currentTimestamp,
|
|
274
|
+
paginationOpts: {
|
|
275
|
+
numItems: 500,
|
|
276
|
+
cursor,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
count += result.count;
|
|
280
|
+
cursor =
|
|
281
|
+
result.pageStatus &&
|
|
282
|
+
result.splitCursor &&
|
|
283
|
+
["SplitRecommended", "SplitRequired"].includes(result.pageStatus)
|
|
284
|
+
? result.splitCursor
|
|
285
|
+
: result.continueCursor;
|
|
286
|
+
isDone = result.isDone;
|
|
287
|
+
} while (!isDone);
|
|
288
|
+
return count;
|
|
446
289
|
},
|
|
447
290
|
});
|
|
448
291
|
|
|
449
|
-
export const
|
|
292
|
+
export const deleteExpiredSessions = mutation({
|
|
450
293
|
args: {
|
|
451
|
-
|
|
452
|
-
|
|
294
|
+
userId: v.string(),
|
|
295
|
+
expiresAt: v.number(),
|
|
453
296
|
},
|
|
454
297
|
handler: async (ctx, args) => {
|
|
455
|
-
const
|
|
456
|
-
|
|
298
|
+
const docs = await ctx.db
|
|
299
|
+
.query("session")
|
|
300
|
+
.withIndex("userId_expiresAt", (q) =>
|
|
301
|
+
q.eq("userId", args.userId).lt("expiresAt", args.expiresAt)
|
|
302
|
+
)
|
|
303
|
+
.collect();
|
|
304
|
+
await asyncMap(docs, async (doc) => {
|
|
457
305
|
await ctx.db.delete(doc._id);
|
|
458
306
|
});
|
|
459
|
-
return
|
|
460
|
-
|
|
461
|
-
|
|
307
|
+
return docs.length;
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
export const deleteAllForUserPage = mutation({
|
|
312
|
+
args: {
|
|
313
|
+
table: v.string(),
|
|
314
|
+
userId: v.string(),
|
|
315
|
+
paginationOpts: v.optional(paginationOptsValidator),
|
|
316
|
+
},
|
|
317
|
+
handler: async (ctx, args) => {
|
|
318
|
+
const paginationOpts = args.paginationOpts ?? {
|
|
319
|
+
numItems: 500,
|
|
320
|
+
cursor: null,
|
|
462
321
|
};
|
|
322
|
+
const { page, ...result } = await paginator(ctx.db, schema)
|
|
323
|
+
.query(args.table as any)
|
|
324
|
+
.withIndex("userId", (q) => q.eq("userId", args.userId))
|
|
325
|
+
.paginate(paginationOpts);
|
|
326
|
+
await asyncMap(page, async (doc) => {
|
|
327
|
+
await ctx.db.delete(doc._id);
|
|
328
|
+
});
|
|
329
|
+
return { ...result, count: page.length };
|
|
463
330
|
},
|
|
464
331
|
});
|
|
465
332
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
333
|
+
export const deleteAllForUser = action({
|
|
334
|
+
args: {
|
|
335
|
+
table: v.string(),
|
|
336
|
+
userId: v.string(),
|
|
337
|
+
},
|
|
338
|
+
handler: async (ctx, args) => {
|
|
339
|
+
let count = 0;
|
|
340
|
+
let cursor = null;
|
|
341
|
+
let isDone = false;
|
|
342
|
+
do {
|
|
343
|
+
const result: Omit<PaginationResult<Doc<"session">>, "page"> & {
|
|
344
|
+
count: number;
|
|
345
|
+
} = await ctx.runMutation(api.lib.deleteAllForUserPage, {
|
|
346
|
+
table: args.table,
|
|
347
|
+
userId: args.userId,
|
|
348
|
+
paginationOpts: {
|
|
349
|
+
numItems: 500,
|
|
350
|
+
cursor,
|
|
351
|
+
},
|
|
352
|
+
});
|
|
353
|
+
count += result.count;
|
|
354
|
+
cursor =
|
|
355
|
+
result.pageStatus &&
|
|
356
|
+
result.splitCursor &&
|
|
357
|
+
["SplitRecommended", "SplitRequired"].includes(result.pageStatus)
|
|
358
|
+
? result.splitCursor
|
|
359
|
+
: result.continueCursor;
|
|
360
|
+
isDone = result.isDone;
|
|
361
|
+
} while (!isDone);
|
|
362
|
+
return count;
|
|
476
363
|
},
|
|
477
364
|
});
|
|
478
365
|
|
|
479
|
-
|
|
366
|
+
export const getAccountByAccountIdAndProviderId = query({
|
|
367
|
+
args: { accountId: v.string(), providerId: v.string() },
|
|
368
|
+
handler: async (ctx, args) => {
|
|
369
|
+
const doc = await ctx.db
|
|
370
|
+
.query("account")
|
|
371
|
+
.withIndex("providerId_accountId", (q) =>
|
|
372
|
+
q.eq("providerId", args.providerId).eq("accountId", args.accountId)
|
|
373
|
+
)
|
|
374
|
+
.unique();
|
|
375
|
+
if (!doc) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
return transformOutput(doc, "account");
|
|
379
|
+
},
|
|
380
|
+
});
|
|
480
381
|
|
|
481
|
-
export const
|
|
482
|
-
args:
|
|
382
|
+
export const updateUserProviderAccounts = mutation({
|
|
383
|
+
args: {
|
|
384
|
+
userId: v.string(),
|
|
385
|
+
providerId: v.string(),
|
|
386
|
+
update: v.object(partial(schema.tables.account.validator.fields)),
|
|
387
|
+
},
|
|
483
388
|
handler: async (ctx, args) => {
|
|
484
|
-
const
|
|
485
|
-
|
|
486
|
-
|
|
389
|
+
const docs = await ctx.db
|
|
390
|
+
.query("account")
|
|
391
|
+
.withIndex("userId_providerId", (q) =>
|
|
392
|
+
q.eq("userId", args.userId).eq("providerId", args.providerId)
|
|
393
|
+
)
|
|
394
|
+
.collect();
|
|
395
|
+
if (docs.length === 0) {
|
|
396
|
+
return 0;
|
|
487
397
|
}
|
|
488
|
-
|
|
489
|
-
await
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
}
|
|
493
|
-
const query = ctx.db
|
|
494
|
-
.query(args.model as any)
|
|
495
|
-
.withIndex(where.field as any, (q) => q.eq(where.field, value));
|
|
496
|
-
if (args.limit) {
|
|
497
|
-
return await query.take(args.limit);
|
|
498
|
-
}
|
|
499
|
-
return await query.collect();
|
|
500
|
-
})
|
|
501
|
-
)
|
|
502
|
-
.flat()
|
|
503
|
-
.filter(Boolean);
|
|
398
|
+
await asyncMap(docs, async (doc) => {
|
|
399
|
+
await ctx.db.patch(doc._id, args.update);
|
|
400
|
+
});
|
|
401
|
+
return docs.length;
|
|
504
402
|
},
|
|
505
403
|
});
|
|
506
404
|
|
|
507
|
-
export const
|
|
405
|
+
export const updateTwoFactor = mutation({
|
|
508
406
|
args: {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
table: v.literal("session"),
|
|
512
|
-
field: v.literal("token"),
|
|
513
|
-
values: v.array(v.string()),
|
|
514
|
-
})
|
|
515
|
-
),
|
|
407
|
+
userId: v.string(),
|
|
408
|
+
update: v.object(partial(schema.tables.twoFactor.validator.fields)),
|
|
516
409
|
},
|
|
517
410
|
handler: async (ctx, args) => {
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
await ctx.db.delete(doc._id);
|
|
528
|
-
return doc;
|
|
411
|
+
const docs = await ctx.db
|
|
412
|
+
.query("twoFactor")
|
|
413
|
+
.withIndex("userId", (q) => q.eq("userId", args.userId))
|
|
414
|
+
.collect();
|
|
415
|
+
if (docs.length === 0) {
|
|
416
|
+
return 0;
|
|
417
|
+
}
|
|
418
|
+
await asyncMap(docs, async (doc) => {
|
|
419
|
+
await ctx.db.patch(doc._id, args.update);
|
|
529
420
|
});
|
|
530
|
-
return docs.
|
|
421
|
+
return docs.length;
|
|
531
422
|
},
|
|
532
423
|
});
|