@objectstack/plugin-auth 6.2.0 → 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
@@ -665,26 +665,49 @@ var AuthManager = class {
665
665
  *
666
666
  * better-auth defaults to `@better-auth/utils/password.node`, which calls
667
667
  * `node:crypto.scrypt`. WebContainer polyfills that API incompletely and
668
- * signup throws `TypeError: y.run is not a function`. The pure-JS variant
669
- * at `@better-auth/utils/password` uses `@noble/hashes/scrypt` with
670
- * identical params (N=16384, r=16, p=1, dkLen=64) and emits the same
671
- * `{salt}:{keyHex}` format, so existing hashes remain verifiable.
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.
672
678
  *
673
679
  * Returns `undefined` outside WebContainer so production deployments keep
674
- * the native (fast) hasher and never load the JS fallback.
680
+ * the native (fast) hasher and never load `@noble/hashes`.
675
681
  */
676
682
  async resolvePasswordHasher() {
677
683
  const isWebContainer = typeof globalThis !== "undefined" && (Boolean(globalThis.process?.versions?.webcontainer) || Boolean(globalThis.process?.env?.SHELL?.includes?.("jsh")) || Boolean(globalThis.process?.env?.STACKBLITZ));
678
684
  if (!isWebContainer) return void 0;
679
685
  try {
680
- const mod = await import("@better-auth/utils/password");
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);
681
694
  return {
682
- hash: (password) => mod.hashPassword(password),
683
- verify: ({ hash, password }) => mod.verifyPassword(hash, password)
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
+ }
684
707
  };
685
708
  } catch (err) {
686
709
  console.warn(
687
- `[AuthManager] WebContainer detected but pure-JS password hasher unavailable: ${err?.message ?? err}. Falling back to default.`
710
+ `[AuthManager] WebContainer detected but pure-JS scrypt unavailable: ${err?.message ?? err}. Falling back to default.`
688
711
  );
689
712
  return void 0;
690
713
  }