@better-i18n/server 0.2.0 → 0.3.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.
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # @better-i18n/server
2
+
3
+ Framework-agnostic server-side i18n for [Better i18n](https://better-i18n.com). Built-in support for Hono, Express, Fastify, and any Node.js HTTP server.
4
+
5
+ [![npm](https://img.shields.io/npm/v/@better-i18n/server)](https://www.npmjs.com/package/@better-i18n/server)
6
+
7
+ ## Features
8
+
9
+ - **Framework Agnostic** — Core API uses Web Standards `Headers`, works everywhere
10
+ - **Hono Middleware** — First-class middleware with typed context variables
11
+ - **Express/Fastify Middleware** — Node.js adapter with `req.locale` and `req.t`
12
+ - **Accept-Language Detection** — RFC 5646 compliant locale matching
13
+ - **CDN-Cached** — Singleton pattern with shared TtlCache across all requests
14
+ - **Type-Safe Translations** — Built on `use-intl/core` for consistent formatting
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @better-i18n/server
20
+ # or
21
+ bun add @better-i18n/server
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ### 1. Create a singleton instance
27
+
28
+ ```ts
29
+ // i18n.ts (module scope — shared across all requests)
30
+ import { createServerI18n } from "@better-i18n/server";
31
+
32
+ export const i18n = createServerI18n({
33
+ project: "acme/api",
34
+ defaultLocale: "en",
35
+ });
36
+ ```
37
+
38
+ ### 2. Use with your framework
39
+
40
+ #### Hono
41
+
42
+ ```ts
43
+ import { Hono } from "hono";
44
+ import { betterI18n } from "@better-i18n/server/hono";
45
+ import type { Translator } from "@better-i18n/server";
46
+ import { i18n } from "./i18n";
47
+
48
+ const app = new Hono<{
49
+ Variables: {
50
+ locale: string;
51
+ t: Translator;
52
+ };
53
+ }>();
54
+
55
+ app.use("*", betterI18n(i18n));
56
+
57
+ app.get("/users/:id", (c) => {
58
+ const t = c.get("t");
59
+ const locale = c.get("locale");
60
+ return c.json({ message: t("users.welcome"), locale });
61
+ });
62
+ ```
63
+
64
+ #### Express
65
+
66
+ ```ts
67
+ import express from "express";
68
+ import { betterI18nMiddleware } from "@better-i18n/server/node";
69
+ import { i18n } from "./i18n";
70
+
71
+ const app = express();
72
+ app.use(betterI18nMiddleware(i18n));
73
+
74
+ app.get("/users/:id", (req, res) => {
75
+ res.json({ message: req.t("users.welcome"), locale: req.locale });
76
+ });
77
+ ```
78
+
79
+ TypeScript augmentation (add to a `.d.ts` file):
80
+
81
+ ```ts
82
+ import type { Translator } from "@better-i18n/server";
83
+
84
+ declare global {
85
+ namespace Express {
86
+ interface Request {
87
+ locale: string;
88
+ t: Translator;
89
+ }
90
+ }
91
+ }
92
+ ```
93
+
94
+ #### Fastify / Koa / Custom
95
+
96
+ Use `fromNodeHeaders` to convert Node.js headers to Web Standards `Headers`:
97
+
98
+ ```ts
99
+ import { fromNodeHeaders } from "@better-i18n/server/node";
100
+ import { i18n } from "./i18n";
101
+
102
+ // In any request handler
103
+ const headers = fromNodeHeaders(req.headers);
104
+ const locale = await i18n.detectLocaleFromHeaders(headers);
105
+ const t = await i18n.getTranslator(locale);
106
+
107
+ t("errors.notFound"); // → "Bulunamadı"
108
+ ```
109
+
110
+ #### Direct API (no middleware)
111
+
112
+ ```ts
113
+ import { i18n } from "./i18n";
114
+
115
+ // Translate with any locale
116
+ const t = await i18n.getTranslator("tr");
117
+ t("errors.notFound"); // → "Bulunamadı"
118
+
119
+ // With namespace
120
+ const tAuth = await i18n.getTranslator("tr", "auth");
121
+ tAuth("loginRequired"); // → "Giriş yapmanız gerekiyor"
122
+
123
+ // Get available locales
124
+ const locales = await i18n.getLocales();
125
+ // ["en", "tr", "de"]
126
+ ```
127
+
128
+ ## API
129
+
130
+ ### `createServerI18n(config)`
131
+
132
+ Creates a singleton i18n instance. Call once at module scope.
133
+
134
+ | Option | Type | Default | Description |
135
+ |--------|------|---------|-------------|
136
+ | `project` | `string` | — | Project identifier (`"org/project"`) |
137
+ | `defaultLocale` | `string` | — | Fallback locale |
138
+ | `cdnBaseUrl` | `string` | CDN default | CDN base URL override |
139
+ | `debug` | `boolean` | `false` | Enable debug logging |
140
+
141
+ ### Instance Methods
142
+
143
+ | Method | Returns | Description |
144
+ |--------|---------|-------------|
145
+ | `getTranslator(locale, namespace?)` | `Promise<Translator>` | Get a translator function for a locale |
146
+ | `detectLocaleFromHeaders(headers)` | `Promise<string>` | Detect locale from Web Standards `Headers` |
147
+ | `getLocales()` | `Promise<string[]>` | Get available locale codes |
148
+ | `getLanguages()` | `Promise<LanguageOption[]>` | Get languages with metadata |
149
+
150
+ ### Entry Points
151
+
152
+ | Import | Use Case |
153
+ |--------|----------|
154
+ | `@better-i18n/server` | Core `createServerI18n`, types |
155
+ | `@better-i18n/server/hono` | `betterI18n()` Hono middleware |
156
+ | `@better-i18n/server/node` | `betterI18nMiddleware()` for Express, `fromNodeHeaders()` for Fastify/Koa |
157
+
158
+ ## How It Works
159
+
160
+ 1. **Singleton pattern** — `createServerI18n` creates one `@better-i18n/core` instance with shared TtlCache
161
+ 2. **Locale detection** — `detectLocaleFromHeaders` parses Accept-Language, matches against CDN manifest locales
162
+ 3. **Translation** — `getTranslator` fetches messages from CDN (cached), creates a `use-intl/core` translator
163
+ 4. **Match strategy** — Exact match (`tr-TR`) → base language (`tr`) → region expansion (`tr` → `tr-TR`)
164
+
165
+ ## Peer Dependencies
166
+
167
+ | Package | Required | Version |
168
+ |---------|----------|---------|
169
+ | `hono` | Optional | `>=4.0.0` |
170
+
171
+ ## Documentation
172
+
173
+ Full documentation at [docs.better-i18n.com/frameworks/server-sdk](https://docs.better-i18n.com/frameworks/server-sdk)
174
+
175
+ ## License
176
+
177
+ MIT © [Better i18n](https://better-i18n.com)
package/dist/node.d.ts CHANGED
@@ -49,6 +49,9 @@ export declare function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Heade
49
49
  * }
50
50
  * ```
51
51
  */
52
- export declare function betterI18nMiddleware(i18n: ServerI18n): (req: any, _res: any, next: () => void) => Promise<void>;
52
+ export declare function betterI18nMiddleware(i18n: ServerI18n): (req: {
53
+ headers: IncomingHttpHeaders;
54
+ [key: string]: unknown;
55
+ }, _res: unknown, next: () => void) => Promise<void>;
53
56
  export type { Translator };
54
57
  //# sourceMappingURL=node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,mBAAmB,GAAG,OAAO,CASzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,IACrC,KAAK,GAAG,EAAE,MAAM,GAAG,EAAE,MAAM,MAAM,IAAI,mBAUpD;AAED,YAAY,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,mBAAmB,GAAG,OAAO,CASzE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,UAAU,IAEjD,KAAK;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAC7D,MAAM,OAAO,EACb,MAAM,MAAM,IAAI,mBAWnB;AAED,YAAY,EAAE,UAAU,EAAE,CAAC"}
package/dist/node.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,WAAgC;IAC9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACvD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAgB;IACnD,OAAO,KAAK,EAAE,GAAQ,EAAE,IAAS,EAAE,IAAgB,EAAE,EAAE;QACrD,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAA8B,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAE3C,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;QACpB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAEV,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"node.js","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,WAAgC;IAC9D,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACvD,IAAI,KAAK,KAAK,SAAS;YAAE,SAAS;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAgB;IACnD,OAAO,KAAK,EACV,GAA6D,EAC7D,IAAa,EACb,IAAgB,EAChB,EAAE;QACF,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,OAA8B,CAAC,CAAC;QACpE,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC3D,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;QAE3C,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC;QACpB,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAEV,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,101 @@
1
+ import type { ServerI18n } from "../types.js";
2
+ /** @internal Duck-typed subset of Better Auth's HookEndpointContext */
3
+ interface HookContext {
4
+ context: {
5
+ returned?: unknown;
6
+ responseHeaders?: Headers;
7
+ };
8
+ headers?: Headers;
9
+ path?: string;
10
+ }
11
+ /**
12
+ * Options for the Better Auth localization provider.
13
+ */
14
+ export interface BetterAuthProviderOptions {
15
+ /**
16
+ * CDN namespace where auth error translations are stored.
17
+ * Maps to the namespace in your Better i18n project.
18
+ * @default "auth"
19
+ */
20
+ namespace?: string;
21
+ /**
22
+ * Custom locale resolver. Overrides the default Accept-Language detection.
23
+ *
24
+ * Useful when locale is stored in a cookie, database, or user profile.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * createBetterAuthProvider(i18n, {
29
+ * getLocale: async ({ headers }) => {
30
+ * const cookie = headers?.get("cookie");
31
+ * return parseCookie(cookie)?.locale ?? "en";
32
+ * },
33
+ * })
34
+ * ```
35
+ */
36
+ getLocale?: (context: {
37
+ headers?: Headers;
38
+ }) => string | Promise<string>;
39
+ /**
40
+ * Log a warning when a translation key is missing in the namespace.
41
+ * Helps identify untranslated error codes during development.
42
+ * @default true
43
+ */
44
+ warnOnMissingKeys?: boolean;
45
+ }
46
+ /**
47
+ * Creates a Better Auth plugin that translates error messages using your
48
+ * Better i18n project's CDN translations.
49
+ *
50
+ * Unlike bundled localization packages, translations are fetched from the CDN
51
+ * at runtime — add or update translations from the dashboard, no redeployment
52
+ * needed. Missing keys log a warning and fall back to the original English
53
+ * message, so auth never breaks.
54
+ *
55
+ * @param i18n - The `ServerI18n` singleton from `createServerI18n()`
56
+ * @param options - Optional configuration (namespace, locale resolver, etc.)
57
+ * @returns A Better Auth plugin — pass it to `betterAuth({ plugins: [...] })`
58
+ *
59
+ * @example
60
+ * ```ts
61
+ * import { createServerI18n } from "@better-i18n/server";
62
+ * import { createBetterAuthProvider } from "@better-i18n/server/providers/better-auth";
63
+ *
64
+ * const i18n = createServerI18n({
65
+ * project: "acme/dashboard",
66
+ * defaultLocale: "en",
67
+ * });
68
+ *
69
+ * export const auth = betterAuth({
70
+ * plugins: [
71
+ * createBetterAuthProvider(i18n),
72
+ * ],
73
+ * });
74
+ * ```
75
+ */
76
+ export declare function createBetterAuthProvider(i18n: ServerI18n, options?: BetterAuthProviderOptions): {
77
+ id: "better-i18n";
78
+ hooks: {
79
+ after: {
80
+ matcher: () => boolean;
81
+ handler: (ctx: HookContext) => Promise<void>;
82
+ }[];
83
+ };
84
+ };
85
+ /**
86
+ * All Better Auth core error codes with their default English messages.
87
+ * Use these to seed your project's "auth" namespace.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * import { DEFAULT_AUTH_KEYS } from "@better-i18n/server/providers/better-auth";
92
+ *
93
+ * // Seed via MCP createKeys tool
94
+ * for (const [key, message] of Object.entries(DEFAULT_AUTH_KEYS)) {
95
+ * await createKey({ namespace: "auth", key, translations: { en: message } });
96
+ * }
97
+ * ```
98
+ */
99
+ export declare const DEFAULT_AUTH_KEYS: Record<string, string>;
100
+ export {};
101
+ //# sourceMappingURL=better-auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"better-auth.d.ts","sourceRoot":"","sources":["../../src/providers/better-auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,uEAAuE;AACvE,UAAU,WAAW;IACnB,OAAO,EAAE;QACP,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzE;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AA6BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,yBAAyB;;;;;2BAWN,WAAW;;;EAuDzC;AAaD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAuEpD,CAAC"}
@@ -0,0 +1,187 @@
1
+ function isAPIErrorLike(value) {
2
+ if (!value || typeof value !== "object")
3
+ return false;
4
+ const obj = value;
5
+ if (obj.name !== "APIError" || typeof obj.statusCode !== "number")
6
+ return false;
7
+ const body = obj.body;
8
+ if (!body || typeof body !== "object")
9
+ return false;
10
+ return typeof body.code === "string";
11
+ }
12
+ /**
13
+ * Creates a Better Auth plugin that translates error messages using your
14
+ * Better i18n project's CDN translations.
15
+ *
16
+ * Unlike bundled localization packages, translations are fetched from the CDN
17
+ * at runtime — add or update translations from the dashboard, no redeployment
18
+ * needed. Missing keys log a warning and fall back to the original English
19
+ * message, so auth never breaks.
20
+ *
21
+ * @param i18n - The `ServerI18n` singleton from `createServerI18n()`
22
+ * @param options - Optional configuration (namespace, locale resolver, etc.)
23
+ * @returns A Better Auth plugin — pass it to `betterAuth({ plugins: [...] })`
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { createServerI18n } from "@better-i18n/server";
28
+ * import { createBetterAuthProvider } from "@better-i18n/server/providers/better-auth";
29
+ *
30
+ * const i18n = createServerI18n({
31
+ * project: "acme/dashboard",
32
+ * defaultLocale: "en",
33
+ * });
34
+ *
35
+ * export const auth = betterAuth({
36
+ * plugins: [
37
+ * createBetterAuthProvider(i18n),
38
+ * ],
39
+ * });
40
+ * ```
41
+ */
42
+ export function createBetterAuthProvider(i18n, options) {
43
+ const namespace = options?.namespace ?? "auth";
44
+ const warnOnMissing = options?.warnOnMissingKeys ?? true;
45
+ return {
46
+ id: "better-i18n",
47
+ hooks: {
48
+ after: [
49
+ {
50
+ matcher: () => true,
51
+ handler: async (ctx) => {
52
+ const returned = ctx.context.returned;
53
+ // Only intercept APIError responses that carry an error code
54
+ if (!isAPIErrorLike(returned))
55
+ return;
56
+ const { body } = returned;
57
+ const errorCode = body.code;
58
+ // ── Detect locale ──────────────────────────────────────
59
+ let locale;
60
+ try {
61
+ if (options?.getLocale) {
62
+ locale = await options.getLocale({ headers: ctx.headers });
63
+ }
64
+ else if (ctx.headers) {
65
+ locale = await i18n.detectLocaleFromHeaders(ctx.headers);
66
+ }
67
+ else {
68
+ locale = i18n.config.defaultLocale;
69
+ }
70
+ }
71
+ catch {
72
+ // Locale detection failed — keep original message
73
+ return;
74
+ }
75
+ // ── Translate ──────────────────────────────────────────
76
+ try {
77
+ const t = await i18n.getTranslator(locale, namespace);
78
+ const translated = t(errorCode);
79
+ // use-intl returns "namespace.key" for missing keys (default
80
+ // getMessageFallback). Detect this to avoid replacing a
81
+ // readable message with a raw fallback string.
82
+ const isFallback = translated === errorCode ||
83
+ translated === `${namespace}.${errorCode}`;
84
+ if (!isFallback && translated) {
85
+ body.message = translated;
86
+ // Also update Error.message for consistent logging
87
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- APIError.message is writable
88
+ returned.message = translated;
89
+ }
90
+ else if (warnOnMissing) {
91
+ console.warn(`[better-i18n] Missing auth translation: "${errorCode}" (locale: ${locale}, namespace: ${namespace})`);
92
+ }
93
+ }
94
+ catch {
95
+ // CDN fetch failed or namespace missing — keep original message.
96
+ // Auth must never break because of i18n.
97
+ }
98
+ },
99
+ },
100
+ ],
101
+ },
102
+ };
103
+ }
104
+ // ---------------------------------------------------------------------------
105
+ // Default English keys for Better Auth core error codes.
106
+ //
107
+ // Seed your Better i18n project's "auth" namespace with these keys,
108
+ // then translate them from the dashboard. Use with MCP `createKeys` tool
109
+ // or import in your seed script.
110
+ //
111
+ // These cover Better Auth core only. Plugin-specific error codes
112
+ // (admin, two-factor, email-otp, etc.) can be added as separate keys.
113
+ // ---------------------------------------------------------------------------
114
+ /**
115
+ * All Better Auth core error codes with their default English messages.
116
+ * Use these to seed your project's "auth" namespace.
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { DEFAULT_AUTH_KEYS } from "@better-i18n/server/providers/better-auth";
121
+ *
122
+ * // Seed via MCP createKeys tool
123
+ * for (const [key, message] of Object.entries(DEFAULT_AUTH_KEYS)) {
124
+ * await createKey({ namespace: "auth", key, translations: { en: message } });
125
+ * }
126
+ * ```
127
+ */
128
+ export const DEFAULT_AUTH_KEYS = {
129
+ // ── Authentication ─────────────────────────────────────────────────
130
+ INVALID_EMAIL_OR_PASSWORD: "Invalid email or password",
131
+ INVALID_PASSWORD: "Invalid password",
132
+ INVALID_EMAIL: "Invalid email",
133
+ INVALID_TOKEN: "Invalid token",
134
+ TOKEN_EXPIRED: "Token expired",
135
+ EMAIL_NOT_VERIFIED: "Email not verified",
136
+ EMAIL_ALREADY_VERIFIED: "Email is already verified",
137
+ EMAIL_MISMATCH: "Email mismatch",
138
+ // ── User management ────────────────────────────────────────────────
139
+ USER_NOT_FOUND: "User not found",
140
+ USER_ALREADY_EXISTS: "User already exists.",
141
+ USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL: "User already exists. Use another email.",
142
+ INVALID_USER: "Invalid user",
143
+ USER_EMAIL_NOT_FOUND: "User email not found",
144
+ USER_ALREADY_HAS_PASSWORD: "User already has a password. Provide that to delete the account.",
145
+ FAILED_TO_CREATE_USER: "Failed to create user",
146
+ FAILED_TO_UPDATE_USER: "Failed to update user",
147
+ FAILED_TO_GET_USER_INFO: "Failed to get user info",
148
+ // ── Session ────────────────────────────────────────────────────────
149
+ SESSION_EXPIRED: "Session expired. Re-authenticate to perform this action.",
150
+ SESSION_NOT_FRESH: "Session is not fresh",
151
+ FAILED_TO_CREATE_SESSION: "Failed to create session",
152
+ FAILED_TO_GET_SESSION: "Failed to get session",
153
+ // ── Password ───────────────────────────────────────────────────────
154
+ PASSWORD_TOO_SHORT: "Password too short",
155
+ PASSWORD_TOO_LONG: "Password too long",
156
+ PASSWORD_ALREADY_SET: "User already has a password set",
157
+ CREDENTIAL_ACCOUNT_NOT_FOUND: "Credential account not found",
158
+ // ── Account & Social ──────────────────────────────────────────────
159
+ ACCOUNT_NOT_FOUND: "Account not found",
160
+ SOCIAL_ACCOUNT_ALREADY_LINKED: "Social account already linked",
161
+ LINKED_ACCOUNT_ALREADY_EXISTS: "Linked account already exists",
162
+ FAILED_TO_UNLINK_LAST_ACCOUNT: "You can't unlink your last account",
163
+ PROVIDER_NOT_FOUND: "Provider not found",
164
+ ID_TOKEN_NOT_SUPPORTED: "id_token not supported",
165
+ // ── Email verification ─────────────────────────────────────────────
166
+ VERIFICATION_EMAIL_NOT_ENABLED: "Verification email isn't enabled",
167
+ EMAIL_CAN_NOT_BE_UPDATED: "Email can not be updated",
168
+ FAILED_TO_CREATE_VERIFICATION: "Unable to create verification",
169
+ // ── URL validation ─────────────────────────────────────────────────
170
+ INVALID_ORIGIN: "Invalid origin",
171
+ INVALID_CALLBACK_URL: "Invalid callbackURL",
172
+ INVALID_REDIRECT_URL: "Invalid redirectURL",
173
+ INVALID_ERROR_CALLBACK_URL: "Invalid errorCallbackURL",
174
+ INVALID_NEW_USER_CALLBACK_URL: "Invalid newUserCallbackURL",
175
+ MISSING_OR_NULL_ORIGIN: "Missing or null Origin",
176
+ CALLBACK_URL_REQUIRED: "callbackURL is required",
177
+ // ── Security ───────────────────────────────────────────────────────
178
+ CROSS_SITE_NAVIGATION_LOGIN_BLOCKED: "Cross-site navigation login blocked. This request appears to be a CSRF attack.",
179
+ // ── Validation ─────────────────────────────────────────────────────
180
+ VALIDATION_ERROR: "Validation Error",
181
+ MISSING_FIELD: "Field is required",
182
+ FIELD_NOT_ALLOWED: "Field not allowed to be set",
183
+ ASYNC_VALIDATION_NOT_SUPPORTED: "Async validation is not supported",
184
+ BODY_MUST_BE_AN_OBJECT: "Body must be an object",
185
+ METHOD_NOT_ALLOWED_DEFER_SESSION_REQUIRED: "POST method requires deferSessionRefresh to be enabled in session config",
186
+ };
187
+ //# sourceMappingURL=better-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"better-auth.js","sourceRoot":"","sources":["../../src/providers/better-auth.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-i18n/server",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Framework-agnostic server-side i18n for Better i18n (Hono, Express, Fastify)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,6 +31,11 @@
31
31
  "bun": "./src/node.ts",
32
32
  "default": "./dist/node.js"
33
33
  },
34
+ "./providers/better-auth": {
35
+ "types": "./dist/providers/better-auth.d.ts",
36
+ "bun": "./src/providers/better-auth.ts",
37
+ "default": "./dist/providers/better-auth.js"
38
+ },
34
39
  "./package.json": "./package.json"
35
40
  },
36
41
  "files": [
@@ -49,7 +54,10 @@
49
54
  "express",
50
55
  "fastify",
51
56
  "server",
52
- "middleware"
57
+ "middleware",
58
+ "better-auth",
59
+ "auth",
60
+ "localization"
53
61
  ],
54
62
  "scripts": {
55
63
  "build": "tsc",
@@ -59,7 +67,7 @@
59
67
  "test": "vitest run"
60
68
  },
61
69
  "dependencies": {
62
- "@better-i18n/core": "0.2.0",
70
+ "@better-i18n/core": "0.6.1",
63
71
  "use-intl": ">=4.0.0"
64
72
  },
65
73
  "peerDependencies": {