@payload-auth-link/migrate 0.6.0 → 0.7.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.
Files changed (66) hide show
  1. package/README.md +20 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +85 -30
  4. package/dist/cli.js.map +1 -1
  5. package/dist/doctor/plugins.d.ts.map +1 -1
  6. package/dist/doctor/plugins.js +6 -2
  7. package/dist/doctor/plugins.js.map +1 -1
  8. package/dist/doctor/run-doctor.d.ts.map +1 -1
  9. package/dist/doctor/run-doctor.js +27 -2
  10. package/dist/doctor/run-doctor.js.map +1 -1
  11. package/dist/doctor/users.d.ts +13 -1
  12. package/dist/doctor/users.d.ts.map +1 -1
  13. package/dist/doctor/users.js +17 -7
  14. package/dist/doctor/users.js.map +1 -1
  15. package/dist/exporters.d.ts +43 -5
  16. package/dist/exporters.d.ts.map +1 -1
  17. package/dist/exporters.js +88 -5
  18. package/dist/exporters.js.map +1 -1
  19. package/dist/importer/apply.d.ts.map +1 -1
  20. package/dist/importer/apply.js +79 -23
  21. package/dist/importer/apply.js.map +1 -1
  22. package/dist/importer/guards.d.ts +49 -0
  23. package/dist/importer/guards.d.ts.map +1 -0
  24. package/dist/importer/guards.js +175 -0
  25. package/dist/importer/guards.js.map +1 -0
  26. package/dist/importer/host-writes.d.ts +6 -2
  27. package/dist/importer/host-writes.d.ts.map +1 -1
  28. package/dist/importer/host-writes.js +9 -4
  29. package/dist/importer/host-writes.js.map +1 -1
  30. package/dist/importer/lifecycle.d.ts +59 -14
  31. package/dist/importer/lifecycle.d.ts.map +1 -1
  32. package/dist/importer/lifecycle.js +123 -20
  33. package/dist/importer/lifecycle.js.map +1 -1
  34. package/dist/importer/manifest-mac.d.ts +15 -3
  35. package/dist/importer/manifest-mac.d.ts.map +1 -1
  36. package/dist/importer/manifest-mac.js +47 -27
  37. package/dist/importer/manifest-mac.js.map +1 -1
  38. package/dist/importer/prelink.d.ts.map +1 -1
  39. package/dist/importer/prelink.js +11 -1
  40. package/dist/importer/prelink.js.map +1 -1
  41. package/dist/importer/run-import.d.ts +22 -5
  42. package/dist/importer/run-import.d.ts.map +1 -1
  43. package/dist/importer/run-import.js +27 -6
  44. package/dist/importer/run-import.js.map +1 -1
  45. package/dist/importer/types.d.ts +7 -4
  46. package/dist/importer/types.d.ts.map +1 -1
  47. package/dist/importer/types.js.map +1 -1
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +1 -1
  51. package/dist/index.js.map +1 -1
  52. package/package.json +6 -6
  53. package/src/cli.ts +84 -30
  54. package/src/doctor/plugins.ts +8 -3
  55. package/src/doctor/run-doctor.ts +30 -3
  56. package/src/doctor/users.ts +25 -7
  57. package/src/exporters.ts +113 -12
  58. package/src/importer/apply.ts +92 -22
  59. package/src/importer/guards.ts +223 -0
  60. package/src/importer/host-writes.ts +15 -4
  61. package/src/importer/lifecycle.ts +185 -29
  62. package/src/importer/manifest-mac.ts +65 -30
  63. package/src/importer/prelink.ts +13 -1
  64. package/src/importer/run-import.ts +52 -11
  65. package/src/importer/types.ts +7 -4
  66. package/src/index.ts +10 -1
