better-auth 0.4.2 → 0.4.3-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,7 @@
1
- import { A as Adapter } from '../index-C-85i2-P.js';
1
+ import { A as Adapter } from '../index-CBfuy92d.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
- import '../types-DoyeJ_dw.js';
5
- import 'arctic';
4
+ import '../types-IzAbV4nB.js';
6
5
  import '../helper-DPDj8Nix.js';
7
6
  import 'better-call';
8
7
  import 'better-sqlite3';
@@ -1,9 +1,8 @@
1
1
  import { Db } from 'mongodb';
2
- import { W as Where } from '../index-C-85i2-P.js';
2
+ import { W as Where } from '../index-CBfuy92d.js';
3
3
  import 'zod';
4
4
  import 'kysely';
5
- import '../types-DoyeJ_dw.js';
6
- import 'arctic';
5
+ import '../types-IzAbV4nB.js';
7
6
  import '../helper-DPDj8Nix.js';
8
7
  import 'better-call';
9
8
  import 'better-sqlite3';
@@ -1,8 +1,7 @@
1
- import { A as Adapter } from '../index-C-85i2-P.js';
1
+ import { A as Adapter } from '../index-CBfuy92d.js';
2
2
  import 'zod';
3
3
  import 'kysely';
4
- import '../types-DoyeJ_dw.js';
5
- import 'arctic';
4
+ import '../types-IzAbV4nB.js';
6
5
  import '../helper-DPDj8Nix.js';
7
6
  import 'better-call';
8
7
  import 'better-sqlite3';
package/dist/api.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- export { e as AuthEndpoint, f as AuthMiddleware, v as callbackOAuth, T as changePassword, d as createAuthEndpoint, c as createAuthMiddleware, M as createEmailVerificationToken, $ as csrfMiddleware, V as deleteUser, Y as error, J as forgetPassword, K as forgetPasswordCallback, X as getCSRFToken, r as getEndpoints, w as getSession, x as getSessionFromCtx, z as listSessions, Z as ok, o as optionsMiddleware, L as resetPassword, C as revokeSession, D as revokeSessions, s as router, N as sendVerificationEmail, y as sessionMiddleware, U as setPassword, u as signInEmail, t as signInOAuth, E as signOut, _ as signUpEmail, Q as updateUser, O as verifyEmail } from './index-C-85i2-P.js';
1
+ export { e as AuthEndpoint, f as AuthMiddleware, v as callbackOAuth, T as changePassword, d as createAuthEndpoint, c as createAuthMiddleware, M as createEmailVerificationToken, $ as csrfMiddleware, V as deleteUser, Y as error, J as forgetPassword, K as forgetPasswordCallback, X as getCSRFToken, r as getEndpoints, w as getSession, x as getSessionFromCtx, z as listSessions, Z as ok, o as optionsMiddleware, L as resetPassword, C as revokeSession, D as revokeSessions, s as router, N as sendVerificationEmail, y as sessionMiddleware, U as setPassword, u as signInEmail, t as signInOAuth, E as signOut, _ as signUpEmail, Q as updateUser, O as verifyEmail } from './index-CBfuy92d.js';
2
2
  import './helper-DPDj8Nix.js';
3
3
  import 'zod';
4
4
  export { APIError } from 'better-call';
5
5
  import 'kysely';
6
- import './types-DoyeJ_dw.js';
7
- import 'arctic';
6
+ import './types-IzAbV4nB.js';
8
7
  import 'better-sqlite3';
9
8
  import 'mysql2';
package/dist/api.js CHANGED
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  import { xchacha20poly1305 } from "@noble/ciphers/chacha";
10
10
  import { bytesToHex, hexToBytes, utf8ToBytes } from "@noble/ciphers/utils";
11
11
  import { managedNonce } from "@noble/ciphers/webcrypto";
