@auth/dgraph-adapter 1.0.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/index.js ADDED
@@ -0,0 +1,499 @@
1
+ /**
2
+ * <div style={{display: "flex", justifyContent: "space-between", alignItems: "center", padding: 16}}>
3
+ * <p style={{fontWeight: "normal"}}>Official <a href="https://dgraph.io/docs">Dgraph</a> adapter for Auth.js / NextAuth.js.</p>
4
+ * <a href="https://dgraph.io/">
5
+ * <img style={{display: "block"}} src="https://authjs.dev/img/adapters/dgraph.svg" width="100"/>
6
+ * </a>
7
+ * </div>
8
+ *
9
+ * ## Installation
10
+ *
11
+ * ```bash npm2yarn2pnpm
12
+ * npm install next-auth @auth/dgraph-adapter
13
+ * ```
14
+ *
15
+ * @module @auth/dgraph-adapter
16
+ */
17
+ import { client as dgraphClient } from "./lib/client";
18
+ import { format } from "./lib/utils";
19
+ import * as defaultFragments from "./lib/graphql/fragments";
20
+ export { format };
21
+ /**
22
+ * ## Setup
23
+ *
24
+ * Add this adapter to your `pages/api/[...nextauth].js` next-auth configuration object:
25
+ *
26
+ * ```ts title="pages/api/auth/[...nextauth].js"
27
+ * import NextAuth from "next-auth"
28
+ * import { DgraphAdapter } from "@auth/dgraph-adapter"
29
+ *
30
+ * export default NextAuth({
31
+ * providers: [],
32
+ * adapter: DgraphAdapter({
33
+ * endpoint: process.env.DGRAPH_GRAPHQL_ENDPOINT,
34
+ * authToken: process.env.DGRAPH_GRAPHQL_KEY,
35
+ * // you can omit the following properties if you are running an unsecure schema
36
+ * authHeader: process.env.AUTH_HEADER, // default: "Authorization",
37
+ * jwtSecret: process.env.SECRET,
38
+ * }),
39
+ * })
40
+ * ```
41
+ *
42
+ * ### Unsecure schema
43
+ *
44
+ * The quickest way to use Dgraph is by applying the unsecure schema to your [local](https://dgraph.io/docs/graphql/admin/#modifying-a-schema) Dgraph instance or if using Dgraph [cloud](https://dgraph.io/docs/cloud/cloud-quick-start/#the-schema) you can paste the schema in the codebox to update.
45
+ *
46
+ * :::warning
47
+ * This approach is not secure or for production use, and does not require a `jwtSecret`.
48
+ * :::
49
+ *
50
+ * > This schema is adapted for use in Dgraph and based upon our main [schema](https://authjs.dev/reference/adapters#models)
51
+ *
52
+ * #### Example
53
+ *
54
+ *```graphql
55
+ * type Account {
56
+ * id: ID
57
+ * type: String
58
+ * provider: String @search(by: [hash])
59
+ * providerAccountId: String @search(by: [hash])
60
+ * refreshToken: String
61
+ * expires_at: Int64
62
+ * accessToken: String
63
+ * token_type: String
64
+ * refresh_token: String
65
+ * access_token: String
66
+ * scope: String
67
+ * id_token: String
68
+ * session_state: String
69
+ * user: User @hasInverse(field: "accounts")
70
+ * }
71
+ * type Session {
72
+ * id: ID
73
+ * expires: DateTime
74
+ * sessionToken: String @search(by: [hash])
75
+ * user: User @hasInverse(field: "sessions")
76
+ * }
77
+ * type User {
78
+ * id: ID
79
+ * name: String
80
+ * email: String @search(by: [hash])
81
+ * emailVerified: DateTime
82
+ * image: String
83
+ * accounts: [Account] @hasInverse(field: "user")
84
+ * sessions: [Session] @hasInverse(field: "user")
85
+ * }
86
+ *
87
+ * type VerificationToken {
88
+ * id: ID
89
+ * identifier: String @search(by: [hash])
90
+ * token: String @search(by: [hash])
91
+ * expires: DateTime
92
+ * }
93
+ *```
94
+ *
95
+ * ### Secure schema
96
+ *
97
+ * For production deployments you will want to restrict the access to the types used
98
+ * by next-auth. The main form of access control used in Dgraph is via `@auth` directive alongside types in the schema.
99
+ * #### Example
100
+ *
101
+ * ```graphql
102
+ * type Account
103
+ * @auth(
104
+ * delete: { rule: "{$nextAuth: { eq: true } }" }
105
+ * add: { rule: "{$nextAuth: { eq: true } }" }
106
+ * query: { rule: "{$nextAuth: { eq: true } }" }
107
+ * update: { rule: "{$nextAuth: { eq: true } }" }
108
+ * ) {
109
+ * id: ID
110
+ * type: String
111
+ * provider: String @search(by: [hash])
112
+ * providerAccountId: String @search(by: [hash])
113
+ * refreshToken: String
114
+ * expires_at: Int64
115
+ * accessToken: String
116
+ * token_type: String
117
+ * refresh_token: String
118
+ * access_token: String
119
+ * scope: String
120
+ * id_token: String
121
+ * session_state: String
122
+ * user: User @hasInverse(field: "accounts")
123
+ * }
124
+ * type Session
125
+ * @auth(
126
+ * delete: { rule: "{$nextAuth: { eq: true } }" }
127
+ * add: { rule: "{$nextAuth: { eq: true } }" }
128
+ * query: { rule: "{$nextAuth: { eq: true } }" }
129
+ * update: { rule: "{$nextAuth: { eq: true } }" }
130
+ * ) {
131
+ * id: ID
132
+ * expires: DateTime
133
+ * sessionToken: String @search(by: [hash])
134
+ * user: User @hasInverse(field: "sessions")
135
+ * }
136
+ * type User
137
+ * @auth(
138
+ * query: {
139
+ * or: [
140
+ * {
141
+ * rule: """
142
+ * query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
143
+ * """
144
+ * }
145
+ * { rule: "{$nextAuth: { eq: true } }" }
146
+ * ]
147
+ * }
148
+ * delete: { rule: "{$nextAuth: { eq: true } }" }
149
+ * add: { rule: "{$nextAuth: { eq: true } }" }
150
+ * update: {
151
+ * or: [
152
+ * {
153
+ * rule: """
154
+ * query ($userId: String!) {queryUser(filter: { id: { eq: $userId } } ) {id}}
155
+ * """
156
+ * }
157
+ * { rule: "{$nextAuth: { eq: true } }" }
158
+ * ]
159
+ * }
160
+ * ) {
161
+ * id: ID
162
+ * name: String
163
+ * email: String @search(by: [hash])
164
+ * emailVerified: DateTime
165
+ * image: String
166
+ * accounts: [Account] @hasInverse(field: "user")
167
+ * sessions: [Session] @hasInverse(field: "user")
168
+ * }
169
+ *
170
+ * type VerificationToken
171
+ * @auth(
172
+ * delete: { rule: "{$nextAuth: { eq: true } }" }
173
+ * add: { rule: "{$nextAuth: { eq: true } }" }
174
+ * query: { rule: "{$nextAuth: { eq: true } }" }
175
+ * update: { rule: "{$nextAuth: { eq: true } }" }
176
+ * ) {
177
+ * id: ID
178
+ * identifier: String @search(by: [hash])
179
+ * token: String @search(by: [hash])
180
+ * expires: DateTime
181
+ * }
182
+ *
183
+ * # Dgraph.Authorization {"VerificationKey":"<YOUR JWT SECRET HERE>","Header":"<YOUR AUTH HEADER HERE>","Namespace":"<YOUR CUSTOM NAMESPACE HERE>","Algo":"HS256"}
184
+ * ```
185
+ *
186
+ * ### Dgraph.Authorization
187
+ *
188
+ * In order to secure your graphql backend define the `Dgraph.Authorization` object at the
189
+ * bottom of your schema and provide `authHeader` and `jwtSecret` values to the DgraphClient.
190
+ *
191
+ * ```js
192
+ * # Dgraph.Authorization {"VerificationKey":"<YOUR JWT SECRET HERE>","Header":"<YOUR AUTH HEADER HERE>","Namespace":"YOUR CUSTOM NAMESPACE HERE","Algo":"HS256"}
193
+ * ```
194
+ *
195
+ * ### VerificationKey and jwtSecret
196
+ *
197
+ * This is the key used to sign the JWT. Ex. `process.env.SECRET` or `process.env.APP_SECRET`.
198
+ *
199
+ * ### Header and authHeader
200
+ *
201
+ * The `Header` tells Dgraph where to lookup a JWT within the headers of the incoming requests made to the dgraph server.
202
+ * You have to configure it at the bottom of your schema file. This header is the same as the `authHeader` property you
203
+ * provide when you instantiate the `DgraphClient`.
204
+ *
205
+ * ### The nextAuth secret
206
+ *
207
+ * The `$nextAuth` secret is securely generated using the `jwtSecret` and injected by the DgraphAdapter in order to allow interacting with the JWT DgraphClient for anonymous user requests made within the system `ie. login, register`. This allows
208
+ * secure interactions to be made with all the auth types required by next-auth. You have to specify it for each auth rule of
209
+ * each type defined in your secure schema.
210
+ *
211
+ * ```js
212
+ * type VerificationRequest
213
+ * @auth(
214
+ * delete: { rule: "{$nextAuth: { eq: true } }" },
215
+ * add: { rule: "{$nextAuth: { eq: true } }" },
216
+ * query: { rule: "{$nextAuth: { eq: true } }" },
217
+ * update: { rule: "{$nextAuth: { eq: true } }" }
218
+ * ) {
219
+ * ...
220
+ * }
221
+ * ```
222
+ *
223
+ * ### JWT session and `@auth` directive
224
+ *
225
+ * Dgraph only works with HS256 or RS256 algorithms. If you want to use session jwt to securely interact with your dgraph
226
+ * database you must customize next-auth `encode` and `decode` functions, as the default algorithm is HS512. You can
227
+ * further customize the jwt with roles if you want to implement [`RBAC logic`](https://dgraph.io/docs/graphql/authorization/directive/#role-based-access-control).
228
+ *
229
+ * ```js
230
+ * import * as jwt from "jsonwebtoken"
231
+ * export default NextAuth({
232
+ * session: {
233
+ * strategy: "jwt",
234
+ * },
235
+ * jwt: {
236
+ * secret: process.env.SECRET,
237
+ * encode: async ({ secret, token }) => {
238
+ * return jwt.sign({ ...token, userId: token.id }, secret, {
239
+ * algorithm: "HS256",
240
+ * expiresIn: 30 * 24 * 60 * 60, // 30 days
241
+ * })
242
+ * },
243
+ * decode: async ({ secret, token }) => {
244
+ * return jwt.verify(token, secret, { algorithms: ["HS256"] })
245
+ * },
246
+ * },
247
+ * })
248
+ * ```
249
+ *
250
+ * Once your `Dgraph.Authorization` is defined in your schema and the JWT settings are set, this will allow you to define
251
+ * [`@auth rules`](https://dgraph.io/docs/graphql/authorization/authorization-overview/) for every part of your schema.
252
+ **/
253
+ export function DgraphAdapter(client, options) {
254
+ const c = dgraphClient(client);
255
+ const fragments = { ...defaultFragments, ...options?.fragments };
256
+ return {
257
+ async createUser(input) {
258
+ const result = await c.run(
259
+ /* GraphQL */ `
260
+ mutation ($input: [AddUserInput!]!) {
261
+ addUser(input: $input) {
262
+ user {
263
+ ...UserFragment
264
+ }
265
+ }
266
+ }
267
+ ${fragments.User}
268
+ `, { input });
269
+ return format.from(result?.user[0]);
270
+ },
271
+ async getUser(id) {
272
+ const result = await c.run(
273
+ /* GraphQL */ `
274
+ query ($id: ID!) {
275
+ getUser(id: $id) {
276
+ ...UserFragment
277
+ }
278
+ }
279
+ ${fragments.User}
280
+ `, { id });
281
+ return format.from(result);
282
+ },
283
+ async getUserByEmail(email) {
284
+ const [user] = await c.run(
285
+ /* GraphQL */ `
286
+ query ($email: String = "") {
287
+ queryUser(filter: { email: { eq: $email } }) {
288
+ ...UserFragment
289
+ }
290
+ }
291
+ ${fragments.User}
292
+ `, { email });
293
+ return format.from(user);
294
+ },
295
+ async getUserByAccount(provider_providerAccountId) {
296
+ const [account] = await c.run(
297
+ /* GraphQL */ `
298
+ query ($providerAccountId: String = "", $provider: String = "") {
299
+ queryAccount(
300
+ filter: {
301
+ and: {
302
+ providerAccountId: { eq: $providerAccountId }
303
+ provider: { eq: $provider }
304
+ }
305
+ }
306
+ ) {
307
+ user {
308
+ ...UserFragment
309
+ }
310
+ id
311
+ }
312
+ }
313
+ ${fragments.User}
314
+ `, provider_providerAccountId);
315
+ return format.from(account?.user);
316
+ },
317
+ async updateUser({ id, ...input }) {
318
+ const result = await c.run(
319
+ /* GraphQL */ `
320
+ mutation ($id: [ID!] = "", $input: UserPatch) {
321
+ updateUser(input: { filter: { id: $id }, set: $input }) {
322
+ user {
323
+ ...UserFragment
324
+ }
325
+ }
326
+ }
327
+ ${fragments.User}
328
+ `, { id, input });
329
+ return format.from(result.user[0]);
330
+ },
331
+ async deleteUser(id) {
332
+ const result = await c.run(
333
+ /* GraphQL */ `
334
+ mutation ($id: [ID!] = "") {
335
+ deleteUser(filter: { id: $id }) {
336
+ numUids
337
+ user {
338
+ accounts {
339
+ id
340
+ }
341
+ sessions {
342
+ id
343
+ }
344
+ }
345
+ }
346
+ }
347
+ `, { id });
348
+ const deletedUser = format.from(result.user[0]);
349
+ await c.run(
350
+ /* GraphQL */ `
351
+ mutation ($accounts: [ID!], $sessions: [ID!]) {
352
+ deleteAccount(filter: { id: $accounts }) {
353
+ numUids
354
+ }
355
+ deleteSession(filter: { id: $sessions }) {
356
+ numUids
357
+ }
358
+ }
359
+ `, {
360
+ sessions: deletedUser.sessions.map((x) => x.id),
361
+ accounts: deletedUser.accounts.map((x) => x.id),
362
+ });
363
+ return deletedUser;
364
+ },
365
+ async linkAccount(data) {
366
+ const { userId, ...input } = data;
367
+ await c.run(
368
+ /* GraphQL */ `
369
+ mutation ($input: [AddAccountInput!]!) {
370
+ addAccount(input: $input) {
371
+ account {
372
+ ...AccountFragment
373
+ }
374
+ }
375
+ }
376
+ ${fragments.Account}
377
+ `, { input: { ...input, user: { id: userId } } });
378
+ return data;
379
+ },
380
+ async unlinkAccount(provider_providerAccountId) {
381
+ await c.run(
382
+ /* GraphQL */ `
383
+ mutation ($providerAccountId: String = "", $provider: String = "") {
384
+ deleteAccount(
385
+ filter: {
386
+ and: {
387
+ providerAccountId: { eq: $providerAccountId }
388
+ provider: { eq: $provider }
389
+ }
390
+ }
391
+ ) {
392
+ numUids
393
+ }
394
+ }
395
+ `, provider_providerAccountId);
396
+ },
397
+ async getSessionAndUser(sessionToken) {
398
+ const [sessionAndUser] = await c.run(
399
+ /* GraphQL */ `
400
+ query ($sessionToken: String = "") {
401
+ querySession(filter: { sessionToken: { eq: $sessionToken } }) {
402
+ ...SessionFragment
403
+ user {
404
+ ...UserFragment
405
+ }
406
+ }
407
+ }
408
+ ${fragments.User}
409
+ ${fragments.Session}
410
+ `, { sessionToken });
411
+ if (!sessionAndUser)
412
+ return null;
413
+ const { user, ...session } = sessionAndUser;
414
+ return {
415
+ user: format.from(user),
416
+ session: { ...format.from(session), userId: user.id },
417
+ };
418
+ },
419
+ async createSession(data) {
420
+ const { userId, ...input } = data;
421
+ await c.run(
422
+ /* GraphQL */ `
423
+ mutation ($input: [AddSessionInput!]!) {
424
+ addSession(input: $input) {
425
+ session {
426
+ ...SessionFragment
427
+ }
428
+ }
429
+ }
430
+ ${fragments.Session}
431
+ `, { input: { ...input, user: { id: userId } } });
432
+ return data;
433
+ },
434
+ async updateSession({ sessionToken, ...input }) {
435
+ const result = await c.run(
436
+ /* GraphQL */ `
437
+ mutation ($input: SessionPatch = {}, $sessionToken: String) {
438
+ updateSession(
439
+ input: {
440
+ filter: { sessionToken: { eq: $sessionToken } }
441
+ set: $input
442
+ }
443
+ ) {
444
+ session {
445
+ ...SessionFragment
446
+ user {
447
+ id
448
+ }
449
+ }
450
+ }
451
+ }
452
+ ${fragments.Session}
453
+ `, { sessionToken, input });
454
+ const session = format.from(result.session[0]);
455
+ if (!session?.user?.id)
456
+ return null;
457
+ return { ...session, userId: session.user.id };
458
+ },
459
+ async deleteSession(sessionToken) {
460
+ await c.run(
461
+ /* GraphQL */ `
462
+ mutation ($sessionToken: String = "") {
463
+ deleteSession(filter: { sessionToken: { eq: $sessionToken } }) {
464
+ numUids
465
+ }
466
+ }
467
+ `, { sessionToken });
468
+ },
469
+ async createVerificationToken(input) {
470
+ const result = await c.run(
471
+ /* GraphQL */ `
472
+ mutation ($input: [AddVerificationTokenInput!]!) {
473
+ addVerificationToken(input: $input) {
474
+ numUids
475
+ }
476
+ }
477
+ `, { input });
478
+ return format.from(result);
479
+ },
480
+ async useVerificationToken(params) {
481
+ const result = await c.run(
482
+ /* GraphQL */ `
483
+ mutation ($token: String = "", $identifier: String = "") {
484
+ deleteVerificationToken(
485
+ filter: {
486
+ and: { token: { eq: $token }, identifier: { eq: $identifier } }
487
+ }
488
+ ) {
489
+ verificationToken {
490
+ ...VerificationTokenFragment
491
+ }
492
+ }
493
+ }
494
+ ${fragments.VerificationToken}
495
+ `, params);
496
+ return format.from(result.verificationToken[0]);
497
+ },
498
+ };
499
+ }
@@ -0,0 +1,31 @@
1
+ export interface DgraphClientParams {
2
+ endpoint: string;
3
+ /**
4
+ * `X-Auth-Token` header value
5
+ *
6
+ * [Dgraph Cloud Authentication](https://dgraph.io/docs/cloud/cloud-api/overview/#dgraph-cloud-authentication)
7
+ */
8
+ authToken: string;
9
+ /** [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims) */
10
+ jwtSecret?: string;
11
+ /**
12
+ * @default "RS256"
13
+ *
14
+ * [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims)
15
+ */
16
+ jwtAlgorithm?: "HS256" | "RS256";
17
+ /**
18
+ * @default "Authorization"
19
+ *
20
+ * [Using JWT and authorization claims](https://dgraph.io/docs/graphql/authorization/authorization-overview#using-jwts-and-authorization-claims)
21
+ */
22
+ authHeader?: string;
23
+ }
24
+ export declare class DgraphClientError extends Error {
25
+ name: string;
26
+ constructor(errors: any[], query: string, variables: any);
27
+ }
28
+ export declare function client(params: DgraphClientParams): {
29
+ run<T>(query: string, variables?: Record<string, any>): Promise<T | null>;
30
+ };
31
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/lib/client.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB,oJAAoJ;IACpJ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;IAChC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,IAAI,SAAsB;gBACd,MAAM,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;CAIzD;AAED,wBAAgB,MAAM,CAAC,MAAM,EAAE,kBAAkB;kBA4BpC,MAAM,cACD,OAAO,MAAM,EAAE,GAAG,CAAC;EAepC"}
package/lib/client.js ADDED
@@ -0,0 +1,40 @@
1
+ import * as jwt from "jsonwebtoken";
2
+ export class DgraphClientError extends Error {
3
+ constructor(errors, query, variables) {
4
+ super(errors.map((error) => error.message).join("\n"));
5
+ this.name = "DgraphClientError";
6
+ console.error({ query, variables });
7
+ }
8
+ }
9
+ export function client(params) {
10
+ if (!params.authToken) {
11
+ throw new Error("Dgraph client error: Please provide an api key");
12
+ }
13
+ if (!params.endpoint) {
14
+ throw new Error("Dgraph client error: Please provide a graphql endpoint");
15
+ }
16
+ const { endpoint, authToken, jwtSecret, jwtAlgorithm = "HS256", authHeader = "Authorization", } = params;
17
+ const headers = {
18
+ "Content-Type": "application/json",
19
+ "X-Auth-Token": authToken,
20
+ };
21
+ if (authHeader && jwtSecret) {
22
+ headers[authHeader] = jwt.sign({ nextAuth: true }, jwtSecret, {
23
+ algorithm: jwtAlgorithm,
24
+ });
25
+ }
26
+ return {
27
+ async run(query, variables) {
28
+ const response = await fetch(endpoint, {
29
+ method: "POST",
30
+ headers,
31
+ body: JSON.stringify({ query, variables }),
32
+ });
33
+ const { data = {}, errors } = await response.json();
34
+ if (errors?.length) {
35
+ throw new DgraphClientError(errors, query, variables);
36
+ }
37
+ return Object.values(data)[0];
38
+ },
39
+ };
40
+ }
@@ -0,0 +1,5 @@
1
+ export declare const User = "\n fragment UserFragment on User {\n email\n id\n image\n name\n emailVerified\n }\n";
2
+ export declare const Account = "\n fragment AccountFragment on Account {\n id\n type\n provider\n providerAccountId\n expires_at\n token_type\n scope\n access_token\n refresh_token\n id_token\n session_state\n }\n";
3
+ export declare const Session = "\n fragment SessionFragment on Session {\n expires\n id\n sessionToken\n }\n";
4
+ export declare const VerificationToken = "\n fragment VerificationTokenFragment on VerificationToken {\n identifier\n token\n expires\n }\n";
5
+ //# sourceMappingURL=fragments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fragments.d.ts","sourceRoot":"","sources":["../../src/lib/graphql/fragments.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,IAAI,0GAQhB,CAAA;AAED,eAAO,MAAM,OAAO,6NAcnB,CAAA;AACD,eAAO,MAAM,OAAO,4FAMnB,CAAA;AAED,eAAO,MAAM,iBAAiB,iHAM7B,CAAA"}
@@ -0,0 +1,38 @@
1
+ export const User = /* GraphQL */ `
2
+ fragment UserFragment on User {
3
+ email
4
+ id
5
+ image
6
+ name
7
+ emailVerified
8
+ }
9
+ `;
10
+ export const Account = /* GraphQL */ `
11
+ fragment AccountFragment on Account {
12
+ id
13
+ type
14
+ provider
15
+ providerAccountId
16
+ expires_at
17
+ token_type
18
+ scope
19
+ access_token
20
+ refresh_token
21
+ id_token
22
+ session_state
23
+ }
24
+ `;
25
+ export const Session = /* GraphQL */ `
26
+ fragment SessionFragment on Session {
27
+ expires
28
+ id
29
+ sessionToken
30
+ }
31
+ `;
32
+ export const VerificationToken = /* GraphQL */ `
33
+ fragment VerificationTokenFragment on VerificationToken {
34
+ identifier
35
+ token
36
+ expires
37
+ }
38
+ `;
package/lib/utils.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export declare const format: {
2
+ from<T>(object?: Record<string, any>): T | null;
3
+ };
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/lib/utils.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,MAAM;qBACA,OAAO,MAAM,EAAE,GAAG,CAAC;CAcrC,CAAA"}
package/lib/utils.js ADDED
@@ -0,0 +1,22 @@
1
+ // https://github.com/honeinc/is-iso-date/blob/master/index.js
2
+ const isoDateRE = /(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/;
3
+ function isDate(value) {
4
+ return value && isoDateRE.test(value) && !isNaN(Date.parse(value));
5
+ }
6
+ export const format = {
7
+ from(object) {
8
+ const newObject = {};
9
+ if (!object)
10
+ return null;
11
+ for (const key in object) {
12
+ const value = object[key];
13
+ if (isDate(value)) {
14
+ newObject[key] = new Date(value);
15
+ }
16
+ else {
17
+ newObject[key] = value;
18
+ }
19
+ }
20
+ return newObject;
21
+ },
22
+ };