@payload-auth-link/migrate 0.4.3 → 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.
- package/LICENSE +21 -0
- package/README.md +7 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +109 -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 +25 -5
- package/dist/importer/apply.d.ts.map +1 -1
- package/dist/importer/apply.js +164 -180
- 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 +26 -0
- package/dist/importer/lifecycle.d.ts.map +1 -1
- package/dist/importer/lifecycle.js +107 -22
- package/dist/importer/lifecycle.js.map +1 -1
- package/dist/importer/manifest-mac.d.ts +15 -0
- package/dist/importer/manifest-mac.d.ts.map +1 -0
- package/dist/importer/manifest-mac.js +73 -0
- package/dist/importer/manifest-mac.js.map +1 -0
- package/dist/importer/prelink.d.ts +57 -0
- package/dist/importer/prelink.d.ts.map +1 -0
- package/dist/importer/prelink.js +159 -0
- package/dist/importer/prelink.js.map +1 -0
- package/dist/importer/run-import.d.ts +15 -0
- package/dist/importer/run-import.d.ts.map +1 -1
- package/dist/importer/run-import.js +155 -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 +34 -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 +10 -10
- package/src/cli.ts +117 -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 +198 -182
- package/src/importer/host-writes.ts +231 -0
- package/src/importer/lifecycle.ts +131 -24
- package/src/importer/manifest-mac.ts +90 -0
- package/src/importer/prelink.ts +237 -0
- package/src/importer/run-import.ts +207 -29
- package/src/importer/source.ts +72 -14
- package/src/importer/types.ts +35 -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;
|
|
@@ -37,7 +48,16 @@ export type ApplyOptions = {
|
|
|
37
48
|
/** Injectable clock for deterministic `linkedAt` stamps. */
|
|
38
49
|
readonly now?: () => Date;
|
|
39
50
|
readonly log?: (message: string) => void;
|
|
51
|
+
/** Resume from a pre-0.6.0 manifest that has no MAC (`--allow-unsigned-manifest`). */
|
|
52
|
+
readonly allowUnsignedManifest?: boolean | undefined;
|
|
40
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* Plugin user state the target must be able to hold (issue #88),
|
|
56
|
+
* checked BEFORE any write: a banned user whose target has no `banned`
|
|
57
|
+
* field would import unbanned; an anonymous user without `isAnonymous`
|
|
58
|
+
* would import as a full account.
|
|
59
|
+
*/
|
|
60
|
+
export declare function pluginStateUnmappable(users: readonly SourceUser[], targetFields: ReadonlySet<string>, targetSlug: string): Unmappable[];
|
|
41
61
|
export declare function applyImport(options: ApplyOptions): Promise<ImportResult>;
|
|
42
62
|
/** Collapse per-row plan entries into one line per model (dry-run print). */
|
|
43
63
|
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;AAGtC,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;IACxC,sFAAsF;IACtF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACrD,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,CAsgB9E;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,EAAE,CAerE"}
|
package/dist/importer/apply.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { capturedKeys, captureBefore } from './host-writes.js';
|
|
2
|
+
import { authenticateManifest, signManifest } from './manifest-mac.js';
|
|
1
3
|
import { readFlatRows, openSource, readSourceUsers, } from './source.js';
|
|
2
4
|
import { defaultTargetSlugs, resolveSourceTables, } from './types.js';
|
|
3
5
|
const slugsOf = (overrides) => ({
|
|
@@ -14,14 +16,80 @@ function numberOrNull(value) {
|
|
|
14
16
|
const numeric = typeof value === 'number' ? value : Number(value);
|
|
15
17
|
return Number.isFinite(numeric) ? numeric : undefined;
|
|
16
18
|
}
|
|
19
|
+
/** The source row's timestamps, when its layout has them (issue #88). */
|
|
20
|
+
function stamps(row) {
|
|
21
|
+
return {
|
|
22
|
+
...(row.created_at instanceof Date ? { createdAt: row.created_at.toISOString() } : {}),
|
|
23
|
+
...(row.updated_at instanceof Date ? { updatedAt: row.updated_at.toISOString() } : {}),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const timestampColumns = ['created_at', 'updated_at'];
|
|
17
27
|
/**
|
|
18
28
|
* Rows for one mapped model. A `null` mapping records the model as
|
|
19
29
|
* not installed (issue #68) — no read, no rows; anything else goes
|
|
20
30
|
* through the strict `readFlatRows` (a missing mapped table throws;
|
|
21
|
-
* the probe aborts the run first).
|
|
31
|
+
* the probe aborts the run first). Row timestamps are read when the
|
|
32
|
+
* layout has them.
|
|
22
33
|
*/
|
|
23
34
|
async function readMapped(client, table, columns) {
|
|
24
|
-
return table === null ? [] : readFlatRows(client, table, columns);
|
|
35
|
+
return table === null ? [] : readFlatRows(client, table, columns, timestampColumns);
|
|
36
|
+
}
|
|
37
|
+
/** Field names a target collection declares (top level, flattened). */
|
|
38
|
+
function targetFieldNames(payload, slug) {
|
|
39
|
+
const collection = payload.collections[slug];
|
|
40
|
+
const names = new Set();
|
|
41
|
+
for (const field of collection?.config.flattenedFields ?? []) {
|
|
42
|
+
names.add(field.name);
|
|
43
|
+
}
|
|
44
|
+
return names;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Plugin user state the target must be able to hold (issue #88),
|
|
48
|
+
* checked BEFORE any write: a banned user whose target has no `banned`
|
|
49
|
+
* field would import unbanned; an anonymous user without `isAnonymous`
|
|
50
|
+
* would import as a full account.
|
|
51
|
+
*/
|
|
52
|
+
export function pluginStateUnmappable(users, targetFields, targetSlug) {
|
|
53
|
+
const found = [];
|
|
54
|
+
for (const user of users) {
|
|
55
|
+
if (user.banned === true && !targetFields.has('banned')) {
|
|
56
|
+
found.push({
|
|
57
|
+
model: 'user',
|
|
58
|
+
key: user.id,
|
|
59
|
+
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`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (user.isAnonymous === true && !targetFields.has('isAnonymous')) {
|
|
63
|
+
found.push({
|
|
64
|
+
model: 'user',
|
|
65
|
+
key: user.id,
|
|
66
|
+
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`,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
/** Plugin user state carried onto the ba-users row (issue #88). */
|
|
73
|
+
function pluginUserState(user, targetFields) {
|
|
74
|
+
const state = {};
|
|
75
|
+
if (user.banned !== null && targetFields.has('banned')) {
|
|
76
|
+
state.banned = user.banned;
|
|
77
|
+
}
|
|
78
|
+
if (user.banReason !== null && targetFields.has('banReason')) {
|
|
79
|
+
state.banReason = user.banReason;
|
|
80
|
+
}
|
|
81
|
+
if (user.banExpires !== null && targetFields.has('banExpires')) {
|
|
82
|
+
state.banExpires = user.banExpires.toISOString();
|
|
83
|
+
}
|
|
84
|
+
if (user.isAnonymous !== null && targetFields.has('isAnonymous')) {
|
|
85
|
+
state.isAnonymous = user.isAnonymous;
|
|
86
|
+
}
|
|
87
|
+
// Better Auth's admin plugin stores roles as one comma-separated
|
|
88
|
+
// string; payload-auth kept them in the users_role child table.
|
|
89
|
+
if (user.roles.length > 0 && targetFields.has('role')) {
|
|
90
|
+
state.role = user.roles.join(',');
|
|
91
|
+
}
|
|
92
|
+
return state;
|
|
25
93
|
}
|
|
26
94
|
/** Find an existing target row by `baId` — the resumable dedupe key. */
|
|
27
95
|
async function findByBaId(payload, collection, baId) {
|
|
@@ -53,19 +121,6 @@ async function createDeduped(payload, collection, baId, data, created, sourceKey
|
|
|
53
121
|
}
|
|
54
122
|
return true;
|
|
55
123
|
}
|
|
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
124
|
/**
|
|
70
125
|
* The identity rows pre-populated on the host user (issue #69): ONE
|
|
71
126
|
* `better-auth` identity per imported user, `providerUserId` set to
|
|
@@ -98,9 +153,21 @@ export async function applyImport(options) {
|
|
|
98
153
|
const { payload, sourceConnectionString, apply, sessions, log = () => { }, now = () => new Date(), } = options;
|
|
99
154
|
const slugs = slugsOf(options.slugs);
|
|
100
155
|
const sourceTables = resolveSourceTables(options.sourceTables);
|
|
156
|
+
if (options.manifest !== null) {
|
|
157
|
+
// Resuming merges the old entries and re-signs them: never launder
|
|
158
|
+
// an edited manifest into a signed one.
|
|
159
|
+
authenticateManifest(payload.secret, options.manifest, {
|
|
160
|
+
allowUnsigned: options.allowUnsignedManifest,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
101
163
|
const created = [...(options.manifest?.created ?? [])];
|
|
102
164
|
const fieldWrites = [...(options.manifest?.fieldWrites ?? [])];
|
|
103
|
-
|
|
165
|
+
// First capture wins (issue #88): fields captured by an earlier pass
|
|
166
|
+
// keep their pre-import value.
|
|
167
|
+
const captured = capturedKeys(fieldWrites);
|
|
168
|
+
// Per-PASS totals (issue #88): a re-apply reports what this pass
|
|
169
|
+
// planned, never the sum of every pass.
|
|
170
|
+
const totals = {};
|
|
104
171
|
const planRows = [];
|
|
105
172
|
const unmappable = [];
|
|
106
173
|
let createdCount = 0;
|
|
@@ -112,6 +179,20 @@ export async function applyImport(options) {
|
|
|
112
179
|
const client = await openSource(sourceConnectionString);
|
|
113
180
|
try {
|
|
114
181
|
const users = await readSourceUsers(client, sourceTables);
|
|
182
|
+
const baUserFields = targetFieldNames(payload, slugs.user);
|
|
183
|
+
// --- 0. target-capability gate (issue #88) ---------------------------
|
|
184
|
+
// Runs before ANY write: plugin state the target cannot hold aborts
|
|
185
|
+
// the run instead of importing a banned user unbanned.
|
|
186
|
+
const blocked = pluginStateUnmappable(users, baUserFields, slugs.user);
|
|
187
|
+
if (blocked.length > 0) {
|
|
188
|
+
log(`ABORT: ${blocked.length} user(s) carry state the target cannot hold; nothing was written`);
|
|
189
|
+
return {
|
|
190
|
+
created: 0,
|
|
191
|
+
skipped: 0,
|
|
192
|
+
fieldWrites: 0,
|
|
193
|
+
plan: { rows: [], unmappable: blocked, sessions, warnings: [] },
|
|
194
|
+
};
|
|
195
|
+
}
|
|
115
196
|
const seenUsers = new Set();
|
|
116
197
|
// --- 1. ba-users + host field writes ---------------------------------
|
|
117
198
|
for (const user of users) {
|
|
@@ -128,6 +209,7 @@ export async function applyImport(options) {
|
|
|
128
209
|
name: user.name ?? '',
|
|
129
210
|
emailVerified: user.emailVerified,
|
|
130
211
|
...(user.image === null ? {} : { image: user.image }),
|
|
212
|
+
...pluginUserState(user, baUserFields),
|
|
131
213
|
createdAt: user.createdAt.toISOString(),
|
|
132
214
|
updatedAt: user.updatedAt.toISOString(),
|
|
133
215
|
}, created, `user:${baId}`)
|
|
@@ -141,30 +223,32 @@ export async function applyImport(options) {
|
|
|
141
223
|
}
|
|
142
224
|
// Host-side writes on the EXISTING Payload user (the source
|
|
143
225
|
// layout's user id IS the host id): identities, roles, and the
|
|
144
|
-
// verified-email linking proof.
|
|
145
|
-
// rollback
|
|
226
|
+
// verified-email linking proof. The prior values (and the
|
|
227
|
+
// doc's updatedAt) are captured first — once — so rollback
|
|
228
|
+
// restores the pre-import document exactly.
|
|
146
229
|
const hostId = Number(baId);
|
|
147
230
|
if (Number.isSafeInteger(hostId)) {
|
|
231
|
+
const { present, newlyCaptured } = await captureBefore({
|
|
232
|
+
payload,
|
|
233
|
+
collection: 'users',
|
|
234
|
+
id: hostId,
|
|
235
|
+
fields: ['identities', 'roles', 'linkable', 'linkableEmail'],
|
|
236
|
+
captured,
|
|
237
|
+
into: fieldWrites,
|
|
238
|
+
});
|
|
239
|
+
fieldWriteCount += newlyCaptured;
|
|
148
240
|
const writes = {
|
|
149
241
|
identities: identityRows(user, now),
|
|
150
|
-
linkable: user.emailVerified,
|
|
151
242
|
};
|
|
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) {
|
|
243
|
+
if (user.roles.length > 0 && present.has('roles')) {
|
|
163
244
|
// Stored role values pass through unchanged (issue #56: the
|
|
164
245
|
// storage edge owns translation; the map is the app's).
|
|
165
246
|
writes.roles = user.roles;
|
|
166
247
|
}
|
|
167
248
|
if (user.emailVerified) {
|
|
249
|
+
// Grant-only: the proof is bound to the address (both
|
|
250
|
+
// fields), and an existing proof is never revoked here.
|
|
251
|
+
writes.linkable = true;
|
|
168
252
|
writes.linkableEmail = user.email;
|
|
169
253
|
}
|
|
170
254
|
await payload.update({
|
|
@@ -184,6 +268,24 @@ export async function applyImport(options) {
|
|
|
184
268
|
unmappable: [],
|
|
185
269
|
});
|
|
186
270
|
}
|
|
271
|
+
const tally = (model, sourceTable, target, isNew) => {
|
|
272
|
+
if (apply) {
|
|
273
|
+
if (isNew) {
|
|
274
|
+
createdCount += 1;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
skippedCount += 1;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
record({
|
|
281
|
+
model,
|
|
282
|
+
sourceTable,
|
|
283
|
+
targetCollection: target,
|
|
284
|
+
rows: 1,
|
|
285
|
+
skipped: isNew ? 0 : apply ? 1 : 0,
|
|
286
|
+
unmappable: [],
|
|
287
|
+
});
|
|
288
|
+
};
|
|
187
289
|
// --- 2. accounts (hashes verbatim) ------------------------------------
|
|
188
290
|
const accountsTable = sourceTables['accounts'];
|
|
189
291
|
for (const user of users) {
|
|
@@ -206,24 +308,15 @@ export async function applyImport(options) {
|
|
|
206
308
|
...(account.refreshTokenExpiresAt === null
|
|
207
309
|
? {}
|
|
208
310
|
: { refreshTokenExpiresAt: account.refreshTokenExpiresAt.toISOString() }),
|
|
311
|
+
...(account.createdAt === null
|
|
312
|
+
? {}
|
|
313
|
+
: { createdAt: account.createdAt.toISOString() }),
|
|
314
|
+
...(account.updatedAt === null
|
|
315
|
+
? {}
|
|
316
|
+
: { updatedAt: account.updatedAt.toISOString() }),
|
|
209
317
|
}, created, `account:${account.id}`)
|
|
210
318
|
: 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
|
-
});
|
|
319
|
+
tally('account', accountsTable ?? 'accounts', slugs.account, isNew);
|
|
227
320
|
}
|
|
228
321
|
}
|
|
229
322
|
// --- 3. sessions (carry keeps every token) -----------------------------
|
|
@@ -236,8 +329,6 @@ export async function applyImport(options) {
|
|
|
236
329
|
'expires_at',
|
|
237
330
|
'ip_address',
|
|
238
331
|
'user_agent',
|
|
239
|
-
'created_at',
|
|
240
|
-
'updated_at',
|
|
241
332
|
]);
|
|
242
333
|
for (const row of rows) {
|
|
243
334
|
totals.session = (totals.session ?? 0) + 1;
|
|
@@ -255,30 +346,10 @@ export async function applyImport(options) {
|
|
|
255
346
|
...(textOrNull(row.user_agent) === undefined
|
|
256
347
|
? {}
|
|
257
348
|
: { 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
|
-
: {}),
|
|
349
|
+
...stamps(row),
|
|
264
350
|
}, created, `session:${String(row.id)}`)
|
|
265
351
|
: 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
|
-
});
|
|
352
|
+
tally('session', sessionsTable ?? 'sessions', slugs.session, isNew);
|
|
282
353
|
}
|
|
283
354
|
}
|
|
284
355
|
// --- 4. verifications ---------------------------------------------------
|
|
@@ -297,24 +368,10 @@ export async function applyImport(options) {
|
|
|
297
368
|
identifier: String(row.identifier),
|
|
298
369
|
value: String(row.value),
|
|
299
370
|
expiresAt: row.expires_at instanceof Date ? row.expires_at.toISOString() : now().toISOString(),
|
|
371
|
+
...stamps(row),
|
|
300
372
|
}, created, `verification:${String(row.id)}`)
|
|
301
373
|
: 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
|
-
});
|
|
374
|
+
tally('verification', verificationsTable ?? 'verifications', slugs.verification, isNew);
|
|
318
375
|
}
|
|
319
376
|
// --- 5. api keys (hash, prefix, metadata, rate-limit state) --------------
|
|
320
377
|
const apiKeysTable = sourceTables['api_keys'];
|
|
@@ -325,8 +382,8 @@ export async function applyImport(options) {
|
|
|
325
382
|
'start',
|
|
326
383
|
'prefix',
|
|
327
384
|
'key',
|
|
328
|
-
// payload-auth stores the satellite's
|
|
329
|
-
//
|
|
385
|
+
// payload-auth stores the satellite's owner as reference_id — the
|
|
386
|
+
// same name @better-auth/api-key 1.7 uses (`referenceId`).
|
|
330
387
|
'reference_id',
|
|
331
388
|
'refill_interval',
|
|
332
389
|
'refill_amount',
|
|
@@ -352,9 +409,9 @@ export async function applyImport(options) {
|
|
|
352
409
|
...(textOrNull(row.start) === undefined ? {} : { start: textOrNull(row.start) }),
|
|
353
410
|
...(textOrNull(row.prefix) === undefined ? {} : { prefix: textOrNull(row.prefix) }),
|
|
354
411
|
key: String(row.key),
|
|
355
|
-
//
|
|
356
|
-
//
|
|
357
|
-
//
|
|
412
|
+
// @better-auth/api-key 1.7 names the owner `referenceId`;
|
|
413
|
+
// `userId` is offered for 1.6-era target schemas (Payload
|
|
414
|
+
// drops it where the collection has no such field).
|
|
358
415
|
userId: String(row.reference_id),
|
|
359
416
|
referenceId: String(row.reference_id),
|
|
360
417
|
...(numberOrNull(row.refill_interval) === undefined
|
|
@@ -394,24 +451,10 @@ export async function applyImport(options) {
|
|
|
394
451
|
...(textOrNull(row.metadata) === undefined
|
|
395
452
|
? {}
|
|
396
453
|
: { metadata: textOrNull(row.metadata) }),
|
|
454
|
+
...stamps(row),
|
|
397
455
|
}, created, `apikey:${String(row.id)}`)
|
|
398
456
|
: 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
|
-
});
|
|
457
|
+
tally('apikey', apiKeysTable ?? 'api_keys', slugs.apikey, isNew);
|
|
415
458
|
}
|
|
416
459
|
// --- 6. jwks --------------------------------------------------------------
|
|
417
460
|
const jwksTable = sourceTables['jwks'];
|
|
@@ -423,24 +466,10 @@ export async function applyImport(options) {
|
|
|
423
466
|
? await createDeduped(payload, slugs.jwks, baId, {
|
|
424
467
|
publicKey: String(row.public_key),
|
|
425
468
|
privateKey: String(row.private_key),
|
|
469
|
+
...stamps(row),
|
|
426
470
|
}, created, `jwks:${String(row.id)}`)
|
|
427
471
|
: 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
|
-
});
|
|
472
|
+
tally('jwks', jwksTable ?? 'jwks', slugs.jwks, isNew);
|
|
444
473
|
}
|
|
445
474
|
// --- 7. organization plugin rows ---------------------------------------
|
|
446
475
|
const organizationsTable = sourceTables['organizations'];
|
|
@@ -462,24 +491,10 @@ export async function applyImport(options) {
|
|
|
462
491
|
...(textOrNull(row.metadata) === undefined
|
|
463
492
|
? {}
|
|
464
493
|
: { metadata: textOrNull(row.metadata) }),
|
|
494
|
+
...stamps(row),
|
|
465
495
|
}, created, `organization:${String(row.id)}`)
|
|
466
496
|
: 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
|
-
});
|
|
497
|
+
tally('organization', organizationsTable ?? 'organizations', slugs.organization, isNew);
|
|
483
498
|
}
|
|
484
499
|
const membersTable = sourceTables['members'];
|
|
485
500
|
const members = await readMapped(client, membersTable, [
|
|
@@ -496,24 +511,10 @@ export async function applyImport(options) {
|
|
|
496
511
|
organizationId: `org-${String(row.organization_id)}`,
|
|
497
512
|
userId: String(row.user_id),
|
|
498
513
|
...(textOrNull(row.role) === undefined ? {} : { role: textOrNull(row.role) }),
|
|
514
|
+
...stamps(row),
|
|
499
515
|
}, created, `member:${String(row.id)}`)
|
|
500
516
|
: 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
|
-
});
|
|
517
|
+
tally('member', membersTable ?? 'members', slugs.member, isNew);
|
|
517
518
|
}
|
|
518
519
|
const invitationsTable = sourceTables['invitations'];
|
|
519
520
|
const invitations = await readMapped(client, invitationsTable, [
|
|
@@ -538,31 +539,18 @@ export async function applyImport(options) {
|
|
|
538
539
|
? { expiresAt: row.expires_at.toISOString() }
|
|
539
540
|
: {}),
|
|
540
541
|
...(typeof row.inviter_id === 'number' ? { inviterId: String(row.inviter_id) } : {}),
|
|
542
|
+
...stamps(row),
|
|
541
543
|
}, created, `invitation:${String(row.id)}`)
|
|
542
544
|
: 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
|
-
});
|
|
545
|
+
tally('invitation', invitationsTable ?? 'invitations', slugs.invitation, isNew);
|
|
559
546
|
}
|
|
560
|
-
log(`plan: ${planRows.length} row group(s), ${createdCount} created, ${skippedCount} skipped, ${fieldWriteCount} field
|
|
547
|
+
log(`plan: ${planRows.length} row group(s), ${createdCount} created, ${skippedCount} skipped, ${fieldWriteCount} field value(s) captured`);
|
|
561
548
|
if (apply) {
|
|
562
549
|
// The manifest is the run's contract: merge this pass onto any
|
|
563
550
|
// resumed run's rows and write it back (issue #50).
|
|
564
|
-
const manifest = {
|
|
565
|
-
version:
|
|
551
|
+
const manifest = signManifest(payload.secret, {
|
|
552
|
+
version: 3,
|
|
553
|
+
kind: 'import',
|
|
566
554
|
createdAt: options.manifest?.createdAt ?? now().toISOString(),
|
|
567
555
|
sourceDatabase: options.sourceDatabase,
|
|
568
556
|
options: { sessions },
|
|
@@ -570,12 +558,8 @@ export async function applyImport(options) {
|
|
|
570
558
|
fieldWrites,
|
|
571
559
|
finalized: options.manifest?.finalized ?? false,
|
|
572
560
|
sourceCounts: options.sourceCounts,
|
|
573
|
-
totals
|
|
574
|
-
|
|
575
|
-
...(options.manifest?.totals ?? {}),
|
|
576
|
-
...totals,
|
|
577
|
-
},
|
|
578
|
-
};
|
|
561
|
+
totals,
|
|
562
|
+
});
|
|
579
563
|
const { writeManifest } = await import('./lifecycle.js');
|
|
580
564
|
writeManifest(manifest, options.manifestPath);
|
|
581
565
|
}
|