@effectify/node-better-auth 0.5.11 → 0.5.12-alpha.1

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/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@effectify/node-better-auth",
3
- "version": "0.5.11",
3
+ "version": "0.5.12-alpha.1",
4
4
  "description": "Integration of better-auth with Effect for Node.js applications",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/devx-op/effectify",
8
+ "directory": "packages/node/better-auth"
9
+ },
5
10
  "type": "module",
6
11
  "main": "./dist/src/index.js",
7
12
  "module": "./dist/src/index.js",
@@ -25,21 +30,20 @@
25
30
  "test": "vitest run"
26
31
  },
27
32
  "peerDependencies": {
28
- "@effect/platform": "catalog:",
29
- "@effect/platform-node": "catalog:",
30
33
  "better-auth": "catalog:",
31
34
  "effect": "catalog:"
32
35
  },
33
36
  "devDependencies": {
37
+ "@effect/platform-node": "catalog:",
34
38
  "@effect/vitest": "catalog:",
35
- "vitest": "catalog:",
36
- "better-sqlite3": "catalog:",
37
39
  "@types/better-sqlite3": "catalog:",
38
- "@types/node": "catalog:"
40
+ "@types/node": "catalog:",
41
+ "better-sqlite3": "catalog:",
42
+ "effect": "catalog:",
43
+ "vitest": "catalog:"
39
44
  },
40
45
  "dependenciesMeta": {},
41
46
  "dependencies": {
42
47
  "zod": "catalog:"
43
- },
44
- "optionalDependencies": {}
48
+ }
45
49
  }
@@ -1,27 +1,42 @@
1
1
  import { betterAuth, type BetterAuthOptions, type Session, type User } from "better-auth";
2
2
  import * as Context from "effect/Context";
3
+ import * as Effect from "effect/Effect";
3
4
  import * as Layer from "effect/Layer";
