diff options
| -rw-r--r-- | apps/cli/src/commands/dump.ts | 291 | ||||
| -rw-r--r-- | apps/cli/src/commands/migrate.ts | 281 | ||||
| -rw-r--r-- | apps/cli/src/commands/wipe.ts | 151 |
3 files changed, 419 insertions, 304 deletions
diff --git a/apps/cli/src/commands/dump.ts b/apps/cli/src/commands/dump.ts index 2e126654..5f3f8f5e 100644 --- a/apps/cli/src/commands/dump.ts +++ b/apps/cli/src/commands/dump.ts @@ -103,6 +103,19 @@ export const dumpCmd = new Command() .description("dump all account data and assets into an archive") .option("--output <file>", "output archive path (.tar.gz)") .option( + "--exclude-assets", + "exclude binary assets (skip assets index and files)", + ) + .option("--exclude-bookmarks", "exclude bookmarks (metadata/content)") + .option("--exclude-lists", "exclude lists and list membership") + .option("--exclude-tags", "exclude tags") + .option("--exclude-ai-prompts", "exclude AI prompts") + .option("--exclude-rules", "exclude rule engine rules") + .option("--exclude-feeds", "exclude RSS feeds") + .option("--exclude-webhooks", "exclude webhooks") + .option("--exclude-user-settings", "exclude user settings") + .option("--exclude-link-content", "exclude link content") + .option( "--batch-size <n>", `number of bookmarks per page (max ${MAX_NUM_BOOKMARKS_PER_PAGE})`, (v) => Math.min(Number(v || 50), MAX_NUM_BOOKMARKS_PER_PAGE), @@ -154,150 +167,178 @@ export const dumpCmd = new Command() }; // 1) User settings - stepStart("Exporting user settings"); - const settings = await api.users.settings.query(); - await writeJson(path.join(workRoot, "users", "settings.json"), settings); - stepEndSuccess(); + if (!opts.excludeUserSettings) { + stepStart("Exporting user settings"); + const settings = await api.users.settings.query(); + await writeJson( + path.join(workRoot, "users", "settings.json"), + settings, + ); + stepEndSuccess(); + } // 2) Lists - stepStart("Exporting lists"); - const { lists } = await api.lists.list.query(); - await writeJson(path.join(workRoot, "lists", "index.json"), lists); - manifest.counts.lists = lists.length; - stepEndSuccess(); + let lists: ZBookmarkList[] | undefined; + if (!opts.excludeLists) { + stepStart("Exporting lists"); + const resp = await api.lists.list.query(); + lists = resp.lists; + await writeJson(path.join(workRoot, "lists", "index.json"), lists); + manifest.counts.lists = lists.length; + stepEndSuccess(); + } // 3) Tags - stepStart("Exporting tags"); - const { tags } = await api.tags.list.query(); - await writeJson(path.join(workRoot, "tags", "index.json"), tags); - manifest.counts.tags = tags.length; - stepEndSuccess(); + if (!opts.excludeTags) { + stepStart("Exporting tags"); + const { tags } = await api.tags.list.query(); + await writeJson(path.join(workRoot, "tags", "index.json"), tags); + manifest.counts.tags = tags.length; + stepEndSuccess(); + } // 4) Rules - stepStart("Exporting rules"); - const { rules } = await api.rules.list.query(); - await writeJson(path.join(workRoot, "rules", "index.json"), rules); - manifest.counts.rules = rules.length; - stepEndSuccess(); + if (!opts.excludeRules) { + stepStart("Exporting rules"); + const { rules } = await api.rules.list.query(); + await writeJson(path.join(workRoot, "rules", "index.json"), rules); + manifest.counts.rules = rules.length; + stepEndSuccess(); + } // 5) Feeds - stepStart("Exporting feeds"); - const { feeds } = await api.feeds.list.query(); - await writeJson(path.join(workRoot, "feeds", "index.json"), feeds); - manifest.counts.feeds = feeds.length; - stepEndSuccess(); + if (!opts.excludeFeeds) { + stepStart("Exporting feeds"); + const { feeds } = await api.feeds.list.query(); + await writeJson(path.join(workRoot, "feeds", "index.json"), feeds); + manifest.counts.feeds = feeds.length; + stepEndSuccess(); + } // 6) Prompts - stepStart("Exporting AI prompts"); - const prompts = await api.prompts.list.query(); - await writeJson(path.join(workRoot, "prompts", "index.json"), prompts); - manifest.counts.prompts = prompts.length; - stepEndSuccess(); + if (!opts.excludeAiPrompts) { + stepStart("Exporting AI prompts"); + const prompts = await api.prompts.list.query(); + await writeJson(path.join(workRoot, "prompts", "index.json"), prompts); + manifest.counts.prompts = prompts.length; + stepEndSuccess(); + } // 7) Webhooks - stepStart("Exporting webhooks"); - const webhooks = await api.webhooks.list.query(); - await writeJson( - path.join(workRoot, "webhooks", "index.json"), - webhooks.webhooks, - ); - manifest.counts.webhooks = webhooks.webhooks.length; - stepEndSuccess(); + if (!opts.excludeWebhooks) { + stepStart("Exporting webhooks"); + const webhooks = await api.webhooks.list.query(); + await writeJson( + path.join(workRoot, "webhooks", "index.json"), + webhooks.webhooks, + ); + manifest.counts.webhooks = webhooks.webhooks.length; + stepEndSuccess(); + } // 8) Bookmarks (JSONL + list membership) - stepStart("Exporting bookmarks (metadata/content)"); - const bookmarkJsonl = path.join(workRoot, "bookmarks", "index.jsonl"); - let bookmarksExported = 0; - const bookmarkIterator = async function* (): AsyncGenerator<ZBookmark> { - let cursor: ZCursor | null = null; - do { - const resp = await api.bookmarks.getBookmarks.query({ - includeContent: true, - limit: Number(opts.batchSize) || 50, - cursor, - useCursorV2: true, - }); - for (const b of resp.bookmarks) { - yield b; - bookmarksExported++; - progressUpdate("Bookmarks", bookmarksExported); - } - cursor = resp.nextCursor; - } while (cursor); - }; - await writeJsonl(bookmarkJsonl, bookmarkIterator()); - progressDone(); - manifest.counts.bookmarks = bookmarksExported; - stepEndSuccess(); + if (!opts.excludeBookmarks) { + stepStart("Exporting bookmarks (metadata/content)"); + const bookmarkJsonl = path.join(workRoot, "bookmarks", "index.jsonl"); + let bookmarksExported = 0; + const bookmarkIterator = async function* (): AsyncGenerator<ZBookmark> { + let cursor: ZCursor | null = null; + do { + const resp = await api.bookmarks.getBookmarks.query({ + includeContent: !opts.excludeLinkContent, + limit: Number(opts.batchSize) || 50, + cursor, + useCursorV2: true, + }); + for (const b of resp.bookmarks) { + yield b; + bookmarksExported++; + progressUpdate("Bookmarks", bookmarksExported); + } + cursor = resp.nextCursor; + } while (cursor); + }; + await writeJsonl(bookmarkJsonl, bookmarkIterator()); + progressDone(); + manifest.counts.bookmarks = bookmarksExported; + stepEndSuccess(); + } // 9) List membership (listId -> [bookmarkId]) - stepStart("Exporting list membership"); - const membership = await buildListMembership(api, lists, (p, t) => - progressUpdate("Lists scanned", p, t), - ); - progressDone(); - await writeJson( - path.join(workRoot, "lists", "membership.json"), - Object.fromEntries(membership.entries()), - ); - stepEndSuccess(); + if (!opts.excludeLists && !opts.excludeBookmarks && lists) { + stepStart("Exporting list membership"); + const membership = await buildListMembership(api, lists, (p, t) => + progressUpdate("Lists scanned", p, t), + ); + progressDone(); + await writeJson( + path.join(workRoot, "lists", "membership.json"), + Object.fromEntries(membership.entries()), + ); + stepEndSuccess(); + } // 10) Assets: index + files - stepStart("Exporting assets (binary files)"); - const assetsDir = path.join(workRoot, "assets", "files"); - await ensureDir(assetsDir); - const assetsIndex: { - id: string; - assetType: string; - size: number; - contentType: string | null; - fileName: string | null; - bookmarkId: string | null; - filePath: string; // relative inside archive - }[] = []; - let assetPageCursor: number | null | undefined = null; - let downloaded = 0; - let totalAssets: number | undefined = undefined; - do { - const resp = await api.assets.list.query({ - limit: 50, - cursor: assetPageCursor ?? undefined, - }); - if (totalAssets == null) totalAssets = resp.totalCount; - for (const a of resp.assets) { - const relPath = path.join("assets", "files", a.id); - const absPath = path.join(workRoot, relPath); - try { - await downloadAsset( - globals.serverAddr, - globals.apiKey, - a.id, - absPath, - ); - assetsIndex.push({ - id: a.id, - assetType: a.assetType, - size: a.size, - contentType: a.contentType, - fileName: a.fileName, - bookmarkId: a.bookmarkId, - filePath: relPath.replace(/\\/g, "/"), - }); - downloaded++; - progressUpdate("Assets", downloaded, totalAssets); - } catch (e) { - printErrorMessageWithReason( - `Failed to download asset "${a.id}"`, - e as object, - ); + if (!opts.excludeAssets) { + stepStart("Exporting assets (binary files)"); + const assetsDir = path.join(workRoot, "assets", "files"); + await ensureDir(assetsDir); + const assetsIndex: { + id: string; + assetType: string; + size: number; + contentType: string | null; + fileName: string | null; + bookmarkId: string | null; + filePath: string; // relative inside archive + }[] = []; + let assetPageCursor: number | null | undefined = null; + let downloaded = 0; + let totalAssets: number | undefined = undefined; + do { + const resp = await api.assets.list.query({ + limit: 50, + cursor: assetPageCursor ?? undefined, + }); + if (totalAssets == null) totalAssets = resp.totalCount; + for (const a of resp.assets) { + const relPath = path.join("assets", "files", a.id); + const absPath = path.join(workRoot, relPath); + try { + await downloadAsset( + globals.serverAddr, + globals.apiKey, + a.id, + absPath, + ); + assetsIndex.push({ + id: a.id, + assetType: a.assetType, + size: a.size, + contentType: a.contentType, + fileName: a.fileName, + bookmarkId: a.bookmarkId, + filePath: relPath.replace(/\\/g, "/"), + }); + downloaded++; + progressUpdate("Assets", downloaded, totalAssets); + } catch (e) { + printErrorMessageWithReason( + `Failed to download asset "${a.id}"`, + e as object, + ); + } } - } - assetPageCursor = resp.nextCursor; - } while (assetPageCursor); - progressDone(); - manifest.counts.assets = downloaded; - await writeJson(path.join(workRoot, "assets", "index.json"), assetsIndex); - stepEndSuccess(); + assetPageCursor = resp.nextCursor; + } while (assetPageCursor); + progressDone(); + manifest.counts.assets = downloaded; + await writeJson( + path.join(workRoot, "assets", "index.json"), + assetsIndex, + ); + stepEndSuccess(); + } // 11) Manifest stepStart("Writing manifest"); diff --git a/apps/cli/src/commands/migrate.ts b/apps/cli/src/commands/migrate.ts index 48343992..750daf61 100644 --- a/apps/cli/src/commands/migrate.ts +++ b/apps/cli/src/commands/migrate.ts @@ -71,6 +71,15 @@ export const migrateCmd = new Command() ) .requiredOption("--dest-api-key <key>", "API key for the destination server") .option("-y, --yes", "skip confirmation prompt") + .option("--exclude-assets", "exclude assets (skip asset bookmarks)") + .option("--exclude-lists", "exclude lists and list membership") + .option("--exclude-ai-prompts", "exclude AI prompts") + .option("--exclude-rules", "exclude rule engine rules") + .option("--exclude-feeds", "exclude RSS feeds") + .option("--exclude-webhooks", "exclude webhooks") + .option("--exclude-bookmarks", "exclude bookmarks migration") + .option("--exclude-tags", "exclude tags migration") + .option("--exclude-user-settings", "exclude user settings migration") .option( "--batch-size <n>", `number of bookmarks per page (max ${MAX_NUM_BOOKMARKS_PER_PAGE})`, @@ -118,130 +127,163 @@ export const migrateCmd = new Command() } // 1) User settings - stepStart("Migrating user settings"); - await migrateUserSettings(src, dest); - stepEndSuccess(); + if (!opts.excludeUserSettings) { + stepStart("Migrating user settings"); + await migrateUserSettings(src, dest); + stepEndSuccess(); + } // 2) Lists (and mapping) - stepStart("Migrating lists"); - const listsStart = Date.now(); - const { - lists, - listIdMap, - createdCount: listsCreated, - } = await migrateLists(src, dest, (created, alreadyExists, total) => { - progressUpdate("Lists (created)", created + alreadyExists, total); - }); - progressDone(); - stepEndSuccess( - `${listsCreated} created in ${Math.round((Date.now() - listsStart) / 1000)}s`, - ); + let lists: ZBookmarkList[] = []; + let listIdMap = new Map<string, string>(); + if (!opts.excludeLists) { + stepStart("Migrating lists"); + const listsStart = Date.now(); + const listsRes = await migrateLists( + src, + dest, + (created, alreadyExists, total) => { + progressUpdate("Lists (created)", created + alreadyExists, total); + }, + ); + lists = listsRes.lists; + listIdMap = listsRes.listIdMap; + progressDone(); + stepEndSuccess( + `${listsRes.createdCount} created in ${Math.round((Date.now() - listsStart) / 1000)}s`, + ); + } // 3) Feeds - stepStart("Migrating feeds"); - const feedsStart = Date.now(); - const { idMap: feedIdMap, count: feedsCount } = await migrateFeeds( - src, - dest, - (created, total) => { + let feedIdMap = new Map<string, string>(); + if (!opts.excludeFeeds) { + stepStart("Migrating feeds"); + const feedsStart = Date.now(); + const res = await migrateFeeds(src, dest, (created, total) => { progressUpdate("Feeds", created, total); - }, - ); - progressDone(); - stepEndSuccess( - `${feedsCount} migrated in ${Math.round((Date.now() - feedsStart) / 1000)}s`, - ); + }); + feedIdMap = res.idMap; + progressDone(); + stepEndSuccess( + `${res.count} migrated in ${Math.round((Date.now() - feedsStart) / 1000)}s`, + ); + } // 4) AI settings (custom prompts) - stepStart("Migrating AI prompts"); - const promptsStart = Date.now(); - const promptsCount = await migratePrompts(src, dest, (created, total) => { - progressUpdate("Prompts", created, total); - }); - progressDone(); - stepEndSuccess( - `${promptsCount} migrated in ${Math.round((Date.now() - promptsStart) / 1000)}s`, - ); + if (!opts.excludeAiPrompts) { + stepStart("Migrating AI prompts"); + const promptsStart = Date.now(); + const promptsCount = await migratePrompts( + src, + dest, + (created, total) => { + progressUpdate("Prompts", created, total); + }, + ); + progressDone(); + stepEndSuccess( + `${promptsCount} migrated in ${Math.round((Date.now() - promptsStart) / 1000)}s`, + ); + } // 5) Webhooks (tokens cannot be read; created without token) - stepStart("Migrating webhooks"); - const webhooksStart = Date.now(); - const webhooksCount = await migrateWebhooks( - src, - dest, - (created, total) => { - progressUpdate("Webhooks", created, total); - }, - ); - progressDone(); - stepEndSuccess( - `${webhooksCount} migrated in ${Math.round((Date.now() - webhooksStart) / 1000)}s`, - ); + if (!opts.excludeWebhooks) { + stepStart("Migrating webhooks"); + const webhooksStart = Date.now(); + const webhooksCount = await migrateWebhooks( + src, + dest, + (created, total) => { + progressUpdate("Webhooks", created, total); + }, + ); + progressDone(); + stepEndSuccess( + `${webhooksCount} migrated in ${Math.round((Date.now() - webhooksStart) / 1000)}s`, + ); + } // 6) Tags (build id map for rules) - stepStart("Ensuring tags on destination"); - const tagsStart = Date.now(); - const { idMap: tagIdMap, count: tagsCount } = await migrateTags( - src, - dest, - (ensured, total) => { + let tagIdMap = new Map<string, string>(); + if (!opts.excludeTags) { + stepStart("Ensuring tags on destination"); + const tagsStart = Date.now(); + const res = await migrateTags(src, dest, (ensured, total) => { progressUpdate("Tags", ensured, total); - }, - ); - progressDone(); - stepEndSuccess( - `${tagsCount} ensured in ${Math.round((Date.now() - tagsStart) / 1000)}s`, - ); + }); + tagIdMap = res.idMap; + progressDone(); + stepEndSuccess( + `${res.count} ensured in ${Math.round((Date.now() - tagsStart) / 1000)}s`, + ); + } // 7) Rules (requires tag/list/feed id maps) - stepStart("Migrating rule engine rules"); - const rulesStart = Date.now(); - const rulesCount = await migrateRules( - src, - dest, - { tagIdMap, listIdMap, feedIdMap }, - (created, total) => { - progressUpdate("Rules", created, total); - }, - ); - progressDone(); - stepEndSuccess( - `${rulesCount} migrated in ${Math.round((Date.now() - rulesStart) / 1000)}s`, - ); + if ( + !opts.excludeRules && + !opts.excludeLists && + !opts.excludeFeeds && + !opts.excludeTags + ) { + stepStart("Migrating rule engine rules"); + const rulesStart = Date.now(); + const rulesCount = await migrateRules( + src, + dest, + { tagIdMap, listIdMap, feedIdMap }, + (created, total) => { + progressUpdate("Rules", created, total); + }, + ); + progressDone(); + stepEndSuccess( + `${rulesCount} migrated in ${Math.round((Date.now() - rulesStart) / 1000)}s`, + ); + } // 8) Bookmarks (with list membership + tags) - stepStart("Building list membership for bookmarks"); - const blmStart = Date.now(); - const { bookmarkListsMap, scannedLists } = - await buildBookmarkListMembership(src, lists, (processed, total) => { - progressUpdate("Scanning lists", processed, total); + let bookmarkListsMap = new Map<string, string[]>(); + if (!opts.excludeLists && !opts.excludeBookmarks) { + stepStart("Building list membership for bookmarks"); + const blmStart = Date.now(); + const res = await buildBookmarkListMembership( + src, + lists, + (processed, total) => { + progressUpdate("Scanning lists", processed, total); + }, + ); + bookmarkListsMap = res.bookmarkListsMap; + progressDone(); + stepEndSuccess( + `${res.scannedLists} lists scanned in ${Math.round((Date.now() - blmStart) / 1000)}s`, + ); + } + if (!opts.excludeBookmarks) { + stepStart("Migrating bookmarks"); + const bmStart = Date.now(); + const res = await migrateBookmarks(src, dest, { + pageSize: Number(opts.batchSize) || 50, + listIdMap, + bookmarkListsMap, + total: totalBookmarks, + onProgress: (migrated, skipped, total) => { + const suffix = + skipped > 0 ? `(skipped ${skipped} assets)` : undefined; + progressUpdate("Bookmarks", migrated, total, suffix); + }, + srcServer: globals.serverAddr, + srcApiKey: globals.apiKey, + destServer: opts.destServer, + destApiKey: opts.destApiKey, + excludeAssets: !!opts.excludeAssets, + excludeLists: !!opts.excludeLists, }); - progressDone(); - stepEndSuccess( - `${scannedLists} lists scanned in ${Math.round((Date.now() - blmStart) / 1000)}s`, - ); - - stepStart("Migrating bookmarks"); - const bmStart = Date.now(); - const res = await migrateBookmarks(src, dest, { - pageSize: Number(opts.batchSize) || 50, - listIdMap, - bookmarkListsMap, - total: totalBookmarks, - onProgress: (migrated, skipped, total) => { - const suffix = - skipped > 0 ? `(skipped ${skipped} assets)` : undefined; - progressUpdate("Bookmarks", migrated, total, suffix); - }, - srcServer: globals.serverAddr, - srcApiKey: globals.apiKey, - destServer: opts.destServer, - destApiKey: opts.destApiKey, - }); - progressDone(); - stepEndSuccess( - `${res.migrated} migrated${res.skippedAssets ? `, ${res.skippedAssets} skipped` : ""} in ${Math.round((Date.now() - bmStart) / 1000)}s`, - ); + progressDone(); + stepEndSuccess( + `${res.migrated} migrated${res.skippedAssets ? `, ${res.skippedAssets} skipped` : ""} in ${Math.round((Date.now() - bmStart) / 1000)}s`, + ); + } printStatusMessage(true, "Migration completed successfully"); } catch (error) { @@ -629,6 +671,8 @@ async function migrateBookmarks( srcApiKey: string; destServer: string; destApiKey: string; + excludeAssets: boolean; + excludeLists: boolean; }, ) { let cursor: ZCursor | null = null; @@ -674,6 +718,11 @@ async function migrateBookmarks( break; } case BookmarkTypes.ASSET: { + if (opts.excludeAssets) { + // Skip migrating asset bookmarks when excluded + skippedAssets++; + continue; + } // Download from source and re-upload to destination try { const downloadResp = await fetch( @@ -746,14 +795,16 @@ async function migrateBookmarks( } // Add to lists (map src -> dest list ids) - const srcListIds = opts.bookmarkListsMap.get(b.id) ?? []; - for (const srcListId of srcListIds) { - const destListId = opts.listIdMap.get(srcListId); - if (destListId) { - await dest.lists.addToList.mutate({ - listId: destListId, - bookmarkId: createdId!, - }); + if (!opts.excludeLists) { + const srcListIds = opts.bookmarkListsMap.get(b.id) ?? []; + for (const srcListId of srcListIds) { + const destListId = opts.listIdMap.get(srcListId); + if (destListId) { + await dest.lists.addToList.mutate({ + listId: destListId, + bookmarkId: createdId!, + }); + } } } migrated++; diff --git a/apps/cli/src/commands/wipe.ts b/apps/cli/src/commands/wipe.ts index 34281e2b..713ac452 100644 --- a/apps/cli/src/commands/wipe.ts +++ b/apps/cli/src/commands/wipe.ts @@ -58,6 +58,14 @@ export const wipeCmd = new Command() .name("wipe") .description("wipe all data for the current user from the server") .option("-y, --yes", "skip confirmation prompt") + .option("--exclude-lists", "exclude lists from deletion") + .option("--exclude-ai-prompts", "exclude AI prompts from deletion") + .option("--exclude-rules", "exclude rules from deletion") + .option("--exclude-feeds", "exclude RSS feeds from deletion") + .option("--exclude-webhooks", "exclude webhooks from deletion") + .option("--exclude-bookmarks", "exclude bookmarks from deletion") + .option("--exclude-tags", "exclude tags cleanup from deletion") + .option("--exclude-user-settings", "exclude user settings (no-op)") .option( "--batch-size <n>", `number of bookmarks per page (max ${MAX_NUM_BOOKMARKS_PER_PAGE})`, @@ -100,82 +108,96 @@ export const wipeCmd = new Command() } // 1) Rules - stepStart("Deleting rule engine rules"); - const rulesStart = Date.now(); - const rulesDeleted = await wipeRules(api, (deleted, total) => { - progressUpdate("Rules", deleted, total); - }); - progressDone(); - stepEndSuccess( - `${rulesDeleted} deleted in ${Math.round((Date.now() - rulesStart) / 1000)}s`, - ); + if (!opts.excludeRules) { + stepStart("Deleting rule engine rules"); + const rulesStart = Date.now(); + const rulesDeleted = await wipeRules(api, (deleted, total) => { + progressUpdate("Rules", deleted, total); + }); + progressDone(); + stepEndSuccess( + `${rulesDeleted} deleted in ${Math.round((Date.now() - rulesStart) / 1000)}s`, + ); + } // 2) Feeds - stepStart("Deleting feeds"); - const feedsStart = Date.now(); - const feedsDeleted = await wipeFeeds(api, (deleted, total) => { - progressUpdate("Feeds", deleted, total); - }); - progressDone(); - stepEndSuccess( - `${feedsDeleted} deleted in ${Math.round((Date.now() - feedsStart) / 1000)}s`, - ); + if (!opts.excludeFeeds) { + stepStart("Deleting feeds"); + const feedsStart = Date.now(); + const feedsDeleted = await wipeFeeds(api, (deleted, total) => { + progressUpdate("Feeds", deleted, total); + }); + progressDone(); + stepEndSuccess( + `${feedsDeleted} deleted in ${Math.round((Date.now() - feedsStart) / 1000)}s`, + ); + } // 3) Webhooks - stepStart("Deleting webhooks"); - const webhooksStart = Date.now(); - const webhooksDeleted = await wipeWebhooks(api, (deleted, total) => { - progressUpdate("Webhooks", deleted, total); - }); - progressDone(); - stepEndSuccess( - `${webhooksDeleted} deleted in ${Math.round((Date.now() - webhooksStart) / 1000)}s`, - ); + if (!opts.excludeWebhooks) { + stepStart("Deleting webhooks"); + const webhooksStart = Date.now(); + const webhooksDeleted = await wipeWebhooks(api, (deleted, total) => { + progressUpdate("Webhooks", deleted, total); + }); + progressDone(); + stepEndSuccess( + `${webhooksDeleted} deleted in ${Math.round((Date.now() - webhooksStart) / 1000)}s`, + ); + } // 4) Prompts - stepStart("Deleting AI prompts"); - const promptsStart = Date.now(); - const promptsDeleted = await wipePrompts(api, (deleted, total) => { - progressUpdate("Prompts", deleted, total); - }); - progressDone(); - stepEndSuccess( - `${promptsDeleted} deleted in ${Math.round((Date.now() - promptsStart) / 1000)}s`, - ); + if (!opts.excludeAiPrompts) { + stepStart("Deleting AI prompts"); + const promptsStart = Date.now(); + const promptsDeleted = await wipePrompts(api, (deleted, total) => { + progressUpdate("Prompts", deleted, total); + }); + progressDone(); + stepEndSuccess( + `${promptsDeleted} deleted in ${Math.round((Date.now() - promptsStart) / 1000)}s`, + ); + } // 5) Bookmarks - stepStart("Deleting bookmarks"); - const bmStart = Date.now(); - const bookmarksDeleted = await wipeBookmarks(api, { - pageSize: Number(opts.batchSize) || 50, - total: totalBookmarks, - onProgress: (deleted, total) => { - progressUpdate("Bookmarks", deleted, total); - }, - }); - progressDone(); - stepEndSuccess( - `${bookmarksDeleted} deleted in ${Math.round((Date.now() - bmStart) / 1000)}s`, - ); + if (!opts.excludeBookmarks) { + stepStart("Deleting bookmarks"); + const bmStart = Date.now(); + const bookmarksDeleted = await wipeBookmarks(api, { + pageSize: Number(opts.batchSize) || 50, + total: totalBookmarks, + onProgress: (deleted, total) => { + progressUpdate("Bookmarks", deleted, total); + }, + }); + progressDone(); + stepEndSuccess( + `${bookmarksDeleted} deleted in ${Math.round((Date.now() - bmStart) / 1000)}s`, + ); + } // 6) Lists - stepStart("Deleting lists"); - const listsStart = Date.now(); - const listsDeleted = await wipeLists(api, (deleted, total) => { - progressUpdate("Lists", deleted, total); - }); - progressDone(); - stepEndSuccess( - `${listsDeleted} deleted in ${Math.round((Date.now() - listsStart) / 1000)}s`, - ); + if (!opts.excludeLists) { + stepStart("Deleting lists"); + const listsStart = Date.now(); + const listsDeleted = await wipeLists(api, (deleted, total) => { + progressUpdate("Lists", deleted, total); + }); + progressDone(); + stepEndSuccess( + `${listsDeleted} deleted in ${Math.round((Date.now() - listsStart) / 1000)}s`, + ); + } // 7) Tags (unused) - stepStart("Deleting unused tags"); - const tagsStart = Date.now(); - const deletedTags = await wipeTags(api); - stepEndSuccess( - `${deletedTags} deleted in ${Math.round((Date.now() - tagsStart) / 1000)}s`, - ); + if (!opts.excludeTags) { + stepStart("Deleting unused tags"); + const tagsStart = Date.now(); + const deletedTags = await wipeTags(api); + stepEndSuccess( + `${deletedTags} deleted in ${Math.round((Date.now() - tagsStart) / 1000)}s`, + ); + } printStatusMessage(true, "Wipe completed successfully"); } catch (error) { @@ -304,6 +326,7 @@ async function wipeBookmarks( limit: opts.pageSize, cursor, useCursorV2: true, + includeContent: false, }); for (const b of resp.bookmarks) { try { |
