@anysoftinc/anydb-sdk 0.1.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +100 -163
- package/dist/anydb.datascript.core.js +336 -0
- package/dist/anydb.datascript.rules.js +29 -0
- package/dist/anydb.datascript.schema.js +35 -0
- package/dist/client.d.ts +46 -96
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +332 -305
- package/dist/cljs.core.js +38752 -0
- package/dist/cljs.reader.js +450 -0
- package/dist/cljs.tools.reader.edn.js +945 -0
- package/dist/cljs.tools.reader.impl.commons.js +205 -0
- package/dist/cljs.tools.reader.impl.errors.js +429 -0
- package/dist/cljs.tools.reader.impl.inspect.js +170 -0
- package/dist/cljs.tools.reader.impl.utils.js +413 -0
- package/dist/cljs.tools.reader.js +1815 -0
- package/dist/cljs.tools.reader.reader_types.js +826 -0
- package/dist/cljs_env.js +7672 -0
- package/dist/clojure.data.js +307 -0
- package/dist/clojure.edn.js +107 -0
- package/dist/clojure.set.js +394 -0
- package/dist/clojure.string.js +490 -0
- package/dist/clojure.walk.js +144 -0
- package/dist/datascript-backend.d.ts +26 -0
- package/dist/datascript-backend.d.ts.map +1 -0
- package/dist/datascript-backend.js +113 -0
- package/dist/datascript.built_ins.js +680 -0
- package/dist/datascript.conn.js +814 -0
- package/dist/datascript.core.js +1285 -0
- package/dist/datascript.db.js +4058 -0
- package/dist/datascript.impl.entity.js +588 -0
- package/dist/datascript.lru.js +213 -0
- package/dist/datascript.parser.js +8598 -0
- package/dist/datascript.pull_api.js +2287 -0
- package/dist/datascript.pull_parser.js +865 -0
- package/dist/datascript.query.js +2785 -0
- package/dist/datascript.serialize.js +352 -0
- package/dist/datascript.storage.js +50 -0
- package/dist/datascript.util.js +82 -0
- package/dist/extend_clj.core.js +134 -0
- package/dist/me.tonsky.persistent_sorted_set.arrays.js +54 -0
- package/dist/me.tonsky.persistent_sorted_set.js +2485 -0
- package/dist/nextauth-adapter.d.ts +7 -2
- package/dist/nextauth-adapter.d.ts.map +1 -1
- package/dist/nextauth-adapter.js +251 -149
- package/package.json +9 -5
- package/dist/query-builder.d.ts +0 -126
- package/dist/query-builder.d.ts.map +0 -1
- package/dist/query-builder.js +0 -207
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { Adapter } from "next-auth/adapters";
|
|
2
|
-
import type {
|
|
2
|
+
import type { AnyDBClient } from "./client";
|
|
3
|
+
/**
|
|
4
|
+
* Creates NextAuth cookie configuration with proper security settings
|
|
5
|
+
* Uses __Host- prefix and secure cookies in production, regular cookies in development
|
|
6
|
+
*/
|
|
7
|
+
export declare function createNextAuthCookies(cookieIdentifier: string): Record<string, any>;
|
|
3
8
|
/**
|
|
4
9
|
* Creates a NextAuth.js adapter for AnyDB/Datomic
|
|
5
10
|
*
|
|
@@ -19,5 +24,5 @@ import type { DatomicDatabase } from "./client";
|
|
|
19
24
|
* });
|
|
20
25
|
* ```
|
|
21
26
|
*/
|
|
22
|
-
export declare function AnyDBAdapter(db:
|
|
27
|
+
export declare function AnyDBAdapter(db: AnyDBClient): Adapter;
|
|
23
28
|
//# sourceMappingURL=nextauth-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nextauth-adapter.d.ts","sourceRoot":"","sources":["../src/nextauth-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"nextauth-adapter.d.ts","sourceRoot":"","sources":["../src/nextauth-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAkB,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,UAAU,CAAC;AAI3D;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkCrB;AA2DD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CA6WrD"}
|
package/dist/nextauth-adapter.js
CHANGED
|
@@ -1,100 +1,90 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { kw, sym, uuid as uuidEdn } from "./client";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
/**
|
|
4
|
+
* Creates NextAuth cookie configuration with proper security settings
|
|
5
|
+
* Uses __Host- prefix and secure cookies in production, regular cookies in development
|
|
6
|
+
*/
|
|
7
|
+
export function createNextAuthCookies(cookieIdentifier) {
|
|
8
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
9
|
+
const prefix = isProduction ? "__Host-" : "";
|
|
10
|
+
const secure = isProduction;
|
|
11
|
+
return {
|
|
12
|
+
sessionToken: {
|
|
13
|
+
name: `${prefix}${cookieIdentifier}.session-token`,
|
|
14
|
+
options: {
|
|
15
|
+
httpOnly: true,
|
|
16
|
+
sameSite: "lax",
|
|
17
|
+
path: "/",
|
|
18
|
+
secure,
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
callbackUrl: {
|
|
22
|
+
name: `${prefix}${cookieIdentifier}.callback-url`,
|
|
23
|
+
options: {
|
|
24
|
+
httpOnly: true,
|
|
25
|
+
sameSite: "lax",
|
|
26
|
+
path: "/",
|
|
27
|
+
secure,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
csrfToken: {
|
|
31
|
+
name: `${prefix}${cookieIdentifier}.csrf-token`,
|
|
32
|
+
options: {
|
|
33
|
+
httpOnly: true,
|
|
34
|
+
sameSite: "lax",
|
|
35
|
+
path: "/",
|
|
36
|
+
secure,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
2
41
|
// Datomic schema idents
|
|
3
42
|
const USER = {
|
|
4
|
-
id: "
|
|
5
|
-
name: "
|
|
6
|
-
email: "
|
|
7
|
-
emailVerified: "
|
|
8
|
-
image: "
|
|
43
|
+
id: "anydb.auth.user.v1/id", // uuid identity
|
|
44
|
+
name: "anydb.auth.user.v1/name",
|
|
45
|
+
email: "anydb.auth.user.v1/email",
|
|
46
|
+
emailVerified: "anydb.auth.user.v1/email-verified",
|
|
47
|
+
image: "anydb.auth.user.v1/image",
|
|
9
48
|
};
|
|
10
49
|
const ACCOUNT = {
|
|
11
|
-
id: "
|
|
12
|
-
userId: "
|
|
13
|
-
type: "
|
|
14
|
-
provider: "
|
|
15
|
-
providerAccountId: "
|
|
16
|
-
refreshToken: "
|
|
17
|
-
accessToken: "
|
|
18
|
-
expiresAt: "
|
|
19
|
-
tokenType: "
|
|
20
|
-
scope: "
|
|
21
|
-
idToken: "
|
|
22
|
-
sessionState: "
|
|
50
|
+
id: "anydb.auth.account.v1/id", // uuid identity
|
|
51
|
+
userId: "anydb.auth.account.v1/user-id", // uuid ref by value
|
|
52
|
+
type: "anydb.auth.account.v1/type",
|
|
53
|
+
provider: "anydb.auth.account.v1/provider",
|
|
54
|
+
providerAccountId: "anydb.auth.account.v1/provider-account-id",
|
|
55
|
+
refreshToken: "anydb.auth.account.v1/refresh-token",
|
|
56
|
+
accessToken: "anydb.auth.account.v1/access-token",
|
|
57
|
+
expiresAt: "anydb.auth.account.v1/expires-at",
|
|
58
|
+
tokenType: "anydb.auth.account.v1/token-type",
|
|
59
|
+
scope: "anydb.auth.account.v1/scope",
|
|
60
|
+
idToken: "anydb.auth.account.v1/id-token",
|
|
61
|
+
sessionState: "anydb.auth.account.v1/session-state",
|
|
23
62
|
};
|
|
24
63
|
const SESSION = {
|
|
25
|
-
id: "
|
|
26
|
-
sessionToken: "
|
|
27
|
-
userId: "
|
|
28
|
-
expires: "
|
|
64
|
+
id: "anydb.auth.session.v1/id", // uuid identity
|
|
65
|
+
sessionToken: "anydb.auth.session.v1/session-token",
|
|
66
|
+
userId: "anydb.auth.session.v1/user-id",
|
|
67
|
+
expires: "anydb.auth.session.v1/expires",
|
|
29
68
|
};
|
|
30
69
|
const VTOKEN = {
|
|
31
|
-
id: "
|
|
32
|
-
identifier: "
|
|
33
|
-
token: "
|
|
34
|
-
expires: "
|
|
70
|
+
id: "anydb.auth.vtoken.v1/id", // uuid identity
|
|
71
|
+
identifier: "anydb.auth.vtoken.v1/identifier",
|
|
72
|
+
token: "anydb.auth.vtoken.v1/token",
|
|
73
|
+
expires: "anydb.auth.vtoken.v1/expires",
|
|
35
74
|
};
|
|
36
|
-
async function ensureAuthSchema(db) {
|
|
37
|
-
const defs = [];
|
|
38
|
-
// Helper to conditionally add attribute definitions
|
|
39
|
-
const addAttr = async (ident, vt, card, opts = {}) => {
|
|
40
|
-
const exists = await db.querySymbolic({ find: [sym("?e")], where: [[sym("?e"), kw(":db/ident"), kw(ident)]] });
|
|
41
|
-
if (!exists || (Array.isArray(exists) && exists.length === 0)) {
|
|
42
|
-
defs.push(SchemaBuilder.attribute({ ":db/ident": ident, ":db/valueType": vt, ":db/cardinality": card, ...opts }));
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
// User attributes
|
|
46
|
-
await addAttr(USER.id, ":db.type/uuid", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
47
|
-
await addAttr(USER.name, ":db.type/string", ":db.cardinality/one");
|
|
48
|
-
// Make email an identity attribute so we can upsert users by email
|
|
49
|
-
await addAttr(USER.email, ":db.type/string", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
50
|
-
await addAttr(USER.emailVerified, ":db.type/instant", ":db.cardinality/one");
|
|
51
|
-
await addAttr(USER.image, ":db.type/string", ":db.cardinality/one");
|
|
52
|
-
// Account attributes
|
|
53
|
-
await addAttr(ACCOUNT.id, ":db.type/uuid", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
54
|
-
await addAttr(ACCOUNT.userId, ":db.type/uuid", ":db.cardinality/one", { ":db/index": true });
|
|
55
|
-
await addAttr(ACCOUNT.type, ":db.type/string", ":db.cardinality/one");
|
|
56
|
-
await addAttr(ACCOUNT.provider, ":db.type/string", ":db.cardinality/one", { ":db/index": true });
|
|
57
|
-
await addAttr(ACCOUNT.providerAccountId, ":db.type/string", ":db.cardinality/one", { ":db/index": true });
|
|
58
|
-
await addAttr(ACCOUNT.refreshToken, ":db.type/string", ":db.cardinality/one");
|
|
59
|
-
await addAttr(ACCOUNT.accessToken, ":db.type/string", ":db.cardinality/one");
|
|
60
|
-
await addAttr(ACCOUNT.expiresAt, ":db.type/long", ":db.cardinality/one");
|
|
61
|
-
await addAttr(ACCOUNT.tokenType, ":db.type/string", ":db.cardinality/one");
|
|
62
|
-
await addAttr(ACCOUNT.scope, ":db.type/string", ":db.cardinality/one");
|
|
63
|
-
await addAttr(ACCOUNT.idToken, ":db.type/string", ":db.cardinality/one");
|
|
64
|
-
await addAttr(ACCOUNT.sessionState, ":db.type/string", ":db.cardinality/one");
|
|
65
|
-
// Session attributes
|
|
66
|
-
await addAttr(SESSION.id, ":db.type/uuid", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
67
|
-
await addAttr(SESSION.userId, ":db.type/uuid", ":db.cardinality/one", { ":db/index": true });
|
|
68
|
-
await addAttr(SESSION.sessionToken, ":db.type/string", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
69
|
-
await addAttr(SESSION.expires, ":db.type/instant", ":db.cardinality/one");
|
|
70
|
-
// Verification token attributes
|
|
71
|
-
await addAttr(VTOKEN.id, ":db.type/uuid", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
72
|
-
await addAttr(VTOKEN.identifier, ":db.type/string", ":db.cardinality/one", { ":db/index": true });
|
|
73
|
-
await addAttr(VTOKEN.token, ":db.type/string", ":db.cardinality/one", { ":db/unique": ":db.unique/identity", ":db/index": true });
|
|
74
|
-
await addAttr(VTOKEN.expires, ":db.type/instant", ":db.cardinality/one");
|
|
75
|
-
// Install schema if there are new definitions
|
|
76
|
-
if (defs.length) {
|
|
77
|
-
try {
|
|
78
|
-
await db.transact(defs);
|
|
79
|
-
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
// Schema attributes may already exist, which is fine
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
75
|
function toUser(m) {
|
|
86
76
|
const get = (k) => m && (m[k] ?? m[`:${k}`]);
|
|
87
77
|
// USER.id is ":auth.user.v1/id", so slice(1) gives "auth.user.v1/id"
|
|
88
|
-
const idKey = USER.id
|
|
78
|
+
const idKey = USER.id; // "auth.user.v1/id"
|
|
89
79
|
const idVal = get(idKey);
|
|
90
|
-
const id = typeof idVal ===
|
|
91
|
-
const emailVerified = get(USER.emailVerified
|
|
80
|
+
const id = typeof idVal === "string" ? idVal : idVal?.value ?? String(idVal);
|
|
81
|
+
const emailVerified = get(USER.emailVerified);
|
|
92
82
|
return {
|
|
93
83
|
id,
|
|
94
|
-
name: get(USER.name
|
|
95
|
-
email: get(USER.email
|
|
84
|
+
name: get(USER.name) || null,
|
|
85
|
+
email: get(USER.email) || null,
|
|
96
86
|
emailVerified: emailVerified ? new Date(emailVerified) : null,
|
|
97
|
-
image: get(USER.image
|
|
87
|
+
image: get(USER.image) || null,
|
|
98
88
|
};
|
|
99
89
|
}
|
|
100
90
|
/**
|
|
@@ -118,15 +108,44 @@ function toUser(m) {
|
|
|
118
108
|
*/
|
|
119
109
|
export function AnyDBAdapter(db) {
|
|
120
110
|
async function getUserByEmail(email) {
|
|
121
|
-
|
|
122
|
-
const q =
|
|
111
|
+
const norm = typeof email === "string" ? email.toLowerCase() : email;
|
|
112
|
+
const q = {
|
|
113
|
+
find: [
|
|
114
|
+
[
|
|
115
|
+
sym("pull"),
|
|
116
|
+
sym("?e"),
|
|
117
|
+
[
|
|
118
|
+
kw(USER.id),
|
|
119
|
+
kw(USER.name),
|
|
120
|
+
kw(USER.email),
|
|
121
|
+
kw(USER.emailVerified),
|
|
122
|
+
kw(USER.image),
|
|
123
|
+
],
|
|
124
|
+
],
|
|
125
|
+
],
|
|
126
|
+
where: [[sym("?e"), kw(USER.email), norm]],
|
|
127
|
+
};
|
|
123
128
|
const res = await db.query(q);
|
|
124
129
|
const rows = Array.isArray(res) ? res : [];
|
|
125
130
|
return rows.length ? toUser(rows[0][0]) : null;
|
|
126
131
|
}
|
|
127
132
|
async function getUser(id) {
|
|
128
|
-
|
|
129
|
-
|
|
133
|
+
const q = {
|
|
134
|
+
find: [
|
|
135
|
+
[
|
|
136
|
+
sym("pull"),
|
|
137
|
+
sym("?e"),
|
|
138
|
+
[
|
|
139
|
+
kw(USER.id),
|
|
140
|
+
kw(USER.name),
|
|
141
|
+
kw(USER.email),
|
|
142
|
+
kw(USER.emailVerified),
|
|
143
|
+
kw(USER.image),
|
|
144
|
+
],
|
|
145
|
+
],
|
|
146
|
+
],
|
|
147
|
+
where: [[sym("?e"), kw(USER.id), uuidEdn(id)]],
|
|
148
|
+
};
|
|
130
149
|
const res = await db.query(q);
|
|
131
150
|
const rows = Array.isArray(res) ? res : [];
|
|
132
151
|
if (!rows.length)
|
|
@@ -136,7 +155,6 @@ export function AnyDBAdapter(db) {
|
|
|
136
155
|
return {
|
|
137
156
|
// Users
|
|
138
157
|
async createUser(data) {
|
|
139
|
-
await ensureAuthSchema(db);
|
|
140
158
|
// Check if user already exists by email
|
|
141
159
|
if (data.email) {
|
|
142
160
|
const existing = await getUserByEmail(data.email);
|
|
@@ -144,47 +162,65 @@ export function AnyDBAdapter(db) {
|
|
|
144
162
|
return existing;
|
|
145
163
|
}
|
|
146
164
|
}
|
|
147
|
-
const id =
|
|
165
|
+
const id = uuidv4();
|
|
148
166
|
const tx = {
|
|
149
|
-
'db/id': DatomicUtils.tempId(),
|
|
150
167
|
[USER.id]: uuidEdn(id),
|
|
151
168
|
...(data.name ? { [USER.name]: data.name } : {}),
|
|
152
|
-
...(data.email ? { [USER.email]: data.email } : {}),
|
|
153
|
-
...(data.emailVerified
|
|
169
|
+
...(data.email ? { [USER.email]: String(data.email).toLowerCase() } : {}),
|
|
170
|
+
...(data.emailVerified
|
|
171
|
+
? { [USER.emailVerified]: data.emailVerified }
|
|
172
|
+
: {}),
|
|
154
173
|
...(data.image ? { [USER.image]: data.image } : {}),
|
|
155
174
|
};
|
|
156
175
|
await db.transact([tx]);
|
|
157
176
|
return {
|
|
158
177
|
id,
|
|
159
178
|
name: data.name ?? null,
|
|
160
|
-
email: data.email
|
|
179
|
+
email: (data.email ? String(data.email).toLowerCase() : null),
|
|
161
180
|
emailVerified: data.emailVerified ?? null,
|
|
162
|
-
image: data.image ?? null
|
|
181
|
+
image: data.image ?? null,
|
|
163
182
|
};
|
|
164
183
|
},
|
|
165
184
|
getUser,
|
|
166
185
|
getUserByEmail,
|
|
167
186
|
async getUserByAccount({ provider, providerAccountId }) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
[
|
|
187
|
+
const q = {
|
|
188
|
+
find: [
|
|
189
|
+
[
|
|
190
|
+
sym("pull"),
|
|
191
|
+
sym("?u"),
|
|
192
|
+
[
|
|
193
|
+
kw(USER.id),
|
|
194
|
+
kw(USER.name),
|
|
195
|
+
kw(USER.email),
|
|
196
|
+
kw(USER.emailVerified),
|
|
197
|
+
kw(USER.image),
|
|
198
|
+
],
|
|
199
|
+
],
|
|
200
|
+
],
|
|
201
|
+
where: [
|
|
202
|
+
[sym("?a"), kw(ACCOUNT.provider), provider],
|
|
203
|
+
[sym("?a"), kw(ACCOUNT.providerAccountId), providerAccountId],
|
|
204
|
+
[sym("?a"), kw(ACCOUNT.userId), sym("?uid")],
|
|
205
|
+
[sym("?u"), kw(USER.id), sym("?uid")],
|
|
206
|
+
],
|
|
207
|
+
};
|
|
174
208
|
const res = await db.query(q);
|
|
175
209
|
const rows = Array.isArray(res) ? res : [];
|
|
176
210
|
return rows.length ? toUser(rows[0][0]) : null;
|
|
177
211
|
},
|
|
178
212
|
async updateUser(data) {
|
|
179
|
-
await ensureAuthSchema(db);
|
|
180
213
|
if (!data.id)
|
|
181
214
|
throw new Error("updateUser requires id");
|
|
182
215
|
const tx = {
|
|
183
|
-
'db/id': DatomicUtils.tempId(),
|
|
184
216
|
[USER.id]: uuidEdn(data.id),
|
|
185
217
|
...(data.name !== undefined ? { [USER.name]: data.name } : {}),
|
|
186
|
-
...(data.email !== undefined
|
|
187
|
-
|
|
218
|
+
...(data.email !== undefined
|
|
219
|
+
? { [USER.email]: data.email ? String(data.email).toLowerCase() : null }
|
|
220
|
+
: {}),
|
|
221
|
+
...(data.emailVerified !== undefined
|
|
222
|
+
? { [USER.emailVerified]: data.emailVerified }
|
|
223
|
+
: {}),
|
|
188
224
|
...(data.image !== undefined ? { [USER.image]: data.image } : {}),
|
|
189
225
|
};
|
|
190
226
|
await db.transact([tx]);
|
|
@@ -192,58 +228,72 @@ export function AnyDBAdapter(db) {
|
|
|
192
228
|
return u;
|
|
193
229
|
},
|
|
194
230
|
async deleteUser(id) {
|
|
195
|
-
await
|
|
196
|
-
await db.transact([[":db/retractEntity", [USER.id], uuidEdn(id)]]);
|
|
231
|
+
await db.transact([[kw("db/retractEntity"), [USER.id], uuidEdn(id)]]);
|
|
197
232
|
return null;
|
|
198
233
|
},
|
|
199
234
|
// Accounts
|
|
200
235
|
async linkAccount(account) {
|
|
201
|
-
|
|
202
|
-
const id = globalThis.crypto?.randomUUID?.() || (await import("crypto")).randomUUID();
|
|
236
|
+
const id = uuidv4();
|
|
203
237
|
const tx = {
|
|
204
|
-
'db/id': DatomicUtils.tempId(),
|
|
205
238
|
[ACCOUNT.id]: uuidEdn(id),
|
|
206
239
|
[ACCOUNT.userId]: uuidEdn(account.userId),
|
|
207
240
|
[ACCOUNT.type]: account.type,
|
|
208
241
|
[ACCOUNT.provider]: account.provider,
|
|
209
242
|
[ACCOUNT.providerAccountId]: account.providerAccountId,
|
|
210
|
-
...(account.refresh_token
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
...(account.
|
|
243
|
+
...(account.refresh_token
|
|
244
|
+
? { [ACCOUNT.refreshToken]: account.refresh_token }
|
|
245
|
+
: {}),
|
|
246
|
+
...(account.access_token
|
|
247
|
+
? { [ACCOUNT.accessToken]: account.access_token }
|
|
248
|
+
: {}),
|
|
249
|
+
...(account.expires_at
|
|
250
|
+
? { [ACCOUNT.expiresAt]: account.expires_at }
|
|
251
|
+
: {}),
|
|
252
|
+
...(account.token_type
|
|
253
|
+
? { [ACCOUNT.tokenType]: account.token_type }
|
|
254
|
+
: {}),
|
|
214
255
|
...(account.scope ? { [ACCOUNT.scope]: account.scope } : {}),
|
|
215
256
|
...(account.id_token ? { [ACCOUNT.idToken]: account.id_token } : {}),
|
|
216
|
-
...(account.session_state
|
|
257
|
+
...(account.session_state
|
|
258
|
+
? { [ACCOUNT.sessionState]: account.session_state }
|
|
259
|
+
: {}),
|
|
217
260
|
};
|
|
218
261
|
await db.transact([tx]);
|
|
219
262
|
return account;
|
|
220
263
|
},
|
|
221
264
|
async unlinkAccount({ provider, providerAccountId }) {
|
|
222
|
-
|
|
223
|
-
|
|
265
|
+
const q = {
|
|
266
|
+
find: [sym("?id")],
|
|
267
|
+
where: [
|
|
268
|
+
[sym("?a"), kw(ACCOUNT.provider), provider],
|
|
269
|
+
[sym("?a"), kw(ACCOUNT.providerAccountId), providerAccountId],
|
|
270
|
+
[sym("?a"), kw(ACCOUNT.id), sym("?id")],
|
|
271
|
+
],
|
|
272
|
+
};
|
|
224
273
|
const res = await db.query(q);
|
|
225
274
|
const id = Array.isArray(res) && res[0]?.[0];
|
|
226
275
|
if (id) {
|
|
227
|
-
await db.transact([["
|
|
276
|
+
await db.transact([[kw("db/retractEntity"), [ACCOUNT.id], id]]);
|
|
228
277
|
}
|
|
229
278
|
},
|
|
230
279
|
// Sessions
|
|
231
280
|
async createSession(session) {
|
|
232
|
-
|
|
233
|
-
const id = globalThis.crypto?.randomUUID?.() || (await import("crypto")).randomUUID();
|
|
281
|
+
const id = uuidv4();
|
|
234
282
|
let expiresDate;
|
|
235
|
-
if (session.expires instanceof Date &&
|
|
283
|
+
if (session.expires instanceof Date &&
|
|
284
|
+
!isNaN(session.expires.getTime())) {
|
|
236
285
|
expiresDate = session.expires;
|
|
237
286
|
}
|
|
238
287
|
else if (session.expires) {
|
|
239
288
|
const d = new Date(session.expires);
|
|
240
|
-
expiresDate = isNaN(d.getTime())
|
|
289
|
+
expiresDate = isNaN(d.getTime())
|
|
290
|
+
? new Date(Date.now() + 30 * 24 * 60 * 60 * 1000)
|
|
291
|
+
: d;
|
|
241
292
|
}
|
|
242
293
|
else {
|
|
243
294
|
expiresDate = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
|
|
244
295
|
}
|
|
245
296
|
const tx = {
|
|
246
|
-
'db/id': DatomicUtils.tempId(),
|
|
247
297
|
[SESSION.id]: uuidEdn(id),
|
|
248
298
|
[SESSION.userId]: uuidEdn(session.userId),
|
|
249
299
|
[SESSION.sessionToken]: session.sessionToken,
|
|
@@ -253,11 +303,36 @@ export function AnyDBAdapter(db) {
|
|
|
253
303
|
return { ...session, expires: expiresDate };
|
|
254
304
|
},
|
|
255
305
|
async getSessionAndUser(sessionToken) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
306
|
+
const q = {
|
|
307
|
+
find: [
|
|
308
|
+
[
|
|
309
|
+
sym("pull"),
|
|
310
|
+
sym("?s"),
|
|
311
|
+
[
|
|
312
|
+
kw(SESSION.id),
|
|
313
|
+
kw(SESSION.sessionToken),
|
|
314
|
+
kw(SESSION.userId),
|
|
315
|
+
kw(SESSION.expires),
|
|
316
|
+
],
|
|
317
|
+
],
|
|
318
|
+
[
|
|
319
|
+
sym("pull"),
|
|
320
|
+
sym("?u"),
|
|
321
|
+
[
|
|
322
|
+
kw(USER.id),
|
|
323
|
+
kw(USER.name),
|
|
324
|
+
kw(USER.email),
|
|
325
|
+
kw(USER.emailVerified),
|
|
326
|
+
kw(USER.image),
|
|
327
|
+
],
|
|
328
|
+
],
|
|
329
|
+
],
|
|
330
|
+
where: [
|
|
331
|
+
[sym("?s"), kw(SESSION.sessionToken), sessionToken],
|
|
332
|
+
[sym("?s"), kw(SESSION.userId), sym("?uid")],
|
|
333
|
+
[sym("?u"), kw(USER.id), sym("?uid")],
|
|
334
|
+
],
|
|
335
|
+
};
|
|
261
336
|
const res = await db.query(q);
|
|
262
337
|
const row = Array.isArray(res) ? res[0] : null;
|
|
263
338
|
if (!row)
|
|
@@ -265,49 +340,62 @@ export function AnyDBAdapter(db) {
|
|
|
265
340
|
const s = row[0];
|
|
266
341
|
const u = row[1];
|
|
267
342
|
const getS = (k) => s && (s[k] ?? s[`:${k}`]);
|
|
268
|
-
const expiresRaw = getS(SESSION.expires
|
|
343
|
+
const expiresRaw = getS(SESSION.expires);
|
|
269
344
|
const expires = expiresRaw instanceof Date ? expiresRaw : new Date(expiresRaw);
|
|
270
345
|
const sessionResult = {
|
|
271
|
-
sessionToken: getS(SESSION.sessionToken
|
|
272
|
-
userId: (getS(SESSION.userId
|
|
346
|
+
sessionToken: getS(SESSION.sessionToken),
|
|
347
|
+
userId: (getS(SESSION.userId)?.value ?? getS(SESSION.userId)),
|
|
273
348
|
expires,
|
|
274
349
|
};
|
|
275
350
|
return { session: sessionResult, user: toUser(u) };
|
|
276
351
|
},
|
|
277
352
|
async updateSession(partial) {
|
|
278
|
-
await ensureAuthSchema(db);
|
|
279
353
|
let expiresDate;
|
|
280
354
|
if (partial.expires instanceof Date) {
|
|
281
|
-
expiresDate = isNaN(partial.expires.getTime())
|
|
355
|
+
expiresDate = isNaN(partial.expires.getTime())
|
|
356
|
+
? undefined
|
|
357
|
+
: partial.expires;
|
|
282
358
|
}
|
|
283
359
|
else if (partial.expires) {
|
|
284
360
|
const d = new Date(partial.expires);
|
|
285
361
|
expiresDate = isNaN(d.getTime()) ? undefined : d;
|
|
286
362
|
}
|
|
363
|
+
if (!partial.sessionToken) {
|
|
364
|
+
throw new Error("updateSession requires sessionToken to upsert by identity");
|
|
365
|
+
}
|
|
287
366
|
const tx = {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
367
|
+
...(partial.sessionToken
|
|
368
|
+
? { [SESSION.sessionToken]: partial.sessionToken }
|
|
369
|
+
: {}),
|
|
370
|
+
...(partial.userId
|
|
371
|
+
? { [SESSION.userId]: uuidEdn(partial.userId) }
|
|
372
|
+
: {}),
|
|
291
373
|
...(expiresDate ? { [SESSION.expires]: expiresDate } : {}),
|
|
292
374
|
};
|
|
293
375
|
await db.transact([tx]);
|
|
294
|
-
return {
|
|
376
|
+
return {
|
|
377
|
+
...partial,
|
|
378
|
+
...(expiresDate ? { expires: expiresDate } : {}),
|
|
379
|
+
};
|
|
295
380
|
},
|
|
296
381
|
async deleteSession(sessionToken) {
|
|
297
|
-
|
|
298
|
-
|
|
382
|
+
const q = {
|
|
383
|
+
find: [sym("?id")],
|
|
384
|
+
where: [
|
|
385
|
+
[sym("?s"), kw(SESSION.sessionToken), sessionToken],
|
|
386
|
+
[sym("?s"), kw(SESSION.id), sym("?id")],
|
|
387
|
+
],
|
|
388
|
+
};
|
|
299
389
|
const res = await db.query(q);
|
|
300
390
|
const id = Array.isArray(res) && res[0]?.[0];
|
|
301
391
|
if (id) {
|
|
302
|
-
await db.transact([["
|
|
392
|
+
await db.transact([[kw("db/retractEntity"), [SESSION.id], id]]);
|
|
303
393
|
}
|
|
304
394
|
},
|
|
305
395
|
// Verification tokens (email sign-in, passwordless)
|
|
306
396
|
async createVerificationToken(token) {
|
|
307
|
-
|
|
308
|
-
const id = globalThis.crypto?.randomUUID?.() || (await import("crypto")).randomUUID();
|
|
397
|
+
const id = uuidv4();
|
|
309
398
|
const tx = {
|
|
310
|
-
'db/id': DatomicUtils.tempId(),
|
|
311
399
|
[VTOKEN.id]: uuidEdn(id),
|
|
312
400
|
[VTOKEN.identifier]: token.identifier,
|
|
313
401
|
[VTOKEN.token]: token.token,
|
|
@@ -317,23 +405,37 @@ export function AnyDBAdapter(db) {
|
|
|
317
405
|
return token;
|
|
318
406
|
},
|
|
319
407
|
async useVerificationToken(params) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
408
|
+
const q = {
|
|
409
|
+
find: [
|
|
410
|
+
[
|
|
411
|
+
sym("pull"),
|
|
412
|
+
sym("?e"),
|
|
413
|
+
[
|
|
414
|
+
kw(VTOKEN.id),
|
|
415
|
+
kw(VTOKEN.identifier),
|
|
416
|
+
kw(VTOKEN.token),
|
|
417
|
+
kw(VTOKEN.expires),
|
|
418
|
+
],
|
|
419
|
+
],
|
|
420
|
+
],
|
|
421
|
+
where: [
|
|
422
|
+
[sym("?e"), kw(VTOKEN.identifier), params.identifier],
|
|
423
|
+
[sym("?e"), kw(VTOKEN.token), params.token],
|
|
424
|
+
],
|
|
425
|
+
};
|
|
324
426
|
const res = await db.query(q);
|
|
325
427
|
const rows = Array.isArray(res) ? res : [];
|
|
326
428
|
if (!rows.length)
|
|
327
429
|
return null;
|
|
328
430
|
const m = rows[0][0];
|
|
329
431
|
const get = (k) => m && (m[k] ?? m[`:${k}`]);
|
|
330
|
-
const entityId = get(VTOKEN.id
|
|
432
|
+
const entityId = get(VTOKEN.id);
|
|
331
433
|
// Delete the token after using it
|
|
332
|
-
await db.transact([["
|
|
434
|
+
await db.transact([[kw("db/retractEntity"), entityId]]);
|
|
333
435
|
return {
|
|
334
|
-
identifier: get(VTOKEN.identifier
|
|
335
|
-
token: get(VTOKEN.token
|
|
336
|
-
expires: new Date(get(VTOKEN.expires
|
|
436
|
+
identifier: get(VTOKEN.identifier),
|
|
437
|
+
token: get(VTOKEN.token),
|
|
438
|
+
expires: new Date(get(VTOKEN.expires)),
|
|
337
439
|
};
|
|
338
440
|
},
|
|
339
441
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anysoftinc/anydb-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "AnyDB TypeScript SDK for querying and transacting with Datomic databases",
|
|
5
5
|
"main": "dist/client.js",
|
|
6
6
|
"types": "dist/client.d.ts",
|
|
@@ -22,16 +22,19 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build": "tsc",
|
|
25
|
+
"build": "npm run build:cljs && tsc && node scripts/pack-cljs.js",
|
|
26
|
+
"build:cljs": "npx shadow-cljs compile datascript",
|
|
26
27
|
"dev": "tsc --watch",
|
|
27
|
-
"
|
|
28
|
+
"dev:cljs": "npx shadow-cljs watch datascript",
|
|
29
|
+
"prepublishOnly": "npm run build:cljs && tsc && node scripts/pack-cljs.js",
|
|
28
30
|
"test": "jest",
|
|
29
31
|
"test:watch": "jest --watch",
|
|
30
32
|
"test:coverage": "jest --coverage",
|
|
31
|
-
"clean": "rm -rf dist"
|
|
33
|
+
"clean": "rm -rf dist dist-cljs target"
|
|
32
34
|
},
|
|
33
35
|
"dependencies": {
|
|
34
|
-
"edn-data": "^1.1.2"
|
|
36
|
+
"edn-data": "^1.1.2",
|
|
37
|
+
"uuid": "^9.0.0"
|
|
35
38
|
},
|
|
36
39
|
"peerDependencies": {
|
|
37
40
|
"next-auth": "^4.24.0 || ^5.0.0-beta"
|
|
@@ -46,6 +49,7 @@
|
|
|
46
49
|
"@types/node": "^20",
|
|
47
50
|
"jest": "^29.7.0",
|
|
48
51
|
"next-auth": "^4.24.11",
|
|
52
|
+
"shadow-cljs": "^2.25.10",
|
|
49
53
|
"ts-jest": "^29.1.4",
|
|
50
54
|
"typescript": "^5"
|
|
51
55
|
},
|