@cloudhal/api

中文文档
0.6.5发布于 2026/11/09Apache-2.0TypeScriptES Module构建来源已验证近 30 天下载 4246

Cloudhal HTTP API (Hono): sites, pages, entries, snapshots, auth — runs on Node and Cloudflare Workers

原始使用文档

@cloudhal/api

The Cloudhal HTTP API as a Hono app — one fetch handler that runs on Node (@cloudhal/api/node) and on Cloudflare Workers.

The core routes are below; the feature routes (taxonomy, menus, media, comments, schedules, analytics, members, approvals, …) are one module each in src/routes/.

RouteWhat
GET /api/healthliveness
GET /api/methe calling actor (401 when anonymous)
/api/auth/*Better Auth (sign-up, sign-in, session, organization, admin)
GET/PUT /api/sites[/:id]sites (PUT = full document, CAS on rev)
GET /api/sites/:id/pendingwhat a publish would carry, as counts (Studio's badge beside Publish)
/api/sites/:id/pages[/:pageId]pages (POST creates and appends to Site.pageIds atomically; DELETE needs ?rev=)
/api/sites/:id/entries[/:entryId]content entries (?collection=, locale, status, filter); fields is checked against the collection's typed fields (RFC-0041), and null removes a key there. RFC-0042 §4: with collection, where (a JSON list of up to 4 {field, op, value?/values?}; ops by type, value: "now" for date/datetime fields) and orderBy (JSON {field, direction: "asc"|"desc"}) filter and sort by the collection's listFields, e.g. ?collection=events&where=[{"field":"startsAt","op":"gte","value":"now"}]&orderBy={"field":"startsAt","direction":"asc"} (URL-encoded). limit (1–100) pages the answer as {entries, total, nextCursor?}, continued with cursor=<nextCursor>; without limit the answer stays the plain array
/api/sites/:id/collections[/:key]the collection registry; PUT /:key {settings, rev} (?dryRun=1) declares a collection or changes its settings, typed fields included; DELETE /:key?rev=
/api/sites/:id/collections/:key/fields/operationsRFC-0041 §6 field operations (site:settings and content:write): POST {op, …, dryRun?} with op one of rename_field {from, to}, change_field_type {key, type, options?, multiple?, onInvalid?: "clear"}, set_field_localized {key, localized}, remove_field {key} → {operationId, done, report, rewritten, skipped} (a dry run writes nothing; done: false when the 2,000-entry / 20 s budget ran out, then POST ?continue=<operationId>); GET /:operationId → state and pending entries; POST /:operationId/revert (again while done: false). Only the draft graph changes
/api/sites/:id/snapshotscreate ({label, publish}), list, :id/publish, :id/rollback, :a/diff/:b
/api/agent-keysAPI keys for agents: POST {name, scopes} (key shown once), GET, DELETE /:id — signed-in humans only
/mcpthe Cloudhal MCP server (ADR-0011); session cookie → human, x-api-key or Authorization: Bearer <key> → agent limited to the key's scopes (REST answers agent keys with a pointer to /mcp)

Errors: 400 validation (contract errors with ajv details), 409 conflict (expectedRev/actualRev), 409 unique, 404 not_found, 401 unauthorized. Store invariants answer with their code (src/errors.ts, INVARIANT_STATUS).

Typed fields (RFC-0041) answer with every problem and its path in details.issues ([{ path: "fields/startsAt/at", code, message }]):

CodeStatusWhen
invalid_fields422values that do not fit their definitions (or several kinds of problem at once)
unknown_field422a new key without a definition, in a collection that has definitions
field_not_localized422a translation's own copy of a non-localized value (set it on the original)
required_field422an entry in review or published without a requiredToPublish value
too_large409fields over 256 KB, or collection settings over 256 KB
field_key_reserved, field_key_duplicate, field_option_duplicate, field_bounds400definitions that can never be saved as written
too_many_fields422over 30 fields per collection, 200 per site or 50 options per select
field_change_needs_operation409changing a field's type, localization or multiple, or dropping a key or option that entries still hold
operation_in_progress409another field operation is still rewriting the collection (details.operationId)
field_values_unconvertible422a type change would drop values the conversion table cannot convert, without onInvalid: "clear" (details.report is the dry run)
field_operation_incomplete409reverting an operation that has not finished, or was already reverted

Collections stage 3 (RFC-0042) answers the same way (details.issues, slash paths):

CodeStatusWhen
invalid_query422an entry list's where/orderBy/limit/cursor, or a contentList section's (sections/2/where/0/value), names an unlisted field, an operator or value its type does not take, or breaks a bound
unknown_field422listFields or expiry.field names no field of the collection
invalid_expiry422expiry.field is not a date or datetime field
structured_data_invalid422a structuredData preset that does not fit the type's table or the collection's fields (warnings are not refused)
list_field_in_use409unlisting, dropping or retyping a list field (or dropping a select option) that contentList sections still use (details.pages); remove_field of a field named by listFields, expiry or structuredData; a type change that would break those sections. rename_field renames those references instead
import { createApi } from "@cloudhal/api";
import { createAuth } from "@cloudhal/api/auth";
const auth = createAuth({ database: db, baseURL, secret });
const app = createApi({
  store,
  resolveActor: auth.resolveActor,
  resolvePrincipal: auth.resolvePrincipal,
  authHandler: auth.handler,
  agentKeys: auth.agentKeys,
  mcp: { stateKey: process.env.MCP_STATE_KEY, audit, skills },
});

Auth (ADR-0010): Better Auth 1.7 with email+password, organization and admin; sessions resolve to Actor { kind: "human", id: "user_…" }. Auth tables live in storage migration 0002_auth. The shared test suite (src/testing.ts) runs on better-sqlite3 and Miniflare D1, including the article workflow draft → review → published → snapshot → publish → rollback.

版本与发布记录

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

版本发布日期距今
0.6.5latest2026/11/091 天前
0.6.42026/11/081 天前
0.6.32026/11/081 天前
0.6.22026/10/2614 天前
0.6.12026/10/2417 天前
0.6.02026/10/2317 天前

关于 @cloudhal/api 的常见问题

@cloudhal/api 是什么?

Cloudhal HTTP API (Hono): sites, pages, entries, snapshots, auth — runs on Node and Cloudflare Workers

如何安装 @cloudhal/api?

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

@cloudhal/api 支持 TypeScript 吗?

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

@cloudhal/api 支持 ESM 还是 CommonJS?

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

@cloudhal/api 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=24。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cloudhal/api 可以商用吗?

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

@cloudhal/api 的下载量有多少?

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

@cloudhal/api 还在维护吗?

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