@payload-auth-link/migrate 0.3.1 → 0.4.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 (69) hide show
  1. package/README.md +6 -3
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +49 -6
  4. package/dist/cli.js.map +1 -1
  5. package/dist/codemods.d.ts +17 -8
  6. package/dist/codemods.d.ts.map +1 -1
  7. package/dist/codemods.js +439 -20
  8. package/dist/codemods.js.map +1 -1
  9. package/dist/doctor/database.d.ts +5 -1
  10. package/dist/doctor/database.d.ts.map +1 -1
  11. package/dist/doctor/database.js +98 -34
  12. package/dist/doctor/database.js.map +1 -1
  13. package/dist/doctor/plugins.d.ts +15 -0
  14. package/dist/doctor/plugins.d.ts.map +1 -1
  15. package/dist/doctor/plugins.js +43 -0
  16. package/dist/doctor/plugins.js.map +1 -1
  17. package/dist/doctor/run-doctor.d.ts +11 -0
  18. package/dist/doctor/run-doctor.d.ts.map +1 -1
  19. package/dist/doctor/run-doctor.js +66 -20
  20. package/dist/doctor/run-doctor.js.map +1 -1
  21. package/dist/doctor/source-scan.d.ts +5 -0
  22. package/dist/doctor/source-scan.d.ts.map +1 -1
  23. package/dist/doctor/source-scan.js +9 -0
  24. package/dist/doctor/source-scan.js.map +1 -1
  25. package/dist/doctor/types.d.ts +12 -0
  26. package/dist/doctor/types.d.ts.map +1 -1
  27. package/dist/exporters.d.ts +7 -0
  28. package/dist/exporters.d.ts.map +1 -1
  29. package/dist/exporters.js +36 -1
  30. package/dist/exporters.js.map +1 -1
  31. package/dist/importer/apply.d.ts +5 -0
  32. package/dist/importer/apply.d.ts.map +1 -1
  33. package/dist/importer/apply.js +61 -33
  34. package/dist/importer/apply.js.map +1 -1
  35. package/dist/importer/lifecycle.d.ts +15 -6
  36. package/dist/importer/lifecycle.d.ts.map +1 -1
  37. package/dist/importer/lifecycle.js +131 -39
  38. package/dist/importer/lifecycle.js.map +1 -1
  39. package/dist/importer/run-import.d.ts +6 -0
  40. package/dist/importer/run-import.d.ts.map +1 -1
  41. package/dist/importer/run-import.js +72 -20
  42. package/dist/importer/run-import.js.map +1 -1
  43. package/dist/importer/source.d.ts +47 -4
  44. package/dist/importer/source.d.ts.map +1 -1
  45. package/dist/importer/source.js +159 -27
  46. package/dist/importer/source.js.map +1 -1
  47. package/dist/importer/types.d.ts +33 -0
  48. package/dist/importer/types.d.ts.map +1 -1
  49. package/dist/importer/types.js +48 -0
  50. package/dist/importer/types.js.map +1 -1
  51. package/dist/index.d.ts +5 -3
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +5 -3
  54. package/dist/index.js.map +1 -1
  55. package/package.json +8 -11
  56. package/src/cli.ts +52 -6
  57. package/src/codemods.ts +537 -35
  58. package/src/doctor/database.ts +129 -46
  59. package/src/doctor/plugins.ts +51 -0
  60. package/src/doctor/run-doctor.ts +90 -25
  61. package/src/doctor/source-scan.ts +10 -0
  62. package/src/doctor/types.ts +9 -0
  63. package/src/exporters.ts +46 -1
  64. package/src/importer/apply.ts +78 -32
  65. package/src/importer/lifecycle.ts +163 -43
  66. package/src/importer/run-import.ts +102 -19
  67. package/src/importer/source.ts +214 -30
  68. package/src/importer/types.ts +86 -0
  69. package/src/index.ts +25 -2
