build-integration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Build a GitBook Integration

构建GitBook集成

A skill for building integrations on GitBook's developer platform: apps that run inside GitBook itself. An integration can render custom blocks in the editor, show configuration UI, listen to events (content updated, Git sync completed, space viewed), authenticate against external services with OAuth, and talk to anything over HTTP.
This skill covers the integration lifecycle — scaffold, code, develop, publish. For creating or restructuring the docs site an integration might be installed into, defer to
configure-site
; for authoring page content, defer to
write-docs
.
本技能用于在GitBook开发者平台上构建集成:即运行在GitBook内部的应用。集成可在编辑器中渲染自定义区块、显示配置UI、监听事件(内容更新、Git同步完成、空间浏览)、通过OAuth向外部服务认证,以及通过HTTP与任意服务通信。
本技能涵盖集成的完整生命周期——搭建框架、编码、开发、发布。若需创建或重构集成所安装的文档站点,请使用
configure-site
技能;若需编写页面内容,请使用
write-docs
技能。

What an integration is (mental model)

集成是什么(心智模型)

An integration is a small TypeScript app executed by GitBook's runtime — not a script injected into pages, and not code running on the user's server. Three consequences shape everything else:
  1. Rendering happens on GitBook's backend. Your component's
    render
    function runs server-side on every interaction and returns ContentKit markup (a JSX-like UI description). There is no client-side React tree you control, no DOM access, and UI updates flow through the action → new state → re-render loop.
  2. You cannot inject JavaScript into a site. The
    site:script:inject
    and
    site:script:cookies
    scopes you'll see in GitBook-owned integrations are internal-only. If the user's plan amounts to "add a script tag to their docs", stop and say so early — the supported paths are custom blocks, webframes, and events.
  3. Local development is a proxy, not a server you visit.
    gitbook dev
    routes the installed integration's traffic to your machine. You never open the dev server's port in a browser; you interact with the integration inside app.gitbook.com.
集成是由GitBook运行时执行的小型TypeScript应用——并非注入页面的脚本,也不是运行在用户服务器上的代码。这带来了三个关键影响,决定了集成开发的所有特性:
  1. 渲染在GitBook后端进行。组件的
    render
    函数在每次交互时都在服务器端运行,并返回ContentKit标记(类JSX的UI描述)。你无法控制客户端React树,也无法访问DOM,UI更新遵循“动作→新状态→重新渲染”的循环。
  2. 无法向站点注入JavaScript。你在GitBook官方集成中看到的
    site:script:inject
    site:script:cookies
    权限范围仅内部可用。如果用户的需求是“向文档添加脚本标签”,请尽早告知无法实现——支持的方案包括自定义区块、网页框架和事件处理。
  3. 本地开发是代理模式,而非直接访问服务器
    gitbook dev
    会将已安装集成的流量路由到你的本地机器。你无需在浏览器中打开开发服务器端口,而是在app.gitbook.com内部与集成交互。

The project

项目结构

gitbook new
scaffolds this shape:
my-integration/
├── gitbook-manifest.yaml   # identity, scopes, blocks, configuration schema
├── .gitbook-dev.yaml       # local dev config (generated by `gitbook dev`)
├── package.json
└── src/
    └── index.tsx           # entry file — default-exports createIntegration()
The entry file (whatever
script:
in the manifest points to) default-exports
createIntegration({ fetch, components, events })
:
tsx
import { createIntegration, createComponent } from '@gitbook/runtime';

const helloBlock = createComponent({
    componentId: 'hello-world',            // must match a block id in the manifest
    initialState: { message: 'Say hello!' },
    action: async (element, action, context) => {
        switch (action.action) {
            case 'say':
                return { state: { message: 'Hello world' } };
            default:
                return {};
        }
    },
    render: async (element, context) => (
        <block>
            <button label={element.state.message} onPress={{ action: 'say' }} />
        </block>
    ),
});

export default createIntegration({
    components: [helloBlock],
    events: {
        space_content_updated: async (event, context) => {
            // react to content changes
        },
    },
});
A custom block only appears in the editor's insert palette (⌘ + /) if it is declared in both places:
createComponent
in the code and a
blocks:
entry in the manifest whose
id
matches the
componentId
. Forgetting one half is the most common "my block doesn't show up" cause.
gitbook new
命令会搭建如下项目结构:
my-integration/
├── gitbook-manifest.yaml   # identity, scopes, blocks, configuration schema
├── .gitbook-dev.yaml       # local dev config (generated by `gitbook dev`)
├── package.json
└── src/
    └── index.tsx           # entry file — default-exports createIntegration()
