@ingram-tech/nk-auth 0.15.0 → 0.16.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.
package/README.md CHANGED
@@ -114,10 +114,21 @@ const db = await createTestDb({
114
114
 
115
115
  **Upgrading better-auth** never means hand-writing a migration in your app: a
116
116
  schema-changing upgrade ships as a new file in nk-auth's chain, so you bump the
117
- dependency and your next migrate applies it. Reconcile the shipped schema against
118
- a pinned `better-auth` with `npx @better-auth/cli generate` (a maintainer task,
117
+ dependency and your next migrate applies it. The chain is kept honest by
118
+ `src/migrations.test.ts`, which diffs the applied chain against the schema the
119
+ pinned `better-auth` asks for (`getAuthTables`) — a bump that adds a column fails
120
+ that test until the delta is shipped as the next `000N_*.sql` (a maintainer task,
119
121
  done once in this package).
120
122
 
123
+ One delta needs a word: `0002_better_auth_1_7` backfills the `account.issuer`
124
+ column Better Auth 1.7 keys accounts on, with the exact value 1.7 writes per
125
+ provider (`local:credential`, `https://accounts.google.com`,
126
+ `local:oauth:<providerId>`, …). A provider whose issuer is per-tenant or
127
+ discovered at runtime (`microsoft`, `cognito`, `paybin`, the generic-oauth
128
+ plugin) cannot be derived, so the migration refuses and names the `providerId`s;
129
+ set `issuer` on those rows by hand and re-run. Nothing to do on a site that only
130
+ has password and built-in social sign-in.
131
+
121
132
  > **Adopting from the old copy-in model?** Earlier versions told you to `cp` the
122
133
  > baseline into your own `drizzle/` chain. If you already did, keep that file
123
134
  > (deleting an applied migration causes journal drift) and just add the auth-chain
@@ -0,0 +1,93 @@
1
+ -- @ingram-tech/nk-auth — Better Auth 1.7 schema delta (better-auth ^1.7.2).
2
+ --
3
+ -- Better Auth 1.7 keys an account on (issuer, accountId) instead of
4
+ -- (providerId, accountId): every account row now carries the identity
5
+ -- namespace it was verified under, and all OAuth sign-in / linking lookups go
6
+ -- through that pair (`findAccountOwnerByKey`, `findAccountByKey`). The `jwt`
7
+ -- plugin also gained key rotation, which needs three nullable columns on `jwks`.
8
+ --
9
+ -- The rows that exist before this file runs were written by 1.6, which never
10
+ -- populated `issuer`, so this delta BACKFILLS it with exactly the value 1.7.2
11
+ -- would have written for that provider — otherwise every returning OAuth user
12
+ -- looks like a new identity. The rules, read off better-auth 1.7.2 itself:
13
+ -- - `credential` (email + password, and the otp / phone / admin plugins) →
14
+ -- `local:credential` (core's createLocalAccountIssuer).
15
+ -- - A built-in social provider that declares a fixed `accountIssuer` → that
16
+ -- issuer verbatim (google, apple, facebook, line).
17
+ -- - Any other built-in social provider → `local:oauth:<providerId>` (core's
18
+ -- createOAuthAccountIssuer; the ids are plain slugs, so percent-encoding is
19
+ -- the identity).
20
+ -- Providers whose issuer is per-tenant or discovered at runtime (microsoft →
21
+ -- the token's `iss`, cognito → the user pool URL, paybin, the generic-oauth
22
+ -- plugin) cannot be derived here, so the migration REFUSES to guess: it raises
23
+ -- naming the unmapped providerIds and rolls back. Backfill those by hand with
24
+ -- the issuer your provider config resolves to, then re-run the migrate.
25
+ --
26
+ -- The unique index is what 1.7 relies on for account identity. If it fails to
27
+ -- build, the database already holds two accounts for one (issuer, accountId)
28
+ -- pair — resolve those duplicates rather than dropping the index.
29
+ --
30
+ -- Append-only: this file is hashed by the runner and must never be edited once
31
+ -- shipped. The next better-auth schema change goes in 0003.
32
+
33
+ alter table "public"."account" add column if not exists "issuer" text;
34
+ --> statement-breakpoint
35
+ update "public"."account" set "issuer" = case "providerId"
36
+ when 'credential' then 'local:credential'
37
+ when 'google' then 'https://accounts.google.com'
38
+ when 'apple' then 'https://appleid.apple.com'
39
+ when 'facebook' then 'https://www.facebook.com'
40
+ when 'line' then 'https://access.line.me'
41
+ when 'atlassian' then 'local:oauth:atlassian'
42
+ when 'discord' then 'local:oauth:discord'
43
+ when 'dropbox' then 'local:oauth:dropbox'
44
+ when 'figma' then 'local:oauth:figma'
45
+ when 'github' then 'local:oauth:github'
46
+ when 'gitlab' then 'local:oauth:gitlab'
47
+ when 'huggingface' then 'local:oauth:huggingface'
48
+ when 'kakao' then 'local:oauth:kakao'
49
+ when 'kick' then 'local:oauth:kick'
50
+ when 'linear' then 'local:oauth:linear'
51
+ when 'linkedin' then 'local:oauth:linkedin'
52
+ when 'naver' then 'local:oauth:naver'
53
+ when 'notion' then 'local:oauth:notion'
54
+ when 'paypal' then 'local:oauth:paypal'
55
+ when 'polar' then 'local:oauth:polar'
56
+ when 'railway' then 'local:oauth:railway'
57
+ when 'reddit' then 'local:oauth:reddit'
58
+ when 'roblox' then 'local:oauth:roblox'
59
+ when 'salesforce' then 'local:oauth:salesforce'
60
+ when 'slack' then 'local:oauth:slack'
61
+ when 'spotify' then 'local:oauth:spotify'
62
+ when 'tiktok' then 'local:oauth:tiktok'
63
+ when 'twitch' then 'local:oauth:twitch'
64
+ when 'twitter' then 'local:oauth:twitter'
65
+ when 'vercel' then 'local:oauth:vercel'
66
+ when 'vk' then 'local:oauth:vk'
67
+ when 'wechat' then 'local:oauth:wechat'
68
+ when 'zoom' then 'local:oauth:zoom'
69
+ end where "issuer" is null;
70
+ --> statement-breakpoint
71
+ do $$
72
+ declare
73
+ unmapped text;
74
+ begin
75
+ select string_agg(distinct "providerId", ', ') into unmapped
76
+ from "public"."account" where "issuer" is null;
77
+ if unmapped is not null then
78
+ raise exception 'nk-auth 0002_better_auth_1_7: cannot derive account.issuer for providerId(s): %. Better Auth 1.7 keys accounts on (issuer, accountId) and these providers use a per-tenant or discovered issuer this migration cannot know. Set "issuer" on those rows by hand (the value your provider config resolves to), then re-run the migrate.', unmapped;
79
+ end if;
80
+ end $$;
81
+ --> statement-breakpoint
82
+ alter table "public"."account" alter column "issuer" set not null;
83
+ --> statement-breakpoint
84
+ create unique index if not exists "account_issuer_accountId_uidx" on "public"."account" ("issuer", "accountId");
85
+ --> statement-breakpoint
86
+ -- `jwt` plugin key rotation (1.7): per-key expiry + the algorithm/curve the
87
+ -- JWKS endpoint advertises. Nullable — a pre-rotation key falls back to the
88
+ -- plugin's configured defaults.
89
+ alter table "public"."jwks" add column if not exists "expiresAt" timestamptz;
90
+ --> statement-breakpoint
91
+ alter table "public"."jwks" add column if not exists "alg" text;
92
+ --> statement-breakpoint
93
+ alter table "public"."jwks" add column if not exists "crv" text;
@@ -8,6 +8,13 @@
8
8
  "when": 1735689600000,
9
9
  "tag": "0001_better_auth",
10
10
  "breakpoints": true
11
+ },
12
+ {
13
+ "idx": 1,
14
+ "version": "7",
15
+ "when": 1756598400000,
16
+ "tag": "0002_better_auth_1_7",
17
+ "breakpoints": true
11
18
  }
12
19
  ]
13
20
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingram-tech/nk-auth",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "The Ingram Better Auth foundation: composable presets (org, dual-shape JWT, active-org hooks, pg pool) for Next.js sites.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -68,14 +68,14 @@
68
68
  "test": "vitest run"
69
69
  },
70
70
  "dependencies": {
71
- "@ingram-tech/nk-db": "^2.1.1",
71
+ "@ingram-tech/nk-db": "^2.1.2",
72
72
  "bcrypt": "^6.0.0",
73
- "jose": "^6.2.9",
74
- "zod": "^4.4.3"
73
+ "jose": "^6.2.10",
74
+ "zod": "^4.5.4"
75
75
  },
76
76
  "peerDependencies": {
77
- "@better-auth/passkey": "^1.6.15",
78
- "better-auth": "^1.6.15",
77
+ "@better-auth/passkey": "^1.7.2",
78
+ "better-auth": "^1.7.2",
79
79
  "next": "^15.0.0 || ^16.0.0",
80
80
  "pg": "^8.13.0",
81
81
  "react": "^18.0.0 || ^19.0.0"
@@ -95,17 +95,17 @@
95
95
  }
96
96
  },
97
97
  "devDependencies": {
98
- "@better-auth/passkey": "^1.7.0",
99
- "@ingram-tech/nk-dev": "0.14.0",
98
+ "@better-auth/passkey": "^1.7.2",
99
+ "@ingram-tech/nk-dev": "0.14.1",
100
100
  "@types/bcrypt": "^6.0.0",
101
- "@types/node": "^26.2.0",
101
+ "@types/node": "^26.4.0",
102
102
  "@types/pg": "^8.23.1",
103
103
  "@types/react": "^19.2.18",
104
- "better-auth": "^1.7.0",
105
- "next": "^16.3.1",
104
+ "better-auth": "^1.7.2",
105
+ "next": "^16.3.3",
106
106
  "pg": "^8.23.0",
107
107
  "react": "^19.2.8",
108
108
  "typescript": "^7.0.2",
109
- "vitest": "^4.1.10"
109
+ "vitest": "^4.1.11"
110
110
  }
111
111
  }