@@ -0,0 +1,175 @@
1
+ import { isRecord } from '@payload-auth-link/core';
2
+ import { defaultTargetSlugs, } from './types.js';
3
+ /**
4
+ * The guards every destructive manifest operation runs, independent of
5
+ * the manifest's signature:
6
+ *
7
+ * - created-row scoping: a rollback only ever deletes rows the importer
8
+ * itself creates — rows in the import's own target collections whose
9
+ * deterministic `baId` matches the source key the manifest names;
10
+ * - the finalize marker: `finalize` records the point of no return in
11
+ * the target DATABASE (Payload's key-value store), so a manifest file
12
+ * alone can never reopen a finalized migration;
13
+ * - the host roles field the app configured on `authLink`.
14
+ */
15
+ /** The `baId` prefix the importer stamps per model (see apply.ts). */
16
+ const baIdPrefix = {
17
+ user: '',
18
+ account: 'acct-',
19
+ session: 'sess-',
20
+ verification: 'ver-',
21
+ apikey: 'key-',
22
+ jwks: 'jwks-',
23
+ organization: 'org-',
24
+ member: 'member-',
25
+ invitation: 'inv-',
26
+ };
27
+ const isTargetModel = (value) => value in baIdPrefix;
28
+ /**
29
+ * The model and deterministic `baId` a created row's `sourceKey`
30
+ * (`<model>:<source id>`) names, or `null` when it names none.
31
+ */
32
+ export function expectedBaId(sourceKey) {
33
+ const colon = sourceKey.indexOf(':');
34
+ if (colon <= 0) {
35
+ return null;
36
+ }
37
+ const model = sourceKey.slice(0, colon);
38
+ const sourceId = sourceKey.slice(colon + 1);
39
+ if (!isTargetModel(model) || sourceId === '') {
40
+ return null;
41
+ }
42
+ return { model, baId: `${baIdPrefix[model]}${sourceId}` };
43
+ }
44
+ /** The target slugs with the defaults filled in. */
45
+ export function targetSlugsOf(overrides) {
46
+ return { ...defaultTargetSlugs, ...(overrides ?? {}) };
47
+ }
48
+ /**
49
+ * Refuse a manifest whose created rows reach outside what the importer
50
+ * creates, BEFORE anything is deleted (or re-signed): an `adopt-prelink`
51
+ * manifest creates no rows at all, and an import's rows must sit in the
52
+ * import's own target collections, under the model their source key
53
+ * names. Signed or not — the signature proves who wrote the file, this
54
+ * proves the file only names the kit's own rows.
55
+ */
56
+ export function assertCreatedRowsScoped(manifest, slugs) {
57
+ if (manifest.kind === 'adopt-prelink') {
58
+ if (manifest.created.length > 0) {
59
+ throw new Error(`the adopt-prelink manifest lists ${manifest.created.length} created row(s), which adopt-prelink never creates (edited manifest?); refusing to use it — nothing was deleted`);
60
+ }
61
+ return;
62
+ }
63
+ const bySlug = new Map();
64
+ for (const model of Object.keys(baIdPrefix)) {
65
+ bySlug.set(slugs[model], model);
66
+ }
67
+ const outside = [];
68
+ for (const row of manifest.created) {
69
+ const expected = expectedBaId(row.sourceKey);
70
+ const model = bySlug.get(row.collection);
71
+ if (model === undefined || expected === null || expected.model !== model) {
72
+ outside.push(`${row.collection}#${String(row.id)} (${row.sourceKey})`);
73
+ }
74
+ }
75
+ if (outside.length > 0) {
76
+ throw new Error(`the manifest lists ${outside.length} created row(s) outside the import's target collections (${[...bySlug.keys()].join(', ')}): ${outside.slice(0, 10).join(', ')}${outside.length > 10 ? ', …' : ''}. The importer only creates rows there; refusing to use the manifest — nothing was deleted. If your engine wiring renames the targets, pass the same --slugs the import ran with`);
77
+ }
78
+ }
79
+ /** A created row whose `baId` no longer matches its source key. */
80
+ export function baIdMismatch(row, doc) {
81
+ const expected = expectedBaId(row.sourceKey);
82
+ if (expected === null) {
83
+ return true;
84
+ }
85
+ return !isRecord(doc) || String(doc['baId']) !== expected.baId;
86
+ }
87
+ function keyValueStore(payload) {
88
+ const kv = payload.kv;
89
+ if (isRecord(kv) &&
90
+ typeof kv['get'] === 'function' &&
91
+ typeof kv['set'] === 'function' &&
92
+ typeof kv['keys'] === 'function') {
93
+ return kv;
94
+ }
95
+ return null;
96
+ }
97
+ const markerPrefix = 'payload-auth-link/migrate/finalized/';
98
+ /** The finalize marker key of one manifest (its kind + first-apply stamp). */
99
+ export function finalizeMarkerKey(manifest) {
100
+ return `${markerPrefix}${manifest.kind ?? 'import'}/${manifest.createdAt}`;
101
+ }
102
+ /**
103
+ * Record the point of no return in the target database. One-way: the
104
+ * kit never deletes the marker. Throws when the store is unavailable —
105
+ * `finalize` must not report success it cannot back.
106
+ */
107
+ export async function recordFinalizeMarker(payload, manifest, finalizedAt) {
108
+ const kv = keyValueStore(payload);
109
+ if (kv === null) {
110
+ throw new Error("this Payload version exposes no key-value store (payload.kv); finalize records its marker there — upgrade Payload to a release in the kit's supported band");
111
+ }
112
+ try {
113
+ await kv.set(finalizeMarkerKey(manifest), {
114
+ kind: manifest.kind ?? 'import',
115
+ createdAt: manifest.createdAt,
116
+ finalizedAt,
117
+ });
118
+ }
119
+ catch (error) {
120
+ throw new Error(`could not record the finalize marker in Payload's key-value store (the payload-kv collection): ${error instanceof Error ? error.message : String(error)} — create its table (run your Payload migrations) and re-run finalize; the manifest was not changed`, { cause: error });
121
+ }
122
+ }
123
+ /**
124
+ * Whether the database says this migration was finalized. `anyOfKind`
125
+ * widens the check to every finalized manifest of the same kind — used
126
+ * when the manifest's own `createdAt` is not covered by a signature.
127
+ * Returns `'unavailable'` when the store cannot be read; the caller
128
+ * decides (and logs) what that means.
129
+ */
130
+ export async function finalizeMarkerState(payload, manifest, options) {
131
+ const kv = keyValueStore(payload);
132
+ if (kv === null) {
133
+ return 'unavailable';
134
+ }
135
+ try {
136
+ if ((await kv.get(finalizeMarkerKey(manifest))) !== null) {
137
+ return 'finalized';
138
+ }
139
+ if (options.anyOfKind) {
140
+ const kindPrefix = `${markerPrefix}${manifest.kind ?? 'import'}/`;
141
+ const keys = await kv.keys();
142
+ if (keys.some((key) => key.startsWith(kindPrefix))) {
143
+ return 'finalized';
144
+ }
145
+ }
146
+ return 'open';
147
+ }
148
+ catch {
149
+ return 'unavailable';
150
+ }
151
+ }
152
+ /**
153
+ * The host roles field the app configured (`authLink({ rolesField })`),
154
+ * read off the plugin entry in the booted config (Payload keeps each
155
+ * plugin's `slug` and `options` for cross-plugin discovery). Defaults to
156
+ * the plugin's own default, `roles`.
157
+ */
158
+ export function hostRolesField(payload) {
159
+ const plugins = payload.config.plugins;
160
+ if (Array.isArray(plugins)) {
161
+ for (const plugin of plugins) {
162
+ if (typeof plugin !== 'function') {
163
+ continue;
164
+ }
165
+ const entry = plugin;
166
+ if (entry.slug !== 'payload-auth-link') {
167
+ continue;
168
+ }
169
+ const rolesField = isRecord(entry.options) ? entry.options['rolesField'] : undefined;
170
+ return typeof rolesField === 'string' && rolesField !== '' ? rolesField : 'roles';
171
+ }
172
+ }
173
+ return 'roles';
174
+ }
175
+ //# sourceMappingURL=guards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/importer/guards.ts"],"names":[],"mappings":"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"}
@@ -17,8 +17,10 @@ export declare function unsealValue(secret: string, sealed: string, entry: strin
17
17
  * restored only because the importer writes them).