入口文件(即清单中
script:
指向的文件)需默认导出
createIntegration({ fetch, components, events })
tsx
import { createIntegration, createComponent } from '@gitbook/runtime';

const helloBlock = createComponent({
    componentId: 'hello-world',            // must match a block id in the manifest
    initialState: { message: 'Say hello!' },
    action: async (element, action, context) => {
        switch (action.action) {
            case 'say':
                return { state: { message: 'Hello world' } };
            default:
                return {};
        }
    },
    render: async (element, context) => (
        <block>
            <button label={element.state.message} onPress={{ action: 'say' }} />
        </block>
    ),
});

export default createIntegration({
    components: [helloBlock],
    events: {
        space_content_updated: async (event, context) => {
            // react to content changes
        },
    },
});
自定义区块只有在两处都进行声明时才会出现在编辑器的插入面板(⌘ + /)中:代码中的
createComponent
,以及清单中
blocks:
条目里
id
componentId
匹配的内容。遗漏其中一处是“我的区块不显示”问题最常见的原因。

The manifest, briefly

清单简介

gitbook-manifest.yaml
is the integration's identity and permission grant. Required:
name
(globally unique across all of GitBook — pick something namespaced like
acme-changelog
, not
test
),
title
,
description
,
organization
(org id or subdomain),
visibility
,
scopes
, and
script
. Request only the scopes the code actually uses — installers see them.
The manifest also declares
blocks
, installer-facing
configurations
(account-level and site-level property schemas rendered as a settings form), and
secrets
(e.g.
CLIENT_ID: ${{ env.CLIENT_ID }}
, loaded at publish time — use
dotenv-cli
so
gitbook publish
sees your
.env
).
Full field-by-field schema, scope list, and configuration property types:
references/manifest.md
. Read it whenever you're editing the manifest beyond the basics.
gitbook-manifest.yaml
是集成的身份标识和权限授予文件。必填项包括:
name
(在整个GitBook平台全局唯一——请选择带命名空间的名称,如
acme-changelog
,而非
test
)、
title
description
organization
(组织ID或子域名)、
visibility
scopes
script
。仅请求代码实际使用的权限范围——安装者会看到这些权限。
清单还会声明
blocks
、面向安装者的
configurations
(账户级和站点级属性 schema,会渲染为设置表单),以及
secrets
(例如
CLIENT_ID: ${{ env.CLIENT_ID }}
,在发布时加载——请使用
dotenv-cli
确保
gitbook publish
能读取你的
.env
文件)。
完整的字段schema、权限范围列表和配置属性类型请参考
references/manifest.md
。当你对清单的编辑超出基础内容时,请务必查阅此文档。

The development loop

开发流程

The loop has a non-obvious order — publish comes before local development:
  1. Prerequisites. Node 18+, a personal access token from https://app.gitbook.com/account/developer, and the CLI:
    npm install @gitbook/cli -g
    , then
    gitbook auth
    (or
    gitbook auth --token=<token>
    ). If a token needs to be pasted into the conversation, export it to the environment and never echo it back or commit it.
  2. Scaffold.
    gitbook new <dir>
    — prompts for name, title, organization, and scopes.
  3. Publish once.
    gitbook publish
    in the project root. This registers the integration (private by default) and prints an install link.
  4. Install it into at least one space or site via that link. Local dev doesn't work until it's installed somewhere.
  5. Develop.
    gitbook dev
    starts the proxy: all traffic for the installed integration is served from your local code instead of the published version. Interact with it in the GitBook editor, not at the server URL. UI changes need a browser refresh; disable browser caching for a smoother loop. Logs surface in the browser console or your terminal depending on where the code runs — check both before concluding logging is broken.
  6. Re-publish with
    gitbook publish
    whenever you want the hosted version updated.
    gitbook unpublish <name>
    removes it.
CLI command reference (including
gitbook whoami
and
gitbook openapi publish
):
references/manifest.md
.
开发流程的顺序有些特殊——先发布再进行本地开发
  1. 前置条件。Node 18+版本、从https://app.gitbook.com/account/developer获取的个人访问令牌,以及GitBook CLI:执行
    npm install @gitbook/cli -g
    安装CLI,然后运行
    gitbook auth
    (或
    gitbook auth --token=<token>
    )进行认证。如果需要在对话中粘贴令牌,请将其导出到环境变量中,切勿回显或提交令牌。
  2. 搭建框架。执行
    gitbook new <dir>
    ——系统会提示输入名称、标题、组织和权限范围。
  3. 首次发布。在项目根目录执行
    gitbook publish
    。这会注册集成(默认私有)并打印安装链接。
  4. 安装集成。通过上述链接将集成安装到至少一个空间或站点中。只有安装完成后,本地开发才能正常工作。
  5. 开发调试。执行
    gitbook dev
    启动代理:已安装集成的所有流量都会路由到你的本地代码,而非已发布版本。请在GitBook编辑器中与集成交互,而非访问服务器URL。UI变更需要刷新浏览器;建议禁用浏览器缓存以获得更流畅的开发体验。日志会根据代码运行位置显示在浏览器控制台或终端中——在判断日志功能异常前,请检查这两个位置。
  6. 重新发布。每当你想要更新托管版本时,执行
    gitbook publish
    gitbook unpublish <name>
    命令可移除已发布的集成。
