diff --git a/extension/src/service-worker/router/popup-only.ts b/extension/src/service-worker/router/popup-only.ts index 83a027d..15d3582 100644 --- a/extension/src/service-worker/router/popup-only.ts +++ b/extension/src/service-worker/router/popup-only.ts @@ -507,6 +507,52 @@ export async function handle( return { ok: false, error: (e as Error).message }; } } + + case 'parse_lastpass_csv': { + try { + const json: string = state.wasm.parse_lastpass_csv_json(new Uint8Array(msg.bytes)); + const parsed = JSON.parse(json) as { + items: Item[]; + warnings: Array<{ row: number; title?: string; message: string }>; + }; + return { ok: true, data: parsed }; + } catch (e) { + return { ok: false, error: (e as Error).message }; + } + } + + case 'import_lastpass_commit': { + const handle = session.getCurrent(); + if (!handle || !state.gitHost || !state.manifest) return { ok: false, error: 'vault_locked' }; + if (msg.items.length === 0) return { ok: false, error: 'no items to import' }; + + try { + const total = msg.items.length; + for (let i = 0; i < msg.items.length; i++) { + const item = msg.items[i]; + // Items arrive with IDs already minted by the WASM bridge. We + // overwrite that with a fresh extension-generated ID so the SW + // remains the single ID-issuance authority for new items in the + // remote — same pattern as `add_item`. + const id = state.wasm.new_item_id(); + const reIdItem: Item = { ...item, id }; + + await vault.encryptAndWriteItem( + state.gitHost, handle, id, reIdItem, + `import: ${reIdItem.title} (${i + 1}/${total})`, + ); + state.manifest.items[id] = itemToManifestEntry(reIdItem); + } + + await vault.encryptAndWriteManifest( + state.gitHost, handle, state.manifest, + `manifest: import ${total} items from LastPass`, + ); + return { ok: true, data: { summary: { itemCount: total } } }; + } catch (e) { + return { ok: false, error: (e as Error).message }; + } + } } }