@datafn/client

中文文档
0.1.2发布于 2026/11/11MITTypeScriptESM + CJS构建来源已验证近 30 天下载 2401

DataFn 有事件总线和变异支持的客户端

中文使用文档
文档目录39 节
  1. 安装
  2. 地形矩阵
  3. 特征
  4. 快速启动
  5. 本地支持的苹果网络视频模式
  6. 客户端配置
  7. 创建 DatafnClient( 配置)
  8. Datafn 同步配置
  9. 表 API 数据
  10. 表.query(碎片)
  11. 搜索( 提供备份, 本地第一)
  12. 表格. mutate(碎片)
  13. 表格. signal( 碎片)
  14. 表格. 订阅( 处理器, 过滤器 ?)
  15. 韩国API
  16. KV API 参考文献
  17. 仅线下模式
  18. 同步
  19. 同步外观
  20. 同步引擎
  21. 水分国
  22. 克隆
  23. 活动总线
  24. 事件过滤器
  25. 匹配过滤器
  26. 交易
  27. 存储适配器
  28. 已索引的DbStorageAdapter
  29. 内存图集Adapter
  30. DatafnStorageAdapter 接口
  31. 多用途/多用途隔离
  32. 备选案文1:提供(建议)
  33. 备选案文2:直接认证
  34. 日期编码c
  35. 插件
  36. 远程适应器
  37. 扩展适配器
  38. 出口
  39. 许可证

@ datafn/ 客户端

DataFn 的离线第一反应客户端. 提供流利表和 KV API, 用于 UI 绑定的反应信号, 浏览器拥有的索引DB 存储, 本地支持的核心数据存储通过 @datafn/swift-bridge,双向同步,一个事件总线,交易,插件,以及多用户数据隔离.

安装

npm install @datafn/client @datafn/core

对于想要斯威夫特拥有的持久和同步的苹果Webview主机:

npm install @datafn/client @datafn/core @datafn/swift-bridge

地形矩阵

地形学地方持久性远距离持久性同步所有者
浏览器拥有索引数据库DataFn 服务器Java 脚本
本地支持的数据Fn 服务器核心数据DataFn 服务器挥发
本地备份 CloudKit核心数据CloudKit 私人数据库挥发

原生后盾模式是明确的. 如果桥没了,它不会悄悄倒回索引数据库.

特征