CLI命令参考(包括
gitbook whoami
gitbook openapi publish
)请查阅
references/manifest.md

Runtime: fetch, events, environment, OAuth

运行时:fetch、事件、环境、OAuth

Details and full tables live in
references/runtime.md
— read it when writing event handlers, OAuth flows, or anything touching
context.environment
. The essentials:
  • fetch
    handles incoming HTTP requests to the integration's public endpoint using standard Fetch API
    Request
    /
    Response
    objects. Outgoing HTTP is plain
    fetch
    too.
  • events
    maps event names (
    installation_setup
    ,
    space_installation_setup
    ,
    space_view
    ,
    ui_render
    ,
    space_content_updated
    ,
    space_visibility_updated
    ,
    space_gitsync_started
    ,
    space_gitsync_completed
    ) to handlers. Some events require matching scopes.
  • context.environment
    exposes
    apiEndpoint
    ,
    apiTokens
    , installation info (space, status, per-installation
    configuration
    values entered by the installer),
    secrets
    , and public URLs (
    environment.integration.urls.publicEndpoint
    ).
  • OAuth against an external provider is a fixed pattern: a
    button
    -type configuration property whose
    callback_url
    routes to a
    createOAuthHandler({...})
    in your fetch handler, with client id/secret coming from
    secrets
    . Don't hand-roll the redirect/token exchange.
  • Calling the GitBook API from inside the integration: use
    context.api
    (an authenticated
    @gitbook/api
    client) rather than constructing your own client from raw tokens.
详细信息和完整表格请参考
references/runtime.md
——当你编写事件处理程序、OAuth流程或任何涉及
context.environment
的代码时,请务必查阅此文档。核心要点如下:
  • fetch
    使用标准Fetch API的
    Request
    /
    Response
    对象处理发送到集成公共端点的HTTP请求。对外发送HTTP请求也使用普通的
    fetch
    方法。
  • events
    将事件名称(
    installation_setup
    space_installation_setup
    space_view
    ui_render
    space_content_updated
    space_visibility_updated
    space_gitsync_started
    space_gitsync_completed
    )映射到对应的处理程序。部分事件需要匹配相应的权限范围。
  • context.environment
    暴露
    apiEndpoint
    apiTokens
    、安装信息(空间、状态、安装者输入的每安装实例
    configuration
    值)、
    secrets
    以及公共URL(
    environment.integration.urls.publicEndpoint
    )。
  • OAuth 对接外部服务提供商遵循固定模式:使用
    button
    类型的配置属性,其
    callback_url
    路由到你的fetch处理程序中的
    createOAuthHandler({...})
    ,客户端ID/密钥来自
    secrets
    。请勿手动实现重定向/令牌交换逻辑。
  • 从集成内部调用GitBook API:请使用
    context.api
    (已认证的
    @gitbook/api
    客户端),而非使用原始令牌自行构建客户端。

ContentKit: building the UI

ContentKit:构建UI

ContentKit is the component vocabulary
render
can return: layout (
block
,
vstack
,
hstack
,
divider
), display (
box
,
card
,
text
,
image
,
markdown
), and interactive elements (
button
,
textinput
,
select
,
switch
,
checkbox
,
radio
,
codeblock
,
webframe
,
modal
). Interactivity model in one line: inputs bind their value to a
state
key; buttons dispatch actions; your
action
reducer returns new state; GitBook re-renders.
Read
references/contentkit.md
before writing any component beyond a trivial button — it has the full prop tables plus the patterns that are hard to guess: dynamic state binding for live previews, webframe
postMessage
communication, modals with
returnValue
, persisting props with
@editor.node.updateProps
, link unfurling via
@link.unfurl
+
urlUnfurl
manifest patterns, and markdown code-block serialization of blocks.
ContentKit是
render
函数可返回的组件集合:包括布局组件(
block
vstack
hstack
divider
)、展示组件(
box
card
text
image
markdown
)和交互组件(
button
textinput
select
switch
checkbox
radio
codeblock
webframe
modal
)。交互模式可概括为:输入组件将值绑定到
state
键;按钮触发动作;你的
action
reducer返回新状态;GitBook重新渲染。
在编写除简单按钮外的任何组件之前,请查阅
references/contentkit.md
——该文档包含完整的属性表以及难以自行摸索的模式:实时预览的动态状态绑定、webframe的
postMessage
通信、带
returnValue
的模态框、使用
@editor.node.updateProps
持久化属性、通过
@link.unfurl
+
urlUnfurl
清单模式实现链接展开,以及区块的Markdown代码块序列化。

