@absolutejs/auth 0.80.0 → 0.80.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/CHANGELOG.md CHANGED
@@ -6,6 +6,12 @@ This file is generated by `absolute-changelog` from the entries in
6
6
  `changelog/`. Edit an entry, not this file — and add new ones under
7
7
  `changelog/unreleased/`.
8
8
 
9
+ ## 0.80.1 — 2026-09-22
10
+
11
+ ### Fixed
12
+
13
+ - **Document verified persistent credentials integration and correct Drizzle and migration APIs**
14
+
9
15
  ## 0.80.0 — 2026-09-22
10
16
 
11
17
  ### Added
package/README.md CHANGED
@@ -440,3 +440,5 @@ Studio's `absolute-auth setup` reads the selected adapter from
440
440
  migrations and warns that sessions reset on restart. The Neon adapter requires
441
441
  a real `DATABASE_URL` and runs migrations. Missing or unknown selections fail
442
442
  with an actionable error; custom adapters must configure their own migrations.
443
+
444
+ For a complete credentials-only Bun setup, see [Persistent email/password sign-in](docs/PERSISTENT-CREDENTIALS.md). It includes real migration and auth configuration APIs, durable user records, and driver settings.
package/changelog.json CHANGED
@@ -2,6 +2,16 @@
2
2
  "contract": 1,
3
3
  "name": "@absolutejs/auth",
4
4
  "releases": [
5
+ {
6
+ "changes": [
7
+ {
8
+ "kind": "fixed",
9
+ "summary": "Document verified persistent credentials integration and correct Drizzle and migration APIs"
10
+ }
11
+ ],
12
+ "date": "2026-09-22",
13
+ "version": "0.80.1"
14
+ },
5
15
  {
6
16
  "changes": [
7
17
  {
@@ -0,0 +1,103 @@
1
+ # Persistent email/password sign-in (Bun + Elysia 2)
2
+
3
+ Use this credentials-only setup instead of the social-login manifest recipe.
4
+ The same API pattern passed synthetic browser signup, login, logout, booking and
5
+ full-container restart tests in Studio using auth 0.80.0. The example deliberately
6
+ sends no email and refuses production. For a real business configure email
7
+ verification, delivery, password policy, backups and the application's user schema.
8
+
9
+ Install published auth and a compatible Drizzle release. Set AUTH_DATABASE_URL
10
+ securely to a real isolated PostgreSQL database; never substitute a placeholder.
11
+ The application owns user records. The auth package owns credentials and sessions.
12
+
13
+ ```ts
14
+ import { auth } from '@absolutejs/auth/server';
15
+ import { createPostgresAuthSessionStore, createPostgresCredentialStore, runMigrations } from '@absolutejs/auth';
16
+ import { SQL } from 'bun';
17
+ import { Database } from 'bun:sqlite';
18
+ import { drizzle } from 'drizzle-orm/bun-sql';
19
+ import { mkdirSync } from 'node:fs';
20
+
21
+ if (process.env.NODE_ENV === 'production') throw new Error('Synthetic example: configure verified email and real business policy before production');
22
+ type Customer = { id: string; email: string };
23
+ const databaseUrl = process.env.AUTH_DATABASE_URL;
24
+ if (!databaseUrl)
25
+ throw new Error(
26
+ "AUTH_DATABASE_URL must point to the isolated acceptance database",
27
+ );
28
+ const migrationClient = new SQL({ url: databaseUrl, max: 1, prepare: false });
29
+ try {
30
+ await runMigrations({
31
+ blocks: ["sessions", "credentials"],
32
+ client: {
33
+ query: async (text, values) => ({
34
+ rows: await migrationClient.unsafe(text, values ? [...values] : []),
35
+ }),
36
+ },
37
+ log: () => undefined,
38
+ });
39
+ } finally {
40
+ await migrationClient.close();
41
+ }
42
+ const authDb = drizzle({ client: new SQL(databaseUrl) });
43
+ const decodeCustomer = (value: unknown): Customer => {
44
+ if (typeof value !== "object" || value === null)
45
+ throw new Error("Invalid customer session");
46
+ const id: unknown = Reflect.get(value, "id");
47
+ const email: unknown = Reflect.get(value, "email");
48
+ if (typeof id !== "string" || typeof email !== "string")
49
+ throw new Error("Invalid customer session");
50
+ return { id, email };
51
+ };
52
+ mkdirSync(".data", { recursive: true });
53
+ const db = new Database(".data/customer-example.sqlite", { create: true });
54
+ db.exec(
55
+ "PRAGMA journal_mode=WAL; PRAGMA busy_timeout=5000; CREATE TABLE IF NOT EXISTS customers(id TEXT PRIMARY KEY, email TEXT NOT NULL UNIQUE);",
56
+ );
57
+ const userById = db.query<Customer, [string]>(
58
+ "SELECT id,email FROM customers WHERE id=?",
59
+ );
60
+ const userByEmail = db.query<Customer, [string]>(
61
+ "SELECT id,email FROM customers WHERE email=?",
62
+ );
63
+ const insertUser = db.query("INSERT INTO customers(id,email) VALUES(?,?)");
64
+ const sessions = createPostgresAuthSessionStore(authDb, decodeCustomer);
65
+ export const authentication = await auth<Customer>({
66
+ providersConfiguration: {},
67
+ getUser: (id) => userById.get(String(id)) ?? null,
68
+ authSessionStore: sessions,
69
+ cookieSecure: true,
70
+ credentials: {
71
+ credentialStore: createPostgresCredentialStore(authDb),
72
+ getUserByEmail: (email) => userByEmail.get(email) ?? null,
73
+ onCreateCredentialUser: ({ email }) => {
74
+ const user = { id: crypto.randomUUID(), email };
75
+ insertUser.run(user.id, email);
76
+ return user;
77
+ },
78
+ // Local synthetic mode deliberately delivers no messages.
79
+ onSendEmail: () => undefined,
80
+ requireEmailVerification: false,
81
+ passwordPolicy: { minLength: 12, checkBreaches: false },
82
+ },
83
+ });
84
+
85
+ ```
86
+
87
+ Important API details:
88
+
89
+ - `auth` is asynchronous and comes from `@absolutejs/auth/server`.
90
+ - `authSessionStore` is top-level. `credentialStore` and credential callbacks
91
+ belong inside `credentials`. There is no top-level `sessionStore` option.
92
+ - Stores do not have `.runMigrations()`. Import `runMigrations` from the package
93
+ root and supply its query client as shown above.
94
+ - With Drizzle 1's Bun driver use `drizzle({ client })`, not `drizzle(client)`.
95
+ - Keep `prepare: false` on the migration client only. Application queries need
96
+ Bun's default prepared mode to encode JSON session data correctly.
97
+ - The built-in sign-out route is `DELETE /oauth2/signout`.
98
+ - Use `createAuthContext<Customer>()` from `/server` to read typed authenticated
99
+ users. Business APIs must check the session server-side and scope records to
100
+ that user. Do not implement a second password or cookie system.
101
+ - Preserve cookie headers when exposing a narrow typed JSON wrapper around the
102
+ package's configurable credential routes. Never store session tokens in browser
103
+ localStorage. Browser business requests belong in typed Eden + React Query.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.80.0",
2
+ "version": "0.80.1",
3
3
  "name": "@absolutejs/auth",
4
4
  "description": "An authorization library for absolutejs",
5
5
  "repository": {