@ingram-tech/nk-auth 0.9.1 → 0.10.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/README.md CHANGED
@@ -176,6 +176,8 @@ export const {
176
176
  requireSession,
177
177
  requireUser,
178
178
  redirectIfAuthenticated,
179
+ getLinkedProviders, // providerIds linked to the current user
180
+ hasCredentialAccount, // does the current user have an email/password login?
179
181
  } = createAuthHelpers(auth);
180
182
  ```
181
183
 
@@ -244,6 +246,84 @@ middleware injects — so the self-heal (next + clearing) needs the middleware.
244
246
  Sites that skip middleware still get validated gating from the server helpers,
245
247
  just without automatic `next`/clearing.
246
248
 
249
+ ## 6. Passwords: change, set, and reset
250
+
251
+ nk-auth owns the reset **sender** (`makeEmailSenders.sendResetPassword`, §2) and
252
+ now closes the loop so a site never touches Better Auth's `account` table or
253
+ endpoint names directly. Three pieces:
254
+
255
+ **Detect what login the user has.** A social-only account (Google, …) has no
256
+ password credential until it sets one. `hasCredentialAccount()` drives the
257
+ "Change password" vs "Set password" choice on a security page; reach for
258
+ `getLinkedProviders()` when you need the full list.
259
+
260
+ ```tsx
261
+ // app/settings/security/page.tsx (server component)
262
+ import { hasCredentialAccount } from "@/lib/auth/session";
263
+ export default async function Security() {
264
+ return (await hasCredentialAccount()) ? <ChangePassword /> : <SetPassword />;
265
+ }
266
+ ```
267
+
268
+ **Set a password without a current one.** A social-only user has no current
269
+ password to verify, so the re-auth is an emailed reset link — clicking it proves
270
+ account ownership. Trigger it with the standard client call; there is no separate
271
+ "set password" endpoint:
272
+
273
+ ```ts
274
+ await authClient.requestPasswordReset({
275
+ email,
276
+ redirectTo: "/reset-password", // your token-consumer page (below)
277
+ });
278
+ ```
279
+
280
+ Better Auth's reset endpoint **creates** the credential when the user has none,
281
+ so the same flow both resets a forgotten password and sets a first one. That
282
+ guarantee is pinned by `reset-password.test.ts` against a real instance, so a
283
+ Better Auth upgrade can't silently break the set-password path.
284
+
285
+ **Consume the token.** The email link lands on your page with `?token=` (or
286
+ `?error=INVALID_TOKEN`). `useResetPassword` is the headless state machine —
287
+ invalid-token, submitting, success, and policy validation (length + match) —
288
+ against the shared `passwordSchema` bounds. You bring the shell:
289
+
290
+ ```tsx
291
+ "use client";
292
+ import { useResetPassword } from "@ingram-tech/nk-auth/client";
293
+ import { authClient } from "@/lib/auth/client";
294
+
295
+ export function ResetPasswordForm({ token }: { token: string | null }) {
296
+ const { status, error, submit } = useResetPassword(authClient, { token });
297
+ if (status === "invalid") return <p>This link is invalid or has expired.</p>;
298
+ if (status === "success") return <p>Password set. You can now sign in.</p>;
299
+ // <form onSubmit={() => submit(newPassword, confirm)}>; render `error.code`
300
+ // (stable, for i18n) or `error.message` (English fallback).
301
+ }
302
+ ```
303
+
304
+ Policy constants live at `@ingram-tech/nk-auth/password` (pure, importable from
305
+ both ends): `DEFAULT_MIN_PASSWORD_LENGTH` / `DEFAULT_MAX_PASSWORD_LENGTH`,
306
+ `passwordSchema()`, and `validateNewPassword()`. Pass your resolved bounds to
307
+ `useResetPassword({ token, minLength, maxLength })` if you override Better Auth's
308
+ defaults, so the form and the server never drift.
309
+
310
+ **`.well-known/change-password`.** Add the [W3C well-known
311
+ redirect](https://w3c.github.io/webappsec-change-password-url/) so password
312
+ managers deep-link straight to your security page. It's a per-app route target,
313
+ so nk-auth documents the convention rather than shipping it — in `next.config`:
314
+
315
+ ```ts
316
+ async redirects() {
317
+ return [
318
+ {
319
+ source: "/.well-known/change-password",
320
+ destination: "/settings/security", // your Change/Set password page
321
+ permanent: false,
322
+ },
323
+ ];
324
+ }
325
+ ```
326
+
247
327
  ## Migrating bcrypt passwords to scrypt
248
328
 
249
329
  `bcryptPassword` is **legacy support only** (see its `@deprecated` note). It
package/dist/client.d.ts CHANGED
@@ -20,5 +20,7 @@
20
20
  export { passkeyClient } from "@better-auth/passkey/client";
21
21
  export { jwtClient } from "better-auth/client/plugins";
22
22
  export { createAuthClient } from "better-auth/react";
23
+ export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, type PasswordPolicy, passwordSchema, type ResetPasswordError, type ResetPasswordErrorCode, validateNewPassword, } from "./password.js";
23
24
  export { authBasePath } from "./paths.js";
25
+ export { type ResetPasswordClient, type ResetPasswordStatus, type UseResetPassword, type UseResetPasswordOptions, useResetPassword, } from "./reset-password.js";
24
26
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,mBAAmB,GACnB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,OAAO,EACN,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,gBAAgB,GAChB,MAAM,qBAAqB,CAAC"}
package/dist/client.js CHANGED
@@ -20,6 +20,11 @@
20
20
  export { passkeyClient } from "@better-auth/passkey/client";
21
21
  export { jwtClient } from "better-auth/client/plugins";
22
22
  export { createAuthClient } from "better-auth/react";
23
+ // Password-policy primitives (pure), so a reset form validates against the same
24
+ // bounds the server enforces without a second import.
25
+ export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, passwordSchema, validateNewPassword, } from "./password.js";
23
26
  // Re-exported here too so the client can set `basePath` without a server import.
24
27
  export { authBasePath } from "./paths.js";
28
+ // Headless reset-/set-password controller (React hook); the site brings the shell.
29
+ export { useResetPassword, } from "./reset-password.js";
25
30
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,iFAAiF;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrD,gFAAgF;AAChF,sDAAsD;AACtD,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAE3B,cAAc,EAGd,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,iFAAiF;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,mFAAmF;AACnF,OAAO,EAKN,gBAAgB,GAChB,MAAM,qBAAqB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export { base58Id, fromPrefixedId, toPrefixedId, uuidGenerateId } from "./id.js"
3
3
  export { type AuthEnv, authEnv, isConfigured } from "./keys.js";
4
4
  export { bcryptPassword, makeEmailSenders, makePasskeyOptions, type PasskeyConfig, passkeyOptionsForBaseUrl, type SendEmail, } from "./options.js";
5
5
  export { lastActiveOrganizationHooks, lastActiveOrganizationUserField, nkOrganizationDefaults, } from "./organization.js";
6
+ export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, type PasswordPolicy, passwordSchema, type ResetPasswordError, type ResetPasswordErrorCode, validateNewPassword, } from "./password.js";
6
7
  export { authBasePath } from "./paths.js";
7
8
  export { createAuthPool } from "./pool.js";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,wBAAwB,EACxB,KAAK,SAAS,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,gBAAgB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,KAAK,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,wBAAwB,EACxB,KAAK,SAAS,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAC3B,KAAK,cAAc,EACnB,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,7 @@ export { base58Id, fromPrefixedId, toPrefixedId, uuidGenerateId } from "./id.js"
7
7
  export { authEnv, isConfigured } from "./keys.js";
8
8
  export { bcryptPassword, makeEmailSenders, makePasskeyOptions, passkeyOptionsForBaseUrl, } from "./options.js";
9
9
  export { lastActiveOrganizationHooks, lastActiveOrganizationUserField, nkOrganizationDefaults, } from "./organization.js";
10
+ export { CREDENTIAL_PROVIDER_ID, DEFAULT_MAX_PASSWORD_LENGTH, DEFAULT_MIN_PASSWORD_LENGTH, passwordSchema, validateNewPassword, } from "./password.js";
10
11
  export { authBasePath } from "./paths.js";
11
12
  export { createAuthPool } from "./pool.js";
12
13
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAyB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAgB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAElB,wBAAwB,GAExB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,4EAA4E;AAC5E,wEAAwE;AAExE,OAAO,EAAyB,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACjF,OAAO,EAAgB,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAChE,OAAO,EACN,cAAc,EACd,gBAAgB,EAChB,kBAAkB,EAElB,wBAAwB,GAExB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACN,sBAAsB,EACtB,2BAA2B,EAC3B,2BAA2B,EAE3B,cAAc,EAGd,mBAAmB,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Password-policy primitives, shared by both ends of a site so the client form
3
+ * and the server validate against the *same* numbers. Pure (no `next`, `react`,
4
+ * or server imports) so it resolves identically from "@ingram-tech/nk-auth" and
5
+ * "@ingram-tech/nk-auth/client". Import from the "./password" subpath.
6
+ *
7
+ * The values mirror Better Auth's `emailAndPassword` defaults; if a site
8
+ * overrides `minPasswordLength` / `maxPasswordLength` in its `betterAuth()`
9
+ * config, pass the same numbers to `passwordSchema()` so the two stay in step.
10
+ */
11
+ import { z } from "zod";
12
+ /**
13
+ * The Better Auth `account.providerId` value for an email/password credential
14
+ * (as opposed to a social provider like "google"). This is Better Auth's own
15
+ * table shape, not ours — centralised here so no consuming site hard-codes the
16
+ * string. See {@link import("./server.js").createAuthHelpers}'s
17
+ * `hasCredentialAccount`.
18
+ */
19
+ export declare const CREDENTIAL_PROVIDER_ID = "credential";
20
+ /** Better Auth's default `emailAndPassword.minPasswordLength`. */
21
+ export declare const DEFAULT_MIN_PASSWORD_LENGTH = 8;
22
+ /** Better Auth's default `emailAndPassword.maxPasswordLength`. */
23
+ export declare const DEFAULT_MAX_PASSWORD_LENGTH = 128;
24
+ export interface PasswordPolicy {
25
+ /** Minimum length. Default {@link DEFAULT_MIN_PASSWORD_LENGTH}. */
26
+ minLength?: number;
27
+ /** Maximum length. Default {@link DEFAULT_MAX_PASSWORD_LENGTH}. */
28
+ maxLength?: number;
29
+ }
30
+ /**
31
+ * A Zod schema for a new password, honouring the resolved policy. Use it on both
32
+ * the client (form validation) and the server (before calling Better Auth) so
33
+ * neither side drifts from the other or from the instance's configured bounds.
34
+ */
35
+ export declare function passwordSchema(policy?: PasswordPolicy): z.ZodString;
36
+ /**
37
+ * The failure reasons of a "choose a new password + confirm it" form, as a
38
+ * stable `code` (switch on it for i18n) plus an English `message` fallback.
39
+ * `reset_failed` is the server rejecting the reset token (invalid / expired).
40
+ */
41
+ export type ResetPasswordErrorCode = "password_too_short" | "password_too_long" | "passwords_do_not_match" | "reset_failed";
42
+ export interface ResetPasswordError {
43
+ code: ResetPasswordErrorCode;
44
+ message: string;
45
+ /** Present on `password_too_short`. */
46
+ minLength?: number;
47
+ /** Present on `password_too_long`. */
48
+ maxLength?: number;
49
+ }
50
+ /**
51
+ * Validate a new-password pair (the field and its confirmation) against the
52
+ * policy. Returns the first {@link ResetPasswordError}, or null when valid. Pure
53
+ * so it is unit-testable and reusable outside React; {@link
54
+ * import("./client.js").useResetPassword} calls it before hitting the server.
55
+ */
56
+ export declare function validateNewPassword(newPassword: string, confirmPassword: string, policy?: PasswordPolicy): ResetPasswordError | null;
57
+ //# sourceMappingURL=password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.d.ts","sourceRoot":"","sources":["../src/password.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,eAAe,CAAC;AAEnD,kEAAkE;AAClE,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAE7C,kEAAkE;AAClE,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,cAAmB,GAAG,CAAC,CAAC,SAAS,CAOvE;AAED;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAC/B,oBAAoB,GACpB,mBAAmB,GACnB,wBAAwB,GACxB,cAAc,CAAC;AAElB,MAAM,WAAW,kBAAkB;IAClC,IAAI,EAAE,sBAAsB,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAClC,WAAW,EAAE,MAAM,EACnB,eAAe,EAAE,MAAM,EACvB,MAAM,GAAE,cAAmB,GACzB,kBAAkB,GAAG,IAAI,CAwB3B"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Password-policy primitives, shared by both ends of a site so the client form
3
+ * and the server validate against the *same* numbers. Pure (no `next`, `react`,
4
+ * or server imports) so it resolves identically from "@ingram-tech/nk-auth" and
5
+ * "@ingram-tech/nk-auth/client". Import from the "./password" subpath.
6
+ *
7
+ * The values mirror Better Auth's `emailAndPassword` defaults; if a site
8
+ * overrides `minPasswordLength` / `maxPasswordLength` in its `betterAuth()`
9
+ * config, pass the same numbers to `passwordSchema()` so the two stay in step.
10
+ */
11
+ import { z } from "zod";
12
+ /**
13
+ * The Better Auth `account.providerId` value for an email/password credential
14
+ * (as opposed to a social provider like "google"). This is Better Auth's own
15
+ * table shape, not ours — centralised here so no consuming site hard-codes the
16
+ * string. See {@link import("./server.js").createAuthHelpers}'s
17
+ * `hasCredentialAccount`.
18
+ */
19
+ export const CREDENTIAL_PROVIDER_ID = "credential";
20
+ /** Better Auth's default `emailAndPassword.minPasswordLength`. */
21
+ export const DEFAULT_MIN_PASSWORD_LENGTH = 8;
22
+ /** Better Auth's default `emailAndPassword.maxPasswordLength`. */
23
+ export const DEFAULT_MAX_PASSWORD_LENGTH = 128;
24
+ /**
25
+ * A Zod schema for a new password, honouring the resolved policy. Use it on both
26
+ * the client (form validation) and the server (before calling Better Auth) so
27
+ * neither side drifts from the other or from the instance's configured bounds.
28
+ */
29
+ export function passwordSchema(policy = {}) {
30
+ const min = policy.minLength ?? DEFAULT_MIN_PASSWORD_LENGTH;
31
+ const max = policy.maxLength ?? DEFAULT_MAX_PASSWORD_LENGTH;
32
+ return z
33
+ .string()
34
+ .min(min, `Password must be at least ${min} characters.`)
35
+ .max(max, `Password must be at most ${max} characters.`);
36
+ }
37
+ /**
38
+ * Validate a new-password pair (the field and its confirmation) against the
39
+ * policy. Returns the first {@link ResetPasswordError}, or null when valid. Pure
40
+ * so it is unit-testable and reusable outside React; {@link
41
+ * import("./client.js").useResetPassword} calls it before hitting the server.
42
+ */
43
+ export function validateNewPassword(newPassword, confirmPassword, policy = {}) {
44
+ const min = policy.minLength ?? DEFAULT_MIN_PASSWORD_LENGTH;
45
+ const max = policy.maxLength ?? DEFAULT_MAX_PASSWORD_LENGTH;
46
+ if (newPassword.length < min) {
47
+ return {
48
+ code: "password_too_short",
49
+ message: `Password must be at least ${min} characters.`,
50
+ minLength: min,
51
+ };
52
+ }
53
+ if (newPassword.length > max) {
54
+ return {
55
+ code: "password_too_long",
56
+ message: `Password must be at most ${max} characters.`,
57
+ maxLength: max,
58
+ };
59
+ }
60
+ if (newPassword !== confirmPassword) {
61
+ return {
62
+ code: "passwords_do_not_match",
63
+ message: "Passwords do not match.",
64
+ };
65
+ }
66
+ return null;
67
+ }
68
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../src/password.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAEnD,kEAAkE;AAClE,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,CAAC;AAE7C,kEAAkE;AAClE,MAAM,CAAC,MAAM,2BAA2B,GAAG,GAAG,CAAC;AAS/C;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,SAAyB,EAAE;IACzD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,2BAA2B,CAAC;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,2BAA2B,CAAC;IAC5D,OAAO,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,GAAG,EAAE,6BAA6B,GAAG,cAAc,CAAC;SACxD,GAAG,CAAC,GAAG,EAAE,4BAA4B,GAAG,cAAc,CAAC,CAAC;AAC3D,CAAC;AAsBD;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAClC,WAAmB,EACnB,eAAuB,EACvB,SAAyB,EAAE;IAE3B,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,2BAA2B,CAAC;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,IAAI,2BAA2B,CAAC;IAC5D,IAAI,WAAW,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC9B,OAAO;YACN,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,6BAA6B,GAAG,cAAc;YACvD,SAAS,EAAE,GAAG;SACd,CAAC;IACH,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QAC9B,OAAO;YACN,IAAI,EAAE,mBAAmB;YACzB,OAAO,EAAE,4BAA4B,GAAG,cAAc;YACtD,SAAS,EAAE,GAAG;SACd,CAAC;IACH,CAAC;IACD,IAAI,WAAW,KAAK,eAAe,EAAE,CAAC;QACrC,OAAO;YACN,IAAI,EAAE,wBAAwB;YAC9B,OAAO,EAAE,yBAAyB;SAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { type PasswordPolicy, type ResetPasswordError } from "./password.js";
2
+ export type ResetPasswordStatus =
3
+ /** No usable token in the URL — show an "invalid or expired link" message. */
4
+ "invalid"
5
+ /** Token present; awaiting the user's new password. */
6
+ | "idle"
7
+ /** The reset request is in flight. */
8
+ | "submitting"
9
+ /** The password was set; the user can now sign in with it. */
10
+ | "success"
11
+ /** Validation failed, or the server rejected the reset — see `error`. */
12
+ | "error";
13
+ /** The slice of a Better Auth client this hook calls. */
14
+ export interface ResetPasswordClient {
15
+ resetPassword: (input: {
16
+ newPassword: string;
17
+ token: string;
18
+ }) => Promise<{
19
+ error?: {
20
+ message?: string;
21
+ } | null;
22
+ }>;
23
+ }
24
+ export interface UseResetPasswordOptions extends PasswordPolicy {
25
+ /**
26
+ * The reset token from the URL (`?token=`), or null when it is missing — e.g.
27
+ * the link carried `?error=INVALID_TOKEN` instead. Null puts the controller in
28
+ * the `invalid` state before any submit.
29
+ */
30
+ token: string | null;
31
+ }
32
+ export interface UseResetPassword {
33
+ status: ResetPasswordStatus;
34
+ /** The current failure, or null. `code` is stable for i18n; `message` is an English fallback. */
35
+ error: ResetPasswordError | null;
36
+ /** Validate the pair against the policy, then call the reset endpoint. */
37
+ submit: (newPassword: string, confirmPassword: string) => Promise<void>;
38
+ }
39
+ /**
40
+ * Drive a reset-password form. Returns the current `status`, the last `error`
41
+ * (with an i18n-friendly `code`), and a `submit(newPassword, confirmPassword)`
42
+ * that runs {@link validateNewPassword} against the policy before hitting the
43
+ * server. Pass the resolved `minLength` / `maxLength` when the site overrides
44
+ * Better Auth's defaults so client and server agree.
45
+ */
46
+ export declare function useResetPassword(client: ResetPasswordClient, options: UseResetPasswordOptions): UseResetPassword;
47
+ //# sourceMappingURL=reset-password.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-password.d.ts","sourceRoot":"","sources":["../src/reset-password.ts"],"names":[],"mappings":"AAoBA,OAAO,EACN,KAAK,cAAc,EACnB,KAAK,kBAAkB,EAEvB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,mBAAmB;AAC9B,8EAA8E;AAC5E,SAAS;AACX,uDAAuD;GACrD,MAAM;AACR,sCAAsC;GACpC,YAAY;AACd,8DAA8D;GAC5D,SAAS;AACX,yEAAyE;GACvE,OAAO,CAAC;AAEX,yDAAyD;AACzD,MAAM,WAAW,mBAAmB;IACnC,aAAa,EAAE,CAAC,KAAK,EAAE;QACtB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;KACd,KAAK,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE;YAAE,OAAO,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,uBAAwB,SAAQ,cAAc;IAC9D;;;;OAIG;IACH,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,iGAAiG;IACjG,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACjC,0EAA0E;IAC1E,MAAM,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxE;AAID;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,uBAAuB,GAC9B,gBAAgB,CAoDlB"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Headless controller for a "set / reset your password" page — the token
3
+ * consumer at the end of Better Auth's forget-password round trip. nk-auth owns
4
+ * the *sender* (`makeEmailSenders.sendResetPassword`) and the endpoint contract;
5
+ * this closes the loop so a site never touches the `resetPassword` endpoint name
6
+ * or hand-rolls the invalid-token / success / validation state machine. The site
7
+ * brings its own shell (inputs, buttons, i18n) and wires it to what this returns.
8
+ *
9
+ * The same page serves both entry points, because both land on the identical URL
10
+ * with a `?token=`: the classic "I forgot my password" flow, and "set a password
11
+ * for my social-only account" (Better Auth's reset endpoint creates the
12
+ * credential when the user has none — see the package README).
13
+ *
14
+ * "use client";
15
+ * const { status, error, submit } = useResetPassword(authClient, { token });
16
+ * if (status === "invalid") return <InvalidLink />;
17
+ * if (status === "success") return <Done />;
18
+ * // <form onSubmit={() => submit(pw, confirm)}> … {error && t(error.code)} …
19
+ */
20
+ import { useCallback, useState } from "react";
21
+ import { validateNewPassword, } from "./password.js";
22
+ const RESET_FAILED_FALLBACK = "Could not reset your password.";
23
+ /**
24
+ * Drive a reset-password form. Returns the current `status`, the last `error`
25
+ * (with an i18n-friendly `code`), and a `submit(newPassword, confirmPassword)`
26
+ * that runs {@link validateNewPassword} against the policy before hitting the
27
+ * server. Pass the resolved `minLength` / `maxLength` when the site overrides
28
+ * Better Auth's defaults so client and server agree.
29
+ */
30
+ export function useResetPassword(client, options) {
31
+ const { token, minLength, maxLength } = options;
32
+ const [status, setStatus] = useState(token ? "idle" : "invalid");
33
+ const [error, setError] = useState(null);
34
+ const submit = useCallback(async (newPassword, confirmPassword) => {
35
+ if (!token) {
36
+ setStatus("invalid");
37
+ return;
38
+ }
39
+ const validation = validateNewPassword(newPassword, confirmPassword, {
40
+ minLength,
41
+ maxLength,
42
+ });
43
+ if (validation) {
44
+ setError(validation);
45
+ setStatus("error");
46
+ return;
47
+ }
48
+ setError(null);
49
+ setStatus("submitting");
50
+ try {
51
+ const { error: resetError } = await client.resetPassword({
52
+ newPassword,
53
+ token,
54
+ });
55
+ if (resetError) {
56
+ setError({
57
+ code: "reset_failed",
58
+ message: resetError.message ?? RESET_FAILED_FALLBACK,
59
+ });
60
+ setStatus("error");
61
+ return;
62
+ }
63
+ setStatus("success");
64
+ }
65
+ catch (err) {
66
+ setError({
67
+ code: "reset_failed",
68
+ message: err instanceof Error ? err.message : RESET_FAILED_FALLBACK,
69
+ });
70
+ setStatus("error");
71
+ }
72
+ }, [token, minLength, maxLength, client]);
73
+ return { status, error, submit };
74
+ }
75
+ //# sourceMappingURL=reset-password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reset-password.js","sourceRoot":"","sources":["../src/reset-password.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,EAGN,mBAAmB,GACnB,MAAM,eAAe,CAAC;AAuCvB,MAAM,qBAAqB,GAAG,gCAAgC,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC/B,MAA2B,EAC3B,OAAgC;IAEhC,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAChD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CACnC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAC1B,CAAC;IACF,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAA4B,IAAI,CAAC,CAAC;IAEpE,MAAM,MAAM,GAAG,WAAW,CACzB,KAAK,EAAE,WAAmB,EAAE,eAAuB,EAAiB,EAAE;QACrE,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,SAAS,CAAC,SAAS,CAAC,CAAC;YACrB,OAAO;QACR,CAAC;QAED,MAAM,UAAU,GAAG,mBAAmB,CAAC,WAAW,EAAE,eAAe,EAAE;YACpE,SAAS;YACT,SAAS;SACT,CAAC,CAAC;QACH,IAAI,UAAU,EAAE,CAAC;YAChB,QAAQ,CAAC,UAAU,CAAC,CAAC;YACrB,SAAS,CAAC,OAAO,CAAC,CAAC;YACnB,OAAO;QACR,CAAC;QAED,QAAQ,CAAC,IAAI,CAAC,CAAC;QACf,SAAS,CAAC,YAAY,CAAC,CAAC;QACxB,IAAI,CAAC;YACJ,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC;gBACxD,WAAW;gBACX,KAAK;aACL,CAAC,CAAC;YACH,IAAI,UAAU,EAAE,CAAC;gBAChB,QAAQ,CAAC;oBACR,IAAI,EAAE,cAAc;oBACpB,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,qBAAqB;iBACpD,CAAC,CAAC;gBACH,SAAS,CAAC,OAAO,CAAC,CAAC;gBACnB,OAAO;YACR,CAAC;YACD,SAAS,CAAC,SAAS,CAAC,CAAC;QACtB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,QAAQ,CAAC;gBACR,IAAI,EAAE,cAAc;gBACpB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,qBAAqB;aACnE,CAAC,CAAC;YACH,SAAS,CAAC,OAAO,CAAC,CAAC;QACpB,CAAC;IACF,CAAC,EACD,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CACrC,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAClC,CAAC"}
package/dist/server.d.ts CHANGED
@@ -18,6 +18,17 @@ interface AuthLike<S extends SessionLike> {
18
18
  getSession: (input: {
19
19
  headers: Headers;
20
20
  }) => Promise<S | null>;
21
+ /**
22
+ * Better Auth's `/list-accounts`: the auth methods linked to the current
23
+ * session's user, each `{ providerId }` ("credential" for email/password,
24
+ * or a social provider like "google"). Present on every real `betterAuth()`
25
+ * instance; powers `getLinkedProviders` / `hasCredentialAccount` below.
26
+ */
27
+ listUserAccounts: (input: {
28
+ headers: Headers;
29
+ }) => Promise<Array<{
30
+ providerId: string;
31
+ }>>;
21
32
  };
22
33
  }
23
34
  export interface AuthHelpersOptions {
@@ -36,5 +47,7 @@ export declare function createAuthHelpers<S extends SessionLike>(auth: AuthLike<
36
47
  requireSession: () => Promise<S>;
37
48
  requireUser: () => Promise<S["user"]>;
38
49
  redirectIfAuthenticated: (to: string) => Promise<void>;
50
+ getLinkedProviders: () => Promise<string[]>;
51
+ hasCredentialAccount: () => Promise<boolean>;
39
52
  };
40
53
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA4BA;;;;GAIG;AACH,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAElE,oEAAoE;AACpE,UAAU,WAAW;IACpB,IAAI,EAAE,OAAO,CAAC;CACd;AAED;;;;GAIG;AACH,UAAU,QAAQ,CAAC,CAAC,SAAS,WAAW;IACvC,GAAG,EAAE;QACJ,UAAU,EAAE,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;KAC/D,CAAC;CACF;AAED,MAAM,WAAW,kBAAkB;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EACtD,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EACjB,OAAO,GAAE,kBAAuB;sBAMH,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;mBAKpB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;0BAkClB,OAAO,CAAC,CAAC,CAAC;uBAXb,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;kCAuBL,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;EAWjE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA6BA;;;;GAIG;AACH,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAElE,oEAAoE;AACpE,UAAU,WAAW;IACpB,IAAI,EAAE,OAAO,CAAC;CACd;AAED;;;;GAIG;AACH,UAAU,QAAQ,CAAC,CAAC,SAAS,WAAW;IACvC,GAAG,EAAE;QACJ,UAAU,EAAE,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,KAAK,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/D;;;;;WAKG;QACH,gBAAgB,EAAE,CAAC,KAAK,EAAE;YACzB,OAAO,EAAE,OAAO,CAAC;SACjB,KAAK,OAAO,CAAC,KAAK,CAAC;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC,CAAC;KAC7C,CAAC;CACF;AAED,MAAM,WAAW,kBAAkB;IAClC,iEAAiE;IACjE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,EACtD,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EACjB,OAAO,GAAE,kBAAuB;sBAMH,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC;mBAKpB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;0BAkClB,OAAO,CAAC,CAAC,CAAC;uBAXb,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;kCAuBL,MAAM,KAAG,OAAO,CAAC,IAAI,CAAC;8BAU5B,OAAO,CAAC,MAAM,EAAE,CAAC;gCAcf,OAAO,CAAC,OAAO,CAAC;EAcvD"}
package/dist/server.js CHANGED
@@ -25,6 +25,7 @@
25
25
  import { cookies, headers } from "next/headers";
26
26
  import { redirect } from "next/navigation";
27
27
  import { NK_AUTH_PATH_HEADER, signInUrl } from "./gating-internals.js";
28
+ import { CREDENTIAL_PROVIDER_ID } from "./password.js";
28
29
  /**
29
30
  * Validate a `next` redirect param: returns it only if it's an internal,
30
31
  * non-protocol-relative path, else null. Use on the login page before honoring
@@ -87,12 +88,37 @@ export function createAuthHelpers(auth, options = {}) {
87
88
  if (await getSession())
88
89
  redirect(to);
89
90
  }
91
+ /**
92
+ * The `providerId`s linked to the current session's user — "credential" for
93
+ * email/password, plus any social providers ("google", …). Empty when signed
94
+ * out. Reads Better Auth's own `/list-accounts`, so a site never queries the
95
+ * `account` table or hard-codes provider strings itself.
96
+ */
97
+ async function getLinkedProviders() {
98
+ const accounts = await auth.api.listUserAccounts({
99
+ headers: await headers(),
100
+ });
101
+ return accounts.map((account) => account.providerId);
102
+ }
103
+ /**
104
+ * Whether the current user has an email/password credential. Drives the
105
+ * "Change password" vs "Set password" decision on a security page: a user who
106
+ * signed up purely through a social provider has none until they set one
107
+ * (typically via the reset-password / forgot-password flow — see the
108
+ * `useResetPassword` client hook). Returns false when signed out.
109
+ */
110
+ async function hasCredentialAccount() {
111
+ const providers = await getLinkedProviders();
112
+ return providers.includes(CREDENTIAL_PROVIDER_ID);
113
+ }
90
114
  return {
91
115
  getSession,
92
116
  getUser,
93
117
  requireSession,
94
118
  requireUser,
95
119
  redirectIfAuthenticated,
120
+ getLinkedProviders,
121
+ hasCredentialAccount,
96
122
  };
97
123
  }
98
124
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvE;;;;GAIG;AACH,OAAO,EAAE,aAAa,IAAI,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AA6BlE,MAAM,UAAU,iBAAiB,CAChC,IAAiB,EACjB,UAA8B,EAAE;IAEhC,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC;IAClD,MAAM,YAAY,GAAG,OAAO,CAAC,mBAAmB,IAAI,aAAa,CAAC;IAElE,4DAA4D;IAC5D,KAAK,UAAU,UAAU;QACxB,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,uCAAuC;IACvC,KAAK,UAAU,OAAO;QACrB,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;QACnC,OAAO,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACH,KAAK,UAAU,YAAY;QAC1B,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QACtE,OAAO,SAAS,CAAC,UAAU,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED;;;;OAIG;IACH,KAAK,UAAU,WAAW;QACzB,MAAM,IAAI,GAAG,MAAM,OAAO,EAAE,CAAC;QAC7B,oEAAoE;QACpE,IAAI,CAAC,IAAI;YAAE,QAAQ,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACb,CAAC;IAED;;;OAGG;IACH,KAAK,UAAU,cAAc;QAC5B,MAAM,OAAO,GAAG,MAAM,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC,OAAO;YAAE,QAAQ,CAAC,MAAM,YAAY,EAAE,CAAC,CAAC;QAC7C,OAAO,OAAO,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACH,KAAK,UAAU,uBAAuB,CAAC,EAAU;QAChD,IAAI,MAAM,UAAU,EAAE;YAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,OAAO;QACN,UAAU;QACV,OAAO;QACP,cAAc;QACd,WAAW;QACX,uBAAuB;KACvB,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingram-tech/nk-auth",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
4
4
  "description": "The Ingram Better Auth foundation: composable presets (org, dual-shape JWT, active-org hooks, pg pool) for Next.js sites.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -41,6 +41,10 @@
41
41
  "types": "./dist/paths.d.ts",
42
42
  "import": "./dist/paths.js"
43
43
  },
44
+ "./password": {
45
+ "types": "./dist/password.d.ts",
46
+ "import": "./dist/password.js"
47
+ },
44
48
  "./server": {
45
49
  "types": "./dist/server.d.ts",
46
50
  "import": "./dist/server.js"