跳到主要内容

客户端

客户端

页面只导入一个值:import { bolt } from '$bolt'。$bolt 是 @norbital-ai/bolt/page 的生成别名,由工作区的名称索引以与服务器代码相同的类型进行类型化,因此未知的集合、字段、查询、操作、输入或消息键在 bolt check 中都是类型错误,与服务器端完全一致。

API 参考:bolt/client

<script lang="ts">
  // src/data/collection/job_assignments/+representation.svelte (templates/field-operations, excerpt)
  import { bolt, live } from '$bolt';
  import type { RecordView } from '@norbital-ai/ui';

  let { view }: { view: RecordView<'job_assignments'> } = $props();
  const record = $derived(view.mode === 'update' ? view.record : null);

  // one row by id, with the fields it names
  const site = live(() => record === null ? null
    : bolt.live(bolt.get('sites', record.site_id, { name: true })));
  // a page of rows: every read states limit or all
  const variations = live(() =>
    record == null
      ? null
      : bolt.live(bolt.read('variation_requests', {
          where: { job_assignment_id: { eq: record.id } },
          orderBy: { requested_at: 'desc' },
          limit: 50
        }))
  );
</script>

读取

  • read(collection, { where?, select?, orderBy?, search?, limit | all })——一页行。没有默认页大小:每次读取都要声明 limit 或 all: true。
  • get(collection, id, select?)——一行,或 null。
  • aggregate(collection, { count?, sum?, avg?, min?, max?, by?, where? })——对范围汇总出一行,或按组分页。
  • similar(collection, '<search>', input, options)——具名相似度搜索。
  • history(collection, id, { at? })——一行的修订记录,或它在某个时刻、某个修订或某个审批恢复点时的状态。
  • query('<c>.<q>', input)——集合查询。

每个调用都返回一个尚未执行的查询:await 读取一次,bolt.live(q) 让它保持实时。读取只在失败时抛出拒绝。

写入与运行

// src/app/field_ops_controller/+dispatch.page.svelte (templates/field-operations, excerpt)
import { Effect } from 'effect';
import { bolt, fork } from '$bolt';
import type { Id } from '@norbital-ai/bolt';
import { downloadTextFiles } from '@norbital-ai/ui';

let review = $state<{ id: Id<'sys_run'> } | null>(null);
function runReview() {
  const started = bolt.start('review_job_assignment_suspicion', {});
  review = { id: started.id }; // only plain data enters $state
  fork(started);
}

// src/app/hr_controller/payroll/+payroll.page.svelte (templates/hr-payroll, excerpt)
const exportPayroll = (ids: readonly Id<'payroll_run'>[]) =>
  bolt.query('payroll_run.export_payroll', { ids }).pipe(
    Effect.tap(({ documents }) => Effect.sync(() => downloadTextFiles(documents, 'payroll-exports.zip')))
  ); // return the Effect to toolbar.actions
  • act('<c>.create' | '<c>.update' | '<c>.delete' | '<c>.<action>', input)——所有写入。它返回一个 Outcome,从不抛出拒绝。
  • start(automation, input)——发起一次自动化运行并返回其 RunHandle,可以 await。
  • upload(file, '<c>.<field>')——为 file 字段存储文件,在保存字节之前检查 accept 与 max。fileUrl(ref) 是其下载链接,只有当查看者可以读取保存该文件的字段时才会提供。
  • approvals.process(requestId, decision) 与 approvals.withdraw(requestId)——审批决定。

谁与何处

bolt.actor 是正在查看页面的人;按 actor.id 关联行,而不是按显示名称。bolt.t(key, vars?) 翻译一个消息目录键,bolt.locale 是查看者的区域设置。登录、登出与邀请都是外壳页面,不属于 bolt。

视图会替你完成大部分工作

@norbital-ai/ui 的视图仅凭一个 of 属性就能自行读取、分页、筛选、写入并打开记录。只有在需要计算面板、仪表盘数值或自定义按钮时才直接使用 bolt:参见 UI 组件。