@convex-dev/better-auth 0.7.0-alpha.10 → 0.7.0-alpha.11
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 +183 -192
- package/dist/commonjs/client/adapter.js.map +1 -1
- package/dist/commonjs/client/index.d.ts +238 -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 +218 -548
- package/dist/commonjs/component/lib.d.ts.map +1 -1
- package/dist/commonjs/component/lib.js +315 -286
- package/dist/commonjs/component/lib.js.map +1 -1
- package/dist/commonjs/component/schema.d.ts +90 -28
- package/dist/commonjs/component/schema.d.ts.map +1 -1
- package/dist/commonjs/component/schema.js +76 -18
- package/dist/commonjs/component/schema.js.map +1 -1
- package/dist/commonjs/component/util.d.ts +148 -86
- 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 -0
- 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-start/index.d.ts +4 -4
- 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 +183 -192
- package/dist/esm/client/adapter.js.map +1 -1
- package/dist/esm/client/index.d.ts +238 -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 +218 -548
- package/dist/esm/component/lib.d.ts.map +1 -1
- package/dist/esm/component/lib.js +315 -286
- package/dist/esm/component/lib.js.map +1 -1
- package/dist/esm/component/schema.d.ts +90 -28
- package/dist/esm/component/schema.d.ts.map +1 -1
- package/dist/esm/component/schema.js +76 -18
- package/dist/esm/component/schema.js.map +1 -1
- package/dist/esm/component/util.d.ts +148 -86
- 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 -0
- 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-start/index.d.ts +4 -4
- 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 +20 -5
- package/src/client/adapter.test.ts +144 -0
- package/src/client/adapter.ts +191 -195
- package/src/client/index.ts +46 -71
- package/src/component/_generated/api.d.ts +605 -149
- package/src/component/adapterTest.ts +141 -0
- package/src/component/lib.ts +444 -335
- package/src/component/schema.ts +81 -19
- package/src/nextjs/index.ts +3 -0
- package/src/plugins/convex/index.ts +5 -2
- package/src/plugins/cross-domain/index.ts +19 -5
- package/src/client/cors.ts +0 -425
- /package/src/{util.ts → utils/index.ts} +0 -0
|
@@ -1,351 +1,380 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { mutation, query } from "../component/_generated/server.js";
|
|
2
2
|
import { asyncMap } from "convex-helpers";
|
|
3
3
|
import { v } from "convex/values";
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import { paginationOptsValidator } from "convex/server";
|
|
4
|
+
import schema, { specialFields } from "../component/schema.js";
|
|
5
|
+
import { paginationOptsValidator, } from "convex/server";
|
|
7
6
|
import { paginator } from "convex-helpers/server/pagination";
|
|
8
7
|
import { partial } from "convex-helpers/validators";
|
|
9
|
-
export const
|
|
8
|
+
export const adapterWhereValidator = v.object({
|
|
9
|
+
field: v.string(),
|
|
10
|
+
operator: v.optional(v.union(v.literal("lt"), v.literal("lte"), v.literal("gt"), v.literal("gte"), v.literal("eq"), v.literal("in"), v.literal("ne"), v.literal("contains"), v.literal("starts_with"), v.literal("ends_with"))),
|
|
11
|
+
value: v.union(v.string(), v.number(), v.boolean(), v.array(v.string()), v.array(v.number()), v.null()),
|
|
12
|
+
connector: v.optional(v.union(v.literal("AND"), v.literal("OR"))),
|
|
13
|
+
});
|
|
14
|
+
export const adapterArgsValidator = v.object({
|
|
15
|
+
model: v.string(),
|
|
16
|
+
where: v.optional(v.array(adapterWhereValidator)),
|
|
17
|
+
sortBy: v.optional(v.object({
|
|
18
|
+
field: v.string(),
|
|
19
|
+
direction: v.union(v.literal("asc"), v.literal("desc")),
|
|
20
|
+
})),
|
|
21
|
+
select: v.optional(v.array(v.string())),
|
|
22
|
+
limit: v.optional(v.number()),
|
|
23
|
+
unique: v.optional(v.boolean()),
|
|
24
|
+
});
|
|
25
|
+
const getUniqueFields = (table, input) => {
|
|
26
|
+
const fields = specialFields[table];
|
|
27
|
+
if (!fields) {
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
return Object.entries(fields)
|
|
31
|
+
.filter(([key, value]) => value.unique && Object.keys(input).includes(key))
|
|
32
|
+
.map(([key]) => key);
|
|
33
|
+
};
|
|
34
|
+
const checkUniqueFields = async (ctx, table, input, doc) => {
|
|
35
|
+
const uniqueFields = getUniqueFields(table, input);
|
|
36
|
+
if (!uniqueFields.length) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
for (const field of uniqueFields) {
|
|
40
|
+
const existingDoc = await ctx.db
|
|
41
|
+
.query(table)
|
|
42
|
+
.withIndex(field, (q) => q.eq(field, input[field]))
|
|
43
|
+
.unique();
|
|
44
|
+
if (existingDoc && existingDoc._id !== doc?._id) {
|
|
45
|
+
throw new Error(`${table} ${field} already exists`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const findIndex = async (args) => {
|
|
50
|
+
if (!args.where && !args.sortBy) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (args.where?.some((w) => w.field === "id")) {
|
|
54
|
+
throw new Error("id is not a valid index field");
|
|
55
|
+
}
|
|
56
|
+
if (args.where?.some((w) => w.connector && w.connector !== "AND")) {
|
|
57
|
+
throw new Error(`OR connector not supported: ${JSON.stringify(args.where)}`);
|
|
58
|
+
}
|
|
59
|
+
if (args.where?.some((w) => w.operator &&
|
|
60
|
+
!["lt", "lte", "gt", "gte", "eq", "in"].includes(w.operator))) {
|
|
61
|
+
throw new Error(`where clause not supported: ${JSON.stringify(args.where)}`);
|
|
62
|
+
}
|
|
63
|
+
const lowerBounds = args.where?.filter((w) => w.operator === "lt" || w.operator === "lte") ??
|
|
64
|
+
[];
|
|
65
|
+
if (lowerBounds.length > 1) {
|
|
66
|
+
throw new Error(`cannot have more than one lower bound where clause: ${JSON.stringify(args.where)}`);
|
|
67
|
+
}
|
|
68
|
+
const upperBounds = args.where?.filter((w) => w.operator === "gt" || w.operator === "gte") ??
|
|
69
|
+
[];
|
|
70
|
+
if (upperBounds.length > 1) {
|
|
71
|
+
throw new Error(`cannot have more than one upper bound where clause: ${JSON.stringify(args.where)}`);
|
|
72
|
+
}
|
|
73
|
+
const lowerBound = lowerBounds[0];
|
|
74
|
+
const upperBound = upperBounds[0];
|
|
75
|
+
if (lowerBound && upperBound && lowerBound.field !== upperBound.field) {
|
|
76
|
+
throw new Error(`lower bound and upper bound must have the same field: ${JSON.stringify(args.where)}`);
|
|
77
|
+
}
|
|
78
|
+
const boundField = lowerBound?.field || upperBound?.field;
|
|
79
|
+
if (boundField &&
|
|
80
|
+
args.where?.some((w) => w.field === boundField && w !== lowerBound && w !== upperBound)) {
|
|
81
|
+
throw new Error(`too many where clauses on the bound field: ${JSON.stringify(args.where)}`);
|
|
82
|
+
}
|
|
83
|
+
const indexFields = args.where
|
|
84
|
+
?.filter((w) => !w.operator || w.operator === "eq")
|
|
85
|
+
.sort((a, b) => {
|
|
86
|
+
return a.field.localeCompare(b.field);
|
|
87
|
+
})
|
|
88
|
+
.map((w) => [w.field, w.value]) ?? [];
|
|
89
|
+
if (!indexFields?.length && !boundField && !args.sortBy) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const indexes = schema.tables[args.model][" indexes"]();
|
|
93
|
+
const sortField = args.sortBy?.field;
|
|
94
|
+
// We internally use _creationTime in place of Better Auth's createdAt
|
|
95
|
+
const indexName = indexFields
|
|
96
|
+
.map(([field]) => field)
|
|
97
|
+
.join("_")
|
|
98
|
+
.concat(boundField && boundField !== "createdAt"
|
|
99
|
+
? `${indexFields.length ? "_" : ""}${boundField}`
|
|
100
|
+
: "")
|
|
101
|
+
.concat(sortField && sortField !== "createdAt" && boundField !== sortField
|
|
102
|
+
? `${indexFields.length || boundField ? "_" : ""}${sortField}`
|
|
103
|
+
: "");
|
|
104
|
+
if (!indexName && !boundField && !sortField) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
// Use the built in creationTime index if bounding or sorting by createdAt
|
|
108
|
+
// with no other fields
|
|
109
|
+
const index = !indexName
|
|
110
|
+
? {
|
|
111
|
+
indexDescriptor: "by_creation_time",
|
|
112
|
+
fields: [],
|
|
113
|
+
}
|
|
114
|
+
: indexes.find(({ indexDescriptor }) => {
|
|
115
|
+
return boundField === "createdAt" || sortField === "createdAt"
|
|
116
|
+
? indexDescriptor === indexName
|
|
117
|
+
: indexDescriptor.startsWith(indexName);
|
|
118
|
+
});
|
|
119
|
+
if (!index) {
|
|
120
|
+
throw new Error(`Index ${indexName} not found for table ${args.model}`);
|
|
121
|
+
}
|
|
10
122
|
return {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
123
|
+
index: {
|
|
124
|
+
indexDescriptor: index.indexDescriptor,
|
|
125
|
+
fields: [...index.fields, "_creationTime"],
|
|
126
|
+
},
|
|
127
|
+
boundField,
|
|
128
|
+
sortField,
|
|
129
|
+
values: {
|
|
130
|
+
eq: indexFields.map(([, value]) => value),
|
|
131
|
+
lt: lowerBound?.operator === "lt" ? lowerBound.value : undefined,
|
|
132
|
+
lte: lowerBound?.operator === "lte" ? lowerBound.value : undefined,
|
|
133
|
+
gt: upperBound?.operator === "gt" ? upperBound.value : undefined,
|
|
134
|
+
gte: upperBound?.operator === "gte" ? upperBound.value : undefined,
|
|
135
|
+
},
|
|
17
136
|
};
|
|
18
137
|
};
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
138
|
+
const selectFields = (doc, select) => {
|
|
139
|
+
if (!doc) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (!select?.length) {
|
|
143
|
+
return doc;
|
|
144
|
+
}
|
|
145
|
+
return select.reduce((acc, field) => {
|
|
146
|
+
acc[field] = doc[field];
|
|
147
|
+
return acc;
|
|
148
|
+
}, {});
|
|
23
149
|
};
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return ctx.db.get(args.value);
|
|
150
|
+
// This is the core function for reading from the database, it parses and
|
|
151
|
+
// validates where conditions, selects indexes, and allows the caller to
|
|
152
|
+
// optionally paginate as needed.
|
|
153
|
+
const paginate = async (ctx, args) => {
|
|
154
|
+
// If any index is id, we can only return a single document
|
|
155
|
+
const idWhere = args.where?.find((w) => w.field === "id");
|
|
156
|
+
if (idWhere) {
|
|
157
|
+
const doc = await ctx.db.get(idWhere.value);
|
|
158
|
+
return {
|
|
159
|
+
page: [selectFields(doc, args.select)].filter(Boolean),
|
|
160
|
+
isDone: true,
|
|
161
|
+
continueCursor: "",
|
|
162
|
+
};
|
|
38
163
|
}
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
164
|
+
const { index, values, boundField } = (await findIndex(args)) ?? {};
|
|
165
|
+
const query = paginator(ctx.db, schema).query(args.model);
|
|
166
|
+
const hasValues = values?.eq?.length ||
|
|
167
|
+
values?.lt ||
|
|
168
|
+
values?.lte ||
|
|
169
|
+
values?.gt ||
|
|
170
|
+
values?.gte;
|
|
171
|
+
const indexedQuery = index && index.indexDescriptor !== "by_creation_time"
|
|
172
|
+
? query.withIndex(index.indexDescriptor, hasValues
|
|
173
|
+
? (q) => {
|
|
174
|
+
for (const [idx, value] of (values?.eq ?? []).entries()) {
|
|
175
|
+
q = q.eq(index.fields[idx], value);
|
|
176
|
+
}
|
|
177
|
+
if (values?.lt) {
|
|
178
|
+
q = q.lt(boundField, values.lt);
|
|
179
|
+
}
|
|
180
|
+
if (values?.lte) {
|
|
181
|
+
q = q.lte(boundField, values.lte);
|
|
182
|
+
}
|
|
183
|
+
if (values?.gt) {
|
|
184
|
+
q = q.gt(boundField, values.gt);
|
|
185
|
+
}
|
|
186
|
+
if (values?.gte) {
|
|
187
|
+
q = q.gte(boundField, values.gte);
|
|
188
|
+
}
|
|
189
|
+
return q;
|
|
190
|
+
}
|
|
191
|
+
: undefined)
|
|
192
|
+
: query;
|
|
193
|
+
const orderedQuery = args.sortBy
|
|
194
|
+
? indexedQuery.order(args.sortBy.direction === "asc" ? "asc" : "desc")
|
|
195
|
+
: indexedQuery;
|
|
196
|
+
const result = await orderedQuery.paginate(args.paginationOpts);
|
|
197
|
+
return {
|
|
198
|
+
...result,
|
|
199
|
+
page: result.page.map((doc) => selectFields(doc, args.select)),
|
|
200
|
+
};
|
|
43
201
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
202
|
+
const listOne = async (ctx, args) => {
|
|
203
|
+
return (await paginate(ctx, {
|
|
204
|
+
...args,
|
|
205
|
+
paginationOpts: {
|
|
206
|
+
numItems: 1,
|
|
207
|
+
cursor: null,
|
|
208
|
+
},
|
|
209
|
+
})).page[0];
|
|
49
210
|
};
|
|
50
|
-
// Generic functions
|
|
51
|
-
export const getByQuery = query({
|
|
52
|
-
args: getByArgsValidator,
|
|
53
|
-
handler: async (ctx, args) => {
|
|
54
|
-
const doc = await getByHelper(ctx, args);
|
|
55
|
-
if (!doc) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
return transformOutput(doc, args.table);
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
export { getByQuery as getBy };
|
|
62
211
|
export const create = mutation({
|
|
63
|
-
args:
|
|
64
|
-
input: v.union(...Object.
|
|
65
|
-
|
|
66
|
-
|
|
212
|
+
args: {
|
|
213
|
+
input: v.union(...Object.entries(schema.tables).map(([model, table]) => v.object({
|
|
214
|
+
model: v.literal(model),
|
|
215
|
+
where: v.optional(v.array(adapterWhereValidator)),
|
|
216
|
+
data: v.object(table.validator.fields),
|
|
67
217
|
}))),
|
|
68
|
-
}),
|
|
69
|
-
handler: async (ctx, args) => {
|
|
70
|
-
const { table, ...input } = args.input;
|
|
71
|
-
const id = await ctx.db.insert(table, {
|
|
72
|
-
...input,
|
|
73
|
-
});
|
|
74
|
-
const doc = await ctx.db.get(id);
|
|
75
|
-
if (!doc) {
|
|
76
|
-
throw new Error(`Failed to create ${table}`);
|
|
77
|
-
}
|
|
78
|
-
return transformOutput(doc, table);
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
export const updateArgsInputValidator = (table) => {
|
|
82
|
-
return v.object({
|
|
83
|
-
table: v.literal(table),
|
|
84
|
-
where: v.object({ field: v.string(), value: getByArgsValidator.value }),
|
|
85
|
-
value: v.record(v.string(), v.any()),
|
|
86
|
-
});
|
|
87
|
-
};
|
|
88
|
-
const updateArgsValidator = {
|
|
89
|
-
input: v.union(updateArgsInputValidator("account"), updateArgsInputValidator("session"), updateArgsInputValidator("verification"), updateArgsInputValidator("user")),
|
|
90
|
-
};
|
|
91
|
-
export const update = mutation({
|
|
92
|
-
args: updateArgsValidator,
|
|
93
|
-
handler: async (ctx, args) => {
|
|
94
|
-
const { table, where, value } = args.input;
|
|
95
|
-
const doc = where.field === "id"
|
|
96
|
-
? await ctx.db.get(where.value)
|
|
97
|
-
: await getByHelper(ctx, { table, ...where });
|
|
98
|
-
if (!doc) {
|
|
99
|
-
throw new Error(`Failed to update ${table}`);
|
|
100
|
-
}
|
|
101
|
-
await ctx.db.patch(doc._id, value);
|
|
102
|
-
const updatedDoc = await ctx.db.get(doc._id);
|
|
103
|
-
if (!updatedDoc) {
|
|
104
|
-
throw new Error(`Failed to update ${table}`);
|
|
105
|
-
}
|
|
106
|
-
return transformOutput(updatedDoc, table);
|
|
107
218
|
},
|
|
108
|
-
});
|
|
109
|
-
export const deleteBy = mutation({
|
|
110
|
-
args: getByArgsValidator,
|
|
111
219
|
handler: async (ctx, args) => {
|
|
112
|
-
|
|
220
|
+
await checkUniqueFields(ctx, args.input.model, args.input.data);
|
|
221
|
+
const id = await ctx.db.insert(args.input.model, args.input.data);
|
|
222
|
+
const doc = await ctx.db.get(id);
|
|
113
223
|
if (!doc) {
|
|
114
|
-
|
|
224
|
+
throw new Error(`Failed to create ${args.input.model}`);
|
|
115
225
|
}
|
|
116
|
-
await ctx.db.delete(doc._id);
|
|
117
|
-
// onDeleteUser requires userId from the doc,
|
|
118
|
-
// so just return the whole thing
|
|
119
226
|
return doc;
|
|
120
227
|
},
|
|
121
228
|
});
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
args: { userId: v.string(), limit: v.optional(v.number()) },
|
|
229
|
+
export const findOne = query({
|
|
230
|
+
args: adapterArgsValidator,
|
|
125
231
|
handler: async (ctx, args) => {
|
|
126
|
-
|
|
127
|
-
.query("account")
|
|
128
|
-
.withIndex("userId", (q) => q.eq("userId", args.userId));
|
|
129
|
-
const docs = args.limit
|
|
130
|
-
? await query.take(args.limit)
|
|
131
|
-
: await query.collect();
|
|
132
|
-
return docs.map((doc) => transformOutput(doc, "account"));
|
|
232
|
+
return await listOne(ctx, args);
|
|
133
233
|
},
|
|
134
234
|
});
|
|
135
|
-
export const
|
|
136
|
-
args: { userId: v.string(), limit: v.optional(v.number()) },
|
|
137
|
-
handler: async (ctx, args) => {
|
|
138
|
-
const query = ctx.db
|
|
139
|
-
.query("session")
|
|
140
|
-
.withIndex("userId", (q) => q.eq("userId", args.userId));
|
|
141
|
-
const docs = args.limit
|
|
142
|
-
? await query.take(args.limit)
|
|
143
|
-
: await query.collect();
|
|
144
|
-
return docs.map((doc) => transformOutput(doc, "session"));
|
|
145
|
-
},
|
|
146
|
-
});
|
|
147
|
-
export const getJwks = query({
|
|
235
|
+
export const findMany = query({
|
|
148
236
|
args: {
|
|
149
|
-
|
|
237
|
+
...adapterArgsValidator.fields,
|
|
238
|
+
paginationOpts: paginationOptsValidator,
|
|
150
239
|
},
|
|
151
240
|
handler: async (ctx, args) => {
|
|
152
|
-
|
|
153
|
-
const docs = args.limit
|
|
154
|
-
? await query.take(args.limit)
|
|
155
|
-
: await query.collect();
|
|
156
|
-
return docs.map((doc) => transformOutput(doc, "jwks"));
|
|
241
|
+
return await paginate(ctx, args);
|
|
157
242
|
},
|
|
158
243
|
});
|
|
159
|
-
export const
|
|
244
|
+
export const updateOne = mutation({
|
|
160
245
|
args: {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
246
|
+
input: v.union(...Object.entries(schema.tables).map(([model, table]) => v.object({
|
|
247
|
+
model: v.literal(model),
|
|
248
|
+
where: v.optional(v.array(adapterWhereValidator)),
|
|
249
|
+
update: v.object(Object.fromEntries(Object.entries(table.validator.fields).map(([key, value]) => [
|
|
250
|
+
key,
|
|
251
|
+
value.isOptional === "required" ? v.optional(value) : value,
|
|
252
|
+
]))),
|
|
253
|
+
}))),
|
|
167
254
|
},
|
|
168
255
|
handler: async (ctx, args) => {
|
|
169
|
-
|
|
170
|
-
|
|
256
|
+
const doc = await listOne(ctx, args.input);
|
|
257
|
+
if (!doc) {
|
|
258
|
+
throw new Error(`Failed to update ${args.input.model}`);
|
|
171
259
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
? await query.take(args.limit)
|
|
180
|
-
: await query.collect();
|
|
181
|
-
return docs.map((doc) => transformOutput(doc, "verification"));
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
export const deleteOldVerificationsPage = mutation({
|
|
185
|
-
args: {
|
|
186
|
-
currentTimestamp: v.number(),
|
|
187
|
-
paginationOpts: v.optional(paginationOptsValidator),
|
|
188
|
-
},
|
|
189
|
-
handler: async (ctx, args) => {
|
|
190
|
-
const paginationOpts = args.paginationOpts ?? {
|
|
191
|
-
numItems: 500,
|
|
192
|
-
cursor: null,
|
|
193
|
-
};
|
|
194
|
-
const { page, ...result } = await paginator(ctx.db, schema)
|
|
195
|
-
.query("verification")
|
|
196
|
-
.withIndex("expiresAt", (q) => q.lt("expiresAt", args.currentTimestamp))
|
|
197
|
-
.paginate(paginationOpts);
|
|
198
|
-
await asyncMap(page, async (doc) => {
|
|
199
|
-
await ctx.db.delete(doc._id);
|
|
200
|
-
});
|
|
201
|
-
return { ...result, count: page.length };
|
|
260
|
+
await checkUniqueFields(ctx, args.input.model, args.input.update, doc);
|
|
261
|
+
await ctx.db.patch(doc._id, args.input.update);
|
|
262
|
+
const updatedDoc = await ctx.db.get(doc._id);
|
|
263
|
+
if (!updatedDoc) {
|
|
264
|
+
throw new Error(`Failed to update ${args.input.model}`);
|
|
265
|
+
}
|
|
266
|
+
return updatedDoc;
|
|
202
267
|
},
|
|
203
268
|
});
|
|
204
|
-
export const
|
|
269
|
+
export const updateMany = mutation({
|
|
205
270
|
args: {
|
|
206
|
-
|
|
271
|
+
...adapterArgsValidator.fields,
|
|
272
|
+
update: v.optional(v.object(partial(schema.tables.user.validator.fields))),
|
|
273
|
+
paginationOpts: paginationOptsValidator,
|
|
207
274
|
},
|
|
208
275
|
handler: async (ctx, args) => {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
},
|
|
276
|
+
const { page, ...result } = await paginate(ctx, args);
|
|
277
|
+
if (args.update) {
|
|
278
|
+
const uniqueFields = getUniqueFields(args.model, args.update ?? {});
|
|
279
|
+
if (uniqueFields.length && page.length > 1) {
|
|
280
|
+
throw new Error(`Attempted to set unique fields in multiple documents in ${args.model} with the same value. Fields: ${uniqueFields.join(", ")}`);
|
|
281
|
+
}
|
|
282
|
+
await asyncMap(page, async (doc) => {
|
|
283
|
+
await checkUniqueFields(ctx, args.model, args.update ?? {}, doc);
|
|
284
|
+
await ctx.db.patch(doc._id, args.update);
|
|
219
285
|
});
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
? result.splitCursor
|
|
226
|
-
: result.continueCursor;
|
|
227
|
-
isDone = result.isDone;
|
|
228
|
-
} while (!isDone);
|
|
229
|
-
return count;
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
...result,
|
|
289
|
+
count: page.length,
|
|
290
|
+
};
|
|
230
291
|
},
|
|
231
292
|
});
|
|
232
|
-
export const
|
|
233
|
-
args:
|
|
234
|
-
userId: v.string(),
|
|
235
|
-
expiresAt: v.number(),
|
|
236
|
-
},
|
|
293
|
+
export const deleteOne = mutation({
|
|
294
|
+
args: adapterArgsValidator,
|
|
237
295
|
handler: async (ctx, args) => {
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
await
|
|
243
|
-
|
|
244
|
-
});
|
|
245
|
-
return docs.length;
|
|
296
|
+
const doc = await listOne(ctx, args);
|
|
297
|
+
if (!doc) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
await ctx.db.delete(doc._id);
|
|
301
|
+
return doc;
|
|
246
302
|
},
|
|
247
303
|
});
|
|
248
|
-
export const
|
|
304
|
+
export const deleteMany = mutation({
|
|
249
305
|
args: {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
paginationOpts: v.optional(paginationOptsValidator),
|
|
306
|
+
...adapterArgsValidator.fields,
|
|
307
|
+
paginationOpts: paginationOptsValidator,
|
|
253
308
|
},
|
|
254
309
|
handler: async (ctx, args) => {
|
|
255
|
-
const
|
|
256
|
-
numItems: 500,
|
|
257
|
-
cursor: null,
|
|
258
|
-
};
|
|
259
|
-
const { page, ...result } = await paginator(ctx.db, schema)
|
|
260
|
-
.query(args.table)
|
|
261
|
-
.withIndex("userId", (q) => q.eq("userId", args.userId))
|
|
262
|
-
.paginate(paginationOpts);
|
|
310
|
+
const { page, ...result } = await paginate(ctx, args);
|
|
263
311
|
await asyncMap(page, async (doc) => {
|
|
264
312
|
await ctx.db.delete(doc._id);
|
|
265
313
|
});
|
|
266
|
-
return {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
args: {
|
|
271
|
-
table: v.string(),
|
|
272
|
-
userId: v.string(),
|
|
273
|
-
},
|
|
274
|
-
handler: async (ctx, args) => {
|
|
275
|
-
let count = 0;
|
|
276
|
-
let cursor = null;
|
|
277
|
-
let isDone = false;
|
|
278
|
-
do {
|
|
279
|
-
const result = await ctx.runMutation(api.lib.deleteAllForUserPage, {
|
|
280
|
-
table: args.table,
|
|
281
|
-
userId: args.userId,
|
|
282
|
-
paginationOpts: {
|
|
283
|
-
numItems: 500,
|
|
284
|
-
cursor,
|
|
285
|
-
},
|
|
286
|
-
});
|
|
287
|
-
count += result.count;
|
|
288
|
-
cursor =
|
|
289
|
-
result.pageStatus &&
|
|
290
|
-
result.splitCursor &&
|
|
291
|
-
["SplitRecommended", "SplitRequired"].includes(result.pageStatus)
|
|
292
|
-
? result.splitCursor
|
|
293
|
-
: result.continueCursor;
|
|
294
|
-
isDone = result.isDone;
|
|
295
|
-
} while (!isDone);
|
|
296
|
-
return count;
|
|
314
|
+
return {
|
|
315
|
+
...result,
|
|
316
|
+
count: page.length,
|
|
317
|
+
};
|
|
297
318
|
},
|
|
298
319
|
});
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
return;
|
|
320
|
+
// Get the session via sessionId in jwt claims
|
|
321
|
+
// TODO: this needs a refresh, subquery only necessary for actions
|
|
322
|
+
export const getCurrentSession = query({
|
|
323
|
+
args: {},
|
|
324
|
+
handler: async (ctx) => {
|
|
325
|
+
const identity = await ctx.auth.getUserIdentity();
|
|
326
|
+
if (!identity) {
|
|
327
|
+
return null;
|
|
308
328
|
}
|
|
309
|
-
return
|
|
329
|
+
return ctx.db.get(identity.sessionId);
|
|
310
330
|
},
|
|
311
331
|
});
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
providerId: v.string(),
|
|
316
|
-
update: v.object(partial(schema.tables.account.validator.fields)),
|
|
317
|
-
},
|
|
332
|
+
// TODO: rewrite functions below here to be dynamic
|
|
333
|
+
export const getIn = query({
|
|
334
|
+
args: adapterArgsValidator,
|
|
318
335
|
handler: async (ctx, args) => {
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
.collect();
|
|
323
|
-
if (docs.length === 0) {
|
|
324
|
-
return 0;
|
|
336
|
+
const where = args.where?.[0];
|
|
337
|
+
if (!where || where.operator !== "in" || args.where?.length !== 1) {
|
|
338
|
+
throw new Error("where must be a single in clause");
|
|
325
339
|
}
|
|
326
|
-
await asyncMap(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
340
|
+
return (await asyncMap(where.value, async (value) => {
|
|
341
|
+
if (where.field === "id") {
|
|
342
|
+
return [await ctx.db.get(value)];
|
|
343
|
+
}
|
|
344
|
+
const query = ctx.db
|
|
345
|
+
.query(args.model)
|
|
346
|
+
.withIndex(where.field, (q) => q.eq(where.field, value));
|
|
347
|
+
if (args.limit) {
|
|
348
|
+
return await query.take(args.limit);
|
|
349
|
+
}
|
|
350
|
+
return await query.collect();
|
|
351
|
+
}))
|
|
352
|
+
.flat()
|
|
353
|
+
.filter(Boolean);
|
|
330
354
|
},
|
|
331
355
|
});
|
|
332
|
-
export const
|
|
356
|
+
export const deleteIn = mutation({
|
|
333
357
|
args: {
|
|
334
|
-
|
|
335
|
-
|
|
358
|
+
input: v.union(v.object({
|
|
359
|
+
table: v.literal("session"),
|
|
360
|
+
field: v.literal("token"),
|
|
361
|
+
values: v.array(v.string()),
|
|
362
|
+
})),
|
|
336
363
|
},
|
|
337
364
|
handler: async (ctx, args) => {
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
365
|
+
const { table, field, values } = args.input;
|
|
366
|
+
const docs = await asyncMap(values, async (value) => {
|
|
367
|
+
const doc = await ctx.db
|
|
368
|
+
.query(table)
|
|
369
|
+
.withIndex(field, (q) => q.eq(field, value))
|
|
370
|
+
.unique();
|
|
371
|
+
if (!doc) {
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
await ctx.db.delete(doc._id);
|
|
375
|
+
return doc;
|
|
347
376
|
});
|
|
348
|
-
return docs.length;
|
|
377
|
+
return docs.filter(Boolean).length;
|
|
349
378
|
},
|
|
350
379
|
});
|
|
351
380
|
//# sourceMappingURL=lib.js.map
|