12
- import { sha256 } from "@noble/hashes/sha256";
12
+ import { sha256 } from "oslo/crypto";
13
13
  async function hs256(secretKey, message) {
14
14
  const enc = new TextEncoder();
15
15
  const algorithm = { name: "HMAC", hash: "SHA-256" };
@@ -107,7 +107,7 @@ import { z as z4 } from "zod";
107
107
  import { parseJWT } from "oslo/jwt";
108
108
 
109
109
  // src/social-providers/utils.ts
110
- import { OAuth2Tokens } from "arctic";
110
+ import { sha256 as sha2562 } from "oslo/crypto";
111
111
 
112
112
  // src/error/better-auth-error.ts
113
113
  var BetterAuthError = class extends Error {
@@ -156,7 +156,6 @@ function getBaseURL(url, path) {
156
156
 
157
157
  // src/social-providers/utils.ts
158
158
  import { betterFetch } from "@better-fetch/fetch";
159
- import { sha256 as sha2562 } from "@noble/hashes/sha256";
160
159
  import { base64url } from "oslo/encoding";
161
160
  function getRedirectURI(providerId, redirectURI) {
162
161
  return redirectURI || `${getBaseURL()}/callback/${providerId}`;
@@ -187,16 +186,18 @@ async function validateAuthorizationCode({
187
186
  if (error2) {
188
187
  throw error2;
189
188
  }
190
- const tokens = new OAuth2Tokens(data);
189
+ const tokens = getOAuth2Tokens(data);
191
190
  return tokens;
192
191
  }
193
- function generateCodeChallenge(codeVerifier) {
194
- const codeChallengeBytes = sha2562(new TextEncoder().encode(codeVerifier));
195
- return base64url.encode(codeChallengeBytes, {
192
+ async function generateCodeChallenge(codeVerifier) {
193
+ const codeChallengeBytes = await sha2562(
194
+ new TextEncoder().encode(codeVerifier)
195
+ );
196
+ return base64url.encode(new Uint8Array(codeChallengeBytes), {
196
197
  includePadding: false
197
198
  });
198
199
  }
199
- function createAuthorizationURL({
200
+ async function createAuthorizationURL({
200
201
  id,
201
202
  options,
202
203
  authorizationEndpoint,
@@ -215,12 +216,22 @@ function createAuthorizationURL({
215
216
  options.redirectURI || getRedirectURI(id)
216
217
  );
217
218
  if (!disablePkce && codeVerifier) {
218
- const codeChallenge = generateCodeChallenge(codeVerifier);
219
+ const codeChallenge = await generateCodeChallenge(codeVerifier);
219
220
  url.searchParams.set("code_challenge_method", "S256");
220
221
  url.searchParams.set("code_challenge", codeChallenge);
221
222
  }
222
223
  return url;
223
224
  }
225
+ function getOAuth2Tokens(data) {
226
+ return {
227
+ tokenType: data.token_type,
228
+ accessToken: data.access_token,
229
+ refreshToken: data.refresh_token,
230
+ accessTokenExpiresAt: data.expires_at ? new Date((Date.now() + data.expires_in) * 1e3) : void 0,
231
+ scopes: data.scope?.split(" ") || [],
232
+ idToken: data.id_token
233
+ };
234
+ }
224
235
 
225
236
  // src/social-providers/apple.ts
226
237
  var apple = (options) => {
@@ -244,7 +255,10 @@ var apple = (options) => {
244
255
  });
245
256
  },
246
257
  async getUserInfo(token) {
247
- const data = parseJWT(token.idToken())?.payload;
258
+ if (!token.idToken) {
259
+ return null;
260
+ }
261
+ const data = parseJWT(token.idToken)?.payload;
248
262
  if (!data) {
249
263
  return null;
250
264
  }
@@ -290,7 +304,7 @@ var discord = (options) => {
290
304
  "https://discord.com/api/users/@me",
291
305
  {
292
306
  headers: {
293
- authorization: `Bearer ${token.accessToken()}`
307
+ authorization: `Bearer ${token.accessToken}`
294
308
  }
295
309
  }
296
310
  );
@@ -324,9 +338,9 @@ var facebook = (options) => {
324
338
  return {
325
339
  id: "facebook",
326
340
  name: "Facebook",
327
- createAuthorizationURL({ state, scopes, codeVerifier }) {
341
+ async createAuthorizationURL({ state, scopes, codeVerifier }) {
328
342
  const _scopes = options.scope || scopes || ["email", "public_profile"];
329
- return createAuthorizationURL({
343
+ return await createAuthorizationURL({
330
344
  id: "facebook",
331
345
  options,
332
346
  authorizationEndpoint: "https://www.facebook.com/v16.0/dialog/oauth",
@@ -350,7 +364,7 @@ var facebook = (options) => {
350
364
  {
351
365
  auth: {
352
366
  type: "Bearer",
353
- token: token.accessToken()
367
+ token: token.accessToken
354
368
  }
355
369
  }
356
370
  );
@@ -402,7 +416,7 @@ var github = (options) => {
402
416
  {
403
417
  auth: {
404
418
  type: "Bearer",
405
- token: token.accessToken()
419
+ token: token.accessToken
406
420
  }
407
421
  }
408
422
  );
@@ -414,7 +428,7 @@ var github = (options) => {
414
428
  const { data, error: error3 } = await betterFetch4("https://api.github.com/user/emails", {
415
429
  auth: {
416
430
  type: "Bearer",
417
- token: token.accessToken()
431
+ token: token.accessToken
418
432
  }
419
433
  });
420
434
  if (!error3) {
@@ -440,45 +454,94 @@ var github = (options) => {
440
454
  import { parseJWT as parseJWT2 } from "oslo/jwt";
441
455
 
442
456
  // src/utils/logger.ts
443
- import { createConsola } from "consola";
444
- var consola = createConsola({
445
- formatOptions: {
446
- date: false,
447
- colors: true,
448
- compact: true
449
- },
450
- defaults: {
451
- tag: "Better Auth"
457
+ var LOG_LEVELS = {
458
+ debug: 0,
459
+ info: 1,
460
+ success: 2,
461
+ warn: 3,
462
+ error: 4
463
+ };
464
+ var LIBRARY_NAME = "Better Auth";
465
+ var formatDate = (date) => {
466
+ const pad = (num) => num.toString().padStart(2, "0");
467
+ const year = date.getFullYear();
468
+ const month = pad(date.getMonth() + 1);
469
+ const day = pad(date.getDate());
470
+ const hours = pad(date.getHours());
471
+ const minutes = pad(date.getMinutes());
472
+ const seconds = pad(date.getSeconds());
473
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
474
+ };
475
+ var colorize = (text, color) => {
476
+ const colors = {
477
+ reset: "\x1B[0m",
478
+ green: "\x1B[32m",
479
+ yellow: "\x1B[33m",
480
+ red: "\x1B[31m",
481
+ blue: "\x1B[34m",
482
+ cyan: "\x1B[36m"
483
+ };
484
+ return `${colors[color]}${text}${colors.reset}`;
485
+ };
486
+ var defaultFormat = (level, message, timestamp, libraryName, ...args) => {
487
+ let formattedLevel = level.toUpperCase();
488
+ let colorizedMessage = message;
489
+ switch (level) {
490
+ case "debug":
491
+ formattedLevel = colorize(formattedLevel, "cyan");
492
+ break;
493
+ case "info":
494
+ formattedLevel = colorize(formattedLevel, "blue");
495
+ break;
496
+ case "success":
497
+ formattedLevel = colorize(`\u2713 ${formattedLevel}`, "green");
498
+ colorizedMessage = colorize(message, "green");
499
+ break;
500
+ case "warn":
501
+ formattedLevel = colorize(formattedLevel, "yellow");
502
+ break;
503
+ case "error":
504
+ formattedLevel = colorize(formattedLevel, "red");
505
+ break;
452
506
  }
453
- });
454
- var createLogger = (options) => {
507
+ return `[${timestamp}] [${libraryName}] ${formattedLevel}: ${colorizedMessage} ${args.length ? JSON.stringify(args) : ""}`;
508
+ };
509
+ function createLogger(options = {}) {
510
+ const {
511
+ disabled = false,
512
+ minLevel = "info",
513
+ customFormat = defaultFormat
514
+ } = options;
515
+ const loggerFunction = (level) => {
516
+ return (message, ...args) => {
517
+ if (disabled) return;
518
+ if (LOG_LEVELS[level] >= LOG_LEVELS[minLevel]) {
519
+ const timestamp = formatDate(/* @__PURE__ */ new Date());
520
+ const formattedMessage = customFormat(
521
+ level,
522
+ message,
523
+ timestamp,
524
+ LIBRARY_NAME,
525
+ ...args
526
+ );
527
+ console.log(formattedMessage);
528
+ }
529
+ };
530
+ };
455
531
  return {
456
- log: (...args) => {
457
- !options?.disabled && consola.log("", ...args);
458
- },
459
- error: (...args) => {
460
- !options?.disabled && consola.error("", ...args);
461
- },
462
- warn: (...args) => {
463
- !options?.disabled && consola.warn("", ...args);
464
- },
465
- info: (...args) => {
466
- !options?.disabled && consola.info("", ...args);
467
- },
468
- debug: (...args) => {
469
- !options?.disabled && consola.debug("", ...args);
532
+ debug: loggerFunction("debug"),
533
+ info: loggerFunction("info"),
534
+ break: () => {
535
+ console.log("\n");
470
536
  },
471
- box: (...args) => {
472
- !options?.disabled && consola.box("", ...args);
473
- },
474
- success: (...args) => {
475
- !options?.disabled && consola.success("", ...args);
476
- },
477
- break: (...args) => {
478
- !options?.disabled && console.log("\n");
537
+ success: loggerFunction("success"),
538
+ warn: loggerFunction("warn"),
539
+ error: loggerFunction("error"),
540
+ setMinLevel: (level) => {
541
+ options.minLevel = level;
479
542
  }
480
543
  };
481
- };
544
+ }
482
545
  var logger = createLogger();
483
546
 
484
547
  // src/social-providers/google.ts
@@ -520,7 +583,7 @@ var google = (options) => {
520
583
  if (!token.idToken) {
521
584
  return null;
522
585
  }
523
- const user = parseJWT2(token.idToken())?.payload;
586
+ const user = parseJWT2(token.idToken)?.payload;
524
587
  return {
525
588
  user: {
526
589
  id: user.sub,
@@ -566,13 +629,16 @@ var microsoft = (options) => {
566
629
  });
567
630
  },
568
631
  async getUserInfo(token) {
569
- const user = parseJWT3(token.idToken())?.payload;
632
+ if (!token.idToken) {
633
+ return null;
634
+ }
635
+ const user = parseJWT3(token.idToken)?.payload;
570
636
  const profilePhotoSize = options.profilePhotoSize || 48;
571
637
  await betterFetch5(
572
638
  `https://graph.microsoft.com/v1.0/me/photos/${profilePhotoSize}x${profilePhotoSize}/$value`,
573
639
  {
574
640
  headers: {
575
- Authorization: `Bearer ${token.accessToken()}`
641
+ Authorization: `Bearer ${token.accessToken}`
576
642
  },
577
643
  async onResponse(context) {
578
644
  if (options.disableProfilePhoto || !context.response.ok) {
@@ -635,7 +701,7 @@ var spotify = (options) => {
635
701
  {
636
702
  method: "GET",
637
703
  headers: {
638
- Authorization: `Bearer ${token.accessToken()}`
704
+ Authorization: `Bearer ${token.accessToken}`
639
705
  }
640
706
  }
641
707
  );
@@ -686,7 +752,7 @@ var twitch = (options) => {
686
752
  {
687
753
  method: "GET",
688
754
  headers: {
689
- Authorization: `Bearer ${token.accessToken()}`
755
+ Authorization: `Bearer ${token.accessToken}`
690
756
  }
691
757
  }
692
758
  );
@@ -739,7 +805,7 @@ var twitter = (options) => {
739
805
  {
740
806
  method: "GET",
741
807
  headers: {
742
- Authorization: `Bearer ${token.accessToken()}`
808
+ Authorization: `Bearer ${token.accessToken}`
743
809
  }
744
810
  }
745
811
  );
@@ -763,9 +829,6 @@ var twitter = (options) => {
763
829
  };
764
830
  };
765
831
 
766
- // src/social-providers/types.ts
767
- import "arctic";
768
-
769
832
  // src/social-providers/index.ts
770
833
  var oAuthProviders = {
771
834
  apple,
@@ -1059,7 +1122,7 @@ var signInOAuth = createAuthEndpoint(
1059
1122
  c.context.secret,
1060
1123
  cookie.pkCodeVerifier.options
1061
1124
  );
1062
- const url = provider.createAuthorizationURL({
1125
+ const url = await provider.createAuthorizationURL({
1063
1126
  state: state.state,
1064
1127
  codeVerifier
1065
1128
  });
@@ -1310,11 +1373,11 @@ var HIDE_METADATA = {
1310
1373
 
1311
1374
  // src/utils/getAccount.ts
1312
1375
  function getAccountTokens(tokens) {
1313
- const accessToken = tokens.accessToken();
1314
- let refreshToken = tokens.hasRefreshToken() ? tokens.refreshToken() : void 0;
1376
+ const accessToken = tokens.accessToken;
1377
+ let refreshToken = tokens.refreshToken;
1315
1378
  let accessTokenExpiresAt = void 0;
1316
1379
  try {
1317
- accessTokenExpiresAt = tokens.accessTokenExpiresAt();
1380
+ accessTokenExpiresAt = tokens.accessTokenExpiresAt;
1318
1381
  } catch {
1319
1382
  }
1320
1383
  return {
package/dist/cli.js CHANGED
@@ -10,45 +10,94 @@ import { Command } from "commander";
10
10
  import { loadConfig } from "c12";
11
11
 
12
12
  // src/utils/logger.ts
13
- import { createConsola } from "consola";
14
- var consola = createConsola({
15
- formatOptions: {
16
- date: false,
17
- colors: true,
18
- compact: true
19
- },
20
- defaults: {
21
- tag: "Better Auth"
13
+ var LOG_LEVELS = {
14
+ debug: 0,
15
+ info: 1,
16
+ success: 2,
17
+ warn: 3,
18
+ error: 4
19
+ };
20
+ var LIBRARY_NAME = "Better Auth";
21
+ var formatDate = (date) => {
22
+ const pad = (num) => num.toString().padStart(2, "0");
23
+ const year = date.getFullYear();
24
+ const month = pad(date.getMonth() + 1);
25
+ const day = pad(date.getDate());
26
+ const hours = pad(date.getHours());
27
+ const minutes = pad(date.getMinutes());
28
+ const seconds = pad(date.getSeconds());
29
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
30
+ };
31
+ var colorize = (text, color) => {
32
+ const colors = {
33
+ reset: "\x1B[0m",
34
+ green: "\x1B[32m",
35
+ yellow: "\x1B[33m",
36
+ red: "\x1B[31m",
37
+ blue: "\x1B[34m",
38
+ cyan: "\x1B[36m"
39
+ };
40
+ return `${colors[color]}${text}${colors.reset}`;
41
+ };
42
+ var defaultFormat = (level, message, timestamp, libraryName, ...args) => {
43
+ let formattedLevel = level.toUpperCase();
44
+ let colorizedMessage = message;
45
+ switch (level) {
46
+ case "debug":
47
+ formattedLevel = colorize(formattedLevel, "cyan");
48
+ break;
49
+ case "info":
50
+ formattedLevel = colorize(formattedLevel, "blue");
51
+ break;
52
+ case "success":
53
+ formattedLevel = colorize(`\u2713 ${formattedLevel}`, "green");
54
+ colorizedMessage = colorize(message, "green");
55
+ break;
56
+ case "warn":
57
+ formattedLevel = colorize(formattedLevel, "yellow");
58
+ break;
59
+ case "error":
60
+ formattedLevel = colorize(formattedLevel, "red");
61
+ break;
22
62
  }
23
- });
24
- var createLogger = (options) => {
63
+ return `[${timestamp}] [${libraryName}] ${formattedLevel}: ${colorizedMessage} ${args.length ? JSON.stringify(args) : ""}`;
64
+ };
65
+ function createLogger(options = {}) {
66
+ const {
67
+ disabled = false,
68
+ minLevel = "info",
69
+ customFormat = defaultFormat
70
+ } = options;
71
+ const loggerFunction = (level) => {
72
+ return (message, ...args) => {
73
+ if (disabled) return;
74
+ if (LOG_LEVELS[level] >= LOG_LEVELS[minLevel]) {
75
+ const timestamp = formatDate(/* @__PURE__ */ new Date());
76
+ const formattedMessage = customFormat(
77
+ level,
78
+ message,
79
+ timestamp,
80
+ LIBRARY_NAME,
81
+ ...args
82
+ );
83
+ console.log(formattedMessage);
84
+ }
85
+ };
86
+ };
25
87
  return {
26
- log: (...args) => {
27
- !options?.disabled && consola.log("", ...args);
28
- },
29
- error: (...args) => {
30
- !options?.disabled && consola.error("", ...args);
31
- },
32
- warn: (...args) => {
33
- !options?.disabled && consola.warn("", ...args);
34
- },
35
- info: (...args) => {
36
- !options?.disabled && consola.info("", ...args);
37
- },
38
- debug: (...args) => {
39
- !options?.disabled && consola.debug("", ...args);
88
+ debug: loggerFunction("debug"),
89
+ info: loggerFunction("info"),
90
+ break: () => {
91
+ console.log("\n");
40
92
  },
41
- box: (...args) => {
42
- !options?.disabled && consola.box("", ...args);
43
- },
44
- success: (...args) => {
45
- !options?.disabled && consola.success("", ...args);
46
- },
47
- break: (...args) => {
48
- !options?.disabled && console.log("\n");
93
+ success: loggerFunction("success"),
94
+ warn: loggerFunction("warn"),
95
+ error: loggerFunction("error"),
96
+ setMinLevel: (level) => {
97
+ options.minLevel = level;
49
98
  }
50
99
  };
51
- };
100
+ }
52
101
  var logger = createLogger();
53
102
 
54
103
  // src/cli/get-config.ts
@@ -2,14 +2,13 @@ import * as nanostores from 'nanostores';
2
2
  import { A as AccessControl, S as StatementsPrimitive, R as Role } from '../statement-CfnyN34h.js';
3
3
  import * as _better_fetch_fetch from '@better-fetch/fetch';
4
4
  import { BetterFetchOption } from '@better-fetch/fetch';
5
- import { o as organization, j as Organization, M as Member, I as Invitation, u as username, m as magicLink, d as phoneNumber, e as anonymous, i as admin } from '../index-BOgQnoz7.js';
6
- export { g as getPasskeyActions, c as passkeyClient, a as twoFactorClient } from '../index-BOgQnoz7.js';
5
+ import { o as organization, j as Organization, M as Member, I as Invitation, u as username, m as magicLink, d as phoneNumber, e as anonymous, i as admin } from '../index-CmVVvxZr.js';
6
+ export { g as getPasskeyActions, c as passkeyClient, a as twoFactorClient } from '../index-CmVVvxZr.js';
7
7
  import { P as Prettify } from '../helper-DPDj8Nix.js';
8
- import { F as FieldAttribute, B as BetterAuthOptions, b as BetterAuthPlugin } from '../index-C-85i2-P.js';
8
+ import { F as FieldAttribute, B as BetterAuthOptions, b as BetterAuthPlugin } from '../index-CBfuy92d.js';
9
9
  import * as better_call from 'better-call';
10
10
  import { z } from 'zod';
11
- import { U as User } from '../types-DoyeJ_dw.js';
12
- import { OAuth2Tokens } from 'arctic';
11
+ import { O as OAuth2Tokens, U as User } from '../types-IzAbV4nB.js';
13
12
  import '@simplewebauthn/types';
14
13
  import 'kysely';
15
14
  import 'better-sqlite3';
package/dist/client.d.ts CHANGED
@@ -6,10 +6,9 @@ import { BetterFetch, BetterFetchError, BetterFetchOption } from '@better-fetch/
6
6
  import { U as UnionToIntersection, P as Prettify, S as StripEmptyObjects } from './helper-DPDj8Nix.js';
7
7
  import { ClientOptions, InferClientAPI, InferActions, InferAdditionalFromClient, InferSessionFromClient, InferUserFromClient, BetterAuthClientPlugin, IsSignal } from './types.js';
8
8
  export { AtomListener, InferPluginsFromClient } from './types.js';
9
- import './index-C-85i2-P.js';
9
+ import './index-CBfuy92d.js';
10
10
  import 'kysely';
11
- import './types-DoyeJ_dw.js';
12
- import 'arctic';
11
+ import './types-IzAbV4nB.js';
13
12
  import 'better-call';
14
13
  import 'better-sqlite3';
15
14
  import 'mysql2';