@biltme/backend

中文文档
0.7.1发布于 2026/10/18UNLICENSEDTypeScriptES Module近 30 天下载 3494

Bilt backend SDK — thin shim over @supabase/supabase-js for bilt-cloud projects

原始使用文档
文档目录10 节
  1. Install
  2. Quick start (Expo)
  3. Typed queries
  4. Naming a row
  5. Calling functions
  6. Storage
  7. Web
  8. Server (no session persistence)
  9. What this package adds vs @supabase/supabase-js
  10. Docs

@biltme/backend

Thin shim over @supabase/supabase-js for Bilt projects. Public surface = supabase-js's surface; this package adds storage adapter helpers, a stable import for the agent prompt template, and re-exports the functions error classes for clean catch blocks.

Install

bun add @biltme/backend
# Expo only — also install AsyncStorage as the session store
bun add @react-native-async-storage/async-storage

Quick start (Expo)

import { createClient, asyncStorage } from '@biltme/backend'
import AsyncStorage from '@react-native-async-storage/async-storage'

const url = process.env.EXPO_PUBLIC_BILT_URL!     // https://<pid>.cloud.bilt.me
const key = process.env.EXPO_PUBLIC_BILT_ANON_KEY!

export const bilt = createClient(url, key, {
  auth: {
    storage: asyncStorage(AsyncStorage),
    persistSession: true,
    autoRefreshToken: true,
    detectSessionInUrl: false,
  },
})

Every supabase-js method works:

const { data, error } = await bilt.auth.signInWithPassword({ email, password })
const { data: rows } = await bilt.from('notes').select('*')

Typed queries

createClient reads the schema off an empty Database interface this package exports. Augment it and the columns of every table in the file are typed:

declare module '@biltme/backend' {
  interface Database {
    public: {
      Tables: {
        notes: {
          Row: { id: string; title: string; tags: string[] | null }
          Insert: { id?: string; title: string; tags?: string[] | null }
          Update: { id?: string; title?: string; tags?: string[] | null }
          Relationships: []
        }
      }
      Views: Record<never, never>
      Functions: Record<never, never>
      Enums: Record<never, never>
      CompositeTypes: Record<never, never>
    }
  }
}

You do not write that by hand. bilt-cloud regenerates it from the live schema on every bilt_apply_sql, and the agent drops it into the project. Because it is a module augmentation rather than createClient<Database>, there is no generic to thread through and nothing to keep in sync at the call site.

Every key bilt-cloud emits is closed. A table, view or column that is not in the file fails to compile, and so does an rpc() call to a function the file does not list or with an argument it does not have. A stale file therefore blocks a build until the next schema change regenerates it.

Leave Database unaugmented and rows come back any, which is what 0.5.x did.

Naming a row

Four helpers resolve over that same augmented Database, so a row can cross a component boundary without being restated:

import type { Tables, TablesInsert, TablesUpdate, Enums } from '@biltme/backend'

function MessageCard({ message }: { message: Tables<'messages'> }) { … }
function draft(): TablesInsert<'messages'> { … }
function patch(): TablesUpdate<'messages'> { … }
function badge(status: Enums<'order_status'>) { … }

Tables spans tables and views and gives the same type select() returns per element. TablesInsert and TablesUpdate take tables only, as in supabase-js, so a writable view has a row name but no payload name. Enums resolves to the union bilt-cloud renders under Database['public']['Enums'], so a switch over it is checked for exhaustiveness.

Before the first schema change there are no names, and passing one is a compile error rather than any.

Calling functions

const { data, error } = await bilt.functions.invoke('send-email', {
  body: { to: '[email protected]', subject: 'Welcome' },
})

Auth header is set automatically: the active session's access token if signed in, otherwise the anon key. Functions deployed with verify_jwt: true require either signed-in session or the anon key; verify_jwt: false accepts unsigned requests.

Catch the typed error classes:

import { FunctionsHttpError, FunctionsRelayError, FunctionsFetchError } from '@biltme/backend'

