@hammadj/better-auth-i18n 1.5.0-beta.7

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/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+ Copyright (c) 2024 - present, Bereket Engida
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ this software and associated documentation files (the “Software”), to deal in
6
+ the Software without restriction, including without limitation the rights to
7
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ the Software, and to permit persons to whom the Software is furnished to do so,
9
+ subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
+ DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20
+ DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ //#region src/client.d.ts
2
+ /**
3
+ * i18n client plugin for Better Auth
4
+ *
5
+ * This client plugin provides type inference for the i18n server plugin.
6
+ * Error messages from the server will already be translated based on
7
+ * the detected locale.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { createAuthClient } from "better-auth/client";
12
+ * import { i18nClient } from "@better-auth/i18n/client";
13
+ *
14
+ * export const client = createAuthClient({
15
+ * plugins: [i18nClient()],
16
+ * });
17
+ * ```
18
+ */
19
+ declare const i18nClient: () => BetterAuthClientPlugin;
20
+ //#endregion
21
+ export { i18nClient };
22
+ //# sourceMappingURL=client.d.mts.map
@@ -0,0 +1,28 @@
1
+ //#region src/client.ts
2
+ /**
3
+ * i18n client plugin for Better Auth
4
+ *
5
+ * This client plugin provides type inference for the i18n server plugin.
6
+ * Error messages from the server will already be translated based on
7
+ * the detected locale.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { createAuthClient } from "better-auth/client";
12
+ * import { i18nClient } from "@better-auth/i18n/client";
13
+ *
14
+ * export const client = createAuthClient({
15
+ * plugins: [i18nClient()],
16
+ * });
17
+ * ```
18
+ */
19
+ const i18nClient = () => {
20
+ return {
21
+ id: "i18n",
22
+ $InferServerPlugin: {}
23
+ };
24
+ };
25
+
26
+ //#endregion
27
+ export { i18nClient };
28
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from \"@better-auth/core\";\nimport type { i18n } from \".\";\n\n/**\n * i18n client plugin for Better Auth\n *\n * This client plugin provides type inference for the i18n server plugin.\n * Error messages from the server will already be translated based on\n * the detected locale.\n *\n * @example\n * ```ts\n * import { createAuthClient } from \"better-auth/client\";\n * import { i18nClient } from \"@better-auth/i18n/client\";\n *\n * export const client = createAuthClient({\n * plugins: [i18nClient()],\n * });\n * ```\n */\nexport const i18nClient = () => {\n\treturn {\n\t\tid: \"i18n\",\n\t\t$InferServerPlugin: {} as ReturnType<typeof i18n>,\n\t} satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAoBA,MAAa,mBAAmB;AAC/B,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EACtB"}
@@ -0,0 +1,86 @@
1
+ import { AuthContext } from "@better-auth/core";
2
+
3
+ //#region src/types.d.ts
4
+ /**
5
+ * Translation dictionary mapping error codes to translated messages
6
+ */
7
+ type TranslationDictionary = Record<string, string>;
8
+ /**
9
+ * Locale detection strategy
10
+ */
11
+ type LocaleDetectionStrategy = "header" | "cookie" | "session" | "callback";
12
+ /**
13
+ * Options for the i18n plugin
14
+ */
15
+ interface I18nOptions<Locales extends string[]> {
16
+ /**
17
+ * Translation dictionaries keyed by locale code
18
+ * @example
19
+ * {
20
+ * en: { USER_NOT_FOUND: "User not found" },
21
+ * fr: { USER_NOT_FOUND: "Utilisateur non trouvé" }
22
+ * }
23
+ */
24
+ translations: { [Locale in Locales[number]]: TranslationDictionary };
25
+ /**
26
+ * Default/fallback locale when detection fails
27
+ * @default "en"
28
+ */
29
+ defaultLocale?: Locales[number] | undefined;
30
+ /**
31
+ * Locale detection strategies in priority order
32
+ * @default ["header"]
33
+ */
34
+ detection?: LocaleDetectionStrategy[] | undefined;
35
+ /**
36
+ * Cookie name for locale detection (when "cookie" strategy is used)
37
+ * @default "locale"
38
+ */
39
+ localeCookie?: string | undefined;
40
+ /**
41
+ * User field name for stored locale preference (when "session" strategy is used)
42
+ * @default "locale"
43
+ */
44
+ userLocaleField?: string | undefined;
45
+ /**
46
+ * Custom locale detection function (when "callback" strategy is used)
47
+ * Receives request and AuthContext, return locale code or null
48
+ */
49
+ getLocale?: undefined | ((request: Request, ctx: AuthContext) => Promise<Locales[number] | null> | Locales[number] | null);
50
+ }
51
+ //#endregion
52
+ //#region src/index.d.ts
53
+ declare module "@better-auth/core" {
54
+ interface BetterAuthPluginRegistry<AuthOptions, Options> {
55
+ i18n: {
56
+ creator: typeof i18n;
57
+ };
58
+ }
59
+ }
60
+ /**
61
+ * i18n plugin for Better Auth
62
+ *
63
+ * Translates error messages based on detected locale.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * import { betterAuth } from "better-auth";
68
+ * import { i18n } from "@better-auth/i18n";
69
+ *
70
+ * export const auth = betterAuth({
71
+ * plugins: [
72
+ * i18n({
73
+ * translations: {
74
+ * en: { USER_NOT_FOUND: "User not found" },
75
+ * fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
76
+ * },
77
+ * detection: ["header", "cookie"],
78
+ * }),
79
+ * ],
80
+ * });
81
+ * ```
82
+ */
83
+ declare const i18n: <Locales extends string[]>(options: I18nOptions<Locales>) => BetterAuthPlugin;
84
+ //#endregion
85
+ export { type I18nOptions, type LocaleDetectionStrategy, type TranslationDictionary, i18n };
86
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,113 @@
1
+ import { APIError, createAuthMiddleware, isAPIError } from "better-auth/api";
2
+ import { parseCookies } from "better-auth/cookies";
3
+
4
+ //#region src/index.ts
5
+ /**
6
+ * Parse Accept-Language header and return locales sorted by quality
7
+ */
8
+ function parseAcceptLanguage(header) {
9
+ if (!header) return [];
10
+ return header.split(",").map((part) => {
11
+ const [localeStr, quality = "q=1"] = part.trim().split(";");
12
+ const q = Number.parseFloat(quality.replace("q=", ""));
13
+ return {
14
+ locale: localeStr?.trim().split("-")[0] ?? "",
15
+ q
16
+ };
17
+ }).filter((item) => item.locale.length > 0).sort((a, b) => b.q - a.q).map((item) => item.locale);
18
+ }
19
+ /**
20
+ * i18n plugin for Better Auth
21
+ *
22
+ * Translates error messages based on detected locale.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * import { betterAuth } from "better-auth";
27
+ * import { i18n } from "@better-auth/i18n";
28
+ *
29
+ * export const auth = betterAuth({
30
+ * plugins: [
31
+ * i18n({
32
+ * translations: {
33
+ * en: { USER_NOT_FOUND: "User not found" },
34
+ * fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
35
+ * },
36
+ * detection: ["header", "cookie"],
37
+ * }),
38
+ * ],
39
+ * });
40
+ * ```
41
+ */
42
+ const i18n = (options) => {
43
+ const availableLocales = Object.keys(options.translations);
44
+ let defaultLocale;
45
+ if (options.defaultLocale && availableLocales.includes(options.defaultLocale)) defaultLocale = options.defaultLocale;
46
+ else if (availableLocales.includes("en")) defaultLocale = "en";
47
+ else if (availableLocales.length > 0) defaultLocale = availableLocales[0];
48
+ else throw new Error("i18n plugin: translations object is empty. At least one locale must be provided.");
49
+ const opts = {
50
+ defaultLocale,
51
+ detection: ["header"],
52
+ localeCookie: "locale",
53
+ userLocaleField: "locale",
54
+ ...options
55
+ };
56
+ async function detectLocale(request, headers, ctx) {
57
+ for (const strategy of opts.detection) {
58
+ let locale = null;
59
+ switch (strategy) {
60
+ case "header":
61
+ locale = parseAcceptLanguage(headers?.get("Accept-Language") ?? null).find((l) => availableLocales.includes(l)) ?? null;
62
+ break;
63
+ case "cookie": {
64
+ const cookieHeader = headers?.get("Cookie");
65
+ if (cookieHeader) {
66
+ const cookieLocale = parseCookies(cookieHeader).get(opts.localeCookie);
67
+ if (cookieLocale && availableLocales.includes(cookieLocale)) locale = cookieLocale;
68
+ }
69
+ break;
70
+ }
71
+ case "session":
72
+ if (ctx.session?.user) {
73
+ const userLocale = ctx.session.user[opts.userLocaleField];
74
+ if (typeof userLocale === "string" && availableLocales.includes(userLocale)) locale = userLocale;
75
+ }
76
+ break;
77
+ case "callback":
78
+ if (opts.getLocale && request) {
79
+ const callbackLocale = await opts.getLocale(request, ctx);
80
+ if (callbackLocale && availableLocales.includes(callbackLocale)) locale = callbackLocale;
81
+ }
82
+ break;
83
+ }
84
+ if (locale) return locale;
85
+ }
86
+ return opts.defaultLocale;
87
+ }
88
+ return {
89
+ id: "i18n",
90
+ hooks: { after: [{
91
+ matcher: () => true,
92
+ handler: createAuthMiddleware(async (ctx) => {
93
+ const returned = ctx.context.returned;
94
+ if (!isAPIError(returned)) return;
95
+ const errorCode = returned.body?.code;
96
+ if (typeof errorCode !== "string") return;
97
+ const locale = await detectLocale(ctx.request, ctx.headers, ctx.context);
98
+ const translation = opts.translations[locale]?.[errorCode];
99
+ if (!translation) return;
100
+ throw new APIError(returned.status, {
101
+ code: errorCode,
102
+ message: translation,
103
+ originalMessage: returned.message
104
+ });
105
+ })
106
+ }] },
107
+ options: opts
108
+ };
109
+ };
110
+
111
+ //#endregion
112
+ export { i18n };
113
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type { AuthContext, BetterAuthPlugin } from \"@better-auth/core\";\nimport { APIError, createAuthMiddleware, isAPIError } from \"better-auth/api\";\nimport { parseCookies } from \"better-auth/cookies\";\nimport type { I18nOptions, LocaleDetectionStrategy } from \"./types\";\n\nexport type {\n\tI18nOptions,\n\tLocaleDetectionStrategy,\n\tTranslationDictionary,\n} from \"./types\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\ti18n: {\n\t\t\tcreator: typeof i18n;\n\t\t};\n\t}\n}\n\n/**\n * Parse Accept-Language header and return locales sorted by quality\n */\nfunction parseAcceptLanguage(header: string | null): string[] {\n\tif (!header) return [];\n\treturn header\n\t\t.split(\",\")\n\t\t.map((part) => {\n\t\t\tconst [localeStr, quality = \"q=1\"] = part.trim().split(\";\");\n\t\t\tconst q = Number.parseFloat(quality.replace(\"q=\", \"\"));\n\t\t\t// Get base locale (e.g., \"en\" from \"en-US\")\n\t\t\tconst locale = localeStr?.trim().split(\"-\")[0] ?? \"\";\n\t\t\treturn { locale, q };\n\t\t})\n\t\t.filter((item) => item.locale.length > 0)\n\t\t.sort((a, b) => b.q - a.q)\n\t\t.map((item) => item.locale);\n}\n\n/**\n * i18n plugin for Better Auth\n *\n * Translates error messages based on detected locale.\n *\n * @example\n * ```ts\n * import { betterAuth } from \"better-auth\";\n * import { i18n } from \"@better-auth/i18n\";\n *\n * export const auth = betterAuth({\n * plugins: [\n * i18n({\n * translations: {\n * en: { USER_NOT_FOUND: \"User not found\" },\n * fr: { USER_NOT_FOUND: \"Utilisateur non trouvé\" },\n * },\n * detection: [\"header\", \"cookie\"],\n * }),\n * ],\n * });\n * ```\n */\nexport const i18n = <Locales extends string[]>(\n\toptions: I18nOptions<Locales>,\n) => {\n\tconst availableLocales = Object.keys(options.translations);\n\n\tlet defaultLocale: Locales[number];\n\tif (\n\t\toptions.defaultLocale &&\n\t\tavailableLocales.includes(options.defaultLocale)\n\t) {\n\t\tdefaultLocale = options.defaultLocale;\n\t} else if (availableLocales.includes(\"en\")) {\n\t\tdefaultLocale = \"en\" as Locales[number];\n\t} else if (availableLocales.length > 0) {\n\t\tdefaultLocale = availableLocales[0] as Locales[number];\n\t} else {\n\t\tthrow new Error(\n\t\t\t\"i18n plugin: translations object is empty. At least one locale must be provided.\",\n\t\t);\n\t}\n\n\tconst opts = {\n\t\tdefaultLocale,\n\t\tdetection: [\"header\"] as LocaleDetectionStrategy[],\n\t\tlocaleCookie: \"locale\",\n\t\tuserLocaleField: \"locale\",\n\t\t...options,\n\t};\n\n\tasync function detectLocale(\n\t\trequest: Request | undefined,\n\t\theaders: Headers | undefined,\n\t\tctx: AuthContext,\n\t): Promise<Locales[number]> {\n\t\tfor (const strategy of opts.detection) {\n\t\t\tlet locale: Locales[number] | null = null;\n\n\t\t\tswitch (strategy) {\n\t\t\t\tcase \"header\": {\n\t\t\t\t\tconst acceptLang = headers?.get(\"Accept-Language\") ?? null;\n\t\t\t\t\tconst preferred = parseAcceptLanguage(acceptLang);\n\t\t\t\t\tlocale = preferred.find((l) => availableLocales.includes(l)) ?? null;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"cookie\": {\n\t\t\t\t\tconst cookieHeader = headers?.get(\"Cookie\");\n\t\t\t\t\tif (cookieHeader) {\n\t\t\t\t\t\tconst cookies = parseCookies(cookieHeader);\n\t\t\t\t\t\tconst cookieLocale = cookies.get(opts.localeCookie);\n\t\t\t\t\t\tif (cookieLocale && availableLocales.includes(cookieLocale)) {\n\t\t\t\t\t\t\tlocale = cookieLocale;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"session\": {\n\t\t\t\t\tif (ctx.session?.user) {\n\t\t\t\t\t\tconst userLocale = (ctx.session.user as Record<string, unknown>)[\n\t\t\t\t\t\t\topts.userLocaleField\n\t\t\t\t\t\t];\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof userLocale === \"string\" &&\n\t\t\t\t\t\t\tavailableLocales.includes(userLocale)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tlocale = userLocale;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tcase \"callback\": {\n\t\t\t\t\tif (opts.getLocale && request) {\n\t\t\t\t\t\tconst callbackLocale = await opts.getLocale(request, ctx);\n\t\t\t\t\t\tif (callbackLocale && availableLocales.includes(callbackLocale)) {\n\t\t\t\t\t\t\tlocale = callbackLocale;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (locale) return locale;\n\t\t}\n\n\t\treturn opts.defaultLocale;\n\t}\n\n\treturn {\n\t\tid: \"i18n\",\n\n\t\thooks: {\n\t\t\tafter: [\n\t\t\t\t{\n\t\t\t\t\tmatcher: () => true,\n\t\t\t\t\thandler: createAuthMiddleware(async (ctx) => {\n\t\t\t\t\t\tconst returned = ctx.context.returned;\n\n\t\t\t\t\t\tif (!isAPIError(returned)) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst errorCode = (returned.body as Record<string, unknown>)?.code;\n\t\t\t\t\t\tif (typeof errorCode !== \"string\") {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst locale = await detectLocale(\n\t\t\t\t\t\t\tctx.request,\n\t\t\t\t\t\t\tctx.headers,\n\t\t\t\t\t\t\tctx.context,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst translation = opts.translations[locale]?.[errorCode];\n\n\t\t\t\t\t\tif (!translation) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthrow new APIError(returned.status, {\n\t\t\t\t\t\t\tcode: errorCode,\n\t\t\t\t\t\t\tmessage: translation,\n\t\t\t\t\t\t\toriginalMessage: returned.message,\n\t\t\t\t\t\t});\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\n\t\toptions: opts,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAsBA,SAAS,oBAAoB,QAAiC;AAC7D,KAAI,CAAC,OAAQ,QAAO,EAAE;AACtB,QAAO,OACL,MAAM,IAAI,CACV,KAAK,SAAS;EACd,MAAM,CAAC,WAAW,UAAU,SAAS,KAAK,MAAM,CAAC,MAAM,IAAI;EAC3D,MAAM,IAAI,OAAO,WAAW,QAAQ,QAAQ,MAAM,GAAG,CAAC;AAGtD,SAAO;GAAE,QADM,WAAW,MAAM,CAAC,MAAM,IAAI,CAAC,MAAM;GACjC;GAAG;GACnB,CACD,QAAQ,SAAS,KAAK,OAAO,SAAS,EAAE,CACxC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,EAAE,CACzB,KAAK,SAAS,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;AA0B7B,MAAa,QACZ,YACI;CACJ,MAAM,mBAAmB,OAAO,KAAK,QAAQ,aAAa;CAE1D,IAAI;AACJ,KACC,QAAQ,iBACR,iBAAiB,SAAS,QAAQ,cAAc,CAEhD,iBAAgB,QAAQ;UACd,iBAAiB,SAAS,KAAK,CACzC,iBAAgB;UACN,iBAAiB,SAAS,EACpC,iBAAgB,iBAAiB;KAEjC,OAAM,IAAI,MACT,mFACA;CAGF,MAAM,OAAO;EACZ;EACA,WAAW,CAAC,SAAS;EACrB,cAAc;EACd,iBAAiB;EACjB,GAAG;EACH;CAED,eAAe,aACd,SACA,SACA,KAC2B;AAC3B,OAAK,MAAM,YAAY,KAAK,WAAW;GACtC,IAAI,SAAiC;AAErC,WAAQ,UAAR;IACC,KAAK;AAGJ,cADkB,oBADC,SAAS,IAAI,kBAAkB,IAAI,KACL,CAC9B,MAAM,MAAM,iBAAiB,SAAS,EAAE,CAAC,IAAI;AAChE;IAGD,KAAK,UAAU;KACd,MAAM,eAAe,SAAS,IAAI,SAAS;AAC3C,SAAI,cAAc;MAEjB,MAAM,eADU,aAAa,aAAa,CACb,IAAI,KAAK,aAAa;AACnD,UAAI,gBAAgB,iBAAiB,SAAS,aAAa,CAC1D,UAAS;;AAGX;;IAGD,KAAK;AACJ,SAAI,IAAI,SAAS,MAAM;MACtB,MAAM,aAAc,IAAI,QAAQ,KAC/B,KAAK;AAEN,UACC,OAAO,eAAe,YACtB,iBAAiB,SAAS,WAAW,CAErC,UAAS;;AAGX;IAGD,KAAK;AACJ,SAAI,KAAK,aAAa,SAAS;MAC9B,MAAM,iBAAiB,MAAM,KAAK,UAAU,SAAS,IAAI;AACzD,UAAI,kBAAkB,iBAAiB,SAAS,eAAe,CAC9D,UAAS;;AAGX;;AAIF,OAAI,OAAQ,QAAO;;AAGpB,SAAO,KAAK;;AAGb,QAAO;EACN,IAAI;EAEJ,OAAO,EACN,OAAO,CACN;GACC,eAAe;GACf,SAAS,qBAAqB,OAAO,QAAQ;IAC5C,MAAM,WAAW,IAAI,QAAQ;AAE7B,QAAI,CAAC,WAAW,SAAS,CACxB;IAGD,MAAM,YAAa,SAAS,MAAkC;AAC9D,QAAI,OAAO,cAAc,SACxB;IAGD,MAAM,SAAS,MAAM,aACpB,IAAI,SACJ,IAAI,SACJ,IAAI,QACJ;IAED,MAAM,cAAc,KAAK,aAAa,UAAU;AAEhD,QAAI,CAAC,YACJ;AAGD,UAAM,IAAI,SAAS,SAAS,QAAQ;KACnC,MAAM;KACN,SAAS;KACT,iBAAiB,SAAS;KAC1B,CAAC;KACD;GACF,CACD,EACD;EAED,SAAS;EACT"}
package/package.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "@hammadj/better-auth-i18n",
3
+ "version": "1.5.0-beta.7",
4
+ "type": "module",
5
+ "description": "i18n plugin for Better Auth - translate error messages",
6
+ "main": "dist/index.mjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.mts",
9
+ "publishConfig": {
10
+ "access": "public"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "dev-source": "./src/index.ts",
15
+ "types": "./dist/index.d.mts",
16
+ "default": "./dist/index.mjs"
17
+ },
18
+ "./client": {
19
+ "dev-source": "./src/client.ts",
20
+ "types": "./dist/client.d.mts",
21
+ "default": "./dist/client.mjs"
22
+ }
23
+ },
24
+ "typesVersions": {
25
+ "*": {
26
+ "*": [
27
+ "./dist/index.d.mts"
28
+ ],
29
+ "client": [
30
+ "./dist/client.d.mts"
31
+ ]
32
+ }
33
+ },
34
+ "devDependencies": {
35
+ "tsdown": "^0.20.1",
36
+ "@hammadj/better-auth-core": "1.5.0-beta.9",
37
+ "@hammadj/better-auth": "1.5.0-beta.9"
38
+ },
39
+ "peerDependencies": {
40
+ "@hammadj/better-auth-core": "1.5.0-beta.9",
41
+ "@hammadj/better-auth": "1.5.0-beta.9"
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/META-DREAMER/better-auth.git",
49
+ "directory": "packages/i18n"
50
+ },
51
+ "homepage": "https://www.better-auth.com/docs/plugins/i18n",
52
+ "keywords": [
53
+ "auth",
54
+ "i18n",
55
+ "internationalization",
56
+ "typescript",
57
+ "better-auth"
58
+ ],
59
+ "license": "MIT",
60
+ "scripts": {
61
+ "test": "vitest",
62
+ "coverage": "vitest run --coverage --coverage.provider=istanbul",
63
+ "lint:package": "publint run --strict",
64
+ "lint:types": "attw --profile esm-only --pack .",
65
+ "build": "tsdown",
66
+ "dev": "tsdown --watch",
67
+ "typecheck": "tsc --project tsconfig.json"
68
+ }
69
+ }