package/src/cli.ts CHANGED
@@ -61,19 +61,29 @@ function usage(): string {
61
61
 
62
62
  Commands:
63
63
  doctor --config ./src/payload.config.ts [--src ./src] [--json] [--database-url URL]
64
+ [--source-map '{"accounts":"user_accounts","sessions":"user_sessions"}']
64
65
  export --database-url URL [--out file.jsonl]
66
+ [--tables users,accounts | '["users","accounts"]']
65
67
  (lossless JSONL of every auth table — the off-ramp, #58)
66
68
  codemod --src ./src [--write]
67
69
  from-payload-auth --config ./src/payload.config.ts [--apply] [--sessions=carry|drop]
68
70
  [--manifest ./payload-auth-link-migration.json] [--database-url URL] [--json]
71
+ [--source-map '{"accounts":"user_accounts","sessions":"user_sessions"}']
69
72
  verify --config ./src/payload.config.ts [--database-url URL] [--json]
73
+ [--source-map '{"accounts":"user_accounts","sessions":"user_sessions"}']
70
74
  rollback --config ./src/payload.config.ts [--manifest ...]
71
75
  finalize [--manifest ...]
72
76
 
73
- doctor is read-only: it loads the config, inspects the users
74
- collection and Better Auth plugins, scans sources for call sites
75
- that must migrate, and (with a database URL) reports row counts,
76
- unverified users, and orphans.
77
+ --source-map renames source models to your layout's tables (custom
78
+ slugs like user_accounts/user_sessions); a null value records a
79
+ model as not installed. Without it, a missing source table aborts
80
+ the run — nothing is silently read as empty.
81
+
82
+ doctor is read-only: it loads the config (an unloadable config is a
83
+ blocker, not a crash), inspects the users collection and Better
84
+ Auth plugins, scans sources for call sites that must migrate, and
85
+ (with a database URL) reports row counts, unverified users, and
86
+ orphans.
77
87
 
78
88
  from-payload-auth is a DRY RUN by default: it prints planned row
79
89
  counts per model, collisions, and anything unmappable. --apply
@@ -105,7 +115,13 @@ function formatReport(report: DoctorReport): string {
105
115
  lines.push(' none declared')
106
116
  }
107
117
  for (const finding of report.plugins) {
108
- lines.push(` - ${finding.id}: ${finding.status} — ${finding.detail}`)
118
+ lines.push(
119
+ ` - ${finding.id}: ${finding.status} — ${finding.detail}${
120
+ finding.files !== undefined && finding.files.length > 0
121
+ ? ` (files: ${finding.files.join(', ')})`
122
+ : ''
123
+ }`
124
+ )
109
125
  }
110
126
  lines.push('')
111
127
  lines.push('== users collection ==')
@@ -219,12 +235,33 @@ async function main(
219
235
  err.write('export requires --database-url or DATABASE_URL\n')
220
236
  return 3
221
237
  }
238
+ const tablesFlag = flags.get('tables')
239
+ let tables: readonly string[] | undefined
240
+ if (typeof tablesFlag === 'string') {
241
+ try {
242
+ const { parseExportTables } = await import('./exporters.js')
243
+ tables = parseExportTables(tablesFlag)
244
+ } catch (error) {
245
+ err.write(`${error instanceof Error ? error.message : String(error)}\n`)
246
+ return 3
247
+ }
248
+ }
222
249
  const { exportToJsonl } = await import('./exporters.js')
223
250
  const result = await exportToJsonl({
224
251
  connectionString: databaseUrl,
225
252
  format: 'jsonl',
253
+ ...(tables === undefined ? {} : { tables }),
226
254
  log: (message) => out.write(`${message}\n`),
227
255
  })
256
+ // A requested table that doesn't exist is an error, not a gap
257
+ // (issue #68): nothing is silently omitted.
258
+ if (tables !== undefined && result.missing.length > 0) {
259
+ for (const table of result.missing) {
260
+ err.write(`export: table '${table}' does not exist on the source\n`)
261
+ }
262
+ err.write('nothing silently omitted; fix --tables or drop it\n')
263
+ return 1
264
+ }
228
265
  if (typeof flags.get('out') === 'string') {
229
266
  writeFileSync(flags.get('out') as string, result.jsonl)
230
267
  out.write(`wrote ${result.totalRows} row(s) to ${String(flags.get('out'))}\n`)
@@ -325,6 +362,9 @@ async function main(
325
362
  ...(typeof flags.get('slugs') === 'string'
326
363
  ? { slugsJson: flags.get('slugs') as string }
327
364
  : {}),
365
+ ...(typeof flags.get('source-map') === 'string'
366
+ ? { sourceMapJson: flags.get('source-map') as string }
367
+ : {}),
328
368
  json: flags.get('json') === true,
329
369
  }
330
370
  if (command === 'from-payload-auth') {
@@ -360,6 +400,9 @@ async function main(
360
400
  ? { srcDir: new URL(srcFlag, `file://${process.cwd()}/`).pathname }
361
401
  : {}),
362
402
  ...(typeof dbFlag === 'string' ? { databaseUrl: dbFlag } : {}),
403
+ ...(typeof flags.get('source-map') === 'string'
404
+ ? { sourceMapJson: flags.get('source-map') as string }
405
+ : {}),
363
406
  })
364
407
  if (flags.get('json') === true) {
365
408
  out.write(`${JSON.stringify(report, null, 2)}\n`)
@@ -383,8 +426,11 @@ if (invokedDirectly) {
383
426
  process.exitCode = code
384
427
  })
385
428
  .catch((error: unknown) => {
429
+ // Name the command that failed (issue #71) — 'doctor failed:' was
430
+ // wrong for every other subcommand.
431
+ const { command } = parseArgs(process.argv.slice(2))
386
432
  process.stderr.write(
387
- `doctor failed: ${error instanceof Error ? error.message : String(error)}\n`
433
+ `${command ?? 'cli'} failed: ${error instanceof Error ? error.message : String(error)}\n`
388
434
  )
389
435
  process.exitCode = 1
390
436
  })