const { data, error } = await bilt.functions.invoke('send-email', { body: {...} })
if (error instanceof FunctionsHttpError) {
  // user function returned 4xx/5xx — inspect error.context (Response)
} else if (error instanceof FunctionsRelayError) {
  // bilt-cloud / pool relay failed (function not found, cold start error)
} else if (error instanceof FunctionsFetchError) {
  // transport-level (DNS, TCP, TLS)
}

region option on invoke() is accepted but silently ignored — bilt-cloud is single-region.

Storage

// Admin (server-side, service key) — bucket lifecycle
await bilt.storage.createBucket('avatars', { public: false, fileSizeLimit: 5 * 1024 * 1024 })
await bilt.storage.createBucket('public-assets', { public: true })

// Upload (RLS-gated for anon-key / user-token; bypassed for service key)
const { data, error } = await bilt.storage
  .from('avatars')
  .upload(`${user.id}/photo.jpg`, file, { contentType: 'image/jpeg', upsert: true })

// Public bucket → URL is unauthenticated
const { data: { publicUrl } } = bilt.storage
  .from('public-assets')
  .getPublicUrl('logo.png')

// Private bucket → time-limited signed URL (up to 7 days)
const { data, error } = await bilt.storage
  .from('avatars')
  .createSignedUrl(`${user.id}/photo.jpg`, 3600)

// Catch storage errors:
import { StorageApiError } from '@biltme/backend'
if (error instanceof StorageApiError) { /* … */ }

Bucket admin (createBucket, updateBucket, deleteBucket, emptyBucket, listBuckets) is ServiceKey-only. Object ops are gated by Postgres RLS policies on storage.objects — author them with the bilt_storage_apply agent tool or the SQL editor.

On React Native, a Blob passed to upload, update or uploadToSignedUrl is sent as bytes labelled with contentType, so fetch(uri).blob() from a picked file passes a bucket's MIME allowlist. Pass contentType for such files: a React Native Blob has no type of its own, and without one the upload is labelled application/octet-stream.

Web

import { createClient, webStorage } from '@biltme/backend'

const bilt = createClient(url, key, {
  auth: { storage: webStorage(), persistSession: true, autoRefreshToken: true },
})

Server (no session persistence)

import { createClient, memoryStorage } from '@biltme/backend'

const bilt = createClient(url, key, {
  auth: { storage: memoryStorage(), persistSession: false, autoRefreshToken: false },
})

What this package adds vs @supabase/supabase-js

  • createClient is supabase-js's createClient, re-typed so that a call with no type arguments defaults its schema to the augmentable Database interface above instead of any.
  • Database, the empty interface a project augments to type its schema.
  • On React Native, storage uploads send a Blob as bytes so contentType reaches the bucket (see Storage).
  • Realtime is not available: bilt.channel() throws REALTIME_NOT_SUPPORTED. Refetch with bilt.from(...) on an interval or on screen focus instead.
  • asyncStorage(impl) factory wrapping @react-native-async-storage/async-storage to the supabase-js storage shape.
  • webStorage() and memoryStorage() for completeness.
  • FunctionsHttpError, FunctionsRelayError, FunctionsFetchError, FunctionRegion re-exports for clean catch and option typing.
  • StorageApiError re-export for storage catch blocks.
  • Stable import path for the bilt-agent prompt template.

Docs

For everything else (auth flows, RLS, OAuth, functions reference), use Supabase's docs. The bilt backend speaks the same wire protocol.

版本与发布记录

@biltme/backend 共发布 6 个版本,首次发布于 2026/07/15;过去 12 个月发布了 6 个版本。

版本发布日期距今
0.7.1latest2026/10/1820 天前
0.7.02026/09/081 个月前
0.6.02026/08/312 个月前
0.5.22026/07/183 个月前
0.5.12026/07/173 个月前
0.5.02026/07/153 个月前

关于 @biltme/backend 的常见问题

@biltme/backend 是什么?

Bilt backend SDK — thin shim over @supabase/supabase-js for bilt-cloud projects

如何安装 @biltme/backend?

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

@biltme/backend 支持 TypeScript 吗?

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

@biltme/backend 支持 ESM 还是 CommonJS?

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

@biltme/backend 可以商用吗?

@biltme/backend 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@biltme/backend 的下载量有多少?

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

@biltme/backend 还在维护吗?

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