@basenative/persist

中文文档
3.0.0发布于 2026/10/31Apache-2.0TypeScriptES Module零依赖构建来源已验证

Signal-driven local persistence with TTL, conflict resolution, and a server-rehydrate hook for BaseNative apps

原始使用文档
文档目录11 节
  1. Install
  2. Layer 1 — flat KV with TTL
  3. Layer 2 — signal binding
  4. Layer 3 — server-rehydrate
  5. Storage adapters
  6. Examples
  7. Game session resume
  8. Form draft
  9. Last selection
  10. Links
  11. License

@basenative/persist

Signal-driven local persistence with TTL, conflict resolution, and a server-rehydrate hook. Built for the patterns BaseNative apps actually need:

  • Resume an in-flight session across reloads, tabs, and devices.
  • Preserve form drafts without bespoke useEffect plumbing.
  • Remember last selection (active filter, sort order, theme) with TTL so it doesn't get stuck forever.

Three layers, each composable on its own.

Install

pnpm add @basenative/persist
# Optional — get reactive bindings via signals
pnpm add @basenative/runtime

Layer 1 — flat KV with TTL

import { loadPersisted, savePersisted, clearPersisted } from '@basenative/persist';

await savePersisted('theme', 'dark');                  // forever
await savePersisted('cart',  cart, 60 * 60 * 24);      // 24h TTL
await loadPersisted('cart');                           // null if expired
await clearPersisted('cart');

The on-disk envelope is { v, t, e } — value, savedAt-ms, expiresAt-ms-or-null. Expired entries are evicted on read.

Legacy {...state, savedAt} shape (the t4bs convention) is read transparently with a default 12h expiry — no migration required.

Layer 2 — signal binding

import { signal } from '@basenative/runtime';
import { persisted } from '@basenative/persist';

const draft = signal('');
const dispose = persisted('compose:draft', draft, {
  ttlSeconds: 7 * 24 * 3600,
  debounceMs: 300,
});

The signal is hydrated from storage on mount and written through on every change. Pass resolve(local, current) to merge instead of overwrite.

Works with any signal-shaped object — @basenative/runtime, raw refs, or your own primitive — anything exposing some combination of .value, .get/.set, and .subscribe.

Layer 3 — server-rehydrate

The "session resume" pattern from t4bs's App.jsx:

import { hydrateFromServer } from '@basenative/persist';

await hydrateFromServer({
  key: 't4bs:session',
  ttlSeconds: 12 * 3600,
  fetch: () => api.getSession(),
  reconcile: (local, server) => server ?? local, // server is authoritative
  onResolve: (state, { source }) => {
    if (state) setSession(state);
    if (source === 'server') setLoading(false);
  },
  onError: (e) => console.warn('session refresh failed:', e),
});

Order of operations:

  1. Local cache hit → emit immediately (source: 'local') so the UI paints without waiting on the network.
  2. fetch() runs → emit again with the authoritative result (source: 'server').
  3. Persist the authoritative state.

If the fetch errors, local is left untouched.

Storage adapters

import { setStorageAdapter, indexedDbAdapter } from '@basenative/persist';

setStorageAdapter(indexedDbAdapter()); // for big payloads
  • localStorageAdapter() — default; ~5MB cap.
  • indexedDbAdapter({ dbName, store }) — opt-in for larger blobs.
  • memoryAdapter() — SSR / tests / Workers.

Examples

Game session resume

const session = signal(null);
persisted('t4bs:session', session, { ttlSeconds: 12 * 3600 });

Form draft

const draft = signal({ title: '', body: '' });
persisted('compose:draft', draft, { debounceMs: 500, ttlSeconds: 7 * 24 * 3600 });

Last selection

const filter = signal('all');
persisted('inbox:filter', filter); // no expiry

License

Apache-2.0.

版本与发布记录

@basenative/persist 共发布 11 个版本,首次发布于 2026/10/18;过去 12 个月发布了 11 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.0.0latest2026/10/312 天前
2.4.02026/10/268 天前
2.3.22026/10/2212 天前
2.3.12026/10/2212 天前
2.3.02026/10/2212 天前
2.2.02026/10/2113 天前

关于 @basenative/persist 的常见问题

@basenative/persist 是什么?

带有TTL、冲突解决和用于BaseNative应用程序的服务器补充钩子的信号驱动的本地持久性

如何安装 @basenative/persist?

在项目目录运行 npm install @basenative/persist,或使用 pnpm add / yarn add / bun add。

@basenative/persist 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@basenative/persist 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@basenative/persist 可以商用吗?

@basenative/persist 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@basenative/persist 还在维护吗?

最新版本 3.0.0 发布于 2026/10/31(2 天前);至今共发布 11 个版本,其中过去 12 个月发布了 11 个;首次发布于 2026/10/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。