@trieb.work/payload-plugin-backup-mongodb 0.1.7 → 0.2.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 (85) hide show
  1. package/README.md +130 -62
  2. package/dist/backup-dashboard.css +18 -1
  3. package/dist/collections/BackupTasks.js +8 -1
  4. package/dist/collections/BackupTasks.js.map +1 -1
  5. package/dist/components/BackupDashboard/BackupSettingsModal.client.js +203 -115
  6. package/dist/components/BackupDashboard/BackupSettingsModal.client.js.map +1 -1
  7. package/dist/components/BackupDashboard/RestoreBackupDialog.client.js +1 -1
  8. package/dist/components/BackupDashboard/RestoreBackupDialog.client.js.map +1 -1
  9. package/dist/components/BackupDashboard/TaskActionButton.client.d.ts +1 -1
  10. package/dist/components/BackupDashboard/TaskActionButton.client.js +59 -26
  11. package/dist/components/BackupDashboard/TaskActionButton.client.js.map +1 -1
  12. package/dist/components/BackupDashboard/backupDashboardInlineCss.js +1 -1
  13. package/dist/components/BackupDashboard/backupDashboardInlineCss.js.map +1 -1
  14. package/dist/components/BackupDashboard/index.js +27 -3
  15. package/dist/components/BackupDashboard/index.js.map +1 -1
  16. package/dist/core/backup.d.ts +4 -3
  17. package/dist/core/backup.js +50 -43
  18. package/dist/core/backup.js.map +1 -1
  19. package/dist/core/backupArchiveRead.d.ts +15 -0
  20. package/dist/core/backupArchiveRead.js +30 -0
  21. package/dist/core/backupArchiveRead.js.map +1 -0
  22. package/dist/core/backupSettings.js +5 -0
  23. package/dist/core/backupSettings.js.map +1 -1
  24. package/dist/core/restore.d.ts +5 -2
  25. package/dist/core/restore.js +133 -89
  26. package/dist/core/restore.js.map +1 -1
  27. package/dist/core/restorePreview.d.ts +12 -3
  28. package/dist/core/restorePreview.js +17 -13
  29. package/dist/core/restorePreview.js.map +1 -1
  30. package/dist/core/restoreResult.d.ts +34 -0
  31. package/dist/core/restoreResult.js +45 -0
  32. package/dist/core/restoreResult.js.map +1 -0
  33. package/dist/core/storage/config.d.ts +31 -0
  34. package/dist/core/storage/config.js +60 -0
  35. package/dist/core/storage/config.js.map +1 -0
  36. package/dist/core/storage/index.d.ts +23 -0
  37. package/dist/core/storage/index.js +25 -0
  38. package/dist/core/storage/index.js.map +1 -0
  39. package/dist/core/storage/s3.d.ts +35 -0
  40. package/dist/core/storage/s3.js +200 -0
  41. package/dist/core/storage/s3.js.map +1 -0
  42. package/dist/core/storage/types.d.ts +60 -0
  43. package/dist/core/storage/types.js +6 -0
  44. package/dist/core/storage/types.js.map +1 -0
  45. package/dist/core/storage/vercelBlob.d.ts +25 -0
  46. package/dist/core/storage/vercelBlob.js +53 -0
  47. package/dist/core/storage/vercelBlob.js.map +1 -0
  48. package/dist/core/taskProgress.d.ts +10 -4
  49. package/dist/core/taskProgress.js +11 -2
  50. package/dist/core/taskProgress.js.map +1 -1
  51. package/dist/endpoints/index.js +0 -5
  52. package/dist/endpoints/index.js.map +1 -1
  53. package/dist/endpoints/paths/admin-backup-download.js +8 -7
  54. package/dist/endpoints/paths/admin-backup-download.js.map +1 -1
  55. package/dist/endpoints/paths/admin-delete.js +11 -5
  56. package/dist/endpoints/paths/admin-delete.js.map +1 -1
  57. package/dist/endpoints/paths/admin-manual.js +2 -1
  58. package/dist/endpoints/paths/admin-manual.js.map +1 -1
  59. package/dist/endpoints/paths/admin-preview.js +9 -2
  60. package/dist/endpoints/paths/admin-preview.js.map +1 -1
  61. package/dist/endpoints/paths/admin-restore.js +7 -4
  62. package/dist/endpoints/paths/admin-restore.js.map +1 -1
  63. package/dist/endpoints/paths/admin-settings.js +35 -2
  64. package/dist/endpoints/paths/admin-settings.js.map +1 -1
  65. package/dist/endpoints/paths/cron-list.js +2 -1
  66. package/dist/endpoints/paths/cron-list.js.map +1 -1
  67. package/dist/endpoints/paths/cron-restore.js +14 -4
  68. package/dist/endpoints/paths/cron-restore.js.map +1 -1
  69. package/dist/endpoints/paths/cron-run.js +2 -1
  70. package/dist/endpoints/paths/cron-run.js.map +1 -1
  71. package/dist/endpoints/shared.d.ts +0 -1
  72. package/dist/endpoints/shared.js +0 -6
  73. package/dist/endpoints/shared.js.map +1 -1
  74. package/dist/index.d.ts +5 -3
  75. package/dist/index.js +3 -2
  76. package/dist/index.js.map +1 -1
  77. package/dist/publicApiPaths.d.ts +0 -1
  78. package/dist/publicApiPaths.js +0 -1
  79. package/dist/publicApiPaths.js.map +1 -1
  80. package/dist/types.d.ts +0 -5
  81. package/dist/types.js.map +1 -1
  82. package/package.json +22 -4
  83. package/dist/endpoints/paths/admin-seed.d.ts +0 -3
  84. package/dist/endpoints/paths/admin-seed.js +0 -47
  85. package/dist/endpoints/paths/admin-seed.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/endpoints/paths/admin-settings.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { list } from '@vercel/blob'\nimport { after } from 'next/server'\n\nimport type { BackupPluginOptions } from '../../types'\n\nimport { transferBackupBlobsToToken } from '../../core/backupBlobTransfer'\nimport {\n BACKUP_SETTINGS_SLUG,\n getResolvedCronBackupSettings,\n normalizeSkipMongoCollections,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n toPayloadSkipRows,\n} from '../../core/backupSettings'\nimport { validateBackupBlobToken } from '../../core/blobTokenValidate'\nimport {\n completeBackupTask,\n createBackupTask,\n failBackupTask,\n updateBackupTask,\n} from '../../core/taskProgress'\nimport { describeCronSchedule, readVercelBackupCronFromRepo } from '../../core/vercelBackupCron'\nimport {\n maskBlobReadWriteToken,\n shouldPreserveBackupBlobTokenField,\n} from '../../utils/maskBlobToken'\nimport { readRequestJson, requireBackupAdmin } from '../shared'\n\nfunction clampBackupsToKeep(n: unknown): number {\n if (typeof n !== 'number' || !Number.isFinite(n)) {\n return 10\n }\n return Math.min(365, Math.max(1, Math.floor(n)))\n}\n\nfunction buildSettingsJson(\n stored: Awaited<ReturnType<typeof getResolvedCronBackupSettings>>,\n options: BackupPluginOptions,\n vercelCron: ReturnType<typeof readVercelBackupCronFromRepo>,\n humanDescription: null | string,\n transfer:\n | {\n deferred: boolean\n failed: number\n performed: boolean\n pollSecret?: string\n skipped: number\n taskId?: string\n total: number\n transferred: number\n }\n | undefined,\n) {\n const t = transfer ?? {\n deferred: false,\n failed: 0,\n performed: false,\n skipped: 0,\n total: 0,\n transferred: 0,\n }\n return {\n id: stored.id,\n backupBlobAccess: stored.backupBlobAccess,\n backupBlobAccessEffective: resolveBackupBlobAccess(stored),\n backupBlobTokenMasked: maskBlobReadWriteToken(stored.backupBlobReadWriteToken),\n backupsToKeep: stored.backupsToKeep,\n cron:\n vercelCron ?\n {\n configFileRelative: vercelCron.configFileRelative,\n humanDescription,\n path: vercelCron.path,\n schedule: vercelCron.schedule,\n }\n : null,\n effectiveBackupsToKeep:\n typeof options.backupsToKeep === 'number' ? options.backupsToKeep : stored.backupsToKeep,\n hasBackupBlobReadWriteToken: stored.backupBlobReadWriteToken.trim().length > 0,\n includeMediaForCron: stored.includeMediaForCron,\n pluginBackupsToKeepOverride: typeof options.backupsToKeep === 'number',\n skipMongoCollections: stored.skipMongoCollections,\n transfer: t,\n }\n}\n\nexport function createAdminSettingsEndpoints(options: BackupPluginOptions): Endpoint[] {\n return [\n {\n handler: async (req) => {\n const auth = await requireBackupAdmin(req, options)\n if (auth instanceof Response) {\n return auth\n }\n\n const { payload } = req\n const stored = await getResolvedCronBackupSettings(payload)\n const vercelCron = readVercelBackupCronFromRepo()\n const humanDescription =\n vercelCron?.schedule != null ? describeCronSchedule(vercelCron.schedule) : null\n\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, undefined),\n )\n },\n method: 'get',\n path: '/backup-mongodb/admin/settings',\n },\n {\n handler: async (req) => {\n const auth = await requireBackupAdmin(req, options)\n if (auth instanceof Response) {\n return auth\n }\n\n const { payload } = req\n const body = (await readRequestJson(req)) as Record<string, unknown>\n const backupsToKeep = clampBackupsToKeep(body?.backupsToKeep)\n const skipMongoCollections = normalizeSkipMongoCollections(body?.skipMongoCollections)\n const includeMediaForCron = body?.includeMediaForCron === true\n const transferBackupBlobs =\n typeof body?.transferBackupBlobs === 'boolean' ? body.transferBackupBlobs : false\n const deleteBackupBlobsFromSource =\n typeof body?.deleteBackupBlobsFromSource === 'boolean' ?\n body.deleteBackupBlobsFromSource\n : false\n const requestedRaw =\n typeof body?.backupBlobReadWriteToken === 'string' ? body.backupBlobReadWriteToken : ''\n const requestedTrimmed = requestedRaw.trim()\n\n let stored = await getResolvedCronBackupSettings(payload)\n const previousAccess = resolveBackupBlobAccess(stored)\n const previousBackupBlobToken = stored.backupBlobReadWriteToken.trim()\n const hadStoredToken = previousBackupBlobToken.length > 0\n const preserveTokenField = shouldPreserveBackupBlobTokenField(\n requestedTrimmed,\n hadStoredToken,\n )\n const tokenForDb = preserveTokenField ? previousBackupBlobToken : requestedTrimmed\n\n // Access detection: re-probe when the token actually changes; preserve existing otherwise;\n // clear when the override is removed (falls back to heuristic on the default env token).\n let backupBlobAccessForDb: 'private' | 'public' | null = stored.backupBlobAccess\n if (!preserveTokenField) {\n if (tokenForDb.length === 0) {\n backupBlobAccessForDb = null\n } else {\n const validation = await validateBackupBlobToken(tokenForDb)\n if (!validation.ok) {\n return Response.json(\n { error: `Blob token rejected: ${validation.error ?? 'unknown error'}` },\n { status: 422 },\n )\n }\n backupBlobAccessForDb = validation.access ?? null\n }\n }\n\n if (!stored.id) {\n await payload.create({\n collection: BACKUP_SETTINGS_SLUG,\n data: {\n backupBlobAccess: backupBlobAccessForDb,\n backupBlobReadWriteToken: tokenForDb,\n backupsToKeep,\n includeMediaForCron,\n skipMongoCollections: toPayloadSkipRows(skipMongoCollections),\n },\n overrideAccess: true,\n })\n } else {\n await payload.update({\n id: stored.id,\n collection: BACKUP_SETTINGS_SLUG,\n data: {\n backupBlobAccess: backupBlobAccessForDb,\n backupBlobReadWriteToken: tokenForDb,\n backupsToKeep,\n includeMediaForCron,\n skipMongoCollections: toPayloadSkipRows(skipMongoCollections),\n },\n overrideAccess: true,\n })\n }\n\n stored = await getResolvedCronBackupSettings(payload)\n if (!stored.id) {\n return Response.json({ error: 'Could not persist backup settings' }, { status: 500 })\n }\n\n const vercelCron = readVercelBackupCronFromRepo()\n const humanDescription =\n vercelCron?.schedule != null ? describeCronSchedule(vercelCron.schedule) : null\n\n const newBlobToken = stored.backupBlobReadWriteToken.trim()\n // Read blobs from the *previous* store when rotating tokens; otherwise first-time setup\n // reads from BLOB_READ_WRITE_TOKEN (default Vercel store).\n const sourceTokenForTransfer =\n previousBackupBlobToken.length > 0 ?\n previousBackupBlobToken\n : (process.env.BLOB_READ_WRITE_TOKEN || '').trim()\n\n const shouldTransferToNewBlobToken =\n newBlobToken.length > 0 &&\n sourceTokenForTransfer.length > 0 &&\n newBlobToken !== sourceTokenForTransfer\n\n if (!transferBackupBlobs || !shouldTransferToNewBlobToken) {\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: false,\n failed: 0,\n performed: false,\n skipped: 0,\n total: 0,\n transferred: 0,\n }),\n )\n }\n\n const targetToken = resolveBackupBlobToken(stored)\n const targetAccess = resolveBackupBlobAccess(stored)\n const { blobs } = await list({\n limit: 1000,\n prefix: 'backups/',\n token: sourceTokenForTransfer,\n })\n const total = blobs.length\n\n if (total === 0) {\n const summary = await transferBackupBlobsToToken(\n payload,\n sourceTokenForTransfer,\n targetToken,\n {\n deleteFromSource: deleteBackupBlobsFromSource,\n sourceAccessHint: previousAccess,\n targetAccess,\n },\n )\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: false,\n failed: summary.failed,\n performed: true,\n skipped: summary.skipped,\n total: summary.total,\n transferred: summary.transferred,\n }),\n )\n }\n\n const { pollSecret, taskId } = await createBackupTask(\n payload,\n 'blobTransfer',\n JSON.stringify({ failed: 0, pathname: '', total, transferred: 0 }),\n )\n\n after(\n (async () => {\n try {\n await updateBackupTask(payload, taskId, {\n message: JSON.stringify({ failed: 0, pathname: '', total, transferred: 0 }),\n status: 'running',\n })\n const summary = await transferBackupBlobsToToken(\n payload,\n sourceTokenForTransfer,\n targetToken,\n {\n deleteFromSource: deleteBackupBlobsFromSource,\n sourceAccessHint: previousAccess,\n targetAccess,\n taskId,\n },\n )\n await completeBackupTask(\n payload,\n taskId,\n JSON.stringify({\n failed: summary.failed,\n pathname: '',\n phase: 'done',\n total: summary.total,\n transferred: summary.transferred,\n }),\n )\n } catch (e) {\n await failBackupTask(payload, taskId, e)\n payload.logger.error(\n { err: e, taskId },\n '[backup-settings] Blob transfer task failed',\n )\n }\n })(),\n )\n\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: true,\n failed: 0,\n performed: true,\n pollSecret,\n skipped: 0,\n taskId,\n total,\n transferred: 0,\n }),\n )\n },\n method: 'patch',\n path: '/backup-mongodb/admin/settings',\n },\n ]\n}\n"],"names":["list","after","transferBackupBlobsToToken","BACKUP_SETTINGS_SLUG","getResolvedCronBackupSettings","normalizeSkipMongoCollections","resolveBackupBlobAccess","resolveBackupBlobToken","toPayloadSkipRows","validateBackupBlobToken","completeBackupTask","createBackupTask","failBackupTask","updateBackupTask","describeCronSchedule","readVercelBackupCronFromRepo","maskBlobReadWriteToken","shouldPreserveBackupBlobTokenField","readRequestJson","requireBackupAdmin","clampBackupsToKeep","n","Number","isFinite","Math","min","max","floor","buildSettingsJson","stored","options","vercelCron","humanDescription","transfer","t","deferred","failed","performed","skipped","total","transferred","id","backupBlobAccess","backupBlobAccessEffective","backupBlobTokenMasked","backupBlobReadWriteToken","backupsToKeep","cron","configFileRelative","path","schedule","effectiveBackupsToKeep","hasBackupBlobReadWriteToken","trim","length","includeMediaForCron","pluginBackupsToKeepOverride","skipMongoCollections","createAdminSettingsEndpoints","handler","req","auth","Response","payload","json","undefined","method","body","transferBackupBlobs","deleteBackupBlobsFromSource","requestedRaw","requestedTrimmed","previousAccess","previousBackupBlobToken","hadStoredToken","preserveTokenField","tokenForDb","backupBlobAccessForDb","validation","ok","error","status","access","create","collection","data","overrideAccess","update","newBlobToken","sourceTokenForTransfer","process","env","BLOB_READ_WRITE_TOKEN","shouldTransferToNewBlobToken","targetToken","targetAccess","blobs","limit","prefix","token","summary","deleteFromSource","sourceAccessHint","pollSecret","taskId","JSON","stringify","pathname","message","phase","e","logger","err"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/endpoints/paths/admin-settings.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { list } from '@vercel/blob'\nimport { after } from 'next/server'\n\nimport type { BackupPluginOptions } from '../../types'\n\nimport { transferBackupBlobsToToken } from '../../core/backupBlobTransfer'\nimport {\n BACKUP_SETTINGS_SLUG,\n getResolvedCronBackupSettings,\n normalizeSkipMongoCollections,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n toPayloadSkipRows,\n} from '../../core/backupSettings'\nimport { validateBackupBlobToken } from '../../core/blobTokenValidate'\nimport { getBackupStorageKind, isS3Configured, loadS3Config } from '../../core/storage'\nimport {\n completeBackupTask,\n createBackupTask,\n failBackupTask,\n updateBackupTask,\n} from '../../core/taskProgress'\nimport { describeCronSchedule, readVercelBackupCronFromRepo } from '../../core/vercelBackupCron'\nimport {\n maskBlobReadWriteToken,\n shouldPreserveBackupBlobTokenField,\n} from '../../utils/maskBlobToken'\nimport { readRequestJson, requireBackupAdmin } from '../shared'\n\nfunction clampBackupsToKeep(n: unknown): number {\n if (typeof n !== 'number' || !Number.isFinite(n)) {\n return 10\n }\n return Math.min(365, Math.max(1, Math.floor(n)))\n}\n\n/** Active backup target + a non-secret S3 summary for the admin UI. */\nfunction backupStorageSummary() {\n const kind = getBackupStorageKind()\n if (kind !== 's3' || !isS3Configured()) {\n return { kind }\n }\n const cfg = loadS3Config()\n return {\n kind,\n s3: {\n bucket: cfg.bucket,\n endpoint: cfg.endpoint,\n prefix: cfg.prefix || undefined,\n region: cfg.region,\n },\n }\n}\n\nfunction buildSettingsJson(\n stored: Awaited<ReturnType<typeof getResolvedCronBackupSettings>>,\n options: BackupPluginOptions,\n vercelCron: ReturnType<typeof readVercelBackupCronFromRepo>,\n humanDescription: null | string,\n transfer:\n | {\n deferred: boolean\n failed: number\n performed: boolean\n pollSecret?: string\n skipped: number\n taskId?: string\n total: number\n transferred: number\n }\n | undefined,\n) {\n const t = transfer ?? {\n deferred: false,\n failed: 0,\n performed: false,\n skipped: 0,\n total: 0,\n transferred: 0,\n }\n return {\n id: stored.id,\n backupBlobAccess: stored.backupBlobAccess,\n backupBlobAccessEffective: resolveBackupBlobAccess(stored),\n backupBlobTokenMasked: maskBlobReadWriteToken(stored.backupBlobReadWriteToken),\n backupsToKeep: stored.backupsToKeep,\n cron:\n vercelCron ?\n {\n configFileRelative: vercelCron.configFileRelative,\n humanDescription,\n path: vercelCron.path,\n schedule: vercelCron.schedule,\n }\n : null,\n effectiveBackupsToKeep:\n typeof options.backupsToKeep === 'number' ? options.backupsToKeep : stored.backupsToKeep,\n hasBackupBlobReadWriteToken: stored.backupBlobReadWriteToken.trim().length > 0,\n includeMediaForCron: stored.includeMediaForCron,\n pluginBackupsToKeepOverride: typeof options.backupsToKeep === 'number',\n skipMongoCollections: stored.skipMongoCollections,\n storage: backupStorageSummary(),\n transfer: t,\n }\n}\n\nexport function createAdminSettingsEndpoints(options: BackupPluginOptions): Endpoint[] {\n return [\n {\n handler: async (req) => {\n const auth = await requireBackupAdmin(req, options)\n if (auth instanceof Response) {\n return auth\n }\n\n const { payload } = req\n const stored = await getResolvedCronBackupSettings(payload)\n const vercelCron = readVercelBackupCronFromRepo()\n const humanDescription =\n vercelCron?.schedule != null ? describeCronSchedule(vercelCron.schedule) : null\n\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, undefined),\n )\n },\n method: 'get',\n path: '/backup-mongodb/admin/settings',\n },\n {\n handler: async (req) => {\n const auth = await requireBackupAdmin(req, options)\n if (auth instanceof Response) {\n return auth\n }\n\n const { payload } = req\n const body = (await readRequestJson(req)) as Record<string, unknown>\n const backupsToKeep = clampBackupsToKeep(body?.backupsToKeep)\n const skipMongoCollections = normalizeSkipMongoCollections(body?.skipMongoCollections)\n const includeMediaForCron = body?.includeMediaForCron === true\n const transferBackupBlobs =\n typeof body?.transferBackupBlobs === 'boolean' ? body.transferBackupBlobs : false\n const deleteBackupBlobsFromSource =\n typeof body?.deleteBackupBlobsFromSource === 'boolean' ?\n body.deleteBackupBlobsFromSource\n : false\n const requestedRaw =\n typeof body?.backupBlobReadWriteToken === 'string' ? body.backupBlobReadWriteToken : ''\n const requestedTrimmed = requestedRaw.trim()\n\n let stored = await getResolvedCronBackupSettings(payload)\n const previousAccess = resolveBackupBlobAccess(stored)\n const previousBackupBlobToken = stored.backupBlobReadWriteToken.trim()\n const hadStoredToken = previousBackupBlobToken.length > 0\n const preserveTokenField = shouldPreserveBackupBlobTokenField(\n requestedTrimmed,\n hadStoredToken,\n )\n const tokenForDb = preserveTokenField ? previousBackupBlobToken : requestedTrimmed\n\n // Access detection: re-probe when the token actually changes; preserve existing otherwise;\n // clear when the override is removed (falls back to heuristic on the default env token).\n // Skip Vercel validation when the active target is S3.\n let backupBlobAccessForDb: 'private' | 'public' | null = stored.backupBlobAccess\n if (!preserveTokenField && getBackupStorageKind() !== 's3') {\n if (tokenForDb.length === 0) {\n backupBlobAccessForDb = null\n } else {\n const validation = await validateBackupBlobToken(tokenForDb)\n if (!validation.ok) {\n return Response.json(\n { error: `Blob token rejected: ${validation.error ?? 'unknown error'}` },\n { status: 422 },\n )\n }\n backupBlobAccessForDb = validation.access ?? null\n }\n }\n\n if (!stored.id) {\n await payload.create({\n collection: BACKUP_SETTINGS_SLUG,\n data: {\n backupBlobAccess: backupBlobAccessForDb,\n backupBlobReadWriteToken: tokenForDb,\n backupsToKeep,\n includeMediaForCron,\n skipMongoCollections: toPayloadSkipRows(skipMongoCollections),\n },\n overrideAccess: true,\n })\n } else {\n await payload.update({\n id: stored.id,\n collection: BACKUP_SETTINGS_SLUG,\n data: {\n backupBlobAccess: backupBlobAccessForDb,\n backupBlobReadWriteToken: tokenForDb,\n backupsToKeep,\n includeMediaForCron,\n skipMongoCollections: toPayloadSkipRows(skipMongoCollections),\n },\n overrideAccess: true,\n })\n }\n\n stored = await getResolvedCronBackupSettings(payload)\n if (!stored.id) {\n return Response.json({ error: 'Could not persist backup settings' }, { status: 500 })\n }\n\n const vercelCron = readVercelBackupCronFromRepo()\n const humanDescription =\n vercelCron?.schedule != null ? describeCronSchedule(vercelCron.schedule) : null\n\n // Blob transfer is a Vercel-specific operation (moving blobs between tokens).\n // Skip entirely when the active target is S3.\n if (getBackupStorageKind() === 's3' || !transferBackupBlobs) {\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: false,\n failed: 0,\n performed: false,\n skipped: 0,\n total: 0,\n transferred: 0,\n }),\n )\n }\n\n const newBlobToken = stored.backupBlobReadWriteToken.trim()\n // Read blobs from the *previous* store when rotating tokens; otherwise first-time setup\n // reads from BLOB_READ_WRITE_TOKEN (default Vercel store).\n const sourceTokenForTransfer =\n previousBackupBlobToken.length > 0 ?\n previousBackupBlobToken\n : (process.env.BLOB_READ_WRITE_TOKEN || '').trim()\n\n const shouldTransferToNewBlobToken =\n newBlobToken.length > 0 &&\n sourceTokenForTransfer.length > 0 &&\n newBlobToken !== sourceTokenForTransfer\n\n if (!shouldTransferToNewBlobToken) {\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: false,\n failed: 0,\n performed: false,\n skipped: 0,\n total: 0,\n transferred: 0,\n }),\n )\n }\n\n const targetToken = resolveBackupBlobToken(stored)\n const targetAccess = resolveBackupBlobAccess(stored)\n const { blobs } = await list({\n limit: 1000,\n prefix: 'backups/',\n token: sourceTokenForTransfer,\n })\n const total = blobs.length\n\n if (total === 0) {\n const summary = await transferBackupBlobsToToken(\n payload,\n sourceTokenForTransfer,\n targetToken,\n {\n deleteFromSource: deleteBackupBlobsFromSource,\n sourceAccessHint: previousAccess,\n targetAccess,\n },\n )\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: false,\n failed: summary.failed,\n performed: true,\n skipped: summary.skipped,\n total: summary.total,\n transferred: summary.transferred,\n }),\n )\n }\n\n const { pollSecret, taskId } = await createBackupTask(\n payload,\n 'blobTransfer',\n JSON.stringify({ failed: 0, pathname: '', total, transferred: 0 }),\n )\n\n after(\n (async () => {\n try {\n await updateBackupTask(payload, taskId, {\n message: JSON.stringify({ failed: 0, pathname: '', total, transferred: 0 }),\n status: 'running',\n })\n const summary = await transferBackupBlobsToToken(\n payload,\n sourceTokenForTransfer,\n targetToken,\n {\n deleteFromSource: deleteBackupBlobsFromSource,\n sourceAccessHint: previousAccess,\n targetAccess,\n taskId,\n },\n )\n await completeBackupTask(\n payload,\n taskId,\n JSON.stringify({\n failed: summary.failed,\n pathname: '',\n phase: 'done',\n total: summary.total,\n transferred: summary.transferred,\n }),\n )\n } catch (e) {\n await failBackupTask(payload, taskId, e)\n payload.logger.error(\n { err: e, taskId },\n '[backup-settings] Blob transfer task failed',\n )\n }\n })(),\n )\n\n return Response.json(\n buildSettingsJson(stored, options, vercelCron, humanDescription, {\n deferred: true,\n failed: 0,\n performed: true,\n pollSecret,\n skipped: 0,\n taskId,\n total,\n transferred: 0,\n }),\n )\n },\n method: 'patch',\n path: '/backup-mongodb/admin/settings',\n },\n ]\n}\n"],"names":["list","after","transferBackupBlobsToToken","BACKUP_SETTINGS_SLUG","getResolvedCronBackupSettings","normalizeSkipMongoCollections","resolveBackupBlobAccess","resolveBackupBlobToken","toPayloadSkipRows","validateBackupBlobToken","getBackupStorageKind","isS3Configured","loadS3Config","completeBackupTask","createBackupTask","failBackupTask","updateBackupTask","describeCronSchedule","readVercelBackupCronFromRepo","maskBlobReadWriteToken","shouldPreserveBackupBlobTokenField","readRequestJson","requireBackupAdmin","clampBackupsToKeep","n","Number","isFinite","Math","min","max","floor","backupStorageSummary","kind","cfg","s3","bucket","endpoint","prefix","undefined","region","buildSettingsJson","stored","options","vercelCron","humanDescription","transfer","t","deferred","failed","performed","skipped","total","transferred","id","backupBlobAccess","backupBlobAccessEffective","backupBlobTokenMasked","backupBlobReadWriteToken","backupsToKeep","cron","configFileRelative","path","schedule","effectiveBackupsToKeep","hasBackupBlobReadWriteToken","trim","length","includeMediaForCron","pluginBackupsToKeepOverride","skipMongoCollections","storage","createAdminSettingsEndpoints","handler","req","auth","Response","payload","json","method","body","transferBackupBlobs","deleteBackupBlobsFromSource","requestedRaw","requestedTrimmed","previousAccess","previousBackupBlobToken","hadStoredToken","preserveTokenField","tokenForDb","backupBlobAccessForDb","validation","ok","error","status","access","create","collection","data","overrideAccess","update","newBlobToken","sourceTokenForTransfer","process","env","BLOB_READ_WRITE_TOKEN","shouldTransferToNewBlobToken","targetToken","targetAccess","blobs","limit","token","summary","deleteFromSource","sourceAccessHint","pollSecret","taskId","JSON","stringify","pathname","message","phase","e","logger","err"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { listBackups, resolveBackupListToken } from '../../core/backup';
2
+ import { isBackupStorageConfigured } from '../../core/storage';
2
3
  import { requireCronBearer } from '../shared';
3
4
  export function createCronListEndpoint() {
4
5
  return {
@@ -9,7 +10,7 @@ export function createCronListEndpoint() {
9
10
  }
10
11
  const { payload } = req;
11
12
  const backupBlobToken = await resolveBackupListToken(payload);
12
- if (!backupBlobToken) {
13
+ if (!isBackupStorageConfigured(backupBlobToken)) {
13
14
  return new Response('Service unavailable', {
14
15
  status: 503
15
16
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/endpoints/paths/cron-list.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { listBackups, resolveBackupListToken } from '../../core/backup'\nimport { requireCronBearer } from '../shared'\n\nexport function createCronListEndpoint(): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n\n const { payload } = req\n const backupBlobToken = await resolveBackupListToken(payload)\n if (!backupBlobToken) {\n return new Response('Service unavailable', { status: 503 })\n }\n payload.logger.info('[backup-endpoint] Listing backups')\n const blobs = await listBackups(payload, { blobToken: backupBlobToken })\n payload.logger.info({ count: blobs.length }, '[backup-endpoint] Backup list loaded')\n return Response.json(blobs, { status: 200 })\n },\n method: 'get',\n path: '/backup-mongodb/cron/list',\n }\n}\n"],"names":["listBackups","resolveBackupListToken","requireCronBearer","createCronListEndpoint","handler","req","cronErr","payload","backupBlobToken","Response","status","logger","info","blobs","blobToken","count","length","json","method","path"],"mappings":"AAEA,SAASA,WAAW,EAAEC,sBAAsB,QAAQ,oBAAmB;AACvE,SAASC,iBAAiB,QAAQ,YAAW;AAE7C,OAAO,SAASC;IACd,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUJ,kBAAkBG;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YAEA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,kBAAkB,MAAMP,uBAAuBM;YACrD,IAAI,CAACC,iBAAiB;gBACpB,OAAO,IAAIC,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YACAH,QAAQI,MAAM,CAACC,IAAI,CAAC;YACpB,MAAMC,QAAQ,MAAMb,YAAYO,SAAS;gBAAEO,WAAWN;YAAgB;YACtED,QAAQI,MAAM,CAACC,IAAI,CAAC;gBAAEG,OAAOF,MAAMG,MAAM;YAAC,GAAG;YAC7C,OAAOP,SAASQ,IAAI,CAACJ,OAAO;gBAAEH,QAAQ;YAAI;QAC5C;QACAQ,QAAQ;QACRC,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/endpoints/paths/cron-list.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { listBackups, resolveBackupListToken } from '../../core/backup'\nimport { isBackupStorageConfigured } from '../../core/storage'\nimport { requireCronBearer } from '../shared'\n\nexport function createCronListEndpoint(): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n\n const { payload } = req\n const backupBlobToken = await resolveBackupListToken(payload)\n if (!isBackupStorageConfigured(backupBlobToken)) {\n return new Response('Service unavailable', { status: 503 })\n }\n payload.logger.info('[backup-endpoint] Listing backups')\n const blobs = await listBackups(payload, { blobToken: backupBlobToken })\n payload.logger.info({ count: blobs.length }, '[backup-endpoint] Backup list loaded')\n return Response.json(blobs, { status: 200 })\n },\n method: 'get',\n path: '/backup-mongodb/cron/list',\n }\n}\n"],"names":["listBackups","resolveBackupListToken","isBackupStorageConfigured","requireCronBearer","createCronListEndpoint","handler","req","cronErr","payload","backupBlobToken","Response","status","logger","info","blobs","blobToken","count","length","json","method","path"],"mappings":"AAEA,SAASA,WAAW,EAAEC,sBAAsB,QAAQ,oBAAmB;AACvE,SAASC,yBAAyB,QAAQ,qBAAoB;AAC9D,SAASC,iBAAiB,QAAQ,YAAW;AAE7C,OAAO,SAASC;IACd,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUJ,kBAAkBG;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YAEA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,kBAAkB,MAAMR,uBAAuBO;YACrD,IAAI,CAACN,0BAA0BO,kBAAkB;gBAC/C,OAAO,IAAIC,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YACAH,QAAQI,MAAM,CAACC,IAAI,CAAC;YACpB,MAAMC,QAAQ,MAAMd,YAAYQ,SAAS;gBAAEO,WAAWN;YAAgB;YACtED,QAAQI,MAAM,CAACC,IAAI,CAAC;gBAAEG,OAAOF,MAAMG,MAAM;YAAC,GAAG;YAC7C,OAAOP,SAASQ,IAAI,CAACJ,OAAO;gBAAEH,QAAQ;YAAI;QAC5C;QACAQ,QAAQ;QACRC,MAAM;IACR;AACF"}
@@ -1,5 +1,7 @@
1
1
  import { getResolvedCronBackupSettings, resolveBackupArchiveRead, resolveBackupBlobAccess, resolveBackupBlobToken } from '../../core/backupSettings';
2
2
  import { restoreBackup } from '../../core/restore';
3
+ import { buildRestoreWarnings, formatRestoreSummary, restoreTaskStatus } from '../../core/restoreResult';
4
+ import { getBackupStorageKind, isBackupStorageConfigured } from '../../core/storage';
3
5
  import { readRequestJson, requireCronBearer } from '../shared';
4
6
  export function createCronRestoreEndpoint() {
5
7
  return {
@@ -12,7 +14,7 @@ export function createCronRestoreEndpoint() {
12
14
  const settings = await getResolvedCronBackupSettings(payload);
13
15
  const blobToken = resolveBackupBlobToken(settings);
14
16
  const blobAccess = resolveBackupBlobAccess(settings);
15
- if (!blobToken) {
17
+ if (!isBackupStorageConfigured(blobToken)) {
16
18
  return new Response('Service unavailable', {
17
19
  status: 503
18
20
  });
@@ -31,24 +33,32 @@ export function createCronRestoreEndpoint() {
31
33
  });
32
34
  }
33
35
  const backupRead = resolveBackupArchiveRead(settings, pathname);
34
- if (blobAccess === 'private' && !backupRead) {
36
+ if (getBackupStorageKind() === 'vercel-blob' && blobAccess === 'private' && !backupRead) {
35
37
  return new Response('Missing pathname (required for dedicated backup blob store)', {
36
38
  status: 400
37
39
  });
38
40
  }
41
+ const archivePathname = typeof pathname === 'string' && pathname.startsWith('backups/') ? pathname : undefined;
39
42
  payload.logger.info({
40
43
  url
41
44
  }, '[backup-endpoint] Restore request accepted');
42
- await restoreBackup(payload, url, [], false, undefined, {
45
+ const result = await restoreBackup(payload, url, [], false, undefined, {
46
+ archivePathname,
43
47
  backupRead: backupRead ?? undefined,
44
48
  blobAccess,
45
49
  blobToken
46
50
  });
51
+ const warnings = buildRestoreWarnings(result);
52
+ const status = restoreTaskStatus(result);
47
53
  payload.logger.info({
54
+ result,
55
+ status,
48
56
  url
49
57
  }, '[backup-endpoint] Restore request finished');
50
58
  return Response.json({
51
- message: 'Backup restore finished'
59
+ message: formatRestoreSummary(result),
60
+ status,
61
+ warnings
52
62
  }, {
53
63
  status: 202
54
64
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/endpoints/paths/cron-restore.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport {\n getResolvedCronBackupSettings,\n resolveBackupArchiveRead,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n} from '../../core/backupSettings'\nimport { restoreBackup } from '../../core/restore'\nimport { readRequestJson, requireCronBearer } from '../shared'\n\nexport function createCronRestoreEndpoint(): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n const { payload } = req\n const settings = await getResolvedCronBackupSettings(payload)\n const blobToken = resolveBackupBlobToken(settings)\n const blobAccess = resolveBackupBlobAccess(settings)\n if (!blobToken) {\n return new Response('Service unavailable', { status: 503 })\n }\n\n const { pathname, url } = (await readRequestJson(req)) as { pathname?: string; url?: string }\n if (!url || typeof url !== 'string') {\n return new Response('Missing url', { status: 400 })\n }\n try {\n new URL(url)\n } catch {\n return new Response('Invalid url', { status: 400 })\n }\n\n const backupRead = resolveBackupArchiveRead(settings, pathname)\n if (blobAccess === 'private' && !backupRead) {\n return new Response('Missing pathname (required for dedicated backup blob store)', {\n status: 400,\n })\n }\n\n payload.logger.info({ url }, '[backup-endpoint] Restore request accepted')\n await restoreBackup(payload, url, [], false, undefined, {\n backupRead: backupRead ?? undefined,\n blobAccess,\n blobToken,\n })\n payload.logger.info({ url }, '[backup-endpoint] Restore request finished')\n return Response.json({ message: 'Backup restore finished' }, { status: 202 })\n },\n method: 'post',\n path: '/backup-mongodb/cron/restore',\n }\n}\n"],"names":["getResolvedCronBackupSettings","resolveBackupArchiveRead","resolveBackupBlobAccess","resolveBackupBlobToken","restoreBackup","readRequestJson","requireCronBearer","createCronRestoreEndpoint","handler","req","cronErr","payload","settings","blobToken","blobAccess","Response","status","pathname","url","URL","backupRead","logger","info","undefined","json","message","method","path"],"mappings":"AAEA,SACEA,6BAA6B,EAC7BC,wBAAwB,EACxBC,uBAAuB,EACvBC,sBAAsB,QACjB,4BAA2B;AAClC,SAASC,aAAa,QAAQ,qBAAoB;AAClD,SAASC,eAAe,EAAEC,iBAAiB,QAAQ,YAAW;AAE9D,OAAO,SAASC;IACd,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUJ,kBAAkBG;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YACA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,WAAW,MAAMZ,8BAA8BW;YACrD,MAAME,YAAYV,uBAAuBS;YACzC,MAAME,aAAaZ,wBAAwBU;YAC3C,IAAI,CAACC,WAAW;gBACd,OAAO,IAAIE,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YAEA,MAAM,EAAEC,QAAQ,EAAEC,GAAG,EAAE,GAAI,MAAMb,gBAAgBI;YACjD,IAAI,CAACS,OAAO,OAAOA,QAAQ,UAAU;gBACnC,OAAO,IAAIH,SAAS,eAAe;oBAAEC,QAAQ;gBAAI;YACnD;YACA,IAAI;gBACF,IAAIG,IAAID;YACV,EAAE,OAAM;gBACN,OAAO,IAAIH,SAAS,eAAe;oBAAEC,QAAQ;gBAAI;YACnD;YAEA,MAAMI,aAAanB,yBAAyBW,UAAUK;YACtD,IAAIH,eAAe,aAAa,CAACM,YAAY;gBAC3C,OAAO,IAAIL,SAAS,+DAA+D;oBACjFC,QAAQ;gBACV;YACF;YAEAL,QAAQU,MAAM,CAACC,IAAI,CAAC;gBAAEJ;YAAI,GAAG;YAC7B,MAAMd,cAAcO,SAASO,KAAK,EAAE,EAAE,OAAOK,WAAW;gBACtDH,YAAYA,cAAcG;gBAC1BT;gBACAD;YACF;YACAF,QAAQU,MAAM,CAACC,IAAI,CAAC;gBAAEJ;YAAI,GAAG;YAC7B,OAAOH,SAASS,IAAI,CAAC;gBAAEC,SAAS;YAA0B,GAAG;gBAAET,QAAQ;YAAI;QAC7E;QACAU,QAAQ;QACRC,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/endpoints/paths/cron-restore.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport {\n getResolvedCronBackupSettings,\n resolveBackupArchiveRead,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n} from '../../core/backupSettings'\nimport { restoreBackup } from '../../core/restore'\nimport {\n buildRestoreWarnings,\n formatRestoreSummary,\n restoreTaskStatus,\n} from '../../core/restoreResult'\nimport { getBackupStorageKind, isBackupStorageConfigured } from '../../core/storage'\nimport { readRequestJson, requireCronBearer } from '../shared'\n\nexport function createCronRestoreEndpoint(): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n const { payload } = req\n const settings = await getResolvedCronBackupSettings(payload)\n const blobToken = resolveBackupBlobToken(settings)\n const blobAccess = resolveBackupBlobAccess(settings)\n if (!isBackupStorageConfigured(blobToken)) {\n return new Response('Service unavailable', { status: 503 })\n }\n\n const { pathname, url } = (await readRequestJson(req)) as { pathname?: string; url?: string }\n if (!url || typeof url !== 'string') {\n return new Response('Missing url', { status: 400 })\n }\n try {\n new URL(url)\n } catch {\n return new Response('Invalid url', { status: 400 })\n }\n\n const backupRead = resolveBackupArchiveRead(settings, pathname)\n if (getBackupStorageKind() === 'vercel-blob' && blobAccess === 'private' && !backupRead) {\n return new Response('Missing pathname (required for dedicated backup blob store)', {\n status: 400,\n })\n }\n\n const archivePathname =\n typeof pathname === 'string' && pathname.startsWith('backups/') ? pathname : undefined\n\n payload.logger.info({ url }, '[backup-endpoint] Restore request accepted')\n const result = await restoreBackup(payload, url, [], false, undefined, {\n archivePathname,\n backupRead: backupRead ?? undefined,\n blobAccess,\n blobToken,\n })\n const warnings = buildRestoreWarnings(result)\n const status = restoreTaskStatus(result)\n payload.logger.info({ result, status, url }, '[backup-endpoint] Restore request finished')\n return Response.json(\n {\n message: formatRestoreSummary(result),\n status,\n warnings,\n },\n { status: 202 },\n )\n },\n method: 'post',\n path: '/backup-mongodb/cron/restore',\n }\n}\n"],"names":["getResolvedCronBackupSettings","resolveBackupArchiveRead","resolveBackupBlobAccess","resolveBackupBlobToken","restoreBackup","buildRestoreWarnings","formatRestoreSummary","restoreTaskStatus","getBackupStorageKind","isBackupStorageConfigured","readRequestJson","requireCronBearer","createCronRestoreEndpoint","handler","req","cronErr","payload","settings","blobToken","blobAccess","Response","status","pathname","url","URL","backupRead","archivePathname","startsWith","undefined","logger","info","result","warnings","json","message","method","path"],"mappings":"AAEA,SACEA,6BAA6B,EAC7BC,wBAAwB,EACxBC,uBAAuB,EACvBC,sBAAsB,QACjB,4BAA2B;AAClC,SAASC,aAAa,QAAQ,qBAAoB;AAClD,SACEC,oBAAoB,EACpBC,oBAAoB,EACpBC,iBAAiB,QACZ,2BAA0B;AACjC,SAASC,oBAAoB,EAAEC,yBAAyB,QAAQ,qBAAoB;AACpF,SAASC,eAAe,EAAEC,iBAAiB,QAAQ,YAAW;AAE9D,OAAO,SAASC;IACd,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUJ,kBAAkBG;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YACA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,WAAW,MAAMjB,8BAA8BgB;YACrD,MAAME,YAAYf,uBAAuBc;YACzC,MAAME,aAAajB,wBAAwBe;YAC3C,IAAI,CAACR,0BAA0BS,YAAY;gBACzC,OAAO,IAAIE,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YAEA,MAAM,EAAEC,QAAQ,EAAEC,GAAG,EAAE,GAAI,MAAMb,gBAAgBI;YACjD,IAAI,CAACS,OAAO,OAAOA,QAAQ,UAAU;gBACnC,OAAO,IAAIH,SAAS,eAAe;oBAAEC,QAAQ;gBAAI;YACnD;YACA,IAAI;gBACF,IAAIG,IAAID;YACV,EAAE,OAAM;gBACN,OAAO,IAAIH,SAAS,eAAe;oBAAEC,QAAQ;gBAAI;YACnD;YAEA,MAAMI,aAAaxB,yBAAyBgB,UAAUK;YACtD,IAAId,2BAA2B,iBAAiBW,eAAe,aAAa,CAACM,YAAY;gBACvF,OAAO,IAAIL,SAAS,+DAA+D;oBACjFC,QAAQ;gBACV;YACF;YAEA,MAAMK,kBACJ,OAAOJ,aAAa,YAAYA,SAASK,UAAU,CAAC,cAAcL,WAAWM;YAE/EZ,QAAQa,MAAM,CAACC,IAAI,CAAC;gBAAEP;YAAI,GAAG;YAC7B,MAAMQ,SAAS,MAAM3B,cAAcY,SAASO,KAAK,EAAE,EAAE,OAAOK,WAAW;gBACrEF;gBACAD,YAAYA,cAAcG;gBAC1BT;gBACAD;YACF;YACA,MAAMc,WAAW3B,qBAAqB0B;YACtC,MAAMV,SAASd,kBAAkBwB;YACjCf,QAAQa,MAAM,CAACC,IAAI,CAAC;gBAAEC;gBAAQV;gBAAQE;YAAI,GAAG;YAC7C,OAAOH,SAASa,IAAI,CAClB;gBACEC,SAAS5B,qBAAqByB;gBAC9BV;gBACAW;YACF,GACA;gBAAEX,QAAQ;YAAI;QAElB;QACAc,QAAQ;QACRC,MAAM;IACR;AACF"}
@@ -1,6 +1,7 @@
1
1
  import { after } from 'next/server';
2
2
  import { createBackup } from '../../core/backup';
3
3
  import { getResolvedCronBackupSettings, resolveBackupBlobAccess, resolveBackupBlobToken } from '../../core/backupSettings';
4
+ import { isBackupStorageConfigured } from '../../core/storage';
4
5
  import { requireCronBearer } from '../shared';
5
6
  export function createCronRunEndpoint(options) {
6
7
  return {
@@ -13,7 +14,7 @@ export function createCronRunEndpoint(options) {
13
14
  const settings = await getResolvedCronBackupSettings(payload);
14
15
  const blobToken = resolveBackupBlobToken(settings);
15
16
  const blobAccess = resolveBackupBlobAccess(settings);
16
- if (!blobToken) {
17
+ if (!isBackupStorageConfigured(blobToken)) {
17
18
  return new Response('Service unavailable', {
18
19
  status: 503
19
20
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/endpoints/paths/cron-run.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { after } from 'next/server'\n\nimport type { BackupPluginOptions } from '../../types'\n\nimport { createBackup } from '../../core/backup'\nimport {\n getResolvedCronBackupSettings,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n} from '../../core/backupSettings'\nimport { requireCronBearer } from '../shared'\n\nexport function createCronRunEndpoint(options: BackupPluginOptions): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n\n const { payload } = req\n const settings = await getResolvedCronBackupSettings(payload)\n const blobToken = resolveBackupBlobToken(settings)\n const blobAccess = resolveBackupBlobAccess(settings)\n if (!blobToken) {\n return new Response('Service unavailable', { status: 503 })\n }\n payload.logger.info('[backup-endpoint] Cron backup request accepted')\n after(\n createBackup(payload, {\n backupsToKeep: options.backupsToKeep ?? settings.backupsToKeep,\n blobAccess,\n blobToken,\n cron: true,\n includeMedia: settings.includeMediaForCron,\n skipCollections: settings.skipMongoCollections,\n }).catch((error) => {\n payload.logger.error({ err: error }, '[backup-endpoint] Cron backup failed')\n throw error\n }),\n )\n payload.logger.info('[backup-endpoint] Cron backup queued')\n return new Response('Backup creation started', { status: 202 })\n },\n method: 'get',\n path: '/backup-mongodb/cron/run',\n }\n}\n"],"names":["after","createBackup","getResolvedCronBackupSettings","resolveBackupBlobAccess","resolveBackupBlobToken","requireCronBearer","createCronRunEndpoint","options","handler","req","cronErr","payload","settings","blobToken","blobAccess","Response","status","logger","info","backupsToKeep","cron","includeMedia","includeMediaForCron","skipCollections","skipMongoCollections","catch","error","err","method","path"],"mappings":"AAEA,SAASA,KAAK,QAAQ,cAAa;AAInC,SAASC,YAAY,QAAQ,oBAAmB;AAChD,SACEC,6BAA6B,EAC7BC,uBAAuB,EACvBC,sBAAsB,QACjB,4BAA2B;AAClC,SAASC,iBAAiB,QAAQ,YAAW;AAE7C,OAAO,SAASC,sBAAsBC,OAA4B;IAChE,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUL,kBAAkBI;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YAEA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,WAAW,MAAMV,8BAA8BS;YACrD,MAAME,YAAYT,uBAAuBQ;YACzC,MAAME,aAAaX,wBAAwBS;YAC3C,IAAI,CAACC,WAAW;gBACd,OAAO,IAAIE,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YACAL,QAAQM,MAAM,CAACC,IAAI,CAAC;YACpBlB,MACEC,aAAaU,SAAS;gBACpBQ,eAAeZ,QAAQY,aAAa,IAAIP,SAASO,aAAa;gBAC9DL;gBACAD;gBACAO,MAAM;gBACNC,cAAcT,SAASU,mBAAmB;gBAC1CC,iBAAiBX,SAASY,oBAAoB;YAChD,GAAGC,KAAK,CAAC,CAACC;gBACRf,QAAQM,MAAM,CAACS,KAAK,CAAC;oBAAEC,KAAKD;gBAAM,GAAG;gBACrC,MAAMA;YACR;YAEFf,QAAQM,MAAM,CAACC,IAAI,CAAC;YACpB,OAAO,IAAIH,SAAS,2BAA2B;gBAAEC,QAAQ;YAAI;QAC/D;QACAY,QAAQ;QACRC,MAAM;IACR;AACF"}
1
+ {"version":3,"sources":["../../../src/endpoints/paths/cron-run.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { after } from 'next/server'\n\nimport type { BackupPluginOptions } from '../../types'\n\nimport { createBackup } from '../../core/backup'\nimport {\n getResolvedCronBackupSettings,\n resolveBackupBlobAccess,\n resolveBackupBlobToken,\n} from '../../core/backupSettings'\nimport { isBackupStorageConfigured } from '../../core/storage'\nimport { requireCronBearer } from '../shared'\n\nexport function createCronRunEndpoint(options: BackupPluginOptions): Endpoint {\n return {\n handler: async (req) => {\n const cronErr = requireCronBearer(req)\n if (cronErr) {\n return cronErr\n }\n\n const { payload } = req\n const settings = await getResolvedCronBackupSettings(payload)\n const blobToken = resolveBackupBlobToken(settings)\n const blobAccess = resolveBackupBlobAccess(settings)\n if (!isBackupStorageConfigured(blobToken)) {\n return new Response('Service unavailable', { status: 503 })\n }\n payload.logger.info('[backup-endpoint] Cron backup request accepted')\n after(\n createBackup(payload, {\n backupsToKeep: options.backupsToKeep ?? settings.backupsToKeep,\n blobAccess,\n blobToken,\n cron: true,\n includeMedia: settings.includeMediaForCron,\n skipCollections: settings.skipMongoCollections,\n }).catch((error) => {\n payload.logger.error({ err: error }, '[backup-endpoint] Cron backup failed')\n throw error\n }),\n )\n payload.logger.info('[backup-endpoint] Cron backup queued')\n return new Response('Backup creation started', { status: 202 })\n },\n method: 'get',\n path: '/backup-mongodb/cron/run',\n }\n}\n"],"names":["after","createBackup","getResolvedCronBackupSettings","resolveBackupBlobAccess","resolveBackupBlobToken","isBackupStorageConfigured","requireCronBearer","createCronRunEndpoint","options","handler","req","cronErr","payload","settings","blobToken","blobAccess","Response","status","logger","info","backupsToKeep","cron","includeMedia","includeMediaForCron","skipCollections","skipMongoCollections","catch","error","err","method","path"],"mappings":"AAEA,SAASA,KAAK,QAAQ,cAAa;AAInC,SAASC,YAAY,QAAQ,oBAAmB;AAChD,SACEC,6BAA6B,EAC7BC,uBAAuB,EACvBC,sBAAsB,QACjB,4BAA2B;AAClC,SAASC,yBAAyB,QAAQ,qBAAoB;AAC9D,SAASC,iBAAiB,QAAQ,YAAW;AAE7C,OAAO,SAASC,sBAAsBC,OAA4B;IAChE,OAAO;QACLC,SAAS,OAAOC;YACd,MAAMC,UAAUL,kBAAkBI;YAClC,IAAIC,SAAS;gBACX,OAAOA;YACT;YAEA,MAAM,EAAEC,OAAO,EAAE,GAAGF;YACpB,MAAMG,WAAW,MAAMX,8BAA8BU;YACrD,MAAME,YAAYV,uBAAuBS;YACzC,MAAME,aAAaZ,wBAAwBU;YAC3C,IAAI,CAACR,0BAA0BS,YAAY;gBACzC,OAAO,IAAIE,SAAS,uBAAuB;oBAAEC,QAAQ;gBAAI;YAC3D;YACAL,QAAQM,MAAM,CAACC,IAAI,CAAC;YACpBnB,MACEC,aAAaW,SAAS;gBACpBQ,eAAeZ,QAAQY,aAAa,IAAIP,SAASO,aAAa;gBAC9DL;gBACAD;gBACAO,MAAM;gBACNC,cAAcT,SAASU,mBAAmB;gBAC1CC,iBAAiBX,SAASY,oBAAoB;YAChD,GAAGC,KAAK,CAAC,CAACC;gBACRf,QAAQM,MAAM,CAACS,KAAK,CAAC;oBAAEC,KAAKD;gBAAM,GAAG;gBACrC,MAAMA;YACR;YAEFf,QAAQM,MAAM,CAACC,IAAI,CAAC;YACpB,OAAO,IAAIH,SAAS,2BAA2B;gBAAEC,QAAQ;YAAI;QAC/D;QACAY,QAAQ;QACRC,MAAM;IACR;AACF"}
@@ -7,7 +7,6 @@ export declare function readRequestJson(req: PayloadRequest): Promise<unknown>;
7
7
  * with `Unexpected token ... is not valid JSON`.
8
8
  */
9
9
  export declare function jsonError(message: string, status: number): Response;
10
- export declare function requireBlobEnv(): null | Response;
11
10
  export declare function requireCronBearer(req: PayloadRequest): null | Response;
12
11
  export declare function getAuthorizedBackupAdmin(req: PayloadRequest, options: BackupPluginOptions): Promise<null | Record<string, unknown>>;
13
12
  export declare function requireBackupAdmin(req: PayloadRequest, options: BackupPluginOptions): Promise<Record<string, unknown> | Response>;
@@ -13,12 +13,6 @@ export async function readRequestJson(req) {
13
13
  status
14
14
  });
15
15
  }
16
- export function requireBlobEnv() {
17
- if (!process.env.BLOB_READ_WRITE_TOKEN) {
18
- return jsonError('Service unavailable', 503);
19
- }
20
- return null;
21
- }
22
16
  export function requireCronBearer(req) {
23
17
  // Security gate for cron/external backup routes: only a matching CRON_SECRET bearer may pass.
24
18
  const authHeader = req.headers.get('authorization');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoints/shared.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport type { BackupPluginOptions } from '../types'\n\nimport { isUserAllowedByEnvRoles } from '../utils/dashboardRoleAccess'\n\nexport async function readRequestJson(req: PayloadRequest): Promise<unknown> {\n return (req as unknown as Request).json() as Promise<unknown>\n}\n\n/**\n * Canonical JSON error response for admin-facing endpoints. The dashboard clients\n * always parse responses as JSON, so plain-text bodies would crash `await res.json()`\n * with `Unexpected token ... is not valid JSON`.\n */\nexport function jsonError(message: string, status: number): Response {\n return Response.json({ error: message }, { status })\n}\n\nexport function requireBlobEnv(): null | Response {\n if (!process.env.BLOB_READ_WRITE_TOKEN) {\n return jsonError('Service unavailable', 503)\n }\n return null\n}\n\nexport function requireCronBearer(req: PayloadRequest): null | Response {\n // Security gate for cron/external backup routes: only a matching CRON_SECRET bearer may pass.\n const authHeader = req.headers.get('authorization')\n if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {\n return new Response('Unauthorized', { status: 401 })\n }\n return null\n}\n\nexport async function getAuthorizedBackupAdmin(\n req: PayloadRequest,\n options: BackupPluginOptions,\n): Promise<null | Record<string, unknown>> {\n const fromRequest = (req as { user?: null | Record<string, unknown> } & PayloadRequest).user\n const authUser =\n fromRequest ? fromRequest : (\n ((await req.payload.auth({ headers: req.headers }))?.user as\n | null\n | Record<string, unknown>\n | undefined)\n )\n const user = authUser\n if (!user) {\n return null\n }\n if (options.access) {\n return options.access(user) ? user : null\n }\n // Default access check stays in sync with the dashboard visibility rule:\n // driven by `PAYLOAD_BACKUP_ALLOWED_ROLES` with backwards-compatible defaults\n // (admin role required when roles exist, or allow when the project has no roles field).\n return isUserAllowedByEnvRoles(user) ? user : null\n}\n\nexport async function requireBackupAdmin(\n req: PayloadRequest,\n options: BackupPluginOptions,\n): Promise<Record<string, unknown> | Response> {\n // Security gate for admin routes: request must resolve to an authorized backup admin user.\n const user = await getAuthorizedBackupAdmin(req, options)\n if (!user) {\n return jsonError('Unauthorized', 401)\n }\n return user\n}\n"],"names":["isUserAllowedByEnvRoles","readRequestJson","req","json","jsonError","message","status","Response","error","requireBlobEnv","process","env","BLOB_READ_WRITE_TOKEN","requireCronBearer","authHeader","headers","get","CRON_SECRET","getAuthorizedBackupAdmin","options","fromRequest","user","authUser","payload","auth","access","requireBackupAdmin"],"mappings":"AAIA,SAASA,uBAAuB,QAAQ,+BAA8B;AAEtE,OAAO,eAAeC,gBAAgBC,GAAmB;IACvD,OAAO,AAACA,IAA2BC,IAAI;AACzC;AAEA;;;;CAIC,GACD,OAAO,SAASC,UAAUC,OAAe,EAAEC,MAAc;IACvD,OAAOC,SAASJ,IAAI,CAAC;QAAEK,OAAOH;IAAQ,GAAG;QAAEC;IAAO;AACpD;AAEA,OAAO,SAASG;IACd,IAAI,CAACC,QAAQC,GAAG,CAACC,qBAAqB,EAAE;QACtC,OAAOR,UAAU,uBAAuB;IAC1C;IACA,OAAO;AACT;AAEA,OAAO,SAASS,kBAAkBX,GAAmB;IACnD,8FAA8F;IAC9F,MAAMY,aAAaZ,IAAIa,OAAO,CAACC,GAAG,CAAC;IACnC,IAAIF,eAAe,CAAC,OAAO,EAAEJ,QAAQC,GAAG,CAACM,WAAW,EAAE,EAAE;QACtD,OAAO,IAAIV,SAAS,gBAAgB;YAAED,QAAQ;QAAI;IACpD;IACA,OAAO;AACT;AAEA,OAAO,eAAeY,yBACpBhB,GAAmB,EACnBiB,OAA4B;IAE5B,MAAMC,cAAc,AAAClB,IAAmEmB,IAAI;IAC5F,MAAMC,WACJF,cAAcA,cACV,CAAA,MAAMlB,IAAIqB,OAAO,CAACC,IAAI,CAAC;QAAET,SAASb,IAAIa,OAAO;IAAC,EAAC,GAAIM;IAKzD,MAAMA,OAAOC;IACb,IAAI,CAACD,MAAM;QACT,OAAO;IACT;IACA,IAAIF,QAAQM,MAAM,EAAE;QAClB,OAAON,QAAQM,MAAM,CAACJ,QAAQA,OAAO;IACvC;IACA,yEAAyE;IACzE,8EAA8E;IAC9E,wFAAwF;IACxF,OAAOrB,wBAAwBqB,QAAQA,OAAO;AAChD;AAEA,OAAO,eAAeK,mBACpBxB,GAAmB,EACnBiB,OAA4B;IAE5B,2FAA2F;IAC3F,MAAME,OAAO,MAAMH,yBAAyBhB,KAAKiB;IACjD,IAAI,CAACE,MAAM;QACT,OAAOjB,UAAU,gBAAgB;IACnC;IACA,OAAOiB;AACT"}
1
+ {"version":3,"sources":["../../src/endpoints/shared.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport type { BackupPluginOptions } from '../types'\n\nimport { isUserAllowedByEnvRoles } from '../utils/dashboardRoleAccess'\n\nexport async function readRequestJson(req: PayloadRequest): Promise<unknown> {\n return (req as unknown as Request).json() as Promise<unknown>\n}\n\n/**\n * Canonical JSON error response for admin-facing endpoints. The dashboard clients\n * always parse responses as JSON, so plain-text bodies would crash `await res.json()`\n * with `Unexpected token ... is not valid JSON`.\n */\nexport function jsonError(message: string, status: number): Response {\n return Response.json({ error: message }, { status })\n}\n\nexport function requireCronBearer(req: PayloadRequest): null | Response {\n // Security gate for cron/external backup routes: only a matching CRON_SECRET bearer may pass.\n const authHeader = req.headers.get('authorization')\n if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {\n return new Response('Unauthorized', { status: 401 })\n }\n return null\n}\n\nexport async function getAuthorizedBackupAdmin(\n req: PayloadRequest,\n options: BackupPluginOptions,\n): Promise<null | Record<string, unknown>> {\n const fromRequest = (req as { user?: null | Record<string, unknown> } & PayloadRequest).user\n const authUser =\n fromRequest ? fromRequest : (\n ((await req.payload.auth({ headers: req.headers }))?.user as\n | null\n | Record<string, unknown>\n | undefined)\n )\n const user = authUser\n if (!user) {\n return null\n }\n if (options.access) {\n return options.access(user) ? user : null\n }\n // Default access check stays in sync with the dashboard visibility rule:\n // driven by `PAYLOAD_BACKUP_ALLOWED_ROLES` with backwards-compatible defaults\n // (admin role required when roles exist, or allow when the project has no roles field).\n return isUserAllowedByEnvRoles(user) ? user : null\n}\n\nexport async function requireBackupAdmin(\n req: PayloadRequest,\n options: BackupPluginOptions,\n): Promise<Record<string, unknown> | Response> {\n // Security gate for admin routes: request must resolve to an authorized backup admin user.\n const user = await getAuthorizedBackupAdmin(req, options)\n if (!user) {\n return jsonError('Unauthorized', 401)\n }\n return user\n}\n"],"names":["isUserAllowedByEnvRoles","readRequestJson","req","json","jsonError","message","status","Response","error","requireCronBearer","authHeader","headers","get","process","env","CRON_SECRET","getAuthorizedBackupAdmin","options","fromRequest","user","authUser","payload","auth","access","requireBackupAdmin"],"mappings":"AAIA,SAASA,uBAAuB,QAAQ,+BAA8B;AAEtE,OAAO,eAAeC,gBAAgBC,GAAmB;IACvD,OAAO,AAACA,IAA2BC,IAAI;AACzC;AAEA;;;;CAIC,GACD,OAAO,SAASC,UAAUC,OAAe,EAAEC,MAAc;IACvD,OAAOC,SAASJ,IAAI,CAAC;QAAEK,OAAOH;IAAQ,GAAG;QAAEC;IAAO;AACpD;AAEA,OAAO,SAASG,kBAAkBP,GAAmB;IACnD,8FAA8F;IAC9F,MAAMQ,aAAaR,IAAIS,OAAO,CAACC,GAAG,CAAC;IACnC,IAAIF,eAAe,CAAC,OAAO,EAAEG,QAAQC,GAAG,CAACC,WAAW,EAAE,EAAE;QACtD,OAAO,IAAIR,SAAS,gBAAgB;YAAED,QAAQ;QAAI;IACpD;IACA,OAAO;AACT;AAEA,OAAO,eAAeU,yBACpBd,GAAmB,EACnBe,OAA4B;IAE5B,MAAMC,cAAc,AAAChB,IAAmEiB,IAAI;IAC5F,MAAMC,WACJF,cAAcA,cACV,CAAA,MAAMhB,IAAImB,OAAO,CAACC,IAAI,CAAC;QAAEX,SAAST,IAAIS,OAAO;IAAC,EAAC,GAAIQ;IAKzD,MAAMA,OAAOC;IACb,IAAI,CAACD,MAAM;QACT,OAAO;IACT;IACA,IAAIF,QAAQM,MAAM,EAAE;QAClB,OAAON,QAAQM,MAAM,CAACJ,QAAQA,OAAO;IACvC;IACA,yEAAyE;IACzE,8EAA8E;IAC9E,wFAAwF;IACxF,OAAOnB,wBAAwBmB,QAAQA,OAAO;AAChD;AAEA,OAAO,eAAeK,mBACpBtB,GAAmB,EACnBe,OAA4B;IAE5B,2FAA2F;IAC3F,MAAME,OAAO,MAAMH,yBAAyBd,KAAKe;IACjD,IAAI,CAACE,MAAM;QACT,OAAOf,UAAU,gBAAgB;IACnC;IACA,OAAOe;AACT"}
package/dist/index.d.ts CHANGED
@@ -4,11 +4,13 @@ export { getBackupSourcePreviewForManual } from './core/backupSourcePreview';
4
4
  export type { BackupSourcePreviewResponse } from './core/backupSourcePreview';
5
5
  export { getDb } from './core/db';
6
6
  export type { MongoDb } from './core/db';
7
- export { restoreBackup, restoreSeedMedia } from './core/restore';
8
- export type { RestoreBackupOptions } from './core/restore';
7
+ export { restoreBackup } from './core/restore';
8
+ export type { RestoreBackupOptions, RestoreBackupResult } from './core/restore';
9
9
  export { buildCollectionPreviewGroups, buildRestorePreviewGroups, getRestorePreviewForAdminRestore, loadRestoreBackupIndex, navVisibleCollectionOrderIndex, } from './core/restorePreview';
10
10
  export type { RestorePreviewAdminHiddenReason, RestorePreviewFileKind, RestorePreviewGroup, RestorePreviewResponse, } from './core/restorePreview';
11
- export { completeBackupTask, createBackupTask, failBackupTask, getBackupTask, pollSecretsMatch, stripPollSecretForClient, updateBackupTask, } from './core/taskProgress';
11
+ export { buildRestoreWarnings, formatRestoreSummary, restoreTaskStatus } from './core/restoreResult';
12
+ export type { RestoreArchiveKind, RestoreCollectionOutcome, RestoreMediaOutcome, } from './core/restoreResult';
13
+ export { completeBackupTask, completeRestoreBackupTask, createBackupTask, failBackupTask, getBackupTask, pollSecretsMatch, stripPollSecretForClient, updateBackupTask, } from './core/taskProgress';
12
14
  export type { BackupTaskKind, BackupTaskProgress, BackupTaskStatus, BackupTaskWithPollSecret, } from './core/taskProgress';
13
15
  export { backupMongodbPlugin } from './plugin';
14
16
  export { backupPluginPublicApiPaths } from './publicApiPaths';
package/dist/index.js CHANGED
@@ -2,9 +2,10 @@ export { createTarGzip, resolveTarGzip } from './core/archive';
2
2
  export { createBackup, createMediaBackupFile, listBackups, resolveBackupListToken } from './core/backup';
3
3
  export { getBackupSourcePreviewForManual } from './core/backupSourcePreview';
4
4
  export { getDb } from './core/db';
5
- export { restoreBackup, restoreSeedMedia } from './core/restore';
5
+ export { restoreBackup } from './core/restore';
6
6
  export { buildCollectionPreviewGroups, buildRestorePreviewGroups, getRestorePreviewForAdminRestore, loadRestoreBackupIndex, navVisibleCollectionOrderIndex } from './core/restorePreview';
7
- export { completeBackupTask, createBackupTask, failBackupTask, getBackupTask, pollSecretsMatch, stripPollSecretForClient, updateBackupTask } from './core/taskProgress';
7
+ export { buildRestoreWarnings, formatRestoreSummary, restoreTaskStatus } from './core/restoreResult';
8
+ export { completeBackupTask, completeRestoreBackupTask, createBackupTask, failBackupTask, getBackupTask, pollSecretsMatch, stripPollSecretForClient, updateBackupTask } from './core/taskProgress';
8
9
  export { backupMongodbPlugin } from './plugin';
9
10
  export { backupPluginPublicApiPaths } from './publicApiPaths';
10
11
  export { createBlobName, getBackupSortTimeMs, transformBlobName } from './utils/blobName';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { createTarGzip, resolveTarGzip } from './core/archive'\nexport {\n createBackup,\n createMediaBackupFile,\n listBackups,\n resolveBackupListToken,\n} from './core/backup'\nexport { getBackupSourcePreviewForManual } from './core/backupSourcePreview'\n\nexport type { BackupSourcePreviewResponse } from './core/backupSourcePreview'\nexport { getDb } from './core/db'\nexport type { MongoDb } from './core/db'\nexport { restoreBackup, restoreSeedMedia } from './core/restore'\nexport type { RestoreBackupOptions } from './core/restore'\nexport {\n buildCollectionPreviewGroups,\n buildRestorePreviewGroups,\n getRestorePreviewForAdminRestore,\n loadRestoreBackupIndex,\n navVisibleCollectionOrderIndex,\n} from './core/restorePreview'\nexport type {\n RestorePreviewAdminHiddenReason,\n RestorePreviewFileKind,\n RestorePreviewGroup,\n RestorePreviewResponse,\n} from './core/restorePreview'\nexport {\n completeBackupTask,\n createBackupTask,\n failBackupTask,\n getBackupTask,\n pollSecretsMatch,\n stripPollSecretForClient,\n updateBackupTask,\n} from './core/taskProgress'\nexport type {\n BackupTaskKind,\n BackupTaskProgress,\n BackupTaskStatus,\n BackupTaskWithPollSecret,\n} from './core/taskProgress'\nexport { backupMongodbPlugin } from './plugin'\nexport { backupPluginPublicApiPaths } from './publicApiPaths'\nexport type { BackupPluginOptions } from './types'\n\nexport { createBlobName, getBackupSortTimeMs, transformBlobName } from './utils/blobName'\nexport { formatBytes } from './utils/formatBytes'\nexport { getCurrentDbName, getCurrentHostname } from './utils/hostname'\n"],"names":["createTarGzip","resolveTarGzip","createBackup","createMediaBackupFile","listBackups","resolveBackupListToken","getBackupSourcePreviewForManual","getDb","restoreBackup","restoreSeedMedia","buildCollectionPreviewGroups","buildRestorePreviewGroups","getRestorePreviewForAdminRestore","loadRestoreBackupIndex","navVisibleCollectionOrderIndex","completeBackupTask","createBackupTask","failBackupTask","getBackupTask","pollSecretsMatch","stripPollSecretForClient","updateBackupTask","backupMongodbPlugin","backupPluginPublicApiPaths","createBlobName","getBackupSortTimeMs","transformBlobName","formatBytes","getCurrentDbName","getCurrentHostname"],"mappings":"AAAA,SAASA,aAAa,EAAEC,cAAc,QAAQ,iBAAgB;AAC9D,SACEC,YAAY,EACZC,qBAAqB,EACrBC,WAAW,EACXC,sBAAsB,QACjB,gBAAe;AACtB,SAASC,+BAA+B,QAAQ,6BAA4B;AAG5E,SAASC,KAAK,QAAQ,YAAW;AAEjC,SAASC,aAAa,EAAEC,gBAAgB,QAAQ,iBAAgB;AAEhE,SACEC,4BAA4B,EAC5BC,yBAAyB,EACzBC,gCAAgC,EAChCC,sBAAsB,EACtBC,8BAA8B,QACzB,wBAAuB;AAO9B,SACEC,kBAAkB,EAClBC,gBAAgB,EAChBC,cAAc,EACdC,aAAa,EACbC,gBAAgB,EAChBC,wBAAwB,EACxBC,gBAAgB,QACX,sBAAqB;AAO5B,SAASC,mBAAmB,QAAQ,WAAU;AAC9C,SAASC,0BAA0B,QAAQ,mBAAkB;AAG7D,SAASC,cAAc,EAAEC,mBAAmB,EAAEC,iBAAiB,QAAQ,mBAAkB;AACzF,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,mBAAkB"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { createTarGzip, resolveTarGzip } from './core/archive'\nexport {\n createBackup,\n createMediaBackupFile,\n listBackups,\n resolveBackupListToken,\n} from './core/backup'\nexport { getBackupSourcePreviewForManual } from './core/backupSourcePreview'\n\nexport type { BackupSourcePreviewResponse } from './core/backupSourcePreview'\nexport { getDb } from './core/db'\nexport type { MongoDb } from './core/db'\nexport { restoreBackup } from './core/restore'\nexport type { RestoreBackupOptions, RestoreBackupResult } from './core/restore'\nexport {\n buildCollectionPreviewGroups,\n buildRestorePreviewGroups,\n getRestorePreviewForAdminRestore,\n loadRestoreBackupIndex,\n navVisibleCollectionOrderIndex,\n} from './core/restorePreview'\nexport type {\n RestorePreviewAdminHiddenReason,\n RestorePreviewFileKind,\n RestorePreviewGroup,\n RestorePreviewResponse,\n} from './core/restorePreview'\nexport { buildRestoreWarnings, formatRestoreSummary, restoreTaskStatus } from './core/restoreResult'\nexport type {\n RestoreArchiveKind,\n RestoreCollectionOutcome,\n RestoreMediaOutcome,\n} from './core/restoreResult'\nexport {\n completeBackupTask,\n completeRestoreBackupTask,\n createBackupTask,\n failBackupTask,\n getBackupTask,\n pollSecretsMatch,\n stripPollSecretForClient,\n updateBackupTask,\n} from './core/taskProgress'\nexport type {\n BackupTaskKind,\n BackupTaskProgress,\n BackupTaskStatus,\n BackupTaskWithPollSecret,\n} from './core/taskProgress'\nexport { backupMongodbPlugin } from './plugin'\nexport { backupPluginPublicApiPaths } from './publicApiPaths'\nexport type { BackupPluginOptions } from './types'\n\nexport { createBlobName, getBackupSortTimeMs, transformBlobName } from './utils/blobName'\nexport { formatBytes } from './utils/formatBytes'\nexport { getCurrentDbName, getCurrentHostname } from './utils/hostname'\n"],"names":["createTarGzip","resolveTarGzip","createBackup","createMediaBackupFile","listBackups","resolveBackupListToken","getBackupSourcePreviewForManual","getDb","restoreBackup","buildCollectionPreviewGroups","buildRestorePreviewGroups","getRestorePreviewForAdminRestore","loadRestoreBackupIndex","navVisibleCollectionOrderIndex","buildRestoreWarnings","formatRestoreSummary","restoreTaskStatus","completeBackupTask","completeRestoreBackupTask","createBackupTask","failBackupTask","getBackupTask","pollSecretsMatch","stripPollSecretForClient","updateBackupTask","backupMongodbPlugin","backupPluginPublicApiPaths","createBlobName","getBackupSortTimeMs","transformBlobName","formatBytes","getCurrentDbName","getCurrentHostname"],"mappings":"AAAA,SAASA,aAAa,EAAEC,cAAc,QAAQ,iBAAgB;AAC9D,SACEC,YAAY,EACZC,qBAAqB,EACrBC,WAAW,EACXC,sBAAsB,QACjB,gBAAe;AACtB,SAASC,+BAA+B,QAAQ,6BAA4B;AAG5E,SAASC,KAAK,QAAQ,YAAW;AAEjC,SAASC,aAAa,QAAQ,iBAAgB;AAE9C,SACEC,4BAA4B,EAC5BC,yBAAyB,EACzBC,gCAAgC,EAChCC,sBAAsB,EACtBC,8BAA8B,QACzB,wBAAuB;AAO9B,SAASC,oBAAoB,EAAEC,oBAAoB,EAAEC,iBAAiB,QAAQ,uBAAsB;AAMpG,SACEC,kBAAkB,EAClBC,yBAAyB,EACzBC,gBAAgB,EAChBC,cAAc,EACdC,aAAa,EACbC,gBAAgB,EAChBC,wBAAwB,EACxBC,gBAAgB,QACX,sBAAqB;AAO5B,SAASC,mBAAmB,QAAQ,WAAU;AAC9C,SAASC,0BAA0B,QAAQ,mBAAkB;AAG7D,SAASC,cAAc,EAAEC,mBAAmB,EAAEC,iBAAiB,QAAQ,mBAAkB;AACzF,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,mBAAkB"}
@@ -9,7 +9,6 @@ export declare const backupPluginPublicApiPaths: {
9
9
  readonly adminManual: "/api/backup-mongodb/admin/manual";
10
10
  readonly adminRestore: "/api/backup-mongodb/admin/restore";
11
11
  readonly adminRestorePreview: "/api/backup-mongodb/admin/restore-preview";
12
- readonly adminSeed: "/api/backup-mongodb/admin/seed";
13
12
  readonly adminSettings: "/api/backup-mongodb/admin/settings";
14
13
  readonly adminTask: (id: string) => string;
15
14
  readonly adminValidateBlobToken: "/api/backup-mongodb/admin/validate-blob-token";
@@ -8,7 +8,6 @@
8
8
  adminManual: '/api/backup-mongodb/admin/manual',
9
9
  adminRestore: '/api/backup-mongodb/admin/restore',
10
10
  adminRestorePreview: '/api/backup-mongodb/admin/restore-preview',
11
- adminSeed: '/api/backup-mongodb/admin/seed',
12
11
  adminSettings: '/api/backup-mongodb/admin/settings',
13
12
  adminTask: (id)=>`/api/backup-mongodb/admin/task/${encodeURIComponent(id)}`,
14
13
  adminValidateBlobToken: '/api/backup-mongodb/admin/validate-blob-token',
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/publicApiPaths.ts"],"sourcesContent":["/**\n * Browser-facing paths for the backup plugin (Payload custom REST under default {@code /api}).\n * Must stay in sync with {@link createBackupMongodbEndpoints} in `endpoints/index.ts`.\n */\nexport const backupPluginPublicApiPaths = {\n adminBackupDownload: '/api/backup-mongodb/admin/backup-download',\n adminBackupPreview: '/api/backup-mongodb/admin/backup-preview',\n adminDelete: '/api/backup-mongodb/admin/delete',\n adminManual: '/api/backup-mongodb/admin/manual',\n adminRestore: '/api/backup-mongodb/admin/restore',\n adminRestorePreview: '/api/backup-mongodb/admin/restore-preview',\n adminSeed: '/api/backup-mongodb/admin/seed',\n adminSettings: '/api/backup-mongodb/admin/settings',\n adminTask: (id: string) => `/api/backup-mongodb/admin/task/${encodeURIComponent(id)}`,\n adminValidateBlobToken: '/api/backup-mongodb/admin/validate-blob-token',\n cron: '/api/backup-mongodb/cron/run',\n cronRestore: '/api/backup-mongodb/cron/restore',\n list: '/api/backup-mongodb/cron/list',\n} as const\n"],"names":["backupPluginPublicApiPaths","adminBackupDownload","adminBackupPreview","adminDelete","adminManual","adminRestore","adminRestorePreview","adminSeed","adminSettings","adminTask","id","encodeURIComponent","adminValidateBlobToken","cron","cronRestore","list"],"mappings":"AAAA;;;CAGC,GACD,OAAO,MAAMA,6BAA6B;IACxCC,qBAAqB;IACrBC,oBAAoB;IACpBC,aAAa;IACbC,aAAa;IACbC,cAAc;IACdC,qBAAqB;IACrBC,WAAW;IACXC,eAAe;IACfC,WAAW,CAACC,KAAe,CAAC,+BAA+B,EAAEC,mBAAmBD,KAAK;IACrFE,wBAAwB;IACxBC,MAAM;IACNC,aAAa;IACbC,MAAM;AACR,EAAU"}
1
+ {"version":3,"sources":["../src/publicApiPaths.ts"],"sourcesContent":["/**\n * Browser-facing paths for the backup plugin (Payload custom REST under default {@code /api}).\n * Must stay in sync with {@link createBackupMongodbEndpoints} in `endpoints/index.ts`.\n */\nexport const backupPluginPublicApiPaths = {\n adminBackupDownload: '/api/backup-mongodb/admin/backup-download',\n adminBackupPreview: '/api/backup-mongodb/admin/backup-preview',\n adminDelete: '/api/backup-mongodb/admin/delete',\n adminManual: '/api/backup-mongodb/admin/manual',\n adminRestore: '/api/backup-mongodb/admin/restore',\n adminRestorePreview: '/api/backup-mongodb/admin/restore-preview',\n adminSettings: '/api/backup-mongodb/admin/settings',\n adminTask: (id: string) => `/api/backup-mongodb/admin/task/${encodeURIComponent(id)}`,\n adminValidateBlobToken: '/api/backup-mongodb/admin/validate-blob-token',\n cron: '/api/backup-mongodb/cron/run',\n cronRestore: '/api/backup-mongodb/cron/restore',\n list: '/api/backup-mongodb/cron/list',\n} as const\n"],"names":["backupPluginPublicApiPaths","adminBackupDownload","adminBackupPreview","adminDelete","adminManual","adminRestore","adminRestorePreview","adminSettings","adminTask","id","encodeURIComponent","adminValidateBlobToken","cron","cronRestore","list"],"mappings":"AAAA;;;CAGC,GACD,OAAO,MAAMA,6BAA6B;IACxCC,qBAAqB;IACrBC,oBAAoB;IACpBC,aAAa;IACbC,aAAa;IACbC,cAAc;IACdC,qBAAqB;IACrBC,eAAe;IACfC,WAAW,CAACC,KAAe,CAAC,+BAA+B,EAAEC,mBAAmBD,KAAK;IACrFE,wBAAwB;IACxBC,MAAM;IACNC,aAAa;IACbC,MAAM;AACR,EAAU"}
package/dist/types.d.ts CHANGED
@@ -13,9 +13,4 @@ export type BackupPluginOptions = {
13
13
  backupsToKeep?: number;
14
14
  /** Enable/disable the plugin entirely. Default: true */
15
15
  enabled?: boolean;
16
- /**
17
- * When set, registers POST {@code /api/backup-mongodb/admin/seed} (demo DB + media seed).
18
- * Omit to disable the seed endpoint entirely.
19
- */
20
- seedDemoDumpUrl?: string;
21
16
  };
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type BackupPluginOptions = {\n /**\n * Custom access control function. Receives the user object from Payload and returns true\n * if the user is allowed to see/use the backup dashboard.\n *\n * When omitted, visibility falls back to the `PAYLOAD_BACKUP_ALLOWED_ROLES` env var\n * (comma-separated role slugs, or `*` for any authenticated user). If that env var is\n * also unset, the historical default applies: user has a role with slug `admin`, or —\n * for users collections that have no `roles` field — any authenticated user.\n */\n access?: (user: null | Record<string, unknown>) => boolean\n /** Number of automatic (cron) backups to keep. Default: process.env.BACKUPS_TO_KEEP or 10 */\n backupsToKeep?: number\n /** Enable/disable the plugin entirely. Default: true */\n enabled?: boolean\n /**\n * When set, registers POST {@code /api/backup-mongodb/admin/seed} (demo DB + media seed).\n * Omit to disable the seed endpoint entirely.\n */\n seedDemoDumpUrl?: string\n}\n"],"names":[],"mappings":"AAAA,WAoBC"}
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type BackupPluginOptions = {\n /**\n * Custom access control function. Receives the user object from Payload and returns true\n * if the user is allowed to see/use the backup dashboard.\n *\n * When omitted, visibility falls back to the `PAYLOAD_BACKUP_ALLOWED_ROLES` env var\n * (comma-separated role slugs, or `*` for any authenticated user). If that env var is\n * also unset, the historical default applies: user has a role with slug `admin`, or —\n * for users collections that have no `roles` field — any authenticated user.\n */\n access?: (user: null | Record<string, unknown>) => boolean\n /** Number of automatic (cron) backups to keep. Default: process.env.BACKUPS_TO_KEEP or 10 */\n backupsToKeep?: number\n /** Enable/disable the plugin entirely. Default: true */\n enabled?: boolean\n}\n"],"names":[],"mappings":"AAAA,WAeC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@trieb.work/payload-plugin-backup-mongodb",
3
- "version": "0.1.7",
4
- "description": "Payload CMS plugin for MongoDB backup and recovery via Vercel Blob Storage",
3
+ "version": "0.2.0",
4
+ "description": "Payload CMS plugin for MongoDB backup and recovery via Vercel Blob or AWS S3 (S3-compatible: R2, MinIO)",
5
5
  "keywords": [
6
6
  "payload",
7
7
  "payloadcms",
@@ -76,6 +76,9 @@
76
76
  "tar-stream": "^3.1.7"
77
77
  },
78
78
  "devDependencies": {
79
+ "@aws-sdk/client-s3": "^3.700.0",
80
+ "@aws-sdk/lib-storage": "^3.700.0",
81
+ "@aws-sdk/s3-request-presigner": "^3.700.0",
79
82
  "@changesets/cli": "^2.29.8",
80
83
  "@eslint/eslintrc": "^3.2.0",
81
84
  "@payloadcms/db-mongodb": "3.82.1",
@@ -84,7 +87,7 @@
84
87
  "@payloadcms/richtext-lexical": "3.82.1",
85
88
  "@payloadcms/translations": "3.82.1",
86
89
  "@payloadcms/ui": "3.82.1",
87
- "@playwright/test": "1.58.2",
90
+ "@playwright/test": "1.61.0",
88
91
  "@swc-node/register": "1.10.9",
89
92
  "@swc/cli": "0.6.0",
90
93
  "@types/node": "22.19.9",
@@ -118,14 +121,28 @@
118
121
  "vitest": "4.1.5"
119
122
  },
120
123
  "peerDependencies": {
124
+ "@aws-sdk/client-s3": "^3.0.0",
125
+ "@aws-sdk/lib-storage": "^3.0.0",
126
+ "@aws-sdk/s3-request-presigner": "^3.0.0",
121
127
  "@payloadcms/db-mongodb": "^3.0.0",
122
128
  "@payloadcms/ui": "^3.0.0",
123
129
  "next": "^15.0.0",
124
130
  "payload": "^3.0.0",
125
131
  "react": "^19.0.0"
126
132
  },
133
+ "peerDependenciesMeta": {
134
+ "@aws-sdk/client-s3": {
135
+ "optional": true
136
+ },
137
+ "@aws-sdk/lib-storage": {
138
+ "optional": true
139
+ },
140
+ "@aws-sdk/s3-request-presigner": {
141
+ "optional": true
142
+ }
143
+ },
127
144
  "engines": {
128
- "node": "^18.20.2 || >=20.9.0",
145
+ "node": ">=20.9.0",
129
146
  "pnpm": "^9 || ^10"
130
147
  },
131
148
  "publishConfig": {
@@ -163,6 +180,7 @@
163
180
  "test:e2e": "cross-env NODE_OPTIONS=--no-deprecation playwright test",
164
181
  "test:int": "vitest run",
165
182
  "test:int:cov": "vitest run --coverage",
183
+ "test:int:minio": "vitest run tests/integration/s3MinioLive.test.ts",
166
184
  "test:int:watch": "vitest",
167
185
  "typecheck": "tsc --noEmit"
168
186
  }
@@ -1,3 +0,0 @@
1
- import type { Endpoint } from 'payload';
2
- import type { BackupPluginOptions } from '../../types';
3
- export declare function createAdminSeedEndpoint(options: BackupPluginOptions): Endpoint | null;
@@ -1,47 +0,0 @@
1
- import { after } from 'next/server';
2
- import { restoreBackup, restoreSeedMedia } from '../../core/restore';
3
- import { completeBackupTask, createBackupTask, failBackupTask } from '../../core/taskProgress';
4
- import { requireBackupAdmin, requireBlobEnv } from '../shared';
5
- export function createAdminSeedEndpoint(options) {
6
- const seedUrl = options.seedDemoDumpUrl;
7
- if (!seedUrl) {
8
- return null;
9
- }
10
- return {
11
- handler: async (req)=>{
12
- const blobErr = requireBlobEnv();
13
- if (blobErr) {
14
- return blobErr;
15
- }
16
- const auth = await requireBackupAdmin(req, options);
17
- if (auth instanceof Response) {
18
- return auth;
19
- }
20
- const { payload } = req;
21
- const { pollSecret, taskId } = await createBackupTask(payload, 'seed', 'Seed queued');
22
- payload.logger.info({
23
- taskId
24
- }, '[backup-endpoint] Seed queued');
25
- after(restoreSeedMedia(payload, taskId).then(()=>restoreBackup(payload, seedUrl, [
26
- 'users',
27
- 'roles'
28
- ], false, taskId)).then(()=>completeBackupTask(payload, taskId, 'Seed completed')).catch(async (error)=>{
29
- await failBackupTask(payload, taskId, error);
30
- payload.logger.error({
31
- err: error,
32
- taskId
33
- }, '[backup-endpoint] Seed failed');
34
- }));
35
- return Response.json({
36
- pollSecret,
37
- taskId
38
- }, {
39
- status: 202
40
- });
41
- },
42
- method: 'post',
43
- path: '/backup-mongodb/admin/seed'
44
- };
45
- }
46
-
47
- //# sourceMappingURL=admin-seed.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/endpoints/paths/admin-seed.ts"],"sourcesContent":["import type { Endpoint } from 'payload'\n\nimport { after } from 'next/server'\n\nimport type { BackupPluginOptions } from '../../types'\n\nimport { restoreBackup, restoreSeedMedia } from '../../core/restore'\nimport { completeBackupTask, createBackupTask, failBackupTask } from '../../core/taskProgress'\nimport { requireBackupAdmin, requireBlobEnv } from '../shared'\n\nexport function createAdminSeedEndpoint(options: BackupPluginOptions): Endpoint | null {\n const seedUrl = options.seedDemoDumpUrl\n if (!seedUrl) {\n return null\n }\n\n return {\n handler: async (req) => {\n const blobErr = requireBlobEnv()\n if (blobErr) {\n return blobErr\n }\n\n const auth = await requireBackupAdmin(req, options)\n if (auth instanceof Response) {\n return auth\n }\n\n const { payload } = req\n const { pollSecret, taskId } = await createBackupTask(payload, 'seed', 'Seed queued')\n\n payload.logger.info({ taskId }, '[backup-endpoint] Seed queued')\n\n after(\n restoreSeedMedia(payload, taskId)\n .then(() => restoreBackup(payload, seedUrl, ['users', 'roles'], false, taskId))\n .then(() => completeBackupTask(payload, taskId, 'Seed completed'))\n .catch(async (error) => {\n await failBackupTask(payload, taskId, error)\n payload.logger.error({ err: error, taskId }, '[backup-endpoint] Seed failed')\n }),\n )\n\n return Response.json({ pollSecret, taskId }, { status: 202 })\n },\n method: 'post',\n path: '/backup-mongodb/admin/seed',\n }\n}\n"],"names":["after","restoreBackup","restoreSeedMedia","completeBackupTask","createBackupTask","failBackupTask","requireBackupAdmin","requireBlobEnv","createAdminSeedEndpoint","options","seedUrl","seedDemoDumpUrl","handler","req","blobErr","auth","Response","payload","pollSecret","taskId","logger","info","then","catch","error","err","json","status","method","path"],"mappings":"AAEA,SAASA,KAAK,QAAQ,cAAa;AAInC,SAASC,aAAa,EAAEC,gBAAgB,QAAQ,qBAAoB;AACpE,SAASC,kBAAkB,EAAEC,gBAAgB,EAAEC,cAAc,QAAQ,0BAAyB;AAC9F,SAASC,kBAAkB,EAAEC,cAAc,QAAQ,YAAW;AAE9D,OAAO,SAASC,wBAAwBC,OAA4B;IAClE,MAAMC,UAAUD,QAAQE,eAAe;IACvC,IAAI,CAACD,SAAS;QACZ,OAAO;IACT;IAEA,OAAO;QACLE,SAAS,OAAOC;YACd,MAAMC,UAAUP;YAChB,IAAIO,SAAS;gBACX,OAAOA;YACT;YAEA,MAAMC,OAAO,MAAMT,mBAAmBO,KAAKJ;YAC3C,IAAIM,gBAAgBC,UAAU;gBAC5B,OAAOD;YACT;YAEA,MAAM,EAAEE,OAAO,EAAE,GAAGJ;YACpB,MAAM,EAAEK,UAAU,EAAEC,MAAM,EAAE,GAAG,MAAMf,iBAAiBa,SAAS,QAAQ;YAEvEA,QAAQG,MAAM,CAACC,IAAI,CAAC;gBAAEF;YAAO,GAAG;YAEhCnB,MACEE,iBAAiBe,SAASE,QACvBG,IAAI,CAAC,IAAMrB,cAAcgB,SAASP,SAAS;oBAAC;oBAAS;iBAAQ,EAAE,OAAOS,SACtEG,IAAI,CAAC,IAAMnB,mBAAmBc,SAASE,QAAQ,mBAC/CI,KAAK,CAAC,OAAOC;gBACZ,MAAMnB,eAAeY,SAASE,QAAQK;gBACtCP,QAAQG,MAAM,CAACI,KAAK,CAAC;oBAAEC,KAAKD;oBAAOL;gBAAO,GAAG;YAC/C;YAGJ,OAAOH,SAASU,IAAI,CAAC;gBAAER;gBAAYC;YAAO,GAAG;gBAAEQ,QAAQ;YAAI;QAC7D;QACAC,QAAQ;QACRC,MAAM;IACR;AACF"}