特性说明
流利的表格 APIclient.table("resource") ——范围查询,变异,信号
反应信号当数据变化时自动更新的实时查询
KV 存储包含信号支持的内置密钥值 API(client.kv(中文(简体) )
离线存储有基于更动日志的离线变异的索引DB和内存适配器
同步克隆、拉、推、克隆、调和——与水分计划
仅线下模式sync.mode: "local-only" - 不需要服务器
活动总线用于突变和同步生命周期的全球事件流
交易跨资源原子多步骤行动
插件系统截取询问、突变和自定义逻辑同步
日期编码c日期字段的自动序列化/分页
多用户隔离用户索引数据库 authContext + 储存厂
扩展适配器浏览器扩展支持通过 remoteAdapter 有远程订阅
类型安全从您的计划中得出完整的脚本推论

快速启动

import { createDatafnClient, IndexedDbStorageAdapter } from "@datafn/client";
import type { DatafnSchema } from "@datafn/core";

const schema: DatafnSchema = {
  resources: [
    {
      name: "tasks",
      version: 1,
      fields: [
        { name: "id", type: "string", required: true, unique: true },
        { name: "title", type: "string", required: true },
        { name: "completed", type: "boolean", required: true, default: false },
      ],
    },
  ],
};

const client = createDatafnClient({
  schema,
  clientId: "device-" + crypto.randomUUID(),
  storage: new IndexedDbStorageAdapter("my-app-db"),
  sync: {
    offlinability: true,
    remote: "http://localhost:3000/datafn",
  },
});

// Start sync (clone + pull + push engine)
await client.sync.start();

// Insert a record
await client.table("tasks").mutate({
  operation: "insert",
  record: { title: "Hello DataFn", completed: false },
});

// Create a reactive signal
const signal = client.table("tasks").signal({
  filters: { completed: false },
  sort: ["-createdAt"],
});

signal.subscribe((result) => {
  console.log("Active tasks:", result.data);
});

本地支持的苹果网络视频模式

当同一网页应用程序被嵌入 SwiftUI 主机中时, 配置客户端 :

import { createDatafnClient } from "@datafn/client";
import {
  createNativeBackedRemoteAdapter,
  createNativeBackedSearchProvider,
  createNativeBackedStorageAdapter,
  createNativeSyncController,
  createWKWebViewBridgeBus,
} from "@datafn/swift-bridge";

const bus = createWKWebViewBridgeBus({ handlerName: "datafn" });

const client = createDatafnClient({
  schema,
  clientId: "apple-webview-device",
  namespace: "org-1:user-1",
  storage: createNativeBackedStorageAdapter(bus),
  searchProvider: createNativeBackedSearchProvider(bus),
  sync: {
    owner: "native",
    mode: "sync",
    offlinability: true,
    remoteAdapter: createNativeBackedRemoteAdapter(bus),
    native: {
      syncController: createNativeSyncController(bus),
      remoteMode: "datafn-server",
      expectedSchemaHash: "todo-app-example-v1",
      failIfUnavailable: true,
      remoteProfile: "default",
    },
  },
});

对于 CloudKit 支持的个人应用程序, 更改 remoteMode 改为 "icloud"。在两种本地支持的模式中:

  • 斯威夫特拥有持久性和同步性.
  • 斯威夫特还拥有由SearchFn支撑的本地索引.
  • Java 脚本 SyncEngine 必须保持不活动.
  • DataFn 如果桥不可用, 则在启动持久性前必须失败 .
  • 索引DB不得用作倒置的持久性或搜索-索引层.
  • CloudKit只同步记录. 搜索索引文件仍为每个设备的本地状态 .

客户端配置

创建 DatafnClient( 配置)

interface DatafnClientConfig<S extends DatafnSchema> {
  /** Your DataFn schema definition */
  schema: S;

  /** Stable client/device identifier — required for offline + idempotency */
  clientId: string;

  /** Sync configuration (see below) */
  sync?: DatafnSyncConfig;

  /**
   * Local persistence adapter.
   * Can be a direct adapter instance or a factory function for multi-user isolation.
   */
  storage?: DatafnStorageAdapter | DatafnStorageFactory;

  /** Auth context for multi-user/multi-tenant data isolation */
  authContext?: AuthContext | AuthContextProvider;

  /** Optional plugins for hook execution */
  plugins?: DatafnPlugin[];

  /** Custom timestamp function (for testing) */
  getTimestamp?: () => number;

  /**
   * Custom ID generator for insert operations.
   * Default: `${idPrefix || resource}:${crypto.randomUUID()}`
   */
  generateId?: (params: { resource: string; idPrefix?: string }) => string;
}

Datafn 同步配置

interface DatafnSyncConfig {
  /**
   * Explicit mode selection.
   * - "sync": requires remote or remoteAdapter
   * - "local-only": no server required; all tables start as "ready"
   */
  mode?: "sync" | "local-only";

  /** Enable offline support (requires storage) */
  offlinability?: boolean;

  /** Remote server URL for the default HTTP transport */
  remote?: string;

  /** Injected remote adapter (takes precedence over remote URL) */
  remoteAdapter?: DatafnRemoteAdapter;

  /** Enable WebSocket for real-time server-push updates */
  ws?: boolean;

  /** WebSocket URL (derived from remote if omitted) */
  wsUrl?: string;

  /** Push engine: interval between batches (ms). Default 2000. */
  pushInterval?: number;

  /** Push engine: records per batch. Default 100. */
  pushBatchSize?: number;

  /** Push engine: max retries per mutation. Default 3. */
  pushMaxRetries?: number;

  /** Hydration plan for large datasets */
  hydration?: {
    /** Resources that MUST be cloned before the app is considered "ready" */
    bootResources?: string[];
    /** Resources that hydrate in the background after boot */
    backgroundResources?: string[];
    /** Per-resource clone page size (or a single number for all) */
    clonePageSize?: number | Record<string, number>;
  };
}

表 API 数据

这个 client.table(name) 方法返回特定资源的范围控件。 您也可以作为属性访问表格 : client.tasks 等同为 client.table("tasks")。 。 。 .

const tasks = client.table("tasks");
// or equivalently:
const tasks = client.tasks;

表.query(碎片)

执行此资源的查询范围 .

const result = await tasks.query({
  select: ["id", "title", "completed"],
  filters: { completed: false },
  sort: ["-createdAt"],
  limit: 20,
});
// result.data = [{ id: "task:...", title: "...", completed: false }, ...]

查询特性 :

  • select 编号 : omit - 外地选择
  • filters - 运算符: eq, (中文(简体) ), ne, (中文(简体) ), gt, (中文(简体) ), gte, (中文(简体) ), lt, (中文(简体) ), lte, (中文(简体) ), like, (中文(简体) ), ilike, (中文(简体) ), is_null, (中文(简体) ), is_not_null, (中文(简体) ), in, (中文(简体) ), nin, (中文(简体) ), contains
  • 逻辑组 : $and, (中文(简体) ), $or
  • sort ——多领域: ["name", "-createdAt"] (前缀) - = 下降数)
  • limit 编号 : offset ——以抵消为基础的平面图
  • cursor ——以光标为主的平面({ after: {...} }(中文(简体) )
  • count ——只计算返回数
  • groupBy 编号 : aggregations 编号 : having ——汇总查询
  • search ——全文搜索

搜索( 提供备份, 本地第一)

DataFn 搜索在 searchProvider 已配置。 在同步模式下,在水合准备后搜索是本地第一.

地形特有搜索所有权 :

  • 浏览器拥有模式: 使用 JavaScript 搜索Fn 提供者, 通常 @searchfn/datafn-provider 与 @searchfn/adapter-indexeddb。 。 。 .
  • 本地支持的 Apple WebView 模式: 使用 createNativeBackedSearchProvider(bus) 因此Swift针对共享本地搜索Fn后端执行搜索.
  • 原生后卫CloudKit模式:使用同一种原生的SearchFn后端,但CloudKit同步只记录;索引文件每设备重建并在当地维护.

table.query() 搜索块选项 :

const result = await tasks.query({
  search: {
    query: "test",
    prefix: true,
    fuzzy: 0.2,
    fieldBoosts: { title: 2, description: 1 },
  },
});

具有明确来源路径的跨资源搜索 :

const result = await client.search({
  query: "test",
  resources: ["tasks", "projects"],
  prefix: true,
  fuzzy: 0.2,
  fieldBoosts: { title: 2, name: 1 },
  source: "auto", // auto | local | remote
});

source 语义 :

  • auto (默认): 本地先; 如果本地提供者路径不可用, 返回到远程 .
  • local:强迫本地提供者执行.
  • remote: 强制远程 /datafn/search 执行.

如果找不到请求的来源, DataFn 返回 DFQL_UNSUPPORTED。 。 。 .

MiniSearch-仅限插件模式仍然支持兼容性,但提供者支持的模式是推荐的路径.

表格. mutate(碎片)

执行此资源的突变范围 .

// Insert
await tasks.mutate({
  operation: "insert",
  record: { title: "New task", completed: false },
});

// Merge (partial update)
await tasks.mutate({
  operation: "merge",
  id: "task:abc",
  record: { completed: true },
});

// Replace (full update)
await tasks.mutate({
  operation: "replace",
  id: "task:abc",
  record: { title: "Updated", completed: true },
});

// Delete
await tasks.mutate({
  operation: "delete",
  id: "task:abc",
});

变异操作 :

运行说明
insert创建新记录
merge部分更新( 仅指定字段)
replace完整更新( 替换整个记录)
delete删除记录

关系业务 (使用时 client.mutate() 配备全部资源/版本:

运行说明
relate在记录之间建立关系
unrelate删除记录之间的关系
modifyRelation更新关系元数据
// Tag a todo with a category (many-many relation)
await client.mutate({
  resource: "todos",
  version: 1,
  operation: "relate",
  id: "todo:1",
  relation: "tags",
  targetId: "cat:work",
});

// Remove a tag
await client.mutate({
  resource: "todos",
  version: 1,
  operation: "unrelate",
  id: "todo:1",
  relation: "tags",
  targetId: "cat:work",
});

高级突变特征:

  • 目 录数字 : clientId + 键 mutationId 用于复制
  • 优化货币数字 : if 警卫 预防冲突
  • A. 背景情况: 将任意上下文数据传递给插件和事件

表格. signal( 碎片)

创建反应信号——当数据变化时自动更新的活查询.

const activeTasks = tasks.signal({
  filters: { completed: false },
  sort: ["-createdAt"],
});

// Get current value
console.log(activeTasks.get());

// Subscribe to changes
const unsub = activeTasks.subscribe((result) => {
  console.log("Tasks:", result.data);
  console.log("Loading:", result.loading);
});

// Check states
activeTasks.loading;     // true while initial fetch is in progress
activeTasks.error;       // non-null if last fetch failed
activeTasks.refreshing;  // true while background refresh is in progress

信号特性 :

  • 懒取: 只在第一次订阅时加载数据
  • 自动更新:突变影响查询脚印时重跑
  • 跳出分批:多次快速突变触发单一刷新
  • 缓存: 具有相同查询的信号共享一个缓存实例( 通过) dfqlKey(中文(简体) )

表格. 订阅( 处理器, 过滤器 ?)

只订阅此资源的事件 .

tasks.subscribe((event) => {
  console.log(`${event.action} on ${event.resource}:`, event.ids);
});

韩国API

内置的密钥值商店提供了一个与您输入的资源同步的无计划存储层. 透过 client.kv。 。 。 .

// Set a value
await client.kv.set("user:theme", "dark");

// Get a value
const theme = await client.kv.get<string>("user:theme");
// → "dark"

// Merge into an object value
await client.kv.set("user:prefs", { fontSize: 14, lang: "en" });
await client.kv.merge("user:prefs", { fontSize: 16 });
// → { fontSize: 16, lang: "en" }

// Delete a key
await client.kv.delete("user:theme");

// Reactive signal for a key
const themeSignal = client.kv.signal<string>("user:theme", {
  defaultValue: "dark",
});

themeSignal.subscribe((value) => {
  document.body.className = value; // Updates reactively
});

KV API 参考文献

方法签署说明
getget<T>(key): Promise<T | null>读取一个值
setset<T>(key, value, params?): Promise<Result>写入一个值( 替换语义)
mergemerge(key, patch, params?): Promise<Result>浅入已存在的对象
deletedelete(key, params?): Promise<Result>删除密钥
signalsignal<T>(key, options?): DatafnSignal<T>密钥的响应信号

KV 数据存储在内建 kv 和任何其他资源一样参与同步(clone/pull/push).


仅线下模式

在完全没有服务器的情况下运行客户端 。 所有数据只存在于本地存储中.

const client = createDatafnClient({
  schema,
  clientId: "local-device",
  storage: new IndexedDbStorageAdapter("my-app-local"),
  sync: {
    mode: "local-only",
  },
});

// No sync.start() needed — all tables are immediately "ready"
// Queries and mutations work against local storage
await client.table("tasks").mutate({
  operation: "insert",
  record: { title: "Offline task" },
});

当在 local-only 模式 :

  • 所有资源水分状态设定为 "ready" 马上
  • 只对本地存储执行查询
  • 对本地存储的突变表示乐观
  • 没有网络通话
  • 同步外观方法( E)clone, (中文(简体) ), pull, (中文(简体) ), push(如果调用,则丢出)

同步

同步外观

client.sync.seed(payload)       // Seed data to server
client.sync.clone(payload)      // Full data download
client.sync.pull(payload)       // Incremental sync (cursor-based)
client.sync.push(payload)       // Upload local mutations
client.sync.cloneUp(options?)   // Upload local data to server

同步引擎

何时 offlinability 真实,同步引擎管理整个生命周期:

await client.sync.start();       // Start sync engine (clone → pull loop → push loop)
client.sync.stop();              // Stop sync engine
await client.sync.pullNow();     // Trigger immediate pull
await client.sync.cloneNow();    // Trigger immediate clone
await client.sync.reconcileNow(); // Trigger reconcile

同步引擎行为 :

  • 打开 start(): 克隆启动资源, 然后开始拉和推间隔
  • 调取可见度变化: 标签可见时重排
  • 按下批量:排队突变并分批地推到 pushInterval
  • 重试: 重试失败后再重试 pushMaxRetries 时间

水分国

每个资源跟踪其水分状态:

状态说明
notStarted尚未复制数据
hydrating克隆人正在进行中
ready有数据可供查询

配置启动对背景资源来控制应用准备 :

sync: {
  hydration: {
    bootResources: ["tasks", "projects"],     // Must clone before app is ready
    backgroundResources: ["audit_log"],        // Hydrates after boot
    clonePageSize: { tasks: 500, audit_log: 100 },
  },
}

克隆

上传本地数据到服务器( 例如下线工作后):

const result = await client.sync.cloneUp({
  resources: ["tasks"],         // Which resources to upload (default: all)
  includeManyMany: true,        // Upload join rows too
  recordOperation: "merge",     // "merge" | "replace" | "insert"
  batchSize: 100,               // Records per batch
  maxRetries: 3,                // Retries per batch
  failFast: false,              // Stop on first error?
  clearChangelogOnSuccess: true, // Drain changelog after upload
  setGlobalCursorOnSuccess: true,// Update cursors
  pullAfter: true,              // Pull new data after upload
});

console.log(result.uploadedCount);

活动总线

订阅全局事件或过滤器, 按资源, 类型, 动作等等 .

// Global subscription
const unsub = client.subscribe((event) => {
  console.log(event.type, event.resource, event.ids);
});

// Filtered subscription
const unsub2 = client.subscribe(
  (event) => console.log("Task mutated:", event),
  {
    type: "mutation_applied",
    resource: "tasks",
    action: ["insert", "merge"],
  },
);

事件过滤器

type EventFilter = {
  type?: string | string[];
  resource?: string | string[];
  ids?: string | string[];
  mutationId?: string | string[];
  action?: string | string[];
  fields?: string | string[];
  contextKeys?: string[];
  context?: Record<string, unknown>;
};

匹配过滤器

用于检查事件在程序上是否匹配过滤器的功能 :

import { matchesFilter } from "@datafn/client";

if (matchesFilter(event, { resource: "tasks", type: "mutation_applied" })) {
  // handle
}

交易

执行原子多步骤操作 :

const result = await client.transact({
  transactionId: "tx-complete-all",
  atomic: true,
  steps: [
    {
      query: {
        resource: "tasks",
        version: 1,
        select: ["id"],
        filters: { completed: false },
      },
    },
    {
      mutation: {
        resource: "tasks",
        version: 1,
        operation: "merge",
        id: "task:1",
        record: { completed: true },
      },
    },
    {
      mutation: {
        resource: "tasks",
        version: 1,
        operation: "delete",
        id: "task:2",
      },
    },
  ],
});

存储适配器

已索引的DbStorageAdapter

由IndexedDB支持的持续浏览器存储. 支持多用户隔离.

import { IndexedDbStorageAdapter } from "@datafn/client";

// Simple usage
const storage = new IndexedDbStorageAdapter("my-app-db");

// Multi-user isolation
const storage = IndexedDbStorageAdapter.createForUser(
  "my-app-db",
  userId,
  tenantId, // optional
);
// Creates database: "my-app-db_tenant-456_user-123"

内存图集Adapter

用于测试的内存存储——数据丢失于页面刷新.

import { MemoryStorageAdapter } from "@datafn/client";

const storage = new MemoryStorageAdapter();

DatafnStorageAdapter 接口

为自定义存储后端执行此接口 :

interface DatafnStorageAdapter {
  // Records
  getRecord(resource: string, id: string): Promise<Record<string, unknown> | null>;
  listRecords(resource: string): Promise<Record<string, unknown>[]>;
  upsertRecord(resource: string, record: Record<string, unknown>): Promise<void>;
  deleteRecord(resource: string, id: string): Promise<void>;
  findRecords(resource: string, field: string, value: unknown): Promise<Record<string, unknown>[]>;
  countRecords(resource: string): Promise<number>;

  // Join rows (many-many relations)
  listJoinRows(relationKey: string): Promise<Array<Record<string, unknown>>>;
  getJoinRows(relationKey: string, fromId: string): Promise<Array<Record<string, unknown>>>;
  getJoinRowsInverse(relationKey: string, toId: string): Promise<Array<Record<string, unknown>>>;
  upsertJoinRow(relationKey: string, row: Record<string, unknown>): Promise<void>;
  setJoinRows(relationKey: string, rows: Array<Record<string, unknown>>): Promise<void>;
  deleteJoinRow(relationKey: string, from: string, to: string): Promise<void>;
  countJoinRows(relationKey: string): Promise<number>;

  // Sync state
  getCursor(resource: string): Promise<string | null>;
  setCursor(resource: string, cursor: string | null): Promise<void>;
  getHydrationState(resource: string): Promise<DatafnHydrationState>;
  setHydrationState(resource: string, state: DatafnHydrationState): Promise<void>;

  // Offline changelog
  changelogAppend(entry: Omit<DatafnChangelogEntry, "seq">): Promise<DatafnChangelogEntry>;
  changelogList(options?: { limit?: number }): Promise<DatafnChangelogEntry[]>;
  changelogAck(options: { throughSeq: number }): Promise<void>;
}

多用途/多用途隔离

在单独的索引数据库中孤立每个用户的数据.

import { createDatafnClient, IndexedDbStorageAdapter } from "@datafn/client";

const client = createDatafnClient({
  schema,
  clientId: "device-uuid",
  authContext: authClient.contextProvider, // implements { getContext(): AuthContext }
  storage: (ctx) =>
    IndexedDbStorageAdapter.createForUser("my-app", ctx.userId, ctx.tenantId),
  sync: { remote: "http://localhost:3000/datafn" },
});

备选案文2:直接认证

const client = createDatafnClient({
  schema,
  clientId: "device-uuid",
  authContext: { userId: "user-123", tenantId: "tenant-456" },
  storage: (ctx) =>
    IndexedDbStorageAdapter.createForUser("my-app", ctx.userId, ctx.tenantId),
  sync: { remote: "http://localhost:3000/datafn" },
});

当用户登录和另一个日志输入时,创建新的客户端实例. 每个用户的数据仍被隔离在自己的索引数据库中.


日期编码c

自动序列化和解析 date 字段.

import {
  serializeDateFields,
  parseDateFields,
  parseQueryResultDates,
} from "@datafn/client";

// Serialize Date objects to timestamps for mutations
const serialized = serializeDateFields(schema, "tasks", {
  title: "Hello",
  createdAt: new Date(),
});

// Parse timestamps back to Date objects
const parsed = parseDateFields(schema, "tasks", {
  title: "Hello",
  createdAt: 1707000000000,
});

// Parse all date fields in a query result
const result = parseQueryResultDates(schema, "tasks", queryResult);

插件

扩展客户端行为,以插件来拦截查询,突变,并同步.

import type { DatafnPlugin } from "@datafn/core";

const loggingPlugin: DatafnPlugin = {
  name: "logger",
  runsOn: ["client"],

  afterMutation(ctx, mutation, result) {
    console.log("Mutation:", mutation, "Result:", result);
  },

  afterSync(ctx, phase, payload, result) {
    console.log(`Sync ${phase}:`, result);
  },
};

const client = createDatafnClient({
  schema,
  clientId: "...",
  plugins: [loggingPlugin],
  // ...
});

远程适应器

当您提供时使用默认的 HTTP 传输 sync.remote。对于自定义运输(仅WebSocket、浏览器扩展等),执行 DatafnRemoteAdapter数字 :

interface DatafnRemoteAdapter {
  query(q: unknown): Promise<unknown>;
  mutation(m: unknown): Promise<unknown>;
  transact(t: unknown): Promise<unknown>;
  seed(payload: unknown): Promise<unknown>;
  clone(payload: unknown): Promise<unknown>;
  pull(payload: unknown): Promise<unknown>;
  push(payload: unknown): Promise<unknown>;
  reconcile(payload: unknown): Promise<unknown>;
}

扩展适配器

对于浏览器扩展,远程适配器可以包含事件订阅支持:

const client = createDatafnClient({
  schema,
  clientId: "extension-popup",
  sync: {
    remoteAdapter: {
      ...transportMethods,
      onEvent(handler) { /* wire inbound events */ },
      subscribeRemote(filter) { /* register subscription */ },
      unsubscribeRemote(id) { /* remove subscription */ },
    },
  },
});

出口

// Client factory and types
export { createDatafnClient, type DatafnClient, type DatafnClientConfig, type DatafnRemoteAdapter }

// Table API
export { type DatafnTable }

// Event system
export { EventBus, type EventHandler }
export { matchesFilter, type EventFilter }

// Storage
export { type DatafnStorageAdapter, type DatafnStorageFactory }
export { type DatafnHydrationState, type DatafnChangelogEntry }
export { MemoryStorageAdapter }
export { IndexedDbStorageAdapter }

// KV API
export type { DatafnKvApi }
export { kvId, KV_RESOURCE_NAME }

// CloneUp
export type { CloneUpOptions, CloneUpResult }

// Date Codec
export { serializeDateFields, parseDateFields, parseQueryResultDates }

// Auth (re-exported from @superfunctions/auth)
export type { AuthContext, AuthContextProvider }

// Errors
export { type DatafnClientError, createClientError }
export { unwrapRemoteSuccess }

许可证

麻省理工学院

版本与发布记录

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

版本发布日期距今
0.1.2latest2026/11/11今天
0.1.12026/09/151 个月前
0.1.02026/08/292 个月前
0.0.32026/05/145 个月前
0.0.22026/03/157 个月前
0.0.12026/01/249 个月前

关于 @datafn/client 的常见问题

@datafn/client 是什么?

DataFn 有事件总线和变异支持的客户端

如何安装 @datafn/client?

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

@datafn/client 支持 TypeScript 吗?

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

@datafn/client 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@datafn/client 可以商用吗?

@datafn/client 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@datafn/client 的下载量有多少?

根据 npm 官方下载统计,@datafn/client 在 2026/10/12 – 2026/11/10 这 30 天内被下载 2,401 次,日均约 80 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@datafn/client 还在维护吗?

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