kv-wasm: ItemSummary carries tags and modifiedAt for the web vault's filters and sort

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-17 23:59:58 +09:00
co-authored by Claude Opus 5.5
parent b5ced32be3
commit f9f2d14aa2
6 changed files with 12 additions and 1 deletions
+1 -1
View File
@@ -45,7 +45,7 @@ The generated `pkg/kv_wasm.d.ts` is the reference. It mirrors kv-ffi's `VaultCor
records are plain objects with the same fields as kv-ffi's records (`ItemDto`, `ItemSummary`,
`SyncReport`, `DeviceDto`, `PasskeySummary`, `ImportPreview`, …); enums are camelCase strings
(`"login" | "secureNote" | "card" | "identity"`, `"ok" | "pendingApproval"`); bytes are `Uint8Array`;
absent optionals come back as `null`. **Every `VaultCore` method returns a `Promise`.**
absent optionals come back as `null`. `ItemSummary` also carries `tags` and `modifiedAt` (web only). **Every `VaultCore` method returns a `Promise`.**
```ts
class VaultCore {
+2
View File
@@ -82,6 +82,8 @@ assert.deepEqual(
],
);
assert.equal((await a.itemHistory(bankId))[0].password, "first password");
assert.deepEqual(list[0].tags, ["finance", "ünïcode ✓"]);
assert.ok(list[0].modifiedAt >= bank.modifiedAt);
await rejects(a.getItem("not-a-uuid"), "Invalid");
const code = kv.totpCode("JBSWY3DPEHPK3PXP", Math.floor(Date.now() / 1000));
assert.match(code.code, /^\d{6}$/);
+2
View File
@@ -796,6 +796,8 @@ fn summary(i: &Item) -> ItemSummary {
urls: i.urls.clone(),
favorite: i.favorite,
has_totp: i.totp.is_some(),
tags: i.tags.clone(),
modified_at: i.modified_at,
}
}
+3
View File
@@ -42,6 +42,9 @@ pub struct ItemSummary {
pub urls: Vec<String>,
pub favorite: bool,
pub has_totp: bool,
/// Web only (not in kv-ffi's record): for tag filters and "recently modified" without `getItem`.
pub tags: Vec<String>,
pub modified_at: i64,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+3
View File
@@ -39,6 +39,9 @@ export interface ItemSummary {
urls: string[];
favorite: boolean;
hasTotp: boolean;
tags: string[];
/** Unix seconds. */
modifiedAt: number;
}
/** `id: ""` creates a new item. Omitted optional fields default to null / [] / false / 0. */
+1
View File
@@ -72,6 +72,7 @@ async fn account_lifecycle_persists_in_indexeddb() {
.unwrap();
let list: Vec<ItemSummary> = de(ok(core.list_items()).await);
assert_eq!(list.iter().map(|i| i.title.as_str()).collect::<Vec<_>>(), ["Bank", "Note"]);
assert!(list[0].tags.is_empty() && list[0].modified_at > 1_700_000_000);
let mut item: ItemDto = de(ok(core.get_item(id.clone())).await);
assert_eq!(item.password.as_deref(), Some("hunter2-secret"));
item.password = Some("hunter3-secret".into());