@objectstack/plugin-auth 6.1.1 → 6.3.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/index.mjs CHANGED
@@ -483,6 +483,7 @@ var AuthManager = class {
483
483
  async createAuthInstance() {
484
484
  const { betterAuth } = await import("better-auth");
485
485
  const plugins = await this.buildPluginList();
486
+ const passwordHasher = await this.resolvePasswordHasher();
486
487
  const betterAuthConfig = {
487
488
  // Base configuration
488
489
  secret: this.config.secret || this.generateSecret(),
@@ -542,6 +543,7 @@ var AuthManager = class {
542
543
  // Email and password configuration
543
544
  emailAndPassword: {
544
545
  enabled: this.config.emailAndPassword?.enabled ?? true,
546
+ ...passwordHasher ? { password: passwordHasher } : {},
545
547
  ...this.config.emailAndPassword?.disableSignUp != null ? { disableSignUp: this.config.emailAndPassword.disableSignUp } : {},
546
548
  ...this.config.emailAndPassword?.requireEmailVerification != null ? { requireEmailVerification: this.config.emailAndPassword.requireEmailVerification } : {},
547
549
  ...this.config.emailAndPassword?.minPasswordLength != null ? { minPasswordLength: this.config.emailAndPassword.minPasswordLength } : {},
@@ -658,6 +660,58 @@ var AuthManager = class {
658
660
  };
659
661
  return betterAuth(betterAuthConfig);
660
662
  }
663
+ /**
664
+ * Detect WebContainer (StackBlitz) and swap in a pure-JS scrypt hasher.
665
+ *
666
+ * better-auth defaults to `@better-auth/utils/password.node`, which calls
667
+ * `node:crypto.scrypt`. WebContainer polyfills that API incompletely and
668
+ * signup throws `TypeError: y.run is not a function`.
669
+ *
670
+ * We can't dynamic-import `@better-auth/utils/password` because that
671
+ * package's `exports` map gates the pure-JS build behind a non-`"node"`
672
+ * condition — Node-the-runtime (which WebContainer reports itself as)
673
+ * always resolves to `password.node.mjs`. So we reimplement the same hash
674
+ * here using `@noble/hashes/scrypt` directly, with byte-identical params
675
+ * (N=16384, r=16, p=1, dkLen=64) and the same `{saltHex}:{keyHex}` storage
676
+ * format. Hashes produced by either implementation verify against the
677
+ * other — no migration needed.
678
+ *
679
+ * Returns `undefined` outside WebContainer so production deployments keep
680
+ * the native (fast) hasher and never load `@noble/hashes`.
681
+ */
682
+ async resolvePasswordHasher() {
683
+ const isWebContainer = typeof globalThis !== "undefined" && (Boolean(globalThis.process?.versions?.webcontainer) || Boolean(globalThis.process?.env?.SHELL?.includes?.("jsh")) || Boolean(globalThis.process?.env?.STACKBLITZ));
684
+ if (!isWebContainer) return void 0;
685
+ try {
686
+ const { scryptAsync } = await import("@noble/hashes/scrypt.js");
687
+ const PARAMS = { N: 16384, r: 16, p: 1, dkLen: 64, maxmem: 128 * 16384 * 16 * 2 };
688
+ const toHex = (b) => {
689
+ let s = "";
690
+ for (let i = 0; i < b.length; i++) s += b[i].toString(16).padStart(2, "0");
691
+ return s;
692
+ };
693
+ const generateKey = (password, saltHex) => scryptAsync(password.normalize("NFKC"), saltHex, PARAMS);
694
+ return {
695
+ hash: async (password) => {
696
+ const saltBytes = globalThis.crypto.getRandomValues(new Uint8Array(16));
697
+ const saltHex = toHex(saltBytes);
698
+ const key = await generateKey(password, saltHex);
699
+ return `${saltHex}:${toHex(key)}`;
700
+ },
701
+ verify: async ({ hash, password }) => {
702
+ const [saltHex, keyHex] = hash.split(":");
703
+ if (!saltHex || !keyHex) throw new Error("Invalid password hash");
704
+ const target = await generateKey(password, saltHex);
705
+ return toHex(target) === keyHex;
706
+ }
707
+ };
708
+ } catch (err) {
709
+ console.warn(
710
+ `[AuthManager] WebContainer detected but pure-JS scrypt unavailable: ${err?.message ?? err}. Falling back to default.`
711
+ );
712
+ return void 0;
713
+ }
714
+ }
661
715
  /**
662
716
  * Build the list of better-auth plugins based on AuthPluginConfig flags.
663
717
  *