@amerged/ohmyhost-auth 0.1.10

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.
Files changed (50) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +11 -0
  4. package/THIRD_PARTY_NOTICES.md +3 -0
  5. package/dist/index.d.ts +6 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +6 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/installation-contract.d.ts +18 -0
  10. package/dist/installation-contract.d.ts.map +1 -0
  11. package/dist/installation-contract.js +17 -0
  12. package/dist/installation-contract.js.map +1 -0
  13. package/dist/mail-gateway.d.ts +13 -0
  14. package/dist/mail-gateway.d.ts.map +1 -0
  15. package/dist/mail-gateway.js +125 -0
  16. package/dist/mail-gateway.js.map +1 -0
  17. package/dist/next.d.ts +9 -0
  18. package/dist/next.d.ts.map +1 -0
  19. package/dist/next.js +5 -0
  20. package/dist/next.js.map +1 -0
  21. package/dist/runtime.d.ts +26 -0
  22. package/dist/runtime.d.ts.map +1 -0
  23. package/dist/runtime.js +151 -0
  24. package/dist/runtime.js.map +1 -0
  25. package/dist/schema.d.ts +2 -0
  26. package/dist/schema.d.ts.map +1 -0
  27. package/dist/schema.js +26 -0
  28. package/dist/schema.js.map +1 -0
  29. package/dist/tanstack.d.ts +2 -0
  30. package/dist/tanstack.d.ts.map +1 -0
  31. package/dist/tanstack.js +2 -0
  32. package/dist/tanstack.js.map +1 -0
  33. package/dist/vite-companion.d.ts +5 -0
  34. package/dist/vite-companion.d.ts.map +1 -0
  35. package/dist/vite-companion.js +5 -0
  36. package/dist/vite-companion.js.map +1 -0
  37. package/dist/web-handler.d.ts +3 -0
  38. package/dist/web-handler.d.ts.map +1 -0
  39. package/dist/web-handler.js +19 -0
  40. package/dist/web-handler.js.map +1 -0
  41. package/package.json +49 -0
  42. package/src/packages/customer-auth-better-auth/index.ts +5 -0
  43. package/src/packages/customer-auth-better-auth/installation-contract.ts +17 -0
  44. package/src/packages/customer-auth-better-auth/mail-gateway.ts +149 -0
  45. package/src/packages/customer-auth-better-auth/next.ts +7 -0
  46. package/src/packages/customer-auth-better-auth/runtime.ts +193 -0
  47. package/src/packages/customer-auth-better-auth/schema.ts +29 -0
  48. package/src/packages/customer-auth-better-auth/tanstack.ts +1 -0
  49. package/src/packages/customer-auth-better-auth/vite-companion.ts +6 -0
  50. package/src/packages/customer-auth-better-auth/web-handler.ts +18 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function renderCustomerAuthMigration(generatedSchema: string): string;
