@contentgrowth/content-auth 0.0.2 → 0.0.4

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.
@@ -1057,21 +1057,18 @@ interface AuthConfig {
1057
1057
  * Use 'postgres' or 'mysql' if passing a Drizzle instance for those DBs.
1058
1058
  */
1059
1059
  provider?: "sqlite" | "postgres" | "mysql";
1060
+ /**
1061
+ * Use Cloudflare native crypto.subtle for password hashing to avoid CPU limits.
1062
+ * Defaults to true. Set to false to use Better Auth's default (Scrypt/Argon2).
1063
+ */
1064
+ useCloudflareNativeHashing?: boolean;
1060
1065
  [key: string]: any;
1061
1066
  }
1062
- declare const createAuth: (config: AuthConfig) => better_auth.Auth<{
1063
- database: (options: better_auth.BetterAuthOptions) => better_auth.DBAdapter<better_auth.BetterAuthOptions>;
1064
- secret: string;
1065
- baseURL: string | undefined;
1066
- }>;
1067
+ declare const createAuth: (config: AuthConfig) => better_auth.Auth<any>;
1067
1068
  declare const authMiddleware: (auth: any) => (c: Context) => Promise<any>;
1068
1069
  declare const createAuthApp: (config: AuthConfig) => {
1069
1070
  app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
1070
- auth: better_auth.Auth<{
1071
- database: (options: better_auth.BetterAuthOptions) => better_auth.DBAdapter<better_auth.BetterAuthOptions>;
1072
- secret: string;
1073
- baseURL: string | undefined;
1074
- }>;
1071
+ auth: better_auth.Auth<any>;
1075
1072
  };
1076
1073
 
1077
1074
  export { type AuthConfig, authMiddleware, createAuth, createAuthApp, schema };
@@ -4,7 +4,7 @@ import {
4
4
  createAuth,
5
5
  createAuthApp,
6
6
  schema_exports
7
- } from "../chunk-526JE62U.js";
7
+ } from "../chunk-OOXZHG4Y.js";
8
8
  import "../chunk-R5U7XKVJ.js";
9
9
  export {
10
10
  Hono,
@@ -89,6 +89,67 @@ var invitations = sqliteTable("invitations", {
89
89
  inviterId: text("inviterId").notNull().references(() => users.id, { onDelete: "cascade" })
90
90
  });
91
91
 
92
+ // src/backend/native-hashing.ts
93
+ async function hashPassword(password) {
94
+ const salt = crypto.getRandomValues(new Uint8Array(16));
95
+ const enc = new TextEncoder();
96
+ const keyMaterial = await crypto.subtle.importKey(
97
+ "raw",
98
+ enc.encode(password),
99
+ { name: "PBKDF2" },
100
+ false,
101
+ ["deriveBits", "deriveKey"]
102
+ );
103
+ const hashBuffer = await crypto.subtle.deriveBits(
104
+ {
105
+ name: "PBKDF2",
106
+ salt,
107
+ iterations: 1e5,
108
+ hash: "SHA-256"
109
+ },
110
+ keyMaterial,
111
+ 256
112
+ // 32 bytes
113
+ );
114
+ const saltB64 = btoa(String.fromCharCode(...new Uint8Array(salt)));
115
+ const hashB64 = btoa(String.fromCharCode(...new Uint8Array(hashBuffer)));
116
+ return `pbkdf2:100000:${saltB64}:${hashB64}`;
117
+ }
118
+ async function verifyPassword(password, storedHash) {
119
+ const parts = storedHash.split(":");
120
+ if (parts.length !== 4) return false;
121
+ const [alg, iterationsStr, saltB64, hashB64] = parts;
122
+ if (alg !== "pbkdf2") return false;
123
+ const iterations = parseInt(iterationsStr, 10);
124
+ const salt = Uint8Array.from(atob(saltB64), (c) => c.charCodeAt(0));
125
+ const originalHash = Uint8Array.from(atob(hashB64), (c) => c.charCodeAt(0));
126
+ const enc = new TextEncoder();
127
+ const keyMaterial = await crypto.subtle.importKey(
128
+ "raw",
129
+ enc.encode(password),
130
+ { name: "PBKDF2" },
131
+ false,
132
+ ["deriveBits", "deriveKey"]
133
+ );
134
+ const hashBuffer = await crypto.subtle.deriveBits(
135
+ {
136
+ name: "PBKDF2",
137
+ salt,
138
+ iterations,
139
+ hash: "SHA-256"
140
+ },
141
+ keyMaterial,
142
+ 256
143
+ );
144
+ const newHash = new Uint8Array(hashBuffer);
145
+ if (newHash.length !== originalHash.length) return false;
146
+ let result = 0;
147
+ for (let i = 0; i < newHash.length; i++) {
148
+ result |= newHash[i] ^ originalHash[i];
149
+ }
150
+ return result === 0;
151
+ }
152
+
92
153
  // src/backend/index.ts
93
154
  var createAuth = (config) => {
94
155
  let db;
@@ -98,7 +159,7 @@ var createAuth = (config) => {
98
159
  } else {
99
160
  db = config.database;
100
161
  }
101
- const { database, secret, baseUrl, provider: _, ...rest } = config;
162
+ const { database, secret, baseUrl, provider: _, useCloudflareNativeHashing = true, ...rest } = config;
102
163
  let adapterOptions = {
103
164
  provider,
104
165
  schema: {
@@ -111,11 +172,23 @@ var createAuth = (config) => {
111
172
  invitation: invitations
112
173
  }
113
174
  };
175
+ const emailConfig = rest.emailAndPassword || { enabled: true };
176
+ const { emailAndPassword, ...otherOptions } = rest;
177
+ const emailPasswordOptions = {
178
+ ...emailConfig
179
+ };
180
+ if (useCloudflareNativeHashing) {
181
+ emailPasswordOptions.password = {
182
+ hash: hashPassword,
183
+ verify: verifyPassword
184
+ };
185
+ }
114
186
  const auth = betterAuth({
115
187
  database: drizzleAdapter(db, adapterOptions),
116
188
  secret,
117
189
  baseURL: baseUrl,
118
- ...rest
190
+ emailAndPassword: emailPasswordOptions,
191
+ ...otherOptions
119
192
  });
120
193
  return auth;
121
194
  };
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  createAuth,
5
5
  createAuthApp,
6
6
  schema_exports
7
- } from "./chunk-526JE62U.js";
7
+ } from "./chunk-OOXZHG4Y.js";
8
8
  import {
9
9
  AuthForm,
10
10
  CreateOrganizationForm,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentgrowth/content-auth",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Better Auth wrapper with UI components for Cloudflare Workers & Pages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -50,8 +50,8 @@
50
50
  "author": "Content Growth",
51
51
  "license": "MIT",
52
52
  "peerDependencies": {
53
- "react": "^18.0.0",
54
- "react-dom": "^18.0.0"
53
+ "react": ">=18.2.0",
54
+ "react-dom": ">=18.2.0"
55
55
  },
56
56
  "dependencies": {
57
57
  "better-auth": "^1.4.9",