@payload-auth-link/migrate 0.4.3 → 0.5.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/LICENSE +21 -0
- package/README.md +7 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +103 -19
- package/dist/cli.js.map +1 -1
- package/dist/doctor/database.d.ts.map +1 -1
- package/dist/doctor/database.js +31 -4
- package/dist/doctor/database.js.map +1 -1
- package/dist/doctor/run-doctor.d.ts.map +1 -1
- package/dist/doctor/run-doctor.js +67 -0
- package/dist/doctor/run-doctor.js.map +1 -1
- package/dist/doctor/types.d.ts +12 -0
- package/dist/doctor/types.d.ts.map +1 -1
- package/dist/doctor/users.d.ts.map +1 -1
- package/dist/doctor/users.js +20 -4
- package/dist/doctor/users.js.map +1 -1
- package/dist/importer/apply.d.ts +23 -5
- package/dist/importer/apply.d.ts.map +1 -1
- package/dist/importer/apply.js +154 -178
- package/dist/importer/apply.js.map +1 -1
- package/dist/importer/host-writes.d.ts +47 -0
- package/dist/importer/host-writes.d.ts.map +1 -0
- package/dist/importer/host-writes.js +198 -0
- package/dist/importer/host-writes.js.map +1 -0
- package/dist/importer/lifecycle.d.ts +24 -0
- package/dist/importer/lifecycle.d.ts.map +1 -1
- package/dist/importer/lifecycle.js +104 -22
- package/dist/importer/lifecycle.js.map +1 -1
- package/dist/importer/prelink.d.ts +55 -0
- package/dist/importer/prelink.d.ts.map +1 -0
- package/dist/importer/prelink.js +152 -0
- package/dist/importer/prelink.js.map +1 -0
- package/dist/importer/run-import.d.ts +13 -0
- package/dist/importer/run-import.d.ts.map +1 -1
- package/dist/importer/run-import.js +147 -14
- package/dist/importer/run-import.js.map +1 -1
- package/dist/importer/source.d.ts +35 -7
- package/dist/importer/source.d.ts.map +1 -1
- package/dist/importer/source.js +37 -6
- package/dist/importer/source.js.map +1 -1
- package/dist/importer/types.d.ts +26 -4
- package/dist/importer/types.d.ts.map +1 -1
- package/dist/importer/types.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/private-file.d.ts +8 -0
- package/dist/private-file.d.ts.map +1 -0
- package/dist/private-file.js +19 -0
- package/dist/private-file.js.map +1 -0
- package/package.json +6 -6
- package/src/cli.ts +111 -9
- package/src/doctor/database.ts +36 -4
- package/src/doctor/run-doctor.ts +69 -0
- package/src/doctor/types.ts +12 -0
- package/src/doctor/users.ts +23 -4
- package/src/importer/apply.ts +186 -180
- package/src/importer/host-writes.ts +231 -0
- package/src/importer/lifecycle.ts +126 -24
- package/src/importer/prelink.ts +228 -0
- package/src/importer/run-import.ts +196 -29
- package/src/importer/source.ts +72 -14
- package/src/importer/types.ts +27 -4
- package/src/index.ts +13 -1
- package/src/private-file.ts +18 -0
package/dist/doctor/users.js
CHANGED
|
@@ -83,6 +83,14 @@ export function localStrategyOn(collection) {
|
|
|
83
83
|
}
|
|
84
84
|
return isRecord(auth) ? auth.disableLocalStrategy !== true : false;
|
|
85
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* The payload-auth-link plugin's own auth strategy name
|
|
88
|
+
* (`packages/plugin/src/strategy.ts`). A users collection carrying it
|
|
89
|
+
* has ALREADY been through `authLink` — its identities/linkable/…
|
|
90
|
+
* fields are the plugin's own injections, not host collisions
|
|
91
|
+
* (issue #88: the doctor run against the TARGET config).
|
|
92
|
+
*/
|
|
93
|
+
const pluginStrategyName = 'auth-link';
|
|
86
94
|
export function analyzeUsersCollection(collection, rolesFieldName) {
|
|
87
95
|
if (collection === null) {
|
|
88
96
|
return {
|
|
@@ -95,10 +103,18 @@ export function analyzeUsersCollection(collection, rolesFieldName) {
|
|
|
95
103
|
const fields = fieldList(collection);
|
|
96
104
|
const issues = [];
|
|
97
105
|
const notes = [];
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
106
|
+
// On the target config the plugin already injected these fields:
|
|
107
|
+
// they are its own, never a collision (issue #88).
|
|
108
|
+
const pluginInstalled = strategiesOf(collection).includes(pluginStrategyName);
|
|
109
|
+
const collisions = pluginInstalled
|
|
110
|
+
? []
|
|
111
|
+
: fields
|
|
112
|
+
.map(fieldName)
|
|
113
|
+
.filter((name) => name !== null)
|
|
114
|
+
.filter((name) => injectedFieldNames.has(name));
|
|
115
|
+
if (pluginInstalled) {
|
|
116
|
+
notes.push('payload-auth-link is already installed on this collection (its auth-link strategy is present): the injected fields are the plugin’s own');
|
|
117
|
+
}
|
|
102
118
|
let roleField = null;
|
|
103
119
|
const roleCandidates = fields.filter((field) => {
|
|
104
120
|
const name = fieldName(field);
|
package/dist/doctor/users.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/doctor/users.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/doctor/users.ts"],"names":[],"mappings":"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"}
|
package/dist/importer/apply.d.ts
CHANGED
|
@@ -1,21 +1,32 @@
|
|
|
1
1
|
import type { Payload } from 'payload';
|
|
2
|
-
import { type
|
|
2
|
+
import { type SourceUser } from './source.js';
|
|
3
|
+
import { type ImportManifest, type ImportResult, type PlanRow, type Unmappable } from './types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Apply side (issue #50): copy payload-auth rows into the
|
|
5
6
|
* payload-auth-link collections through the Payload Local API.
|
|
6
7
|
*
|
|
7
8
|
* - Password hashes, OAuth tokens, API-key hashes, and jwks carry over
|
|
8
9
|
* VERBATIM (payload-auth used Better Auth's own hashing).
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
10
|
+
* - Row timestamps (`createdAt`/`updatedAt`) carry from the source rows
|
|
11
|
+
* for every model whose source table has them (issue #88).
|
|
12
|
+
* - Better Auth plugin user state carries (issue #88): admin-plugin
|
|
13
|
+
* `banned`/`banReason`/`banExpires`/`role` and the anonymous plugin's
|
|
14
|
+
* `isAnonymous`, whenever the source has the column AND the target
|
|
15
|
+
* `ba-users` collection declares the field. A banned or anonymous
|
|
16
|
+
* source user whose state the target cannot hold is UNMAPPABLE — the
|
|
17
|
+
* run aborts before writing; a banned user never imports unbanned.
|
|
18
|
+
* - `linkable` + `linkableEmail` are granted from VERIFIED emails only
|
|
19
|
+
* (grant-only: an existing proof is never revoked); unverified users
|
|
20
|
+
* are reported by the plan, never linked.
|
|
11
21
|
* - Sessions default to `carry` so nobody is logged out: the carried
|
|
12
22
|
* rows keep their tokens, and with the same `advanced.cookiePrefix`
|
|
13
23
|
* the existing cookies keep working.
|
|
14
24
|
* - Idempotent and resumable: every target row carries a deterministic
|
|
15
25
|
* `baId` derived from the source id (`acct-<source id>`), so a
|
|
16
26
|
* re-run after a crash finds its own earlier rows and skips them.
|
|
17
|
-
* - Every created row and every field write lands in the
|
|
18
|
-
*
|
|
27
|
+
* - Every created row and every host field write lands in the
|
|
28
|
+
* manifest — the FIRST captured prior value per field wins, sealed —
|
|
29
|
+
* so `rollback` is exact and the source tables stay untouched.
|
|
19
30
|
*/
|
|
20
31
|
export type ApplyOptions = {
|
|
21
32
|
readonly payload: Payload;
|
|
@@ -38,6 +49,13 @@ export type ApplyOptions = {
|
|
|
38
49
|
readonly now?: () => Date;
|
|
39
50
|
readonly log?: (message: string) => void;
|
|
40
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Plugin user state the target must be able to hold (issue #88),
|
|
54
|
+
* checked BEFORE any write: a banned user whose target has no `banned`
|
|
55
|
+
* field would import unbanned; an anonymous user without `isAnonymous`
|
|
56
|
+
* would import as a full account.
|
|
57
|
+
*/
|
|
58
|
+
export declare function pluginStateUnmappable(users: readonly SourceUser[], targetFields: ReadonlySet<string>, targetSlug: string): Unmappable[];
|
|
41
59
|
export declare function applyImport(options: ApplyOptions): Promise<ImportResult>;
|
|
42
60
|
/** Collapse per-row plan entries into one line per model (dry-run print). */
|
|
43
61
|
export declare function summarizePlanRows(rows: readonly PlanRow[]): PlanRow[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/importer/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/importer/apply.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAEtC,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAOL,KAAK,cAAc,EAEnB,KAAK,YAAY,EACjB,KAAK,OAAO,EACZ,KAAK,UAAU,EAChB,MAAM,YAAY,CAAA;AAEnB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAA;IACvC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IACnC,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAA;IACxC,kEAAkE;IAClE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACvD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7D;;;OAGG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAA;IAC3E,4DAA4D;IAC5D,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;CACzC,CAAA;AAsDD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,EACjC,UAAU,EAAE,MAAM,GACjB,UAAU,EAAE,CAmBd;AAmGD,wBAAsB,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CA+f9E;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,CAerE"}
|
package/dist/importer/apply.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { capturedKeys, captureBefore } from './host-writes.js';
|
|
1
2
|
import { readFlatRows, openSource, readSourceUsers, } from './source.js';
|
|
2
3
|
import { defaultTargetSlugs, resolveSourceTables, } from './types.js';
|
|
3
4
|
const slugsOf = (overrides) => ({
|
|
@@ -14,14 +15,80 @@ function numberOrNull(value) {
|
|
|
14
15
|
const numeric = typeof value === 'number' ? value : Number(value);
|
|
15
16
|
return Number.isFinite(numeric) ? numeric : undefined;
|
|
16
17
|
}
|
|
18
|
+
/** The source row's timestamps, when its layout has them (issue #88). */
|
|
19
|
+
function stamps(row) {
|
|
20
|
+
return {
|
|
21
|
+
...(row.created_at instanceof Date ? { createdAt: row.created_at.toISOString() } : {}),
|
|
22
|
+
...(row.updated_at instanceof Date ? { updatedAt: row.updated_at.toISOString() } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const timestampColumns = ['created_at', 'updated_at'];
|
|
17
26
|
/**
|
|
18
27
|
* Rows for one mapped model. A `null` mapping records the model as
|
|
19
28
|
* not installed (issue #68) — no read, no rows; anything else goes
|
|
20
29
|
* through the strict `readFlatRows` (a missing mapped table throws;
|
|
21
|
-
* the probe aborts the run first).
|
|
30
|
+
* the probe aborts the run first). Row timestamps are read when the
|
|
31
|
+
* layout has them.
|
|
22
32
|
*/
|
|
23
33
|
async function readMapped(client, table, columns) {
|
|
24
|
-
return table === null ? [] : readFlatRows(client, table, columns);
|
|
34
|
+
return table === null ? [] : readFlatRows(client, table, columns, timestampColumns);
|
|
35
|
+
}
|
|
36
|
+
/** Field names a target collection declares (top level, flattened). */
|
|
37
|
+
function targetFieldNames(payload, slug) {
|
|
38
|
+
const collection = payload.collections[slug];
|
|
39
|
+
const names = new Set();
|
|
40
|
+
for (const field of collection?.config.flattenedFields ?? []) {
|
|
41
|
+
names.add(field.name);
|
|
42
|
+
}
|
|
43
|
+
return names;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Plugin user state the target must be able to hold (issue #88),
|
|
47
|
+
* checked BEFORE any write: a banned user whose target has no `banned`
|
|
48
|
+
* field would import unbanned; an anonymous user without `isAnonymous`
|
|
49
|
+
* would import as a full account.
|
|
50
|
+
*/
|
|
51
|
+
export function pluginStateUnmappable(users, targetFields, targetSlug) {
|
|
52
|
+
const found = [];
|
|
53
|
+
for (const user of users) {
|
|
54
|
+
if (user.banned === true && !targetFields.has('banned')) {
|
|
55
|
+
found.push({
|
|
56
|
+
model: 'user',
|
|
57
|
+
key: user.id,
|
|
58
|
+
reason: `user #${user.id} is banned on the source, but '${targetSlug}' declares no 'banned' field — add Better Auth's admin() plugin to the engine (autoDeclare derives banned/banReason/banExpires) so the ban carries`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (user.isAnonymous === true && !targetFields.has('isAnonymous')) {
|
|
62
|
+
found.push({
|
|
63
|
+
model: 'user',
|
|
64
|
+
key: user.id,
|
|
65
|
+
reason: `user #${user.id} is anonymous on the source, but '${targetSlug}' declares no 'isAnonymous' field — add Better Auth's anonymous() plugin to the engine, or remove anonymous users before importing`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return found;
|
|
70
|
+
}
|
|
71
|
+
/** Plugin user state carried onto the ba-users row (issue #88). */
|
|
72
|
+
function pluginUserState(user, targetFields) {
|
|
73
|
+
const state = {};
|
|
74
|
+
if (user.banned !== null && targetFields.has('banned')) {
|
|
75
|
+
state.banned = user.banned;
|
|
76
|
+
}
|
|
77
|
+
if (user.banReason !== null && targetFields.has('banReason')) {
|
|
78
|
+
state.banReason = user.banReason;
|
|
79
|
+
}
|
|
80
|
+
if (user.banExpires !== null && targetFields.has('banExpires')) {
|
|
81
|
+
state.banExpires = user.banExpires.toISOString();
|
|
82
|
+
}
|
|
83
|
+
if (user.isAnonymous !== null && targetFields.has('isAnonymous')) {
|
|
84
|
+
state.isAnonymous = user.isAnonymous;
|
|
85
|
+
}
|
|
86
|
+
// Better Auth's admin plugin stores roles as one comma-separated
|
|
87
|
+
// string; payload-auth kept them in the users_role child table.
|
|
88
|
+
if (user.roles.length > 0 && targetFields.has('role')) {
|
|
89
|
+
state.role = user.roles.join(',');
|
|
90
|
+
}
|
|
91
|
+
return state;
|
|
25
92
|
}
|
|
26
93
|
/** Find an existing target row by `baId` — the resumable dedupe key. */
|
|
27
94
|
async function findByBaId(payload, collection, baId) {
|
|
@@ -53,19 +120,6 @@ async function createDeduped(payload, collection, baId, data, created, sourceKey
|
|
|
53
120
|
}
|
|
54
121
|
return true;
|
|
55
122
|
}
|
|
56
|
-
/** Capture a host field's current value for the rollback manifest. */
|
|
57
|
-
async function captureBefore(payload, hostId, field) {
|
|
58
|
-
const doc = await payload.findByID({
|
|
59
|
-
collection: 'users',
|
|
60
|
-
id: hostId,
|
|
61
|
-
depth: 0,
|
|
62
|
-
overrideAccess: true,
|
|
63
|
-
});
|
|
64
|
-
if (typeof doc !== 'object' || doc === null || !(field in doc)) {
|
|
65
|
-
return null;
|
|
66
|
-
}
|
|
67
|
-
return JSON.stringify(doc[field] ?? null);
|
|
68
|
-
}
|
|
69
123
|
/**
|
|
70
124
|
* The identity rows pre-populated on the host user (issue #69): ONE
|
|
71
125
|
* `better-auth` identity per imported user, `providerUserId` set to
|
|
@@ -100,7 +154,12 @@ export async function applyImport(options) {
|
|
|
100
154
|
const sourceTables = resolveSourceTables(options.sourceTables);
|
|
101
155
|
const created = [...(options.manifest?.created ?? [])];
|
|
102
156
|
const fieldWrites = [...(options.manifest?.fieldWrites ?? [])];
|
|
103
|
-
|
|
157
|
+
// First capture wins (issue #88): fields captured by an earlier pass
|
|
158
|
+
// keep their pre-import value.
|
|
159
|
+
const captured = capturedKeys(fieldWrites);
|
|
160
|
+
// Per-PASS totals (issue #88): a re-apply reports what this pass
|
|
161
|
+
// planned, never the sum of every pass.
|
|
162
|
+
const totals = {};
|
|
104
163
|
const planRows = [];
|
|
105
164
|
const unmappable = [];
|
|
106
165
|
let createdCount = 0;
|
|
@@ -112,6 +171,20 @@ export async function applyImport(options) {
|
|
|
112
171
|
const client = await openSource(sourceConnectionString);
|
|
113
172
|
try {
|
|
114
173
|
const users = await readSourceUsers(client, sourceTables);
|
|
174
|
+
const baUserFields = targetFieldNames(payload, slugs.user);
|
|
175
|
+
// --- 0. target-capability gate (issue #88) ---------------------------
|
|
176
|
+
// Runs before ANY write: plugin state the target cannot hold aborts
|
|
177
|
+
// the run instead of importing a banned user unbanned.
|
|
178
|
+
const blocked = pluginStateUnmappable(users, baUserFields, slugs.user);
|
|
179
|
+
if (blocked.length > 0) {
|
|
180
|
+
log(`ABORT: ${blocked.length} user(s) carry state the target cannot hold; nothing was written`);
|
|
181
|
+
return {
|
|
182
|
+
created: 0,
|
|
183
|
+
skipped: 0,
|
|
184
|
+
fieldWrites: 0,
|
|
185
|
+
plan: { rows: [], unmappable: blocked, sessions, warnings: [] },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
115
188
|
const seenUsers = new Set();
|
|
116
189
|
// --- 1. ba-users + host field writes ---------------------------------
|
|
117
190
|
for (const user of users) {
|
|
@@ -128,6 +201,7 @@ export async function applyImport(options) {
|
|
|
128
201
|
name: user.name ?? '',
|
|
129
202
|
emailVerified: user.emailVerified,
|
|
130
203
|
...(user.image === null ? {} : { image: user.image }),
|
|
204
|
+
...pluginUserState(user, baUserFields),
|
|
131
205
|
createdAt: user.createdAt.toISOString(),
|
|
132
206
|
updatedAt: user.updatedAt.toISOString(),
|
|
133
207
|
}, created, `user:${baId}`)
|
|
@@ -141,30 +215,32 @@ export async function applyImport(options) {
|
|
|
141
215
|
}
|
|
142
216
|
// Host-side writes on the EXISTING Payload user (the source
|
|
143
217
|
// layout's user id IS the host id): identities, roles, and the
|
|
144
|
-
// verified-email linking proof.
|
|
145
|
-
// rollback
|
|
218
|
+
// verified-email linking proof. The prior values (and the
|
|
219
|
+
// doc's updatedAt) are captured first — once — so rollback
|
|
220
|
+
// restores the pre-import document exactly.
|
|
146
221
|
const hostId = Number(baId);
|
|
147
222
|
if (Number.isSafeInteger(hostId)) {
|
|
223
|
+
const { present, newlyCaptured } = await captureBefore({
|
|
224
|
+
payload,
|
|
225
|
+
collection: 'users',
|
|
226
|
+
id: hostId,
|
|
227
|
+
fields: ['identities', 'roles', 'linkable', 'linkableEmail'],
|
|
228
|
+
captured,
|
|
229
|
+
into: fieldWrites,
|
|
230
|
+
});
|
|
231
|
+
fieldWriteCount += newlyCaptured;
|
|
148
232
|
const writes = {
|
|
149
233
|
identities: identityRows(user, now),
|
|
150
|
-
linkable: user.emailVerified,
|
|
151
234
|
};
|
|
152
|
-
|
|
153
|
-
for (const field of fields) {
|
|
154
|
-
fieldWrites.push({
|
|
155
|
-
collection: 'users',
|
|
156
|
-
id: hostId,
|
|
157
|
-
field,
|
|
158
|
-
before: await captureBefore(payload, hostId, field),
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
fieldWriteCount += fields.length;
|
|
162
|
-
if (user.roles.length > 0) {
|
|
235
|
+
if (user.roles.length > 0 && present.has('roles')) {
|
|
163
236
|
// Stored role values pass through unchanged (issue #56: the
|
|
164
237
|
// storage edge owns translation; the map is the app's).
|
|
165
238
|
writes.roles = user.roles;
|
|
166
239
|
}
|
|
167
240
|
if (user.emailVerified) {
|
|
241
|
+
// Grant-only: the proof is bound to the address (both
|
|
242
|
+
// fields), and an existing proof is never revoked here.
|
|
243
|
+
writes.linkable = true;
|
|
168
244
|
writes.linkableEmail = user.email;
|
|
169
245
|
}
|
|
170
246
|
await payload.update({
|
|
@@ -184,6 +260,24 @@ export async function applyImport(options) {
|
|
|
184
260
|
unmappable: [],
|
|
185
261
|
});
|
|
186
262
|
}
|
|
263
|
+
const tally = (model, sourceTable, target, isNew) => {
|
|
264
|
+
if (apply) {
|
|
265
|
+
if (isNew) {
|
|
266
|
+
createdCount += 1;
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
skippedCount += 1;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
record({
|
|
273
|
+
model,
|
|
274
|
+
sourceTable,
|
|
275
|
+
targetCollection: target,
|
|
276
|
+
rows: 1,
|
|
277
|
+
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
278
|
+
unmappable: [],
|
|
279
|
+
});
|
|
280
|
+
};
|
|
187
281
|
// --- 2. accounts (hashes verbatim) ------------------------------------
|
|
188
282
|
const accountsTable = sourceTables['accounts'];
|
|
189
283
|
for (const user of users) {
|
|
@@ -206,24 +300,15 @@ export async function applyImport(options) {
|
|
|
206
300
|
...(account.refreshTokenExpiresAt === null
|
|
207
301
|
? {}
|
|
208
302
|
: { refreshTokenExpiresAt: account.refreshTokenExpiresAt.toISOString() }),
|
|
303
|
+
...(account.createdAt === null
|
|
304
|
+
? {}
|
|
305
|
+
: { createdAt: account.createdAt.toISOString() }),
|
|
306
|
+
...(account.updatedAt === null
|
|
307
|
+
? {}
|
|
308
|
+
: { updatedAt: account.updatedAt.toISOString() }),
|
|
209
309
|
}, created, `account:${account.id}`)
|
|
210
310
|
: false;
|
|
211
|
-
|
|
212
|
-
if (isNew) {
|
|
213
|
-
createdCount += 1;
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
skippedCount += 1;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
record({
|
|
220
|
-
model: 'account',
|
|
221
|
-
sourceTable: accountsTable ?? 'accounts',
|
|
222
|
-
targetCollection: slugs.account,
|
|
223
|
-
rows: 1,
|
|
224
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
225
|
-
unmappable: [],
|
|
226
|
-
});
|
|
311
|
+
tally('account', accountsTable ?? 'accounts', slugs.account, isNew);
|
|
227
312
|
}
|
|
228
313
|
}
|
|
229
314
|
// --- 3. sessions (carry keeps every token) -----------------------------
|
|
@@ -236,8 +321,6 @@ export async function applyImport(options) {
|
|
|
236
321
|
'expires_at',
|
|
237
322
|
'ip_address',
|
|
238
323
|
'user_agent',
|
|
239
|
-
'created_at',
|
|
240
|
-
'updated_at',
|
|
241
324
|
]);
|
|
242
325
|
for (const row of rows) {
|
|
243
326
|
totals.session = (totals.session ?? 0) + 1;
|
|
@@ -255,30 +338,10 @@ export async function applyImport(options) {
|
|
|
255
338
|
...(textOrNull(row.user_agent) === undefined
|
|
256
339
|
? {}
|
|
257
340
|
: { userAgent: textOrNull(row.user_agent) }),
|
|
258
|
-
...(row
|
|
259
|
-
? { createdAt: row.created_at.toISOString() }
|
|
260
|
-
: {}),
|
|
261
|
-
...(row.updated_at instanceof Date
|
|
262
|
-
? { updatedAt: row.updated_at.toISOString() }
|
|
263
|
-
: {}),
|
|
341
|
+
...stamps(row),
|
|
264
342
|
}, created, `session:${String(row.id)}`)
|
|
265
343
|
: false;
|
|
266
|
-
|
|
267
|
-
if (isNew) {
|
|
268
|
-
createdCount += 1;
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
skippedCount += 1;
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
record({
|
|
275
|
-
model: 'session',
|
|
276
|
-
sourceTable: sessionsTable ?? 'sessions',
|
|
277
|
-
targetCollection: slugs.session,
|
|
278
|
-
rows: 1,
|
|
279
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
280
|
-
unmappable: [],
|
|
281
|
-
});
|
|
344
|
+
tally('session', sessionsTable ?? 'sessions', slugs.session, isNew);
|
|
282
345
|
}
|
|
283
346
|
}
|
|
284
347
|
// --- 4. verifications ---------------------------------------------------
|
|
@@ -297,24 +360,10 @@ export async function applyImport(options) {
|
|
|
297
360
|
identifier: String(row.identifier),
|
|
298
361
|
value: String(row.value),
|
|
299
362
|
expiresAt: row.expires_at instanceof Date ? row.expires_at.toISOString() : now().toISOString(),
|
|
363
|
+
...stamps(row),
|
|
300
364
|
}, created, `verification:${String(row.id)}`)
|
|
301
365
|
: false;
|
|
302
|
-
|
|
303
|
-
if (isNew) {
|
|
304
|
-
createdCount += 1;
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
skippedCount += 1;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
record({
|
|
311
|
-
model: 'verification',
|
|
312
|
-
sourceTable: verificationsTable ?? 'verifications',
|
|
313
|
-
targetCollection: slugs.verification,
|
|
314
|
-
rows: 1,
|
|
315
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
316
|
-
unmappable: [],
|
|
317
|
-
});
|
|
366
|
+
tally('verification', verificationsTable ?? 'verifications', slugs.verification, isNew);
|
|
318
367
|
}
|
|
319
368
|
// --- 5. api keys (hash, prefix, metadata, rate-limit state) --------------
|
|
320
369
|
const apiKeysTable = sourceTables['api_keys'];
|
|
@@ -325,8 +374,8 @@ export async function applyImport(options) {
|
|
|
325
374
|
'start',
|
|
326
375
|
'prefix',
|
|
327
376
|
'key',
|
|
328
|
-
// payload-auth stores the satellite's
|
|
329
|
-
//
|
|
377
|
+
// payload-auth stores the satellite's owner as reference_id — the
|
|
378
|
+
// same name @better-auth/api-key 1.7 uses (`referenceId`).
|
|
330
379
|
'reference_id',
|
|
331
380
|
'refill_interval',
|
|
332
381
|
'refill_amount',
|
|
@@ -352,9 +401,9 @@ export async function applyImport(options) {
|
|
|
352
401
|
...(textOrNull(row.start) === undefined ? {} : { start: textOrNull(row.start) }),
|
|
353
402
|
...(textOrNull(row.prefix) === undefined ? {} : { prefix: textOrNull(row.prefix) }),
|
|
354
403
|
key: String(row.key),
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
404
|
+
// @better-auth/api-key 1.7 names the owner `referenceId`;
|
|
405
|
+
// `userId` is offered for 1.6-era target schemas (Payload
|
|
406
|
+
// drops it where the collection has no such field).
|
|
358
407
|
userId: String(row.reference_id),
|
|
359
408
|
referenceId: String(row.reference_id),
|
|
360
409
|
...(numberOrNull(row.refill_interval) === undefined
|
|
@@ -394,24 +443,10 @@ export async function applyImport(options) {
|
|
|
394
443
|
...(textOrNull(row.metadata) === undefined
|
|
395
444
|
? {}
|
|
396
445
|
: { metadata: textOrNull(row.metadata) }),
|
|
446
|
+
...stamps(row),
|
|
397
447
|
}, created, `apikey:${String(row.id)}`)
|
|
398
448
|
: false;
|
|
399
|
-
|
|
400
|
-
if (isNew) {
|
|
401
|
-
createdCount += 1;
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
skippedCount += 1;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
record({
|
|
408
|
-
model: 'apikey',
|
|
409
|
-
sourceTable: apiKeysTable ?? 'api_keys',
|
|
410
|
-
targetCollection: slugs.apikey,
|
|
411
|
-
rows: 1,
|
|
412
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
413
|
-
unmappable: [],
|
|
414
|
-
});
|
|
449
|
+
tally('apikey', apiKeysTable ?? 'api_keys', slugs.apikey, isNew);
|
|
415
450
|
}
|
|
416
451
|
// --- 6. jwks --------------------------------------------------------------
|
|
417
452
|
const jwksTable = sourceTables['jwks'];
|
|
@@ -423,24 +458,10 @@ export async function applyImport(options) {
|
|
|
423
458
|
? await createDeduped(payload, slugs.jwks, baId, {
|
|
424
459
|
publicKey: String(row.public_key),
|
|
425
460
|
privateKey: String(row.private_key),
|
|
461
|
+
...stamps(row),
|
|
426
462
|
}, created, `jwks:${String(row.id)}`)
|
|
427
463
|
: false;
|
|
428
|
-
|
|
429
|
-
if (isNew) {
|
|
430
|
-
createdCount += 1;
|
|
431
|
-
}
|
|
432
|
-
else {
|
|
433
|
-
skippedCount += 1;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
record({
|
|
437
|
-
model: 'jwks',
|
|
438
|
-
sourceTable: jwksTable ?? 'jwks',
|
|
439
|
-
targetCollection: slugs.jwks,
|
|
440
|
-
rows: 1,
|
|
441
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
442
|
-
unmappable: [],
|
|
443
|
-
});
|
|
464
|
+
tally('jwks', jwksTable ?? 'jwks', slugs.jwks, isNew);
|
|
444
465
|
}
|
|
445
466
|
// --- 7. organization plugin rows ---------------------------------------
|
|
446
467
|
const organizationsTable = sourceTables['organizations'];
|
|
@@ -462,24 +483,10 @@ export async function applyImport(options) {
|
|
|
462
483
|
...(textOrNull(row.metadata) === undefined
|
|
463
484
|
? {}
|
|
464
485
|
: { metadata: textOrNull(row.metadata) }),
|
|
486
|
+
...stamps(row),
|
|
465
487
|
}, created, `organization:${String(row.id)}`)
|
|
466
488
|
: false;
|
|
467
|
-
|
|
468
|
-
if (isNew) {
|
|
469
|
-
createdCount += 1;
|
|
470
|
-
}
|
|
471
|
-
else {
|
|
472
|
-
skippedCount += 1;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
record({
|
|
476
|
-
model: 'organization',
|
|
477
|
-
sourceTable: organizationsTable ?? 'organizations',
|
|
478
|
-
targetCollection: slugs.organization,
|
|
479
|
-
rows: 1,
|
|
480
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
481
|
-
unmappable: [],
|
|
482
|
-
});
|
|
489
|
+
tally('organization', organizationsTable ?? 'organizations', slugs.organization, isNew);
|
|
483
490
|
}
|
|
484
491
|
const membersTable = sourceTables['members'];
|
|
485
492
|
const members = await readMapped(client, membersTable, [
|
|
@@ -496,24 +503,10 @@ export async function applyImport(options) {
|
|
|
496
503
|
organizationId: `org-${String(row.organization_id)}`,
|
|
497
504
|
userId: String(row.user_id),
|
|
498
505
|
...(textOrNull(row.role) === undefined ? {} : { role: textOrNull(row.role) }),
|
|
506
|
+
...stamps(row),
|
|
499
507
|
}, created, `member:${String(row.id)}`)
|
|
500
508
|
: false;
|
|
501
|
-
|
|
502
|
-
if (isNew) {
|
|
503
|
-
createdCount += 1;
|
|
504
|
-
}
|
|
505
|
-
else {
|
|
506
|
-
skippedCount += 1;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
record({
|
|
510
|
-
model: 'member',
|
|
511
|
-
sourceTable: membersTable ?? 'members',
|
|
512
|
-
targetCollection: slugs.member,
|
|
513
|
-
rows: 1,
|
|
514
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
515
|
-
unmappable: [],
|
|
516
|
-
});
|
|
509
|
+
tally('member', membersTable ?? 'members', slugs.member, isNew);
|
|
517
510
|
}
|
|
518
511
|
const invitationsTable = sourceTables['invitations'];
|
|
519
512
|
const invitations = await readMapped(client, invitationsTable, [
|
|
@@ -538,31 +531,18 @@ export async function applyImport(options) {
|
|
|
538
531
|
? { expiresAt: row.expires_at.toISOString() }
|
|
539
532
|
: {}),
|
|
540
533
|
...(typeof row.inviter_id === 'number' ? { inviterId: String(row.inviter_id) } : {}),
|
|
534
|
+
...stamps(row),
|
|
541
535
|
}, created, `invitation:${String(row.id)}`)
|
|
542
536
|
: false;
|
|
543
|
-
|
|
544
|
-
if (isNew) {
|
|
545
|
-
createdCount += 1;
|
|
546
|
-
}
|
|
547
|
-
else {
|
|
548
|
-
skippedCount += 1;
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
record({
|
|
552
|
-
model: 'invitation',
|
|
553
|
-
sourceTable: invitationsTable ?? 'invitations',
|
|
554
|
-
targetCollection: slugs.invitation,
|
|
555
|
-
rows: 1,
|
|
556
|
-
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
557
|
-
unmappable: [],
|
|
558
|
-
});
|
|
537
|
+
tally('invitation', invitationsTable ?? 'invitations', slugs.invitation, isNew);
|
|
559
538
|
}
|
|
560
|
-
log(`plan: ${planRows.length} row group(s), ${createdCount} created, ${skippedCount} skipped, ${fieldWriteCount} field
|
|
539
|
+
log(`plan: ${planRows.length} row group(s), ${createdCount} created, ${skippedCount} skipped, ${fieldWriteCount} field value(s) captured`);
|
|
561
540
|
if (apply) {
|
|
562
541
|
// The manifest is the run's contract: merge this pass onto any
|
|
563
542
|
// resumed run's rows and write it back (issue #50).
|
|
564
543
|
const manifest = {
|
|
565
|
-
version:
|
|
544
|
+
version: 2,
|
|
545
|
+
kind: 'import',
|
|
566
546
|
createdAt: options.manifest?.createdAt ?? now().toISOString(),
|
|
567
547
|
sourceDatabase: options.sourceDatabase,
|
|
568
548
|
options: { sessions },
|
|
@@ -570,11 +550,7 @@ export async function applyImport(options) {
|
|
|
570
550
|
fieldWrites,
|
|
571
551
|
finalized: options.manifest?.finalized ?? false,
|
|
572
552
|
sourceCounts: options.sourceCounts,
|
|
573
|
-
totals
|
|
574
|
-
...options.sourceCounts,
|
|
575
|
-
...(options.manifest?.totals ?? {}),
|
|
576
|
-
...totals,
|
|
577
|
-
},
|
|
553
|
+
totals,
|
|
578
554
|
};
|
|
579
555
|
const { writeManifest } = await import('./lifecycle.js');
|
|
580
556
|
writeManifest(manifest, options.manifestPath);
|