4
- import * as Schema from "effect/Schema";
5
5
  export declare namespace AuthService {
6
6
  export type AuthInstance = ReturnType<typeof betterAuth>;
7
- const AuthServiceContext_base: Context.TagClass<AuthServiceContext, "AuthServiceContext", {
8
- readonly auth: AuthInstance;
9
- }>;
7
+ const AuthServiceContext_base: Context.ServiceClass<AuthServiceContext, "AuthServiceContext", {
8
+ auth: import("better-auth").Auth<BetterAuthOptions>;
9
+ }> & {
10
+ readonly make: (options: BetterAuthOptions) => Effect.Effect<{
11
+ auth: import("better-auth").Auth<BetterAuthOptions>;
12
+ }, never, never>;
13
+ };
14
+ /**
15
+ * AuthServiceContext provides access to the better-auth instance.
16
+ *
17
+ * In Effect v4 beta57, services are created with Context.Service and still compose through Layers.
18
+ * for easy Layer composition.
19
+ */
10
20
  export class AuthServiceContext extends AuthServiceContext_base {
21
+ static readonly layer: (options: BetterAuthOptions) => Layer.Layer<AuthServiceContext, never, never>;
11
22
  }
12
- export const layer: (options: BetterAuthOptions) => Layer.Layer<AuthServiceContext, never, never>;
13
- const AuthContext_base: Context.TagClass<AuthContext, "AuthContext", {
23
+ const AuthContext_base: Context.ServiceClass<AuthContext, "AuthContext", {
14
24
  readonly user: User;
15
25
  readonly session: Session;
16
26
  }>;
27
+ /**
28
+ * AuthContext provides access to the authenticated user and session.
29
+ *
30
+ * This is request-scoped context provided at runtime during request handling.
31
+ */
17
32
  export class AuthContext extends AuthContext_base {
18
33
  }
19
- const Unauthorized_base: Schema.TaggedErrorClass<Unauthorized, "Unauthorized", {
20
- readonly _tag: Schema.tag<"Unauthorized">;
21
- } & {
22
- details: typeof Schema.String;
23
- }>;
24
- export class Unauthorized extends Unauthorized_base {
34
+ const Unauthorized_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
35
+ readonly _tag: "Unauthorized";
36
+ } & Readonly<A>;
37
+ export class Unauthorized extends Unauthorized_base<{
38
+ readonly details: string;
39
+ }> {
25
40
  }
26
41
  export {};
27
42
  }
@@ -2,30 +2,49 @@ import { betterAuth } from "better-auth";
2
2
  import * as Context from "effect/Context";
3
3
  import * as Effect from "effect/Effect";
4
4
  import * as Layer from "effect/Layer";
5
- import * as Schema from "effect/Schema";
5
+ import * as Data from "effect/Data";
6
6
  export var AuthService;
7
7
  (function (AuthService) {
8
- class AuthServiceContext extends Context.Tag("AuthServiceContext")() {
8
+ /**
9
+ * AuthServiceContext provides access to the better-auth instance.
10
+ *
11
+ * In Effect v4 beta57, services are created with Context.Service and still compose through Layers.
12
+ * for easy Layer composition.
13
+ */
14
+ class AuthServiceContext extends Context.Service()("AuthServiceContext", {
15
+ make: (options) => Effect.gen(function* () {
16
+ // Try to extract database path from Database instance for logging
17
+ const dbPathForLog = options.database &&
18
+ typeof options.database === "object" &&
19
+ "name" in options.database
20
+ ? String(options.database.name || "unknown")
21
+ : "unknown";
22
+ yield* Effect.logInfo(`Creating auth instance with database path: ${dbPathForLog}`);
23
+ const isAdapter = options.database &&
24
+ typeof options.database === "object" &&
25
+ ("createSession" in options.database ||
26
+ "createUser" in options.database ||
27
+ "client" in options.database);
28
+ if (!isAdapter) {
29
+ yield* Effect.logInfo("Auto-migration is disabled in better-auth v1.4.10+. Please run 'better-auth migrate' manually.");
30
+ }
31
+ return { auth: betterAuth(options) };
32
+ }),
33
+ }) {
34
+ // Build the layer yourself from the make effect
35
+ static layer = (options) => Layer.effect(this, this.make(options));
9
36
  }
10
37
  AuthService.AuthServiceContext = AuthServiceContext;
11
- AuthService.layer = (options) => Layer.effect(AuthServiceContext, Effect.gen(function* () {
12
- // Try to extract database path from Database instance for logging
13
- const dbPathForLog = options.database && typeof options.database === "object" && "name" in options.database
14
- ? String(options.database.name || "unknown")
15
- : "unknown";
16
- yield* Effect.logInfo(`Creating auth instance with database path: ${dbPathForLog}`);
17
- const isAdapter = options.database &&
18
- typeof options.database === "object" &&
19
- ("createSession" in options.database || "createUser" in options.database || "client" in options.database);
20
- if (!isAdapter) {
21
- yield* Effect.logInfo("Auto-migration is disabled in better-auth v1.4.10+. Please run 'better-auth migrate' manually.");
22
- }
23
- return { auth: betterAuth(options) };
24
- }));
25
- class AuthContext extends Context.Tag("AuthContext")() {
38
+ /**
39
+ * AuthContext provides access to the authenticated user and session.
40
+ *
41
+ * This is request-scoped context provided at runtime during request handling.
42
+ */
43
+ class AuthContext extends Context.Service()("AuthContext") {
26
44
  }
27
45
  AuthService.AuthContext = AuthContext;
28
- class Unauthorized extends Schema.TaggedError()("Unauthorized", { details: Schema.String }) {
46
+ // In v4, use Data.TaggedError instead of Schema.TaggedError for simple errors
47
+ class Unauthorized extends Data.TaggedError("Unauthorized") {
29
48
  }
30
49
  AuthService.Unauthorized = Unauthorized;
31
50
  })(AuthService || (AuthService = {}));
@@ -1,4 +1,4 @@
1
- declare const BetterAuthApiError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
1
+ declare const BetterAuthApiError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
2
2
  readonly _tag: "BetterAuthApiError";
3
3
  } & Readonly<A>;
4
4
  export declare class BetterAuthApiError extends BetterAuthApiError_base<{
@@ -1,9 +1,9 @@
1
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
2
- import * as HttpServerResponse from "@effect/platform/HttpServerResponse";
3
1
  import type { Auth } from "better-auth";
4
- import type { ConfigError } from "effect/ConfigError";
5
2
  import * as Effect from "effect/Effect";
6
3
  import { BetterAuthApiError } from "./better-auth-error.js";
4
+ import type { ConfigError } from "effect/Config";
5
+ import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
6
+ import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest";
7
7
  export declare const toEffectHandler: (auth: {
8
8
  handler: Auth["handler"];
9
9
  } | Auth["handler"]) => Effect.Effect<HttpServerResponse.HttpServerResponse, BetterAuthApiError | ConfigError, HttpServerRequest.HttpServerRequest>;
@@ -1,10 +1,10 @@
1
- import * as HttpServerRequest from "@effect/platform/HttpServerRequest";
2
- import * as HttpServerResponse from "@effect/platform/HttpServerResponse";
3
- import * as NodeHttpServerRequest from "@effect/platform-node/NodeHttpServerRequest";
4
1
  import { toNodeHandler } from "better-auth/node";
5
2
  import * as Config from "effect/Config";
6
3
  import * as Effect from "effect/Effect";
7
4
  import { BetterAuthApiError } from "./better-auth-error.js";
5
+ import * as HttpServerResponse from "effect/unstable/http/HttpServerResponse";
6
+ import * as HttpServerRequest from "effect/unstable/http/HttpServerRequest";
7
+ import * as NodeHttpServerRequest from "@effect/platform-node/NodeHttpServerRequest";
8
8
  const TRAILING_SLASH_REGEX = /\/+$/;
9
9
  const PROTOCOL_REGEX = /(https?:\/\/)+/;
10
10
  export const toEffectHandler = (auth) => Effect.gen(function* () {
@@ -14,7 +14,10 @@ export const toEffectHandler = (auth) => Effect.gen(function* () {
14
14
  const appUrl = yield* Config.url("BETTER_AUTH_URL");
15
15
  // Debug: log the configured app URL so we can diagnose Config errors
16
16
  yield* Effect.log(`toEffectHandler: BETTER_AUTH_URL=${String(appUrl)}`);
17
- const normalizeUrl = (url) => url.toString().replace(TRAILING_SLASH_REGEX, "").replace(PROTOCOL_REGEX, "http://");
17
+ const normalizeUrl = (url) => url
18
+ .toString()
19
+ .replace(TRAILING_SLASH_REGEX, "")
20
+ .replace(PROTOCOL_REGEX, "http://");
18
21
  const allowedOrigins = [normalizeUrl(appUrl)];
19
22
  const origin = nodeRequest.headers.origin ? normalizeUrl(appUrl) : "";
20
23
  if (allowedOrigins.includes(origin)) {
@@ -31,7 +34,14 @@ export const toEffectHandler = (auth) => Effect.gen(function* () {
31
34
  return HttpServerResponse.empty({ status: 200 });
32
35
  }
33
36
  // Log incoming request for debugging
34
- yield* Effect.log(`toEffectHandler: incoming ${nodeRequest.method} ${String(nodeRequest.url)}`);
37
+ const authHeader = nodeRequest.headers.authorization;
38
+ yield* Effect.log(`toEffectHandler: incoming ${nodeRequest.method} ${String(nodeRequest.url)} headers: cookie=${nodeRequest.headers.cookie?.substring(0, 50) || "none"}, auth=${authHeader?.substring(0, 30) || "none"}`);
39
+ // If no cookie but has Authorization header (bearer token), set it as cookie for better-auth
40
+ if (!nodeRequest.headers.cookie && authHeader?.startsWith("Bearer ")) {
41
+ const token = authHeader.slice(7); // Remove "Bearer " prefix
42
+ nodeRequest.headers.cookie = `better-auth.session_token=${token}`;
43
+ yield* Effect.log(`toEffectHandler: using token from Authorization header as cookie`);
44
+ }
35
45
  try {
36
46
  yield* Effect.tryPromise({
37
47
  try: () => "handler" in auth
@@ -58,5 +68,7 @@ export const toEffectHandler = (auth) => Effect.gen(function* () {
58
68
  }
59
69
  return HttpServerResponse.empty({ status: 500 });
60
70
  }
61
- return HttpServerResponse.empty({ status: nodeResponse.writableFinished ? nodeResponse.statusCode : 499 });
71
+ return HttpServerResponse.empty({
72
+ status: nodeResponse.writableFinished ? nodeResponse.statusCode : 499,
73
+ });
62
74
  });
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@effectify/node-better-auth",
3
- "version": "0.5.11",
3
+ "version": "0.5.12-alpha.1",
4
4
  "description": "Integration of better-auth with Effect for Node.js applications",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/devx-op/effectify",
8
+ "directory": "packages/node/better-auth"
9
+ },
5
10
  "type": "module",
6
11
  "main": "./dist/src/index.js",
7
12
  "module": "./dist/src/index.js",
@@ -22,23 +27,22 @@
22
27
  "!**/*.tsbuildinfo"
23
28
  ],
24
29
  "peerDependencies": {
25
- "@effect/platform": "0.94.0",
26
- "@effect/platform-node": "0.104.1",
27
30
  "better-auth": "1.4.10",
28
- "effect": "3.19.16"
31
+ "effect": "4.0.0-beta.94"
29
32
  },
30
33
  "devDependencies": {
31
- "@effect/vitest": "0.27.0",
32
- "vitest": "4.0.9",
33
- "better-sqlite3": "12.6.2",
34
+ "@effect/platform-node": "4.0.0-beta.94",
35
+ "@effect/vitest": "4.0.0-beta.94",
34
36
  "@types/better-sqlite3": "7.6.13",
35
- "@types/node": "20.19.25"
37
+ "@types/node": "20.19.25",
38
+ "better-sqlite3": "12.11.1",
39
+ "effect": "4.0.0-beta.94",
40
+ "vitest": "4.1.10"
36
41
  },
37
42
  "dependenciesMeta": {},
38
43
  "dependencies": {
39
- "zod": "4.3.6"
44
+ "zod": "4.4.3"
40
45
  },
41
- "optionalDependencies": {},
42
46
  "scripts": {
43
47
  "test": "vitest run"
44
48
  }