2
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAIA,wBAAgB,2BAA2B,CAAC,eAAe,EAAE,MAAM,GAAG,MAAM,CAwB3E"}
package/dist/schema.js ADDED
@@ -0,0 +1,26 @@
1
+ import { CUSTOMER_AUTH_INSTALLATION_CONTRACT } from "./installation-contract.js";
2
+ const EXPECTED_TABLES = CUSTOMER_AUTH_INSTALLATION_CONTRACT.database.tables;
3
+ export function renderCustomerAuthMigration(generatedSchema) {
4
+ if (typeof generatedSchema !== "string" ||
5
+ generatedSchema.length < 1 ||
6
+ generatedSchema.length > 256 * 1024 ||
7
+ generatedSchema.includes("\r") ||
8
+ /^(?:drop|alter|truncate|delete|update|insert)\b/imu.test(generatedSchema)) {
9
+ throw new TypeError("Generated Better Auth schema is invalid");
10
+ }
11
+ const tables = [...generatedSchema.matchAll(/^create table "([^"]+)"/gmu)]
12
+ .map((match) => match[1])
13
+ .sort();
14
+ if (JSON.stringify(tables) !== JSON.stringify(EXPECTED_TABLES)) {
15
+ throw new TypeError("Generated Better Auth schema is invalid");
16
+ }
17
+ const qualified = generatedSchema
18
+ .replace(/^create table "([^"]+)"/gmu, 'create table auth."$1"')
19
+ .replace(/ references "([^"]+)"/gu, ' references auth."$1"')
20
+ .replace(/^(create (?:unique )?index "[^"]+" on) "([^"]+)"/gmu, '$1 auth."$2"');
21
+ if (/^create table "| references "| on "/mu.test(qualified)) {
22
+ throw new TypeError("Generated Better Auth schema is invalid");
23
+ }
24
+ return `create schema if not exists auth;\n\n${qualified.trimEnd()}\n`;
25
+ }
26
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mCAAmC,EAAE,MAAM,4BAA4B,CAAC;AAEjF,MAAM,eAAe,GAAG,mCAAmC,CAAC,QAAQ,CAAC,MAAM,CAAC;AAE5E,MAAM,UAAU,2BAA2B,CAAC,eAAuB;IACjE,IACE,OAAO,eAAe,KAAK,QAAQ;QACnC,eAAe,CAAC,MAAM,GAAG,CAAC;QAC1B,eAAe,CAAC,MAAM,GAAG,GAAG,GAAG,IAAI;QACnC,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC9B,oDAAoD,CAAC,IAAI,CAAC,eAAe,CAAC,EAC1E,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;SACvE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACxB,IAAI,EAAE,CAAC;IACV,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,EAAE,CAAC;QAC/D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,SAAS,GAAG,eAAe;SAC9B,OAAO,CAAC,4BAA4B,EAAE,wBAAwB,CAAC;SAC/D,OAAO,CAAC,yBAAyB,EAAE,uBAAuB,CAAC;SAC3D,OAAO,CAAC,qDAAqD,EAAE,cAAc,CAAC,CAAC;IAClF,IAAI,uCAAuC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,wCAAwC,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC;AACzE,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createCustomerAuthFetchHandler as createTanStackCustomerAuthHandler } from "./web-handler.js";
2
+ //# sourceMappingURL=tanstack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack.d.ts","sourceRoot":"","sources":["../src/tanstack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,IAAI,iCAAiC,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { createCustomerAuthFetchHandler as createTanStackCustomerAuthHandler } from "./web-handler.js";
2
+ //# sourceMappingURL=tanstack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack.js","sourceRoot":"","sources":["../src/tanstack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,IAAI,iCAAiC,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { CustomerAuth } from "./runtime.js";
2
+ export declare function createViteCustomerAuthCompanion(auth: CustomerAuth): Readonly<{
3
+ fetch: (request: Request) => Promise<Response>;
4
+ }>;
5
+ //# sourceMappingURL=vite-companion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-companion.d.ts","sourceRoot":"","sources":["../src/vite-companion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,YAAY;;GAEjE"}
@@ -0,0 +1,5 @@
1
+ import { createCustomerAuthFetchHandler } from "./web-handler.js";
2
+ export function createViteCustomerAuthCompanion(auth) {
3
+ return Object.freeze({ fetch: createCustomerAuthFetchHandler(auth) });
4
+ }
5
+ //# sourceMappingURL=vite-companion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vite-companion.js","sourceRoot":"","sources":["../src/vite-companion.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,UAAU,+BAA+B,CAAC,IAAkB;IAChE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,8BAA8B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxE,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CustomerAuth } from "./runtime.js";
2
+ export declare function createCustomerAuthFetchHandler(auth: CustomerAuth): (request: Request) => Promise<Response>;
3
+ //# sourceMappingURL=web-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-handler.d.ts","sourceRoot":"","sources":["../src/web-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,YAAY,IAEjD,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CAYnD"}
@@ -0,0 +1,19 @@
1
+ import { CUSTOMER_AUTH_INSTALLATION_CONTRACT } from "./installation-contract.js";
2
+ export function createCustomerAuthFetchHandler(auth) {
3
+ if (typeof auth?.handler !== "function")
4
+ throw new TypeError("Customer auth handler is invalid");
5
+ return async (request) => {
6
+ if (!(request instanceof Request))
7
+ throw new TypeError("Customer auth request is invalid");
8
+ const pathname = new URL(request.url).pathname;
9
+ const routePath = CUSTOMER_AUTH_INSTALLATION_CONTRACT.http.routePath;
10
+ if (pathname !== routePath && !pathname.startsWith(`${routePath}/`)) {
11
+ return new Response("Not Found", {
12
+ status: 404,
13
+ headers: { "cache-control": "no-store" },
14
+ });
15
+ }
16
+ return auth.handler(request);
17
+ };
18
+ }
19
+ //# sourceMappingURL=web-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-handler.js","sourceRoot":"","sources":["../src/web-handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mCAAmC,EAAE,MAAM,4BAA4B,CAAC;AAEjF,MAAM,UAAU,8BAA8B,CAAC,IAAkB;IAC/D,IAAI,OAAO,IAAI,EAAE,OAAO,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IACjG,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC,CAAC,OAAO,YAAY,OAAO,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;QAC3F,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC;QAC/C,MAAM,SAAS,GAAG,mCAAmC,CAAC,IAAI,CAAC,SAAS,CAAC;QACrE,IAAI,QAAQ,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC;YACpE,OAAO,IAAI,QAAQ,CAAC,WAAW,EAAE;gBAC/B,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,eAAe,EAAE,UAAU,EAAE;aACzC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@amerged/ohmyhost-auth",
3
+ "version": "0.1.10",
4
+ "type": "module",
5
+ "engines": {
6
+ "node": ">=22"
7
+ },
8
+ "files": [
9
+ "dist",
10
+ "src",
11
+ "LICENSE",
12
+ "NOTICE",
13
+ "README.md",
14
+ "THIRD_PARTY_NOTICES.md"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.js"
20
+ },
21
+ "./next": {
22
+ "types": "./dist/next.d.ts",
23
+ "import": "./dist/next.js"
24
+ },
25
+ "./tanstack": {
26
+ "types": "./dist/tanstack.d.ts",
27
+ "import": "./dist/tanstack.js"
28
+ },
29
+ "./vite-companion": {
30
+ "types": "./dist/vite-companion.d.ts",
31
+ "import": "./dist/vite-companion.js"
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "@better-fetch/fetch": "1.3.1",
36
+ "@cloudflare/workers-types": "5.20260906.1",
37
+ "@types/pg": "8.15.5",
38
+ "better-auth": "1.7.1",
39
+ "bun-types": "1.4.1",
40
+ "pg": "8.22.0"
41
+ },
42
+ "license": "Apache-2.0",
43
+ "homepage": "https://docs.ohmyho.st/",
44
+ "description": "ohmyho.st auth client",
45
+ "publishConfig": {
46
+ "access": "public",
47
+ "registry": "https://registry.npmjs.org/"
48
+ }
49
+ }
@@ -0,0 +1,5 @@
1
+ export * from "./runtime.js";
2
+ export * from "./schema.js";
3
+ export * from "./web-handler.js";
4
+ export * from "./mail-gateway.js";
5
+ export * from "./installation-contract.js";
@@ -0,0 +1,17 @@
1
+ const TABLES = Object.freeze(["account", "rateLimit", "session", "user", "verification"]);
2
+ const SECRETS = Object.freeze(["BETTER_AUTH_SECRET"]);
3
+
4
+ export const CUSTOMER_AUTH_INSTALLATION_CONTRACT = Object.freeze({
5
+ package: Object.freeze({
6
+ name: "better-auth" as const,
7
+ version: "1.7.1" as const,
8
+ }),
9
+ database: Object.freeze({
10
+ schema: "auth" as const,
11
+ idGeneration: "uuid" as const,
12
+ tables: TABLES,
13
+ binding: "OHMYHOST_DATABASE" as const,
14
+ }),
15
+ http: Object.freeze({ routePath: "/api/auth" as const, handlerExport: "fetch" as const }),
16
+ secrets: SECRETS,
17
+ });
@@ -0,0 +1,149 @@
1
+ import type { CustomerAuthEmailSender } from "./runtime.js";
2
+
3
+ const ULID_PATTERN = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u;
4
+
5
+ export class CustomerAuthEmailDeliveryError extends Error {
6
+ public readonly code = "customer_auth_email_delivery_failed";
7
+ public constructor() {
8
+ super("Customer authentication email delivery failed");
9
+ this.name = "CustomerAuthEmailDeliveryError";
10
+ }
11
+ }
12
+
13
+ export function createMailGatewayEmailSender(input: {
14
+ readonly projectId: string;
15
+ readonly gatewayOrigin: string;
16
+ readonly key: string;
17
+ readonly fetch: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
18
+ readonly crypto: Crypto;
19
+ }): CustomerAuthEmailSender {
20
+ const projectId = input.projectId;
21
+ if (typeof projectId !== "string" || !ULID_PATTERN.test(projectId))
22
+ throw new TypeError("Invalid canonical ULID");
23
+ const gatewayOrigin = canonicalOrigin(input.gatewayOrigin);
24
+ if (
25
+ !/^[A-Za-z0-9_-]{43}$/u.test(input.key) ||
26
+ typeof input.fetch !== "function" ||
27
+ typeof input.crypto?.subtle?.digest !== "function"
28
+ ) {
29
+ throw new TypeError("Mail gateway email sender input is invalid");
30
+ }
31
+ return Object.freeze({
32
+ async send(message: Parameters<CustomerAuthEmailSender["send"]>[0]) {
33
+ validateMessage(message);
34
+ const subject =
35
+ message.kind === "verification"
36
+ ? "Verify your account"
37
+ : message.kind === "password-reset"
38
+ ? "Reset your password"
39
+ : "Your password was changed";
40
+ const action = message.kind === "password-changed" ? "Review your account" : subject;
41
+ const body = {
42
+ project_id: projectId,
43
+ to: message.to,
44
+ subject,
45
+ text: `${subject}: ${message.url}`,
46
+ html: `<p><a href="${escapeHtml(message.url)}">${action}</a></p>`,
47
+ };
48
+ const idempotencyKey = await sha256Hex(
49
+ input.crypto,
50
+ `${message.kind}\n${message.to}\n${message.url}`,
51
+ );
52
+ let response: Response;
53
+ try {
54
+ response = await input.fetch(`${gatewayOrigin}/v1/send`, {
55
+ method: "POST",
56
+ headers: {
57
+ Authorization: `Bearer ${input.key}`,
58
+ "Content-Type": "application/json",
59
+ "Idempotency-Key": idempotencyKey,
60
+ },
61
+ body: JSON.stringify(body),
62
+ redirect: "manual",
63
+ signal: AbortSignal.timeout(8_000),
64
+ });
65
+ } catch {
66
+ throw new CustomerAuthEmailDeliveryError();
67
+ }
68
+ const value = await readJson(response);
69
+ if (
70
+ response.status !== 202 ||
71
+ !isRecord(value) ||
72
+ value["state"] !== "accepted" ||
73
+ typeof value["request_id"] !== "string" ||
74
+ typeof value["message_id"] !== "string"
75
+ ) {
76
+ throw new CustomerAuthEmailDeliveryError();
77
+ }
78
+ if (!ULID_PATTERN.test(value["request_id"])) throw new TypeError("Invalid canonical ULID");
79
+ },
80
+ });
81
+ }
82
+
83
+ function validateMessage(message: Parameters<CustomerAuthEmailSender["send"]>[0]): void {
84
+ if (
85
+ (message.kind !== "verification" &&
86
+ message.kind !== "password-reset" &&
87
+ message.kind !== "password-changed") ||
88
+ !/^[a-z0-9](?:[a-z0-9._%+-]{0,62}[a-z0-9])?@(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/u.test(
89
+ message.to,
90
+ ) ||
91
+ !/^https:\/\//u.test(message.url) ||
92
+ message.url.length > 4_096
93
+ ) {
94
+ throw new CustomerAuthEmailDeliveryError();
95
+ }
96
+ }
97
+
98
+ function canonicalOrigin(value: string): string {
99
+ let url: URL;
100
+ try {
101
+ url = new URL(value);
102
+ } catch {
103
+ throw new TypeError("Mail gateway origin is invalid");
104
+ }
105
+ if (
106
+ url.protocol !== "https:" ||
107
+ url.username !== "" ||
108
+ url.password !== "" ||
109
+ url.pathname !== "/" ||
110
+ url.search !== "" ||
111
+ url.hash !== ""
112
+ ) {
113
+ throw new TypeError("Mail gateway origin is invalid");
114
+ }
115
+ return url.origin;
116
+ }
117
+
118
+ async function sha256Hex(crypto: Crypto, value: string): Promise<string> {
119
+ const bytes = Uint8Array.from(new TextEncoder().encode(value));
120
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", bytes.buffer));
121
+ return Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
122
+ }
123
+
124
+ async function readJson(response: Response): Promise<unknown> {
125
+ const declared = response.headers.get("content-length");
126
+ if (declared !== null && (!/^[0-9]+$/u.test(declared) || Number(declared) > 4_096)) {
127
+ await response.body?.cancel().catch(() => undefined);
128
+ throw new CustomerAuthEmailDeliveryError();
129
+ }
130
+ const bytes = new Uint8Array(await response.arrayBuffer());
131
+ if (bytes.byteLength > 4_096) throw new CustomerAuthEmailDeliveryError();
132
+ try {
133
+ return JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
134
+ } catch {
135
+ throw new CustomerAuthEmailDeliveryError();
136
+ }
137
+ }
138
+
139
+ function escapeHtml(value: string): string {
140
+ return value
141
+ .replaceAll("&", "&amp;")
142
+ .replaceAll('"', "&quot;")
143
+ .replaceAll("<", "&lt;")
144
+ .replaceAll(">", "&gt;");
145
+ }
146
+
147
+ function isRecord(value: unknown): value is Record<string, unknown> {
148
+ return typeof value === "object" && value !== null && !Array.isArray(value);
149
+ }
@@ -0,0 +1,7 @@
1
+ import { toNextJsHandler } from "better-auth/next-js";
2
+
3
+ import type { CustomerAuth } from "./runtime.js";
4
+
5
+ export function createNextCustomerAuthHandler(auth: CustomerAuth) {
6
+ return Object.freeze(toNextJsHandler(auth));
7
+ }
@@ -0,0 +1,193 @@
1
+ /// <reference types="bun-types/sqlite.d.ts" preserve="true" />
2
+ import { betterAuth, type BetterAuthOptions } from "better-auth";
3
+ import { Pool } from "pg";
4
+
5
+ import { CUSTOMER_AUTH_INSTALLATION_CONTRACT } from "./installation-contract.js";
6
+
7
+ // Better Fetch 1.3.1 exposes an unbound Timer name; keep its type local to that module.
8
+ // Referencing only Bun's SQLite declarations above avoids changing Node's global APIs.
9
+ declare module "@better-fetch/fetch" {
10
+ type Timer = ReturnType<typeof globalThis.setTimeout>;
11
+ }
12
+
13
+ export interface CustomerAuthEmail {
14
+ readonly kind: "password-changed" | "password-reset" | "verification";
15
+ readonly to: string;
16
+ readonly url: string;
17
+ }
18
+
19
+ export interface CustomerAuthEmailSender {
20
+ send(message: CustomerAuthEmail): Promise<void>;
21
+ }
22
+
23
+ export interface CustomerAuthRuntimeInput {
24
+ readonly appName: string;
25
+ readonly publicOrigin: string;
26
+ readonly database: Pool;
27
+ readonly secret: string;
28
+ readonly email: CustomerAuthEmailSender;
29
+ }
30
+
31
+ export function createCustomerAuthOptions(input: CustomerAuthRuntimeInput): BetterAuthOptions {
32
+ const publicOrigin = parsePublicOrigin(input.publicOrigin);
33
+ const authBasePath = CUSTOMER_AUTH_INSTALLATION_CONTRACT.http.routePath;
34
+ if (
35
+ typeof input.appName !== "string" ||
36
+ input.appName.trim() !== input.appName ||
37
+ input.appName.length < 1 ||
38
+ input.appName.length > 80 ||
39
+ typeof input.database?.query !== "function" ||
40
+ typeof input.secret !== "string" ||
41
+ input.secret.length < 32 ||
42
+ input.secret.length > 512 ||
43
+ typeof input.email?.send !== "function"
44
+ ) {
45
+ throw new TypeError("Customer auth runtime input is invalid");
46
+ }
47
+ const send = async (kind: CustomerAuthEmail["kind"], email: string, url: string) => {
48
+ await input.email.send({
49
+ kind,
50
+ to: email,
51
+ url:
52
+ kind === "password-changed"
53
+ ? sameOriginExactUrl(url, publicOrigin, "/login")
54
+ : sameOriginAuthUrl(url, publicOrigin, authBasePath),
55
+ });
56
+ };
57
+ const options: BetterAuthOptions = {
58
+ appName: input.appName,
59
+ baseURL: publicOrigin,
60
+ basePath: authBasePath,
61
+ trustedOrigins: [publicOrigin],
62
+ secret: input.secret,
63
+ database: input.database,
64
+ emailAndPassword: {
65
+ enabled: true,
66
+ requireEmailVerification: true,
67
+ autoSignIn: false,
68
+ minPasswordLength: 12,
69
+ maxPasswordLength: 128,
70
+ revokeSessionsOnPasswordReset: true,
71
+ resetPasswordTokenExpiresIn: 3_600,
72
+ sendResetPassword: ({ user, url }) => send("password-reset", user.email, url),
73
+ onPasswordReset: ({ user }) => send("password-changed", user.email, `${publicOrigin}/login`),
74
+ },
75
+ emailVerification: {
76
+ sendOnSignUp: true,
77
+ sendOnSignIn: true,
78
+ autoSignInAfterVerification: false,
79
+ expiresIn: 3_600,
80
+ sendVerificationEmail: ({ user, url }) => send("verification", user.email, url),
81
+ },
82
+ session: { expiresIn: 7 * 24 * 60 * 60, updateAge: 24 * 60 * 60 },
83
+ rateLimit: {
84
+ enabled: true,
85
+ window: 60,
86
+ max: 100,
87
+ storage: "database",
88
+ customRules: {
89
+ "/sign-in/email": { window: 60, max: 5 },
90
+ "/sign-up/email": { window: 60, max: 3 },
91
+ "/request-password-reset": { window: 60, max: 3 },
92
+ },
93
+ },
94
+ advanced: {
95
+ useSecureCookies: true,
96
+ database: {
97
+ generateId: CUSTOMER_AUTH_INSTALLATION_CONTRACT.database.idGeneration,
98
+ joins: true,
99
+ },
100
+ ipAddress: { ipAddressHeaders: ["cf-connecting-ip"] },
101
+ },
102
+ };
103
+ return Object.freeze(options);
104
+ }
105
+
106
+ export function createCustomerAuth(input: CustomerAuthRuntimeInput) {
107
+ return betterAuth(createCustomerAuthOptions(input));
108
+ }
109
+
110
+ export function createCustomerAuthPostgresPool(connectionString: string): Pool {
111
+ validateConnectionString(connectionString);
112
+ return new Pool(poolConfiguration(connectionString));
113
+ }
114
+
115
+ function validateConnectionString(connectionString: string): void {
116
+ if (
117
+ typeof connectionString !== "string" ||
118
+ connectionString.length < 1 ||
119
+ connectionString.length > 8_192 ||
120
+ !/^postgres(?:ql)?:\/\//u.test(connectionString)
121
+ ) {
122
+ throw new TypeError("Customer auth database URL is invalid");
123
+ }
124
+ }
125
+
126
+ function poolConfiguration(connectionString: string) {
127
+ return {
128
+ connectionString,
129
+ options: `-c search_path=${CUSTOMER_AUTH_INSTALLATION_CONTRACT.database.schema}`,
130
+ max: 1,
131
+ connectionTimeoutMillis: 5_000,
132
+ idleTimeoutMillis: 30_000,
133
+ query_timeout: 10_000,
134
+ statement_timeout: 10_000,
135
+ };
136
+ }
137
+
138
+ export type CustomerAuth = ReturnType<typeof createCustomerAuth>;
139
+
140
+ function parsePublicOrigin(value: string): string {
141
+ let url: URL;
142
+ try {
143
+ url = new URL(value);
144
+ } catch {
145
+ throw new TypeError("Customer auth public origin is invalid");
146
+ }
147
+ if (
148
+ url.protocol !== "https:" ||
149
+ url.origin !== value ||
150
+ url.pathname !== "/" ||
151
+ url.username !== "" ||
152
+ url.password !== "" ||
153
+ url.search !== "" ||
154
+ url.hash !== ""
155
+ ) {
156
+ throw new TypeError("Customer auth public origin is invalid");
157
+ }
158
+ return url.origin;
159
+ }
160
+
161
+ function sameOriginAuthUrl(value: string, publicOrigin: string, authBasePath: string): string {
162
+ let url: URL;
163
+ try {
164
+ url = new URL(value);
165
+ } catch {
166
+ throw new TypeError("Customer auth e-mail URL is invalid");
167
+ }
168
+ if (
169
+ url.origin !== publicOrigin ||
170
+ (url.pathname !== authBasePath && !url.pathname.startsWith(`${authBasePath}/`))
171
+ ) {
172
+ throw new TypeError("Customer auth e-mail URL is invalid");
173
+ }
174
+ return url.href;
175
+ }
176
+
177
+ function sameOriginExactUrl(value: string, publicOrigin: string, pathname: string): string {
178
+ let url: URL;
179
+ try {
180
+ url = new URL(value);
181
+ } catch {
182
+ throw new TypeError("Customer auth e-mail URL is invalid");
183
+ }
184
+ if (
185
+ url.origin !== publicOrigin ||
186
+ url.pathname !== pathname ||
187
+ url.search !== "" ||
188
+ url.hash !== ""
189
+ ) {
190
+ throw new TypeError("Customer auth e-mail URL is invalid");
191
+ }
192
+ return url.href;
193
+ }
@@ -0,0 +1,29 @@
1
+ import { CUSTOMER_AUTH_INSTALLATION_CONTRACT } from "./installation-contract.js";
2
+
3
+ const EXPECTED_TABLES = CUSTOMER_AUTH_INSTALLATION_CONTRACT.database.tables;
4
+
5
+ export function renderCustomerAuthMigration(generatedSchema: string): string {
6
+ if (
7
+ typeof generatedSchema !== "string" ||
8
+ generatedSchema.length < 1 ||
9
+ generatedSchema.length > 256 * 1024 ||
10
+ generatedSchema.includes("\r") ||
11
+ /^(?:drop|alter|truncate|delete|update|insert)\b/imu.test(generatedSchema)
12
+ ) {
13
+ throw new TypeError("Generated Better Auth schema is invalid");
14
+ }
15
+ const tables = [...generatedSchema.matchAll(/^create table "([^"]+)"/gmu)]
16
+ .map((match) => match[1])
17
+ .sort();
18
+ if (JSON.stringify(tables) !== JSON.stringify(EXPECTED_TABLES)) {
19
+ throw new TypeError("Generated Better Auth schema is invalid");
20
+ }
21
+ const qualified = generatedSchema
22
+ .replace(/^create table "([^"]+)"/gmu, 'create table auth."$1"')
23
+ .replace(/ references "([^"]+)"/gu, ' references auth."$1"')
24
+ .replace(/^(create (?:unique )?index "[^"]+" on) "([^"]+)"/gmu, '$1 auth."$2"');
25
+ if (/^create table "| references "| on "/mu.test(qualified)) {
26
+ throw new TypeError("Generated Better Auth schema is invalid");
27
+ }
28
+ return `create schema if not exists auth;\n\n${qualified.trimEnd()}\n`;
29
+ }
@@ -0,0 +1 @@
1
+ export { createCustomerAuthFetchHandler as createTanStackCustomerAuthHandler } from "./web-handler.js";
@@ -0,0 +1,6 @@
1
+ import type { CustomerAuth } from "./runtime.js";
2
+ import { createCustomerAuthFetchHandler } from "./web-handler.js";
3
+
4
+ export function createViteCustomerAuthCompanion(auth: CustomerAuth) {
5
+ return Object.freeze({ fetch: createCustomerAuthFetchHandler(auth) });
6
+ }
@@ -0,0 +1,18 @@
1
+ import type { CustomerAuth } from "./runtime.js";
2
+ import { CUSTOMER_AUTH_INSTALLATION_CONTRACT } from "./installation-contract.js";
3
+
4
+ export function createCustomerAuthFetchHandler(auth: CustomerAuth) {
5
+ if (typeof auth?.handler !== "function") throw new TypeError("Customer auth handler is invalid");
6
+ return async (request: Request): Promise<Response> => {
7
+ if (!(request instanceof Request)) throw new TypeError("Customer auth request is invalid");
8
+ const pathname = new URL(request.url).pathname;
9
+ const routePath = CUSTOMER_AUTH_INSTALLATION_CONTRACT.http.routePath;
10
+ if (pathname !== routePath && !pathname.startsWith(`${routePath}/`)) {
11
+ return new Response("Not Found", {
12
+ status: 404,
13
+ headers: { "cache-control": "no-store" },
14
+ });
15
+ }
16
+ return auth.handler(request);
17
+ };
18
+ }