@porulle/core 0.44.0 → 0.45.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@porulle/core",
3
- "version": "0.44.0",
3
+ "version": "0.45.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
package/src/auth/setup.ts CHANGED
@@ -141,6 +141,10 @@ export function createAuth(
141
141
 
142
142
  try {
143
143
  const auth = betterAuth({
144
+ // Upstream options core does not own, FIRST so every core-owned key below
145
+ // wins. `AuthConfig["extend"]` Omits the keys core builds, so a consumer
146
+ // cannot reach one from here — it is a compile error, not a silent drop.
147
+ ...(config.auth?.extend ?? {}),
144
148
  ...(config.auth?.baseURL ? { baseURL: config.auth.baseURL } : {}),
145
149
  // Endpoints whose only currency is a raw session bearer token. Read in
146
150
  // the router's own onRequest, before rate limiting and before any plugin
@@ -158,6 +162,33 @@ export function createAuth(
158
162
  emailAndPassword: {
159
163
  enabled: true,
160
164
  requireEmailVerification: config.auth?.requireEmailVerification ?? true,
165
+ // Forwarded from `config.auth.password`. Every one of these was dropped
166
+ // on the floor until 2026-09-20: Better Auth honours them, core never
167
+ // passed them, so setting them in a consumer config did nothing.
168
+ // `revokeSessionsOnPasswordReset` defaults to TRUE here, against Better
169
+ // Auth's own `false`. A password reset is the canonical "I think I am
170
+ // compromised" action, and leaving the attacker's session live through
171
+ // it is the wrong default for a commerce platform. Opt out explicitly.
172
+ revokeSessionsOnPasswordReset:
173
+ config.auth?.password?.revokeSessionsOnPasswordReset ?? true,
174
+ ...(config.auth?.password?.minLength !== undefined
175
+ ? { minPasswordLength: config.auth.password.minLength }
176
+ : {}),
177
+ ...(config.auth?.password?.maxLength !== undefined
178
+ ? { maxPasswordLength: config.auth.password.maxLength }
179
+ : {}),
180
+ ...(config.auth?.password?.disableSignUp !== undefined
181
+ ? { disableSignUp: config.auth.password.disableSignUp }
182
+ : {}),
183
+ ...(config.auth?.password?.autoSignIn !== undefined
184
+ ? { autoSignIn: config.auth.password.autoSignIn }
185
+ : {}),
186
+ ...(config.auth?.password?.resetTokenExpiresIn !== undefined
187
+ ? { resetPasswordTokenExpiresIn: config.auth.password.resetTokenExpiresIn }
188
+ : {}),
189
+ ...(config.auth?.password?.onPasswordReset !== undefined
190
+ ? { onPasswordReset: config.auth.password.onPasswordReset }
191
+ : {}),
161
192
  sendResetPassword: async ({ user, url }: AuthEmailPayload) => {
162
193
  if (!config.email) return;
163
194
  await config.email.send({
@@ -1,3 +1,4 @@
1
+ import type { betterAuth } from "better-auth";
1
2
  import type { Hono, MiddlewareHandler } from "hono";
2
3
  import type { Actor } from "../auth/types.js";
3
4
  import type { BeforeHook, AfterHook } from "../kernel/hooks/types.js";
@@ -14,6 +15,9 @@ import type {
14
15
  TaskDefinition,
15
16
  } from "../kernel/jobs/types.js";
16
17
 
18
+ /** Better Auth's own options type, read off the function so no named export is required. */
19
+ type BetterAuthOptions = Parameters<typeof betterAuth>[0];
20
+
17
21
  export interface RoleDefinition {
18
22
  permissions: string[];
19
23
  }
@@ -259,6 +263,63 @@ export interface AuthConfig {
259
263
  * a trusted actor for integration tests. Default false.
260
264
  */
261
265
  allowTestActor?: boolean;
266
+ /**
267
+ * Password policy and reset behaviour, forwarded into Better Auth's
268
+ * `emailAndPassword` block.
269
+ *
270
+ * These are surfaced deliberately rather than left to `extend`, because core
271
+ * OWNS `emailAndPassword` (it injects `sendResetPassword` and
272
+ * `sendVerificationEmail` from `config.email`), so a consumer cannot supply
273
+ * that block wholesale without losing the transactional email wiring.
274
+ *
275
+ * Every field here is one Better Auth honours and core previously dropped on
276
+ * the floor: setting them in a consumer config typechecked and did nothing.
277
+ */
278
+ password?: {
279
+ /** Minimum password length. Better Auth's own default is 8. */
280
+ minLength?: number;
281
+ /** Maximum password length. Better Auth's own default is 128. */
282
+ maxLength?: number;
283
+ /** Block new email+password registrations. */
284
+ disableSignUp?: boolean;
285
+ /** Sign the user in immediately after sign-up. */
286
+ autoSignIn?: boolean;
287
+ /**
288
+ * End every other session when a password is reset. Better Auth defaults
289
+ * this to FALSE, which leaves an attacker's session live through the one
290
+ * action a compromised user takes to evict them. Set it to true unless you
291
+ * have a specific reason not to.
292
+ */
293
+ revokeSessionsOnPasswordReset?: boolean;
294
+ /** Seconds a reset token stays valid. Better Auth's own default is 3600. */
295
+ resetTokenExpiresIn?: number;
296
+ /** Audit hook fired after a password is successfully changed. */
297
+ onPasswordReset?: (
298
+ data: { user: { id: string; email: string; name: string } },
299
+ request?: Request,
300
+ ) => Promise<void>;
301
+ };
302
+ /**
303
+ * Upstream Better Auth options core does not own, passed straight through.
304
+ *
305
+ * This is the escape hatch that stops the next upstream option from being
306
+ * silently dropped. The keys core builds itself are `Omit`ted, so setting one
307
+ * here is a COMPILE ERROR naming the key rather than a value that is accepted
308
+ * and ignored — the failure mode this option exists to remove.
309
+ *
310
+ * Spread FIRST in `createAuth`, so a core-owned key can never be clobbered.
311
+ */
312
+ extend?: Omit<
313
+ BetterAuthOptions,
314
+ | "database"
315
+ | "trustedOrigins"
316
+ | "emailAndPassword"
317
+ | "socialProviders"
318
+ | "session"
319
+ | "advanced"
320
+ | "user"
321
+ | "plugins"
322
+ >;
262
323
  }
263
324
 
264
325
  export interface CartConfig {