对象存储里,你真正天天打开的往往就那么几个深层前缀:某个桶的 logs/2026/、某个项目的 assets/。每次从桶列表逐级点进去很烦。Nebula 用两件小工具解决:收藏夹(手动钉)和最近访问(自动记)。

收藏夹:手动钉常去位置

头部一个书签下拉:在任意桶 / 前缀点「收藏当前位置」,之后从下拉一键跳回。收藏按 账号 + 路径 存,所以同名前缀在不同账号下互不干扰。

最近访问:自动记录去过的地方

你不需要手动收藏也能快速回到刚才的位置——每次进入一个桶 / 前缀,后台自动记一笔,保留最近 20 条,并在命令面板空输入时优先展示。

前端记录做了防抖:在某个目录停留够久(800ms)才写一次,快速穿行目录不会疯狂刷库。

为什么各用一张独立的表

Nebula 把所有配置从浏览器 localStorage 全部迁进了本地 SQLite,并且按用途分表。收藏和最近访问各占一张:

CREATE TABLE bookmarks (
    account TEXT, path TEXT, created_at INTEGER,
    PRIMARY KEY (account, path)
);
CREATE TABLE recent_locations (
    account TEXT, path TEXT, seq INTEGER,
    PRIMARY KEY (account, path)
);

分表不是洁癖:它们语义不同(收藏是用户显式集合、要长期保留;最近访问是自动流水、要修剪),混在一张 KV 表里迟早互相干扰。

一个小坑:最近访问别用时间戳排序

最直觉的做法是给每条记一个 visited_at 时间戳,按它倒序。但在快速操作或测试里,同一毫秒内多次访问会并列,排序不确定——我们的测试就因此偶发失败过一次。

改法是用一个单调递增的逻辑序号 seq:每次访问把该行的 seq 顶成「当前最大值 + 1」,列表按 seq DESC。逻辑序号严格递增、绝不并列,排序永远确定:

INSERT INTO recent_locations (account, path, seq)
VALUES (?1, ?2, (SELECT COALESCE(MAX(seq), 0) + 1 FROM recent_locations))
ON CONFLICT(account, path) DO UPDATE
   SET seq = (SELECT COALESCE(MAX(seq), 0) + 1 FROM recent_locations);

「用逻辑序号而非墙钟时间来定序」是个很常见的小经验——凡是「谁更靠前」比「具体几点」更重要的场景,都值得想一下。