18
18
  */
19
19
  export declare const restorableFields: ReadonlySet<string>;
20
+ /** {@link restorableFields} plus the app's configured roles field. */
21
+ export declare function restorableFieldsFor(rolesField: string): ReadonlySet<string>;
20
22
  /** The captured prior value of one manifest entry, JSON-parsed. */
21
- export declare function priorValue(secret: string, write: FieldWrite): unknown;
23
+ export declare function priorValue(secret: string, write: FieldWrite, restorable?: ReadonlySet<string>): unknown;
22
24
  /** Keys of the field writes a manifest already holds (first capture wins). */
23
25
  export declare function capturedKeys(writes: readonly FieldWrite[]): Set<string>;
24
26
  /**
@@ -43,5 +45,7 @@ export declare function captureBefore(options: {
43
45
  * `updatedAt` lands exactly as captured. Returns the number of field
44
46
  * values restored.
45
47
  */
46
- export declare function restoreCaptured(payload: Payload, manifest: Pick<ImportManifest, 'fieldWrites'>): Promise<number>;
48
+ export declare function restoreCaptured(payload: Payload, manifest: Pick<ImportManifest, 'fieldWrites'>, options?: {
49
+ readonly rolesField?: string | undefined;
50
+ }): Promise<number>;
47
51
  //# sourceMappingURL=host-writes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"host-writes.d.ts","sourceRoot":"","sources":["../../src/importer/host-writes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAyC5D;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlF;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBjF;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAM/C,CAAA;AAEF,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAerE;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAEvE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAC5B,GAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCrF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAyDjB"}
1
+ {"version":3,"file":"host-writes.d.ts","sourceRoot":"","sources":["../../src/importer/host-writes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAyC5D;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAOlF;AAED,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAkBjF;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAM/C,CAAA;AAEF,sEAAsE;AACtE,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAE3E;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,UAAU,EACjB,UAAU,GAAE,WAAW,CAAC,MAAM,CAAoB,GACjD,OAAO,CAeT;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,CAEvE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE;IAC3C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,CAAA;CAC5B,GAAG,OAAO,CAAC;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCrF;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,IAAI,CAAC,cAAc,EAAE,aAAa,CAAC,EAC7C,OAAO,GAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,GACzD,OAAO,CAAC,MAAM,CAAC,CA0DjB"}
@@ -80,9 +80,13 @@ export const restorableFields = new Set([
80
80
  'linkableEmail',
81
81
  'updatedAt',
82
82
  ]);
83
+ /** {@link restorableFields} plus the app's configured roles field. */
84
+ export function restorableFieldsFor(rolesField) {
85
+ return new Set([...restorableFields, rolesField]);
86
+ }
83
87
  /** The captured prior value of one manifest entry, JSON-parsed. */
84
- export function priorValue(secret, write) {
85
- if (!restorableFields.has(write.field)) {
88
+ export function priorValue(secret, write, restorable = restorableFields) {
89
+ if (!restorable.has(write.field)) {
86
90
  throw new Error(`manifest entry for '${write.collection}.${write.field}' is not a field this kit writes; refusing to restore it (edited manifest?)`);
87
91
  }
88
92
  if (write.sealedBefore !== undefined) {
@@ -141,12 +145,13 @@ export async function captureBefore(options) {
141
145
  * `updatedAt` lands exactly as captured. Returns the number of field
142
146
  * values restored.
143
147
  */
144
- export async function restoreCaptured(payload, manifest) {
148
+ export async function restoreCaptured(payload, manifest, options = {}) {
149
+ const restorable = restorableFieldsFor(options.rolesField ?? 'roles');
145
150
  const byDoc = new Map();
146
151
  for (const write of manifest.fieldWrites) {
147
152
  const key = `${write.collection}\u0000${String(write.id)}`;
148
153
  const entry = byDoc.get(key) ?? { collection: write.collection, id: write.id, data: {} };
149
- entry.data[write.field] = priorValue(payload.secret, write);
154
+ entry.data[write.field] = priorValue(payload.secret, write, restorable);
150
155
  byDoc.set(key, entry);
151
156
  }
152
157
  let restored = 0;
@@ -1 +1 @@
1
- {"version":3,"file":"host-writes.js","sourceRoot":"","sources":["../../src/importer/host-writes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"host-writes.js","sourceRoot":"","sources":["../../src/importer/host-writes.ts"],"names":[],"mappings":"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"}
@@ -2,9 +2,10 @@ import type { Payload } from 'payload';
2
2
  import { type ImportManifest } from './types.js';
3
3
  /**
4
4
  * Manifest lifecycle (issue #50): `verify` checks both sides, `rollback`
5
- * undoes exactly what the manifest records, and `finalize` marks the
6
- * manifest so the source tables may be dropped — by the operator, as a
7
- * separate later step.
5
+ * undoes exactly what the manifest records, and `finalize` records the
6
+ * point of no return (a database marker plus the re-signed manifest) so
7
+ * the source tables may be dropped — by the operator, as a separate
8
+ * later step.
8
9
  */
9
10
  /**
10
11
  * The importer's default manifest location: the CURRENT WORKING
@@ -58,13 +59,8 @@ export declare function verifyImport(options: {
58
59
  /** Injectable clock: what counts as an expired source session. */
59
60
  readonly now?: (() => Date) | undefined;
60
61
  }): Promise<VerifyResult>;
61
- /**
62
- * Rollback (issue #50): delete the created rows in reverse order and
63
- * restore every captured field value. The manifest records exactly
64
- * what to undo — nothing else is touched, and the source tables were
65
- * never modified.
66
- */
67
- export declare function rollbackImport(options: {
62
+ /** Options of {@link rollbackImport}. */
63
+ export type RollbackOptions = {
68
64
  readonly payload: Payload;
69
65
  readonly manifest: ImportManifest;
70
66
  readonly log?: (message: string) => void;
@@ -76,12 +72,61 @@ export declare function rollbackImport(options: {
76
72
  */
77
73
  readonly manifestPath?: string | undefined;
78
74
  readonly now?: (() => Date) | undefined;
79
- /** Accept a pre-0.6.0 manifest that has no MAC (`--allow-unsigned-manifest`). */
75
+ /** Target slugs the import ran with (`--slugs`); defaults to the ba-* set. */
76
+ readonly slugs?: Readonly<Record<string, string>> | undefined;
77
+ /**
78
+ * Accept a manifest without a full signature (`--allow-unsigned-manifest`):
79
+ * a pre-0.6.0 manifest without a MAC, or a 0.6.0 manifest whose MAC
80
+ * does not cover `finalized`.
81
+ */
80
82
  readonly allowUnsignedManifest?: boolean | undefined;
81
- }): Promise<{
83
+ /**
84
+ * Let a rollback driven by an UNSIGNED (pre-0.6.0) manifest delete the
85
+ * rows it lists and restore plaintext (version-1) values
86
+ * (`--allow-unsigned-deletes`). Without it, an unsigned manifest may
87
+ * only restore sealed field values.
88
+ */
89
+ readonly allowUnsignedDeletes?: boolean | undefined;
90
+ };
91
+ /**
92
+ * Rollback (issue #50): delete the created rows in reverse order and
93
+ * restore every captured field value. The manifest records exactly
94
+ * what to undo — nothing else is touched, and the source tables were
95
+ * never modified.
96
+ *
97
+ * Before anything is written, rollback refuses: a finalized manifest,
98
+ * or a migration the DATABASE records as finalized (the marker
99
+ * `finalize` writes — a manifest file alone cannot reopen it); a
100
+ * manifest that fails its signature; created rows outside the import's
101
+ * own target collections (signed or not), or whose row no longer
102
+ * carries the importer's deterministic `baId`; and any delete or
103
+ * plaintext restore driven by an unsigned manifest without
104
+ * `allowUnsignedDeletes`. A row already absent is fine (the goal is
105
+ * "absent"); a delete that FAILS (a foreign key, a hook, a permission)
106
+ * aborts the rollback with the rows named, before any field is
107
+ * restored or the manifest reset — so it can be re-run once fixed.
108
+ */
109
+ export declare function rollbackImport(options: RollbackOptions): Promise<{
82
110
  deleted: number;
83
111
  restored: number;
84
112
  }>;
85
- /** Finalize (issue #50): the point of no return — mark the manifest. */
86
- export declare function finalizeManifest(manifest: ImportManifest, path: string): ImportManifest;
113
+ /** Options of {@link finalizeManifest}. */
114
+ export type FinalizeOptions = {
115
+ readonly payload: Payload;
116
+ readonly manifest: ImportManifest;
117
+ /** Where the finalized, re-signed manifest is written. */
118
+ readonly path: string;
119
+ readonly now?: (() => Date) | undefined;
120
+ /** Accept a manifest without a full signature (`--allow-unsigned-manifest`). */
121
+ readonly allowUnsignedManifest?: boolean | undefined;
122
+ };
123
+ /**
124
+ * Finalize (issue #50): the point of no return. Records a one-way
125
+ * marker in the target database (Payload's key-value store) that every
126
+ * later rollback checks independently of the file, then marks the
127
+ * manifest `finalized` and re-signs it — the signature covers the flag.
128
+ * Idempotent: finalizing a finalized manifest re-records the marker and
129
+ * upgrades its signature.
130
+ */
131
+ export declare function finalizeManifest(options: FinalizeOptions): Promise<ImportManifest>;
87
132
  //# sourceMappingURL=lifecycle.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/importer/lifecycle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AAGtC,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,YAAY,CAAA;AAEnB;;;;;GAKG;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,qCAAqC,CAAA;AAErE,uEAAuE;AACvE,eAAO,MAAM,0BAA0B,mCAAmC,CAAA;AAE1E,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAahE;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE1E;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAA;IACpB,QAAQ,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,CAAA;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;KAAE,EAAE,CAAA;CAChF,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE;IAC1C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAA;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;IAC7D,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAA;IAC3E,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAA;IAChD,kEAAkE;IAClE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;CACxC,GAAG,OAAO,CAAC,YAAY,CAAC,CA6YxB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IACjC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACxC;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAA;IACvC,iFAAiF;IACjF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CACrD,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCjD;AAED,wEAAwE;AACxE,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,GAAG,cAAc,CAOvF"}
1
+ {"version":3,"file":"lifecycle.d.ts","sourceRoot":"","sources":["../../src/importer/lifecycle.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,15 @@
1
1
  import { existsSync, readFileSync } from 'node:fs';
2
2
  import { writePrivateFile } from '../private-file.js';
3
+ import { assertCreatedRowsScoped, baIdMismatch, finalizeMarkerState, hostRolesField, recordFinalizeMarker, targetSlugsOf, } from './guards.js';
3
4
  import { restoreCaptured } from './host-writes.js';
4
5
  import { authenticateManifest, signManifest } from './manifest-mac.js';
5
6
  import { defaultTargetSlugs, resolveSourceTables, sourceModelNames, } from './types.js';
6
7
  /**
7
8
  * Manifest lifecycle (issue #50): `verify` checks both sides, `rollback`
8
- * undoes exactly what the manifest records, and `finalize` marks the
9
- * manifest so the source tables may be dropped — by the operator, as a
10
- * separate later step.
9
+ * undoes exactly what the manifest records, and `finalize` records the
10
+ * point of no return (a database marker plus the re-signed manifest) so
11
+ * the source tables may be dropped — by the operator, as a separate
12
+ * later step.
11
13
  */
12
14
  /**
13
15
  * The importer's default manifest location: the CURRENT WORKING
@@ -201,6 +203,9 @@ export async function verifyImport(options) {
201
203
  // lookup findByProviderIdentity issues on the next provider
202
204
  // sign-in. The host docs also carry the stored roles (issue #68's
203
205
  // users_role accounting) whenever the host declares the field.
206
+ // The roles field the app configured on authLink (issue #110: a
207
+ // hard-coded `roles` silently skipped the check on `role` layouts).
208
+ const rolesField = hostRolesField(payload);
204
209
  let identityIssues = 0;
205
210
  let roleMismatchDocs = 0;
206
211
  let hostDocsWithRoles = 0;
@@ -238,7 +243,7 @@ export async function verifyImport(options) {
238
243
  if (identities.length !== 1 || resolving.length !== 1) {
239
244
  identityIssues += 1;
240
245
  }
241
- const roles = record['roles'];
246
+ const roles = record[rolesField];
242
247
  if (Array.isArray(roles)) {
243
248
  hostDocsWithRoles += 1;
244
249
  const stored = new Set(roles.map((role) => String(role)));
@@ -249,11 +254,11 @@ export async function verifyImport(options) {
249
254
  }
250
255
  check('every imported user resolves through one better-auth identity', identityIssues === 0, `${identityIssues} user(s) without exactly one better-auth identity resolving to their ba-users id`);
251
256
  if (hostDocsWithRoles > 0) {
252
- check('source roles carried onto the host docs', roleMismatchDocs === 0, `${roleMismatchDocs} host doc(s) missing stored role values`);
257
+ check('source roles carried onto the host docs', roleMismatchDocs === 0, `${roleMismatchDocs} host doc(s) missing stored role values in '${rolesField}'`);
253
258
  }
254
259
  else if (sourceTables['users_role'] !== null && users.some((user) => user.roles.length > 0)) {
255
260
  checks.push({
256
- name: 'source roles carried onto the host docs (skipped: the host users carry no roles field)',
261
+ name: `source roles carried onto the host docs (skipped: the host users carry no '${rolesField}' field)`,
257
262
  passed: true,
258
263
  });
259
264
  }
@@ -391,6 +396,18 @@ export async function verifyImport(options) {
391
396
  * restore every captured field value. The manifest records exactly
392
397
  * what to undo — nothing else is touched, and the source tables were
393
398
  * never modified.
399
+ *
400
+ * Before anything is written, rollback refuses: a finalized manifest,
401
+ * or a migration the DATABASE records as finalized (the marker
402
+ * `finalize` writes — a manifest file alone cannot reopen it); a
403
+ * manifest that fails its signature; created rows outside the import's
404
+ * own target collections (signed or not), or whose row no longer
405
+ * carries the importer's deterministic `baId`; and any delete or
406
+ * plaintext restore driven by an unsigned manifest without
407
+ * `allowUnsignedDeletes`. A row already absent is fine (the goal is
408
+ * "absent"); a delete that FAILS (a foreign key, a hook, a permission)
409
+ * aborts the rollback with the rows named, before any field is
410
+ * restored or the manifest reset — so it can be re-run once fixed.
394
411
  */
395
412
  export async function rollbackImport(options) {
396
413
  const { payload, manifest, log = () => { } } = options;
@@ -401,22 +418,80 @@ export async function rollbackImport(options) {
401
418
  }
402
419
  // Every row below is deleted, and every field restored, with
403
420
  // overrideAccess: only a manifest this app signed may drive that.
404
- authenticateManifest(payload.secret, manifest, { allowUnsigned: options.allowUnsignedManifest });
405
- let deleted = 0;
421
+ const trust = authenticateManifest(payload.secret, manifest, {
422
+ allowUnsigned: options.allowUnsignedManifest,
423
+ });
424
+ if (trust === 'signed-legacy' && options.allowUnsignedManifest !== true) {
425
+ throw new Error("the manifest was signed by migrate 0.6.0, whose signature does not cover the 'finalized' flag. If you are sure this migration was never finalized and nobody has edited the manifest, re-run with --allow-unsigned-manifest; the rollback re-signs what it leaves behind");
426
+ }
427
+ // The database's own record of `finalize`, independent of the file.
428
+ // A manifest whose `createdAt` is not covered by a full signature is
429
+ // checked against every finalized migration of its kind.
430
+ const marker = await finalizeMarkerState(payload, manifest, { anyOfKind: trust !== 'signed' });
431
+ if (marker === 'finalized') {
432
+ throw new Error('the database records this migration as finalized; rollback is no longer possible (the manifest file does not override that)');
433
+ }
434
+ if (marker === 'unavailable') {
435
+ log("rollback: Payload's key-value store is unavailable, so the database finalize marker could not be checked; relying on the manifest's own flag");
436
+ }
437
+ assertCreatedRowsScoped(manifest, targetSlugsOf(options.slugs));
438
+ if (trust === 'unsigned' && options.allowUnsignedDeletes !== true) {
439
+ const plaintext = manifest.fieldWrites.filter((write) => write.before !== undefined).length;
440
+ if (manifest.created.length > 0 || plaintext > 0) {
441
+ throw new Error(`the manifest is unsigned: --allow-unsigned-manifest lets it restore sealed field values only, and it lists ${manifest.created.length} row(s) to delete and ${plaintext} plaintext value(s) to restore. Review the manifest's created rows, then re-run with --allow-unsigned-deletes as well — nothing was changed`);
442
+ }
443
+ }
444
+ // Pre-flight every created row BEFORE the first delete: a present row
445
+ // must still carry the importer's deterministic baId for its source
446
+ // key (the imported row, not one that took its id since).
447
+ const present = [];
448
+ const foreign = [];
449
+ let absent = 0;
406
450
  for (const row of [...manifest.created].reverse()) {
451
+ const doc = await findRow(payload, row);
452
+ if (doc === null) {
453
+ absent += 1;
454
+ }
455
+ else if (baIdMismatch(row, doc)) {
456
+ foreign.push(`${row.collection}#${String(row.id)} (${row.sourceKey})`);
457
+ }
458
+ else {
459
+ present.push(row);
460
+ }
461
+ }
462
+ if (foreign.length > 0) {
463
+ throw new Error(`${foreign.length} created row(s) no longer carry the baId the importer gave them, so they are not the imported rows: ${listSome(foreign, ', ')}. Refusing to delete anything`);
464
+ }
465
+ let deleted = 0;
466
+ const failed = [];
467
+ for (const row of present) {
407
468
  try {
408
469
  await payload.delete({ collection: row.collection, id: row.id, overrideAccess: true });
409
470
  deleted += 1;
410
471
  }
411
- catch {
412
- // Already gone (a crash after delete, a manual cleanup) — the
413
- // goal state is "row absent", so absence is success.
414
- log(`rollback: ${row.collection}#${row.id} already absent`);
472
+ catch (error) {
473
+ if ((await findRow(payload, row)) === null) {
474
+ // Removed concurrently: the goal state is "row absent".
475
+ absent += 1;
476
+ continue;
477
+ }
478
+ failed.push(`${row.collection}#${String(row.id)}: ${error instanceof Error ? error.message : String(error)}`);
415
479
  }
416
480
  }
481
+ if (failed.length > 0) {
482
+ for (const line of failed) {
483
+ log(`rollback: FAILED to delete ${line}`);
484
+ }
485
+ throw new Error(`rollback deleted ${deleted} row(s) but could not delete ${failed.length}: ${listSome(failed, '; ')}. No field value was restored and the manifest was kept — fix the cause (e.g. rows that reference them) and re-run rollback`);
486
+ }
487
+ if (absent > 0) {
488
+ log(`rollback: ${absent} created row(s) were already absent`);
489
+ }
417
490
  // Captured values go back through the adapter, one write per
418
491
  // document, `updatedAt` included — see host-writes.ts for why.
419
- const restored = await restoreCaptured(payload, manifest);
492
+ const restored = await restoreCaptured(payload, manifest, {
493
+ rolesField: hostRolesField(payload),
494
+ });
420
495
  if (options.manifestPath !== undefined) {
421
496
  const reset = signManifest(payload.secret, {
422
497
  ...manifest,
@@ -430,13 +505,41 @@ export async function rollbackImport(options) {
430
505
  log(`rollback: ${deleted} row(s) deleted, ${restored} field value(s) restored`);
431
506
  return { deleted, restored };
432
507
  }
433
- /** Finalize (issue #50): the point of no return — mark the manifest. */
434
- export function finalizeManifest(manifest, path) {
435
- if (manifest.finalized) {
436
- return manifest;
437
- }
438
- const finalized = { ...manifest, finalized: true };
439
- writeManifest(finalized, path);
508
+ /** The created row as stored, or `null` when it does not exist. */
509
+ async function findRow(payload, row) {
510
+ const doc = await payload.findByID({
511
+ collection: row.collection,
512
+ id: row.id,
513
+ depth: 0,
514
+ overrideAccess: true,
515
+ disableErrors: true,
516
+ });
517
+ return doc ?? null;
518
+ }
519
+ function listSome(items, separator) {
520
+ return `${items.slice(0, 10).join(separator)}${items.length > 10 ? `${separator}…` : ''}`;
521
+ }
522
+ /**
523
+ * Finalize (issue #50): the point of no return. Records a one-way
524
+ * marker in the target database (Payload's key-value store) that every
525
+ * later rollback checks independently of the file, then marks the
526
+ * manifest `finalized` and re-signs it — the signature covers the flag.
527
+ * Idempotent: finalizing a finalized manifest re-records the marker and
528
+ * upgrades its signature.
529
+ */
530
+ export async function finalizeManifest(options) {
531
+ const { payload, manifest } = options;
532
+ authenticateManifest(payload.secret, manifest, { allowUnsigned: options.allowUnsignedManifest });
533
+ const finalizedAt = manifest.finalizedAt ?? (options.now ?? (() => new Date()))().toISOString();
534
+ // The database marker first: a finalize that cannot record it fails
535
+ // with the manifest unchanged.
536
+ await recordFinalizeMarker(payload, manifest, finalizedAt);
537
+ const finalized = signManifest(payload.secret, {
538
+ ...manifest,
539
+ finalized: true,
540
+ finalizedAt,
541
+ });
542
+ writeManifest(finalized, options.path);
440
543
  return finalized;
441
544
  }
442
545
  //# sourceMappingURL=lifecycle.js.map