@better-auth/i18n 1.5.6 → 1.6.0-beta.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/dist/client.d.mts +3 -3
- package/dist/client.mjs +2 -2
- package/dist/index-CBC5D-Ic.d.mts +431 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -3
- package/dist/version-BqMHXjG-.mjs +5 -0
- package/package.json +8 -7
- package/dist/client.mjs.map +0 -1
- package/dist/index-CLmzQKXC.d.mts +0 -112
- package/dist/index.mjs.map +0 -1
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as i18n } from "./index-
|
|
1
|
+
import { t as i18n } from "./index-CBC5D-Ic.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/client.d.ts
|
|
4
4
|
/**
|
|
@@ -20,8 +20,8 @@ import { t as i18n } from "./index-CLmzQKXC.mjs";
|
|
|
20
20
|
*/
|
|
21
21
|
declare const i18nClient: () => {
|
|
22
22
|
id: "i18n";
|
|
23
|
+
version: string;
|
|
23
24
|
$InferServerPlugin: ReturnType<typeof i18n>;
|
|
24
25
|
};
|
|
25
26
|
//#endregion
|
|
26
|
-
export { i18nClient };
|
|
27
|
-
//# sourceMappingURL=client.d.mts.map
|
|
27
|
+
export { i18nClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as PACKAGE_VERSION } from "./version-BqMHXjG-.mjs";
|
|
1
2
|
//#region src/client.ts
|
|
2
3
|
/**
|
|
3
4
|
* i18n client plugin for Better Auth
|
|
@@ -19,10 +20,9 @@
|
|
|
19
20
|
const i18nClient = () => {
|
|
20
21
|
return {
|
|
21
22
|
id: "i18n",
|
|
23
|
+
version: PACKAGE_VERSION,
|
|
22
24
|
$InferServerPlugin: {}
|
|
23
25
|
};
|
|
24
26
|
};
|
|
25
|
-
|
|
26
27
|
//#endregion
|
|
27
28
|
export { i18nClient };
|
|
28
|
-
//# sourceMappingURL=client.mjs.map
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, UnionToIntersection } from "@better-auth/core";
|
|
2
|
+
|
|
3
|
+
//#region ../../node_modules/.pnpm/better-call@2.0.3_zod@4.3.6/node_modules/better-call/dist/cookies.d.mts
|
|
4
|
+
//#region src/cookies.d.ts
|
|
5
|
+
type CookiePrefixOptions = "host" | "secure";
|
|
6
|
+
type CookieOptions = {
|
|
7
|
+
/**
|
|
8
|
+
* Domain of the cookie
|
|
9
|
+
*
|
|
10
|
+
* The Domain attribute specifies which server can receive a cookie. If specified, cookies are
|
|
11
|
+
* available on the specified server and its subdomains. If the it is not
|
|
12
|
+
* specified, the cookies are available on the server that sets it but not on
|
|
13
|
+
* its subdomains.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* `domain: "example.com"`
|
|
17
|
+
*/
|
|
18
|
+
domain?: string;
|
|
19
|
+
/**
|
|
20
|
+
* A lifetime of a cookie. Permanent cookies are deleted after the date specified in the
|
|
21
|
+
* Expires attribute:
|
|
22
|
+
*
|
|
23
|
+
* Expires has been available for longer than Max-Age, however Max-Age is less error-prone, and
|
|
24
|
+
* takes precedence when both are set. The rationale behind this is that when you set an
|
|
25
|
+
* Expires date and time, they're relative to the client the cookie is being set on. If the
|
|
26
|
+
* server is set to a different time, this could cause errors
|
|
27
|
+
*/
|
|
28
|
+
expires?: Date;
|
|
29
|
+
/**
|
|
30
|
+
* Forbids JavaScript from accessing the cookie, for example, through the Document.cookie
|
|
31
|
+
* property. Note that a cookie that has been created with HttpOnly will still be sent with
|
|
32
|
+
* JavaScript-initiated requests, for example, when calling XMLHttpRequest.send() or fetch().
|
|
33
|
+
* This mitigates attacks against cross-site scripting
|
|
34
|
+
*/
|
|
35
|
+
httpOnly?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Indicates the number of seconds until the cookie expires. A zero or negative number will
|
|
38
|
+
* expire the cookie immediately. If both Expires and Max-Age are set, Max-Age has precedence.
|
|
39
|
+
*
|
|
40
|
+
* @example 604800 - 7 days
|
|
41
|
+
*/
|
|
42
|
+
maxAge?: number;
|
|
43
|
+
/**
|
|
44
|
+
* Indicates the path that must exist in the requested URL for the browser to send the Cookie
|
|
45
|
+
* header.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* "/docs"
|
|
49
|
+
* // -> the request paths /docs, /docs/, /docs/Web/, and /docs/Web/HTTP will all match. the request paths /, /fr/docs will not match.
|
|
50
|
+
*/
|
|
51
|
+
path?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Indicates that the cookie is sent to the server only when a request is made with the https:
|
|
54
|
+
* scheme (except on localhost), and therefore, is more resistant to man-in-the-middle attacks.
|
|
55
|
+
*/
|
|
56
|
+
secure?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Controls whether or not a cookie is sent with cross-site requests, providing some protection
|
|
59
|
+
* against cross-site request forgery attacks (CSRF).
|
|
60
|
+
*
|
|
61
|
+
* Strict - Means that the browser sends the cookie only for same-site requests, that is,
|
|
62
|
+
* requests originating from the same site that set the cookie. If a request originates from a
|
|
63
|
+
* different domain or scheme (even with the same domain), no cookies with the SameSite=Strict
|
|
64
|
+
* attribute are sent.
|
|
65
|
+
*
|
|
66
|
+
* Lax - Means that the cookie is not sent on cross-site requests, such as on requests to load
|
|
67
|
+
* images or frames, but is sent when a user is navigating to the origin site from an external
|
|
68
|
+
* site (for example, when following a link). This is the default behavior if the SameSite
|
|
69
|
+
* attribute is not specified.
|
|
70
|
+
*
|
|
71
|
+
* None - Means that the browser sends the cookie with both cross-site and same-site requests.
|
|
72
|
+
* The Secure attribute must also be set when setting this value.
|
|
73
|
+
*/
|
|
74
|
+
sameSite?: "Strict" | "Lax" | "None" | "strict" | "lax" | "none";
|
|
75
|
+
/**
|
|
76
|
+
* Indicates that the cookie should be stored using partitioned storage. Note that if this is
|
|
77
|
+
* set, the Secure directive must also be set.
|
|
78
|
+
*
|
|
79
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/Privacy/Privacy_sandbox/Partitioned_cookies
|
|
80
|
+
*/
|
|
81
|
+
partitioned?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Cooke Prefix
|
|
84
|
+
*
|
|
85
|
+
* - secure: `__Secure-` -> `__Secure-cookie-name`
|
|
86
|
+
* - host: `__Host-` -> `__Host-cookie-name`
|
|
87
|
+
*
|
|
88
|
+
* `secure` must be set to true to use prefixes
|
|
89
|
+
*/
|
|
90
|
+
prefix?: CookiePrefixOptions;
|
|
91
|
+
};
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region ../../node_modules/.pnpm/better-call@2.0.3_zod@4.3.6/node_modules/better-call/dist/error.d.mts
|
|
94
|
+
declare const statusCodes: {
|
|
95
|
+
OK: number;
|
|
96
|
+
CREATED: number;
|
|
97
|
+
ACCEPTED: number;
|
|
98
|
+
NO_CONTENT: number;
|
|
99
|
+
MULTIPLE_CHOICES: number;
|
|
100
|
+
MOVED_PERMANENTLY: number;
|
|
101
|
+
FOUND: number;
|
|
102
|
+
SEE_OTHER: number;
|
|
103
|
+
NOT_MODIFIED: number;
|
|
104
|
+
TEMPORARY_REDIRECT: number;
|
|
105
|
+
BAD_REQUEST: number;
|
|
106
|
+
UNAUTHORIZED: number;
|
|
107
|
+
PAYMENT_REQUIRED: number;
|
|
108
|
+
FORBIDDEN: number;
|
|
109
|
+
NOT_FOUND: number;
|
|
110
|
+
METHOD_NOT_ALLOWED: number;
|
|
111
|
+
NOT_ACCEPTABLE: number;
|
|
112
|
+
PROXY_AUTHENTICATION_REQUIRED: number;
|
|
113
|
+
REQUEST_TIMEOUT: number;
|
|
114
|
+
CONFLICT: number;
|
|
115
|
+
GONE: number;
|
|
116
|
+
LENGTH_REQUIRED: number;
|
|
117
|
+
PRECONDITION_FAILED: number;
|
|
118
|
+
PAYLOAD_TOO_LARGE: number;
|
|
119
|
+
URI_TOO_LONG: number;
|
|
120
|
+
UNSUPPORTED_MEDIA_TYPE: number;
|
|
121
|
+
RANGE_NOT_SATISFIABLE: number;
|
|
122
|
+
EXPECTATION_FAILED: number;
|
|
123
|
+
"I'M_A_TEAPOT": number;
|
|
124
|
+
MISDIRECTED_REQUEST: number;
|
|
125
|
+
UNPROCESSABLE_ENTITY: number;
|
|
126
|
+
LOCKED: number;
|
|
127
|
+
FAILED_DEPENDENCY: number;
|
|
128
|
+
TOO_EARLY: number;
|
|
129
|
+
UPGRADE_REQUIRED: number;
|
|
130
|
+
PRECONDITION_REQUIRED: number;
|
|
131
|
+
TOO_MANY_REQUESTS: number;
|
|
132
|
+
REQUEST_HEADER_FIELDS_TOO_LARGE: number;
|
|
133
|
+
UNAVAILABLE_FOR_LEGAL_REASONS: number;
|
|
134
|
+
INTERNAL_SERVER_ERROR: number;
|
|
135
|
+
NOT_IMPLEMENTED: number;
|
|
136
|
+
BAD_GATEWAY: number;
|
|
137
|
+
SERVICE_UNAVAILABLE: number;
|
|
138
|
+
GATEWAY_TIMEOUT: number;
|
|
139
|
+
HTTP_VERSION_NOT_SUPPORTED: number;
|
|
140
|
+
VARIANT_ALSO_NEGOTIATES: number;
|
|
141
|
+
INSUFFICIENT_STORAGE: number;
|
|
142
|
+
LOOP_DETECTED: number;
|
|
143
|
+
NOT_EXTENDED: number;
|
|
144
|
+
NETWORK_AUTHENTICATION_REQUIRED: number;
|
|
145
|
+
};
|
|
146
|
+
type Status = 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511;
|
|
147
|
+
declare class InternalAPIError extends Error {
|
|
148
|
+
status: keyof typeof statusCodes | Status;
|
|
149
|
+
body: ({
|
|
150
|
+
message?: string;
|
|
151
|
+
code?: string;
|
|
152
|
+
cause?: unknown;
|
|
153
|
+
} & Record<string, any>) | undefined;
|
|
154
|
+
headers: HeadersInit;
|
|
155
|
+
statusCode: number;
|
|
156
|
+
constructor(status?: keyof typeof statusCodes | Status, body?: ({
|
|
157
|
+
message?: string;
|
|
158
|
+
code?: string;
|
|
159
|
+
cause?: unknown;
|
|
160
|
+
} & Record<string, any>) | undefined, headers?: HeadersInit, statusCode?: number);
|
|
161
|
+
}
|
|
162
|
+
type APIError = InstanceType<typeof InternalAPIError>;
|
|
163
|
+
declare const APIError: new (status?: Status | "OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "FOUND" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "NOT_FOUND" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED" | undefined, body?: ({
|
|
164
|
+
message?: string;
|
|
165
|
+
code?: string;
|
|
166
|
+
cause?: unknown;
|
|
167
|
+
} & Record<string, any>) | undefined, headers?: HeadersInit | undefined, statusCode?: number | undefined) => InternalAPIError & {
|
|
168
|
+
errorStack: string | undefined;
|
|
169
|
+
}; //#endregion
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region ../../node_modules/.pnpm/better-call@2.0.3_zod@4.3.6/node_modules/better-call/dist/helper.d.mts
|
|
172
|
+
type Prettify<T> = 0 extends 1 & T ? any : { [K in keyof T]: T[K] } & {};
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region ../../node_modules/.pnpm/better-call@2.0.3_zod@4.3.6/node_modules/better-call/dist/middleware.d.mts
|
|
175
|
+
//#region src/middleware.d.ts
|
|
176
|
+
type MiddlewareContext<Context = {}> = {
|
|
177
|
+
/**
|
|
178
|
+
* Method
|
|
179
|
+
*
|
|
180
|
+
* The request method
|
|
181
|
+
*/
|
|
182
|
+
method: string;
|
|
183
|
+
/**
|
|
184
|
+
* Path
|
|
185
|
+
*
|
|
186
|
+
* The path of the endpoint
|
|
187
|
+
*/
|
|
188
|
+
path: string;
|
|
189
|
+
/**
|
|
190
|
+
* Body
|
|
191
|
+
*
|
|
192
|
+
* The body object will be the parsed JSON from the request and validated
|
|
193
|
+
* against the body schema if it exists
|
|
194
|
+
*/
|
|
195
|
+
body: any;
|
|
196
|
+
/**
|
|
197
|
+
* Query
|
|
198
|
+
*
|
|
199
|
+
* The query object will be the parsed query string from the request
|
|
200
|
+
* and validated against the query schema if it exists
|
|
201
|
+
*/
|
|
202
|
+
query: Record<string, any> | undefined;
|
|
203
|
+
/**
|
|
204
|
+
* Params
|
|
205
|
+
*
|
|
206
|
+
* If the path is `/user/:id` and the request is `/user/1` then the
|
|
207
|
+
* params will be `{ id: "1" }` and if the path includes a wildcard like
|
|
208
|
+
* `/user/*` then the params will be `{ _: "1" }` where `_` is the wildcard
|
|
209
|
+
* key. If the wildcard is named like `/user/**:name` then the params will
|
|
210
|
+
* be `{ name: string }`
|
|
211
|
+
*/
|
|
212
|
+
params: Record<string, any> | undefined;
|
|
213
|
+
/**
|
|
214
|
+
* Request object
|
|
215
|
+
*
|
|
216
|
+
* If `requireRequest` is set to true in the endpoint options this will be
|
|
217
|
+
* required
|
|
218
|
+
*/
|
|
219
|
+
request: Request | undefined;
|
|
220
|
+
/**
|
|
221
|
+
* Headers
|
|
222
|
+
*
|
|
223
|
+
* If `requireHeaders` is set to true in the endpoint options this will be
|
|
224
|
+
* required
|
|
225
|
+
*/
|
|
226
|
+
headers: Headers | undefined;
|
|
227
|
+
/**
|
|
228
|
+
* Set header
|
|
229
|
+
*
|
|
230
|
+
* If it's called outside of a request it will just be ignored.
|
|
231
|
+
*/
|
|
232
|
+
setHeader: (key: string, value: string) => void;
|
|
233
|
+
/**
|
|
234
|
+
* Set the response status code
|
|
235
|
+
*/
|
|
236
|
+
setStatus: (status: Status) => void;
|
|
237
|
+
/**
|
|
238
|
+
* Get header
|
|
239
|
+
*
|
|
240
|
+
* If it's called outside of a request it will just return null
|
|
241
|
+
*
|
|
242
|
+
* @param key - The key of the header
|
|
243
|
+
*/
|
|
244
|
+
getHeader: (key: string) => string | null;
|
|
245
|
+
/**
|
|
246
|
+
* Get a cookie value from the request
|
|
247
|
+
*
|
|
248
|
+
* @param key - The key of the cookie
|
|
249
|
+
* @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
|
|
250
|
+
* @returns The value of the cookie
|
|
251
|
+
*/
|
|
252
|
+
getCookie: (key: string, prefix?: CookiePrefixOptions) => string | null;
|
|
253
|
+
/**
|
|
254
|
+
* Get a signed cookie value from the request
|
|
255
|
+
*
|
|
256
|
+
* @param key - The key of the cookie
|
|
257
|
+
* @param secret - The secret of the signed cookie
|
|
258
|
+
* @param prefix - The prefix of the cookie between `__Secure-` and `__Host-`
|
|
259
|
+
* @returns The value of the cookie or null if the cookie is not found or false if the signature is invalid
|
|
260
|
+
*/
|
|
261
|
+
getSignedCookie: (key: string, secret: string, prefix?: CookiePrefixOptions) => Promise<string | null | false>;
|
|
262
|
+
/**
|
|
263
|
+
* Set a cookie value in the response
|
|
264
|
+
*
|
|
265
|
+
* @param key - The key of the cookie
|
|
266
|
+
* @param value - The value to set
|
|
267
|
+
* @param options - The options of the cookie
|
|
268
|
+
* @returns The cookie string
|
|
269
|
+
*/
|
|
270
|
+
setCookie: (key: string, value: string, options?: CookieOptions) => string;
|
|
271
|
+
/**
|
|
272
|
+
* Set signed cookie
|
|
273
|
+
*
|
|
274
|
+
* @param key - The key of the cookie
|
|
275
|
+
* @param value - The value to set
|
|
276
|
+
* @param secret - The secret to sign the cookie with
|
|
277
|
+
* @param options - The options of the cookie
|
|
278
|
+
* @returns The cookie string
|
|
279
|
+
*/
|
|
280
|
+
setSignedCookie: (key: string, value: string, secret: string, options?: CookieOptions) => Promise<string>;
|
|
281
|
+
/**
|
|
282
|
+
* JSON
|
|
283
|
+
*
|
|
284
|
+
* A helper function to create a JSON response with the correct headers
|
|
285
|
+
* and status code. If `asResponse` is set to true in the context then
|
|
286
|
+
* it will return a Response object instead of the JSON object.
|
|
287
|
+
*
|
|
288
|
+
* @param json - The JSON object to return
|
|
289
|
+
* @param routerResponse - The response object to return if `asResponse` is
|
|
290
|
+
* true in the context this will take precedence
|
|
291
|
+
*/
|
|
292
|
+
json: <R extends Record<string, any> | null>(json: R, routerResponse?: {
|
|
293
|
+
status?: number;
|
|
294
|
+
headers?: Record<string, string>;
|
|
295
|
+
response?: Response;
|
|
296
|
+
body?: Record<string, any>;
|
|
297
|
+
} | Response) => R;
|
|
298
|
+
/**
|
|
299
|
+
* Middleware context
|
|
300
|
+
*/
|
|
301
|
+
context: Prettify<Context>;
|
|
302
|
+
/**
|
|
303
|
+
* Redirect to a new URL
|
|
304
|
+
*/
|
|
305
|
+
redirect: (url: string) => APIError;
|
|
306
|
+
/**
|
|
307
|
+
* Return error
|
|
308
|
+
*/
|
|
309
|
+
error: (status: keyof typeof statusCodes | Status, body?: {
|
|
310
|
+
message?: string;
|
|
311
|
+
code?: string;
|
|
312
|
+
} & Record<string, any>, headers?: HeadersInit) => APIError;
|
|
313
|
+
asResponse?: boolean;
|
|
314
|
+
returnHeaders?: boolean;
|
|
315
|
+
returnStatus?: boolean;
|
|
316
|
+
responseHeaders: Headers;
|
|
317
|
+
};
|
|
318
|
+
type DefaultHandler = (inputCtx: MiddlewareContext<any>) => Promise<any>;
|
|
319
|
+
type Middleware<Handler extends (inputCtx: MiddlewareContext<any>) => Promise<any> = DefaultHandler> = Handler & {
|
|
320
|
+
options: Record<string, any>;
|
|
321
|
+
};
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/types.d.ts
|
|
324
|
+
type ALL_PLUGIN_ERROR_CODE_KEYS = keyof UnionToIntersection<{ [Key in Exclude<BetterAuthPluginRegistryIdentifier, "i18n">]: BetterAuthPluginRegistry<unknown, unknown>[Key] extends {
|
|
325
|
+
creator: infer C;
|
|
326
|
+
} ? C extends ((...args: any[]) => infer P) ? P extends {
|
|
327
|
+
$ERROR_CODES: infer E;
|
|
328
|
+
} ? E : {} : {} : {} }[Exclude<BetterAuthPluginRegistryIdentifier, "i18n">]>;
|
|
329
|
+
type InternalTranslationDictionary = Partial<{ [Key in ALL_PLUGIN_ERROR_CODE_KEYS]: string }>;
|
|
330
|
+
/**
|
|
331
|
+
* Translation dictionary mapping error codes to translated messages
|
|
332
|
+
*/
|
|
333
|
+
type TranslationDictionary = InternalTranslationDictionary & Record<string, string>;
|
|
334
|
+
/**
|
|
335
|
+
* Locale detection strategy
|
|
336
|
+
*/
|
|
337
|
+
type LocaleDetectionStrategy = "header" | "cookie" | "session" | "callback";
|
|
338
|
+
/**
|
|
339
|
+
* Options for the i18n plugin
|
|
340
|
+
*/
|
|
341
|
+
interface I18nOptions<Locales extends string[]> {
|
|
342
|
+
/**
|
|
343
|
+
* Translation dictionaries keyed by locale code
|
|
344
|
+
* @example
|
|
345
|
+
* {
|
|
346
|
+
* en: { USER_NOT_FOUND: "User not found" },
|
|
347
|
+
* fr: { USER_NOT_FOUND: "Utilisateur non trouvé" }
|
|
348
|
+
* }
|
|
349
|
+
*/
|
|
350
|
+
translations: { [Locale in Locales[number]]: TranslationDictionary };
|
|
351
|
+
/**
|
|
352
|
+
* Default/fallback locale when detection fails
|
|
353
|
+
* @default "en"
|
|
354
|
+
*/
|
|
355
|
+
defaultLocale?: Locales[number] | undefined;
|
|
356
|
+
/**
|
|
357
|
+
* Locale detection strategies in priority order
|
|
358
|
+
* @default ["header"]
|
|
359
|
+
*/
|
|
360
|
+
detection?: LocaleDetectionStrategy[] | undefined;
|
|
361
|
+
/**
|
|
362
|
+
* Cookie name for locale detection (when "cookie" strategy is used)
|
|
363
|
+
* @default "locale"
|
|
364
|
+
*/
|
|
365
|
+
localeCookie?: string | undefined;
|
|
366
|
+
/**
|
|
367
|
+
* User field name for stored locale preference (when "session" strategy is used)
|
|
368
|
+
* @default "locale"
|
|
369
|
+
*/
|
|
370
|
+
userLocaleField?: string | undefined;
|
|
371
|
+
/**
|
|
372
|
+
* Custom locale detection function (when "callback" strategy is used).
|
|
373
|
+
* @example
|
|
374
|
+
* getLocale: (ctx) => {
|
|
375
|
+
* return ctx.headers?.get("X-Custom-Locale") ?? null;
|
|
376
|
+
* }
|
|
377
|
+
*/
|
|
378
|
+
getLocale?: undefined | ((ctx: GenericEndpointContext) => Promise<Locales[number] | null> | Locales[number] | null);
|
|
379
|
+
}
|
|
380
|
+
//#endregion
|
|
381
|
+
//#region src/index.d.ts
|
|
382
|
+
declare module "@better-auth/core" {
|
|
383
|
+
interface BetterAuthPluginRegistry<AuthOptions, Options> {
|
|
384
|
+
i18n: {
|
|
385
|
+
creator: typeof i18n;
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* i18n plugin for Better Auth
|
|
391
|
+
*
|
|
392
|
+
* Translates error messages based on detected locale.
|
|
393
|
+
*
|
|
394
|
+
* @example
|
|
395
|
+
* ```ts
|
|
396
|
+
* import { betterAuth } from "better-auth";
|
|
397
|
+
* import { i18n } from "@better-auth/i18n";
|
|
398
|
+
*
|
|
399
|
+
* export const auth = betterAuth({
|
|
400
|
+
* plugins: [
|
|
401
|
+
* i18n({
|
|
402
|
+
* translations: {
|
|
403
|
+
* en: { USER_NOT_FOUND: "User not found" },
|
|
404
|
+
* fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
|
|
405
|
+
* },
|
|
406
|
+
* detection: ["header", "cookie"],
|
|
407
|
+
* }),
|
|
408
|
+
* ],
|
|
409
|
+
* });
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
declare const i18n: <Locales extends string[]>(options: I18nOptions<Locales>) => {
|
|
413
|
+
id: "i18n";
|
|
414
|
+
version: string;
|
|
415
|
+
hooks: {
|
|
416
|
+
after: {
|
|
417
|
+
matcher: () => true;
|
|
418
|
+
handler: Middleware<(inputContext: Record<string, any>) => Promise<void>>;
|
|
419
|
+
}[];
|
|
420
|
+
};
|
|
421
|
+
options: {
|
|
422
|
+
translations: { [Locale in Locales[number]]: TranslationDictionary };
|
|
423
|
+
defaultLocale: Locales[number];
|
|
424
|
+
detection: LocaleDetectionStrategy[];
|
|
425
|
+
localeCookie: string;
|
|
426
|
+
userLocaleField: string;
|
|
427
|
+
getLocale?: ((ctx: GenericEndpointContext) => Locales[number] | Promise<Locales[number] | null> | null) | undefined;
|
|
428
|
+
};
|
|
429
|
+
};
|
|
430
|
+
//#endregion
|
|
431
|
+
export { TranslationDictionary as i, I18nOptions as n, LocaleDetectionStrategy as r, i18n as t };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as TranslationDictionary, n as I18nOptions, r as LocaleDetectionStrategy, t as i18n } from "./index-
|
|
1
|
+
import { i as TranslationDictionary, n as I18nOptions, r as LocaleDetectionStrategy, t as i18n } from "./index-CBC5D-Ic.mjs";
|
|
2
2
|
export { I18nOptions, LocaleDetectionStrategy, TranslationDictionary, i18n };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { t as PACKAGE_VERSION } from "./version-BqMHXjG-.mjs";
|
|
1
2
|
import { APIError, createAuthMiddleware, isAPIError } from "better-auth/api";
|
|
2
3
|
import { parseCookies } from "better-auth/cookies";
|
|
3
|
-
|
|
4
4
|
//#region src/index.ts
|
|
5
5
|
/**
|
|
6
6
|
* Parse Accept-Language header and return locales sorted by quality
|
|
@@ -87,6 +87,7 @@ const i18n = (options) => {
|
|
|
87
87
|
}
|
|
88
88
|
return {
|
|
89
89
|
id: "i18n",
|
|
90
|
+
version: PACKAGE_VERSION,
|
|
90
91
|
hooks: { after: [{
|
|
91
92
|
matcher: () => true,
|
|
92
93
|
handler: createAuthMiddleware(async (ctx) => {
|
|
@@ -107,7 +108,5 @@ const i18n = (options) => {
|
|
|
107
108
|
options: opts
|
|
108
109
|
};
|
|
109
110
|
};
|
|
110
|
-
|
|
111
111
|
//#endregion
|
|
112
112
|
export { i18n };
|
|
113
|
-
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/i18n",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-beta.0",
|
|
4
4
|
"description": "i18n plugin for Better Auth - translate error messages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"publishConfig": {
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
|
+
"sideEffects": false,
|
|
23
24
|
"files": [
|
|
24
25
|
"dist"
|
|
25
26
|
],
|
|
@@ -49,18 +50,18 @@
|
|
|
49
50
|
}
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
|
-
"tsdown": "0.21.
|
|
53
|
-
"@better-auth/core": "1.
|
|
54
|
-
"better-auth": "1.
|
|
53
|
+
"tsdown": "0.21.1",
|
|
54
|
+
"@better-auth/core": "1.6.0-beta.0",
|
|
55
|
+
"better-auth": "1.6.0-beta.0"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
|
-
"@better-auth/core": "1.
|
|
58
|
-
"better-auth": "1.
|
|
58
|
+
"@better-auth/core": "^1.6.0-beta.0",
|
|
59
|
+
"better-auth": "^1.6.0-beta.0"
|
|
59
60
|
},
|
|
60
61
|
"scripts": {
|
|
61
62
|
"build": "tsdown",
|
|
62
63
|
"dev": "tsdown --watch",
|
|
63
|
-
"lint:package": "publint run --strict",
|
|
64
|
+
"lint:package": "publint run --strict --pack false",
|
|
64
65
|
"lint:types": "attw --profile esm-only --pack .",
|
|
65
66
|
"typecheck": "tsc --project tsconfig.json",
|
|
66
67
|
"test": "vitest",
|
package/dist/client.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import * as better_call0 from "better-call";
|
|
2
|
-
import { BetterAuthPluginRegistry, BetterAuthPluginRegistryIdentifier, GenericEndpointContext, UnionToIntersection } from "@better-auth/core";
|
|
3
|
-
|
|
4
|
-
//#region src/types.d.ts
|
|
5
|
-
type ALL_PLUGIN_ERROR_CODE_KEYS = keyof UnionToIntersection<{ [Key in Exclude<BetterAuthPluginRegistryIdentifier, "i18n">]: BetterAuthPluginRegistry<unknown, unknown>[Key] extends {
|
|
6
|
-
creator: infer C;
|
|
7
|
-
} ? C extends ((...args: any[]) => infer P) ? P extends {
|
|
8
|
-
$ERROR_CODES: infer E;
|
|
9
|
-
} ? E : {} : {} : {} }[Exclude<BetterAuthPluginRegistryIdentifier, "i18n">]>;
|
|
10
|
-
type InternalTranslationDictionary = Partial<{ [Key in ALL_PLUGIN_ERROR_CODE_KEYS]: string }>;
|
|
11
|
-
/**
|
|
12
|
-
* Translation dictionary mapping error codes to translated messages
|
|
13
|
-
*/
|
|
14
|
-
type TranslationDictionary = InternalTranslationDictionary & Record<string, string>;
|
|
15
|
-
/**
|
|
16
|
-
* Locale detection strategy
|
|
17
|
-
*/
|
|
18
|
-
type LocaleDetectionStrategy = "header" | "cookie" | "session" | "callback";
|
|
19
|
-
/**
|
|
20
|
-
* Options for the i18n plugin
|
|
21
|
-
*/
|
|
22
|
-
interface I18nOptions<Locales extends string[]> {
|
|
23
|
-
/**
|
|
24
|
-
* Translation dictionaries keyed by locale code
|
|
25
|
-
* @example
|
|
26
|
-
* {
|
|
27
|
-
* en: { USER_NOT_FOUND: "User not found" },
|
|
28
|
-
* fr: { USER_NOT_FOUND: "Utilisateur non trouvé" }
|
|
29
|
-
* }
|
|
30
|
-
*/
|
|
31
|
-
translations: { [Locale in Locales[number]]: TranslationDictionary };
|
|
32
|
-
/**
|
|
33
|
-
* Default/fallback locale when detection fails
|
|
34
|
-
* @default "en"
|
|
35
|
-
*/
|
|
36
|
-
defaultLocale?: Locales[number] | undefined;
|
|
37
|
-
/**
|
|
38
|
-
* Locale detection strategies in priority order
|
|
39
|
-
* @default ["header"]
|
|
40
|
-
*/
|
|
41
|
-
detection?: LocaleDetectionStrategy[] | undefined;
|
|
42
|
-
/**
|
|
43
|
-
* Cookie name for locale detection (when "cookie" strategy is used)
|
|
44
|
-
* @default "locale"
|
|
45
|
-
*/
|
|
46
|
-
localeCookie?: string | undefined;
|
|
47
|
-
/**
|
|
48
|
-
* User field name for stored locale preference (when "session" strategy is used)
|
|
49
|
-
* @default "locale"
|
|
50
|
-
*/
|
|
51
|
-
userLocaleField?: string | undefined;
|
|
52
|
-
/**
|
|
53
|
-
* Custom locale detection function (when "callback" strategy is used).
|
|
54
|
-
* @example
|
|
55
|
-
* getLocale: (ctx) => {
|
|
56
|
-
* return ctx.headers?.get("X-Custom-Locale") ?? null;
|
|
57
|
-
* }
|
|
58
|
-
*/
|
|
59
|
-
getLocale?: undefined | ((ctx: GenericEndpointContext) => Promise<Locales[number] | null> | Locales[number] | null);
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region src/index.d.ts
|
|
63
|
-
declare module "@better-auth/core" {
|
|
64
|
-
interface BetterAuthPluginRegistry<AuthOptions, Options> {
|
|
65
|
-
i18n: {
|
|
66
|
-
creator: typeof i18n;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* i18n plugin for Better Auth
|
|
72
|
-
*
|
|
73
|
-
* Translates error messages based on detected locale.
|
|
74
|
-
*
|
|
75
|
-
* @example
|
|
76
|
-
* ```ts
|
|
77
|
-
* import { betterAuth } from "better-auth";
|
|
78
|
-
* import { i18n } from "@better-auth/i18n";
|
|
79
|
-
*
|
|
80
|
-
* export const auth = betterAuth({
|
|
81
|
-
* plugins: [
|
|
82
|
-
* i18n({
|
|
83
|
-
* translations: {
|
|
84
|
-
* en: { USER_NOT_FOUND: "User not found" },
|
|
85
|
-
* fr: { USER_NOT_FOUND: "Utilisateur non trouvé" },
|
|
86
|
-
* },
|
|
87
|
-
* detection: ["header", "cookie"],
|
|
88
|
-
* }),
|
|
89
|
-
* ],
|
|
90
|
-
* });
|
|
91
|
-
* ```
|
|
92
|
-
*/
|
|
93
|
-
declare const i18n: <Locales extends string[]>(options: I18nOptions<Locales>) => {
|
|
94
|
-
id: "i18n";
|
|
95
|
-
hooks: {
|
|
96
|
-
after: {
|
|
97
|
-
matcher: () => true;
|
|
98
|
-
handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>;
|
|
99
|
-
}[];
|
|
100
|
-
};
|
|
101
|
-
options: {
|
|
102
|
-
translations: { [Locale in Locales[number]]: TranslationDictionary };
|
|
103
|
-
defaultLocale: Locales[number];
|
|
104
|
-
detection: LocaleDetectionStrategy[];
|
|
105
|
-
localeCookie: string;
|
|
106
|
-
userLocaleField: string;
|
|
107
|
-
getLocale?: ((ctx: GenericEndpointContext) => Locales[number] | Promise<Locales[number] | null> | null) | undefined;
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
|
-
//#endregion
|
|
111
|
-
export { TranslationDictionary as i, I18nOptions as n, LocaleDetectionStrategy as r, i18n as t };
|
|
112
|
-
//# sourceMappingURL=index-CLmzQKXC.d.mts.map
|
package/dist/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import type {\n\tBetterAuthPlugin,\n\tGenericEndpointContext,\n} 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\tctx: GenericEndpointContext,\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 = ctx.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 = ctx.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.context.session?.user) {\n\t\t\t\t\t\tconst userLocale = (\n\t\t\t\t\t\t\tctx.context.session.user as Record<string, unknown>\n\t\t\t\t\t\t)[opts.userLocaleField];\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) {\n\t\t\t\t\t\tconst callbackLocale = await opts.getLocale(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\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(ctx);\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\nexport type * from \"./types\";\n"],"mappings":";;;;;;;AAyBA,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,KAC2B;AAC3B,OAAK,MAAM,YAAY,KAAK,WAAW;GACtC,IAAI,SAAiC;AAErC,WAAQ,UAAR;IACC,KAAK;AAGJ,cADkB,oBADC,IAAI,SAAS,IAAI,kBAAkB,IAAI,KACT,CAC9B,MAAM,MAAM,iBAAiB,SAAS,EAAE,CAAC,IAAI;AAChE;IAGD,KAAK,UAAU;KACd,MAAM,eAAe,IAAI,SAAS,IAAI,SAAS;AAC/C,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,QAAQ,SAAS,MAAM;MAC9B,MAAM,aACL,IAAI,QAAQ,QAAQ,KACnB,KAAK;AACP,UACC,OAAO,eAAe,YACtB,iBAAiB,SAAS,WAAW,CAErC,UAAS;;AAGX;IAGD,KAAK;AACJ,SAAI,KAAK,WAAW;MACnB,MAAM,iBAAiB,MAAM,KAAK,UAAU,IAAI;AAChD,UAAI,kBAAkB,iBAAiB,SAAS,eAAe,CAC9D,UAAS;;AAGX;;AAIF,OAAI,OAAQ,QAAO;;AAGpB,SAAO,KAAK;;AAGb,QAAO;EACN,IAAI;EACJ,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,aAAa,IAAI;IAEtC,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"}
|