Publishing and sharing

发布与分享

Visibility in the manifest controls reach:
  • private
    (default) — installable only by members of the owning org. Right for internal tools; stay here during development.
  • unlisted
    — installable by any org, but only via the shared install link. Right for sharing with specific customers or beta testers.
  • public
    — installable by anyone; required before submitting to the integration marketplace (which is a separate review process — see GitBook's "submit your app for review" docs).
Re-run
gitbook publish
after changing visibility. Before suggesting
public
, sanity-check the manifest is presentable:
icon
,
summary
(Markdown, ≤2048 chars),
previewImages
(1600×800),
categories
,
externalLinks
.
清单中的
visibility
字段控制集成的可访问范围:
  • private
    (默认)——仅所属组织成员可安装。适用于内部工具;开发期间请保持此设置。
  • unlisted
    ——任意组织均可安装,但需通过共享的安装链接。适用于与特定客户或测试人员分享。
  • public
    ——任何人都可安装;提交至集成应用市场前必须设置为此值(应用市场提交需单独审核流程——请查阅GitBook的“提交你的应用进行审核”文档)。
修改
visibility
后需重新执行
gitbook publish
。在建议设置为
public
之前,请检查清单内容是否完整规范:包括
icon
summary
(Markdown格式,≤2048字符)、
previewImages
(尺寸1600×800)、
categories
externalLinks

Working style

开发建议

  • Scaffold with the CLI rather than by hand when starting fresh —
    gitbook new
    wires up the manifest, TypeScript config, and
    @gitbook/runtime
    versions correctly.
  • Trace a block's id chain (manifest
    blocks[].id
    componentId
    ) whenever a component misbehaves.
  • Keep secrets out of the manifest file itself — always the
    ${{ env.X }}
    indirection, never literal values.
  • When the user's goal is content or site automation from outside GitBook (scripts hitting the REST API, CI pipelines), an integration may be the wrong tool — the plain API with a personal token is simpler. Integrations earn their keep when code must run inside GitBook: blocks, config UI, event reactions, OAuth on behalf of installers.
  • 从零开始时使用CLI搭建框架而非手动创建——
    gitbook new
    会正确配置清单、TypeScript配置和
    @gitbook/runtime
    版本。
  • 当组件出现异常时,追踪区块的ID链(清单
    blocks[].id
    componentId
    )。
  • 切勿在清单文件中直接写入密钥——始终使用
    ${{ env.X }}
    的间接引用方式,绝不使用明文值。
  • 当用户的目标是从GitBook外部实现内容或站点自动化(如调用REST API的脚本、CI流水线)时,集成可能并非合适工具——使用带个人令牌的原生API更简单。只有当代码必须在GitBook内部运行时,集成才体现价值:例如自定义区块、配置UI、事件响应、代表安装者完成OAuth认证等场景。

References

参考文档

  • references/manifest.md
    — every
    gitbook-manifest.yaml
    field, all scopes, configuration property types, secrets, CLI command reference, installation/configuration flow.
  • references/runtime.md
    createIntegration
    /
    createComponent
    /
    createOAuthHandler
    signatures, event catalog,
    context.environment
    shape, HTTP in and out.
  • references/contentkit.md
    — full component reference with props, built-in actions, and interactivity recipes (dynamic binding, webframes, modals, unfurling, markdown serialization).
  • references/manifest.md
    ——包含
    gitbook-manifest.yaml
    的所有字段、权限范围列表、配置属性类型、密钥、CLI命令参考、安装/配置流程。
  • references/runtime.md
    ——包含
    createIntegration
    /
    createComponent
    /
    createOAuthHandler
    的签名、事件目录、
    context.environment
    结构、HTTP输入输出处理。
  • references/contentkit.md
    ——包含完整的组件参考(带属性说明)、内置动作以及交互实现方案(动态绑定、网页框架、模态框、链接展开、Markdown序列化)。