@velajs/better-auth 0.5.0 → 0.6.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.
@@ -0,0 +1,46 @@
1
+ /**
2
+ * The slice of `@velajs/testing`'s `TestingModule` this resolver depends on.
3
+ * Declared structurally so `@velajs/better-auth/testing` carries NO runtime
4
+ * (or type) dependency on `@velajs/testing` — a real `TestingModule` satisfies
5
+ * it, and the resolver stays assignable to `@velajs/testing`'s `ActingAsResolver`.
6
+ */
7
+ export interface TestModuleLike {
8
+ get<T>(token: unknown): T;
9
+ }
10
+ /**
11
+ * A test principal. Opaque `Record<string, unknown>` to stay compatible with
12
+ * `@velajs/testing`'s `TestPrincipal`. Recognized fields:
13
+ *
14
+ * - `id` — reuse the user with this id if it already exists.
15
+ * - `email` — reuse the user with this email, else create one.
16
+ * - `name` — display name for a created user (defaults to the email).
17
+ *
18
+ * Any other fields are forwarded to `internalAdapter.createUser` (e.g. `role`)
19
+ * when a new user is minted, so role-guarded routes can be exercised.
20
+ */
21
+ export type ActingAsPrincipal = Record<string, unknown>;
22
+ /**
23
+ * actingAs — a `@velajs/testing` auth resolver for better-auth.
24
+ *
25
+ * Resolves {@link BetterAuthService} from the module, mints a REAL better-auth
26
+ * session for `principal` through `auth.$context.internalAdapter`, and returns
27
+ * a `Headers` carrying a properly signed session cookie. Guarded routes
28
+ * (`AuthGuard`) then accept requests carrying those headers because
29
+ * `auth.api.getSession` validates the cookie against the same session store.
30
+ *
31
+ * The signature `(module, principal) => Promise<Headers>` is exactly
32
+ * `@velajs/testing`'s `ActingAsResolver`, so it plugs straight in:
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { actingAs } from '@velajs/better-auth/testing';
37
+ *
38
+ * // As the default resolver for the module:
39
+ * module.setAuthResolver(actingAs);
40
+ * await module.http.get('/me').actingAs({ email: 'ada@example.com' }).send();
41
+ *
42
+ * // Or passed per-request:
43
+ * await module.http.get('/me').actingAs({ id: existingUserId }, actingAs).send();
44
+ * ```
45
+ */
46
+ export declare function actingAs(module: TestModuleLike, principal: ActingAsPrincipal): Promise<Headers>;
@@ -0,0 +1,70 @@
1
+ // Mechanics adapted from @stratal/testing (MIT, © Temitayo Fadojutimi):
2
+ // mint a real better-auth session via `$context.internalAdapter` and hand back
3
+ // a signed session-cookie header. Adapted to better-auth >=1.6: the session
4
+ // cookie is signed with the package's own `makeSignature` (better-auth/crypto)
5
+ // — the same primitive better-auth's built-in test cookie builder uses — so no
6
+ // endpoint-context shim or `setSessionCookie` mock is needed.
7
+ import { makeSignature } from "better-auth/crypto";
8
+ import { BetterAuthService } from "../better-auth.service.js";
9
+ /**
10
+ * actingAs — a `@velajs/testing` auth resolver for better-auth.
11
+ *
12
+ * Resolves {@link BetterAuthService} from the module, mints a REAL better-auth
13
+ * session for `principal` through `auth.$context.internalAdapter`, and returns
14
+ * a `Headers` carrying a properly signed session cookie. Guarded routes
15
+ * (`AuthGuard`) then accept requests carrying those headers because
16
+ * `auth.api.getSession` validates the cookie against the same session store.
17
+ *
18
+ * The signature `(module, principal) => Promise<Headers>` is exactly
19
+ * `@velajs/testing`'s `ActingAsResolver`, so it plugs straight in:
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { actingAs } from '@velajs/better-auth/testing';
24
+ *
25
+ * // As the default resolver for the module:
26
+ * module.setAuthResolver(actingAs);
27
+ * await module.http.get('/me').actingAs({ email: 'ada@example.com' }).send();
28
+ *
29
+ * // Or passed per-request:
30
+ * await module.http.get('/me').actingAs({ id: existingUserId }, actingAs).send();
31
+ * ```
32
+ */ export async function actingAs(module, principal) {
33
+ const auth = module.get(BetterAuthService).auth;
34
+ const ctx = await auth.$context;
35
+ const internalAdapter = ctx.internalAdapter;
36
+ const id = typeof principal.id === 'string' ? principal.id : undefined;
37
+ const email = typeof principal.email === 'string' ? principal.email : undefined;
38
+ const name = typeof principal.name === 'string' ? principal.name : undefined;
39
+ // `findUserById`/`createUser` yield a bare user; `findUserByEmail` nests it
40
+ // under `{ user, accounts }` — normalize to the id we need.
41
+ let user = null;
42
+ if (id) user = await internalAdapter.findUserById(id);
43
+ if (!user && email) {
44
+ const found = await internalAdapter.findUserByEmail(email);
45
+ user = found?.user ?? null;
46
+ }
47
+ if (!user) {
48
+ if (!email) {
49
+ throw new Error('actingAs: principal must carry an `email` (to create a user) or an ' + '`id` matching an existing user.');
50
+ }
51
+ const { id: _id, email: _email, name: _name, ...extra } = principal;
52
+ user = await internalAdapter.createUser({
53
+ ...extra,
54
+ email,
55
+ name: name ?? email,
56
+ ...id ? {
57
+ id
58
+ } : {}
59
+ });
60
+ }
61
+ const session = await internalAdapter.createSession(user.id, false, {
62
+ ipAddress: '127.0.0.1',
63
+ userAgent: 'vela-test'
64
+ });
65
+ const cookieName = ctx.authCookies.sessionToken.name;
66
+ const signedToken = `${session.token}.${await makeSignature(session.token, ctx.secret)}`;
67
+ const headers = new Headers();
68
+ headers.set('Cookie', `${cookieName}=${signedToken}`);
69
+ return headers;
70
+ }
@@ -0,0 +1,2 @@
1
+ export { actingAs } from './acting-as';
2
+ export type { ActingAsPrincipal, TestModuleLike } from './acting-as';
@@ -0,0 +1,3 @@
1
+ // `@velajs/better-auth/testing` — test-only helpers. Kept in a separate subpath
2
+ // so nothing here is pulled into the runtime surface of `@velajs/better-auth`.
3
+ export { actingAs } from "./acting-as.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@velajs/better-auth",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "better-auth integration for the Vela framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,6 +9,10 @@
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
+ },
13
+ "./testing": {
14
+ "types": "./dist/testing/index.d.ts",
15
+ "import": "./dist/testing/index.js"
12
16
  }
13
17
  },
14
18
  "files": [