@frappe/cloud-sdk

中文文档
0.7.0发布于 2026/11/08TypeScriptES Module零依赖构建来源已验证近 30 天下载 2.4万

API client and dialog for Frappe Cloud site settings

原始使用文档
文档目录11 节
  1. Requirements
  2. Install
  3. Open Cloud Settings
  4. Select panels and appearance
  5. Mount inline
  6. Use API calls without the dialog
  7. Handle feedback and errors
  8. Use the Desk bundle
  9. What needs a release
  10. Release
  11. Build and test

@frappe/cloud-sdk

Use Cloud Settings in a Frappe app. The SDK provides typed API calls and a ready-to-use settings dialog. It works in Desk, React, Vue, and plain browser pages.

Use the shared dialog for a consistent Cloud Settings experience across apps. If your app needs its own UI, use the API calls without the dialog.

Requirements

  • A Pilot-managed Frappe site with the Cloud Settings server APIs.
  • A signed-in user with the System Manager role.
  • The site's session cookie. Write calls also need frappe.csrf_token or window.csrf_token.

The server checks access on every call. The browser does not receive Pilot or Central credentials.

Install

npm install @frappe/cloud-sdk

The package holds the API calls and a small loader. It does not hold the UI. When you first open the dialog, the loader imports the UI from the site's Pilot server, at the esm/ path next to the script URL in bundle.js of get_context. Each panel then loads when it is first shown. So a Pilot update changes the UI in every app, and your app does not need a new release. You do not need to add Vue, Frappe UI, or a stylesheet to your app.

The browser must reach the Pilot server, and the page's Content Security Policy must allow scripts from it. If the UI does not load, openCloudSettings() rejects with a message that says so.

The dialog uses the Inter font. If the page does not load Inter, the dialog adds it to the page the first time it opens.

Open Cloud Settings

Show your button only when isCloudSettingsAvailable() returns true. Call openCloudSettings() when the user clicks it.

import { isCloudSettingsAvailable, openCloudSettings, closeCloudSettings } from '@frappe/cloud-sdk'

const available = await isCloudSettingsAvailable()

async function openSettings() {
  try {
    await openCloudSettings({ panels: ['billing', 'domains', 'advanced'] })
  } catch (error) {
    // Show this message in your app's alert or error component.
    console.error(error instanceof Error ? error.message : 'Could not open Cloud Settings.')
  }
}

// Call this when the host page or component is removed.
closeCloudSettings()

In React, use onClick={openSettings}. In Vue, use @click="openSettings". In a plain page, use button.addEventListener('click', openSettings). Disable the button while the dialog opens.

Availability is asynchronous. It returns false for an unavailable site or a permission denial. A connection error rejects the call. Handle that error in your app too. Importing the package is safe during server rendering. Opening the dialog requires a browser.

Select panels and appearance

await openCloudSettings({
  panels: ['billing', 'domains'],
  tab: 'domains',
  theme: 'auto',
  onClose: () => console.log('Cloud Settings closed'),
})
OptionPurpose
panelsSelect which panels to show. Omit it or use an empty array to show all. Unknown names are ignored. This option does not change permissions.
tabSelect the first panel. The default is the first visible panel.
themeUse auto, light, or dark. Auto follows html[data-theme="dark"] or html.dark.
translateSupply (message, values?) => string. The default uses Frappe's translation catalog and replaces numbered values.
onCloseRun a callback after the dialog closes.
contextSupply a CloudContext. Without it, the SDK reads the current site's context.
targetRender the panels inside this element instead of a dialog. See Mount inline.
appName the app that serves this page, such as crm. When the user uninstalls that app from the Marketplace panel, the page no longer exists, so Cloud Settings sends the user to /desk. Omit it in Desk.

Panel names: billing, marketplace, analytics, domains, backups, usage, site-config, maintenance, and advanced.

The dialog uses Espresso components. On a phone, it fills the viewport and has a panel selector. It keeps clear of the notch and the home indicator when the page sets viewport-fit=cover in its viewport meta tag. On a desktop, it has a sidebar. Its styles, menus, dialogs, alerts, and toasts stay inside a shadow root. Closing removes the UI and returns focus to the button. Opening again replaces the current dialog. Closing also cancels a pending open.

Mount inline

An app with its own settings page can show the panels inside it. Pass the element to fill as target. The panels fill its height, so give the element one. With one panel, the UI has no sidebar and no panel selector, so the app's own navigation stays the only one. With several panels, the sidebar shows inside the element.

await openCloudSettings({ target: document.querySelector('#cloud-settings'), panels: ['billing'] })

// Call this when the host page or component is removed.
closeCloudSettings()

Opening again, inline or as a dialog, replaces the mounted UI. Menus, dialogs, and toasts stay inside the element's shadow root.

The inline UI is in the tab order, so Tab moves from the host page into the panels. A host can show the inline UI inside its own modal. Then Esc, or a click outside the open Cloud menu or dialog, closes it and also the host modal. To prevent this, ignore the modal's close while fc-cloud-settings[overlay-open] exists. The element has this attribute while a Cloud menu or dialog is open.

const isCloudOverlayOpen = () => !!document.querySelector('fc-cloud-settings[overlay-open]')
<Dialog :open="show" @update:open="(open) => (open || !isCloudOverlayOpen()) && (show = open)">

Use API calls without the dialog

You can build your own pages, panels, or controls with the API calls. The /api import does not load the shared UI. Your app controls the layout and handles loading, empty states, errors, and success feedback.

import { getBilling, getDomains } from '@frappe/cloud-sdk/api'

const billing = await getBilling()
const domains = await getDomains()

The root import and /api export the same API calls and TypeScript models. Use /api when you only need data.

Build your own UI on the read calls, for example a plan badge or a banner. For changes, open the dialog on the right panel, such as openCloudSettings({ tab: 'billing' }). The action calls follow the dialog's flows, and their steps can change between versions. Payment setup is an example.

AreaRead callsAction calls
SitegetContext, getAccountUrl, getTaskNone
BillinggetBilling, getPlanOptions, getBillingProfile, getPaymentGateways, getInvoices, getInvoicePdfChange plan, save profile, set up or remove a payment method, reconcile setup, pay an invoice (createInvoiceCheckout, then getCheckoutStatus)
AppsgetMarketplaceAppsInstall, uninstall, update
DomainsgetDomainsRead DNS records, add, remove, set primary
BackupsgetBackups, getBackupDownloadLinksCreate, delete
MonitoringgetAnalytics, getUptime, getStorageRefresh storage
Site configgetSiteConfigUpdate config
MaintenanceNoneClear cache, migrate

Requests use the current origin and session. They time out after 30 seconds. The SDK does not retry write calls.

getBilling returns next_bill: this site's server's share of the team's next bill, with amount, subtotal, tax, tax_type, charge_on, days_left, the lines behind it, and blockers, the reasons the team's charge would fail. Show a warning only for a blocker. getInvoices returns this server's share of each team invoice, newest first. has_pdf and can_pay are true only when the invoice covers this server alone, because the invoice PDF and its payment cover the whole team. getInvoicePdf(invoice) returns { filename, content }, with the PDF as base64.

changePlan(plan) returns { queued, resized, progress_url }. A new size stops the site for a few minutes. When progress_url is set, open it: the page lives on Central and brings the user back when the site is ready. During a free trial, the call resizes nothing: Central keeps the plan, and the site moves to it when a payment method converts the trial. getPlanOptions then lists the paid plans the trial may move to, with selected set to the plan it moves to. getBilling returns plan_change.progress_url while a plan change runs, such as that move.

Handle feedback and errors

StateDialog behavior
LoadingShow a skeleton in the panel.
No dataShow an empty message and the next available action.
Load failedShow an error in the panel with a Try again button.
Form or action failedShow the error beside the form or action.
Action runningShow a loading button and disable conflicting actions.
Action completeRefresh the data or show a short success toast.
Task still runningShow a background status message. Closing the UI stops polling, not the server task.

Direct API calls and errors before the dialog opens belong to your app. Catch CloudSettingsError and show its message. It also has status, serverMessages, and excType. Status 0 means a network failure. Messages are plain text.

Use the Desk bundle

Pilot serves two builds of the same UI under /embed/cloud-settings/:

PathFormatUsed by
cloud-settings.jsOne classic scriptDesk, through frappe.cloudSettings.show(context, options). It also exposes window.FrappeCloudSettings with the same availability, open, and close methods.
esm/cloud-settings.js and esm/chunks/ES module with a chunk per panelThe npm package

Both entry files revalidate on every load, so a Pilot update takes effect at once. Chunk names contain a content hash, so the browser caches them for a year. The ES files are sent with Access-Control-Allow-Origin: *, because a site imports them from the Pilot origin.

What needs a release

ChangeRelease
Anything inside the dialog, such as copy, layout, fields, or flows that use existing callsPilot update
New data in a responseCentral deploy. The Frappe proxy passes responses through.
A new or renamed call the dialog makesFrappe release, because the whitelisted proxy methods live in Frappe
The public API of this package: openCloudSettings options, panel names, isCloudSettingsAvailable, or the typed calls in @frappe/cloud-sdk/apiNew version of this package, then an upgrade in each app

Release

Raise version in package.json and package-lock.json in a pull request. When it merges into develop, the Publish Cloud SDK workflow tests, builds and publishes that version to npm. It skips a version that npm already has. Run the workflow by hand to publish the current version again after a failed run.

npm trusts the workflow through trusted publishing, so the repository holds no npm token. A package maintainer sets this once on npmjs.com: in the @frappe/cloud-sdk settings, add a GitHub Actions trusted publisher for the repository frappe/pilot and the workflow cloud-sdk-publish.yml.

Build and test

Run npm test and npm run build in this package. Run npm run build in admin/frontend/in-app-embed to build both Pilot outputs into admin/backend/static/in-app-embed/cloud-settings/. That build also checks that the ES runtime exports its methods, contains its styles, and loads panels on demand.

To run browser regression tests, install the dependencies in admin/frontend/dashboard and admin/frontend/in-app-embed, then build this package and the in-app embed. Run npx playwright install chromium and npx playwright test --config cloud-settings.config.ts from admin/frontend/dashboard. The tests check that the SDK loads the UI from Pilot and loads a panel only when it is shown, dialog cleanup, custom feedback translations, task cancellation and resume, and the phone layout. cloud-settings-billing.spec.ts checks the billing tab: the trial notice and its states, the billing details and payment steps during a trial, the country and Indian state lists, a card that fails verification, the plan list, the move to the progress page, and the refusal, spending limit and retry states. cloud-settings-marketplace.spec.ts checks that a trial keeps the app it is for, the backup offer before an uninstall, the move to Desk after the host app is removed, the logo and position of a task card, and that app details wait for the pointer to move. CI runs these tests in the MariaDB browser job.

To test all panels with sample data, build this package and the in-app embed. Run python3 -m http.server 8123 from the repository root. Open http://localhost:8123/admin/frontend/cloud-sdk/tests/embed.html. No real payment or site action runs in this fixture.

To test billing without host metadata, run this from the Pilot repository:

.venv/bin/python -m scripts.cloud_settings_simulator --bench-root /path/to/local/bench

Use a local development site that has the server APIs and a button to open the dialog. Set that site's pilot_endpoint to http://127.0.0.1:8003, then clear its cache. Keep its existing site token. Sign in as a System Manager and open Billing. The simulation controls are at http://127.0.0.1:8124. Save the sample profile, complete the local checkout, then click Check status. To test the trial flow, choose Start a free trial on the controls page: Billing then shows an open trial with no invoices, and a completed checkout converts it. End the free trial shows a trial that ended without converting. When the trial converts to a bigger plan, Billing shows the move, then sends the browser to a simulated progress page, which returns to the site when the move ends. Start the simulator with --trial-app <app> to name the app the trial is for, as Central does. The Marketplace panel then keeps that app installed until the trial converts. The simulation answers as Central does: the country and GST state lists come from the bench's Frappe and Central apps, an address in India bills in INR through Razorpay and every other country in USD through Stripe, and a trial offers only the paid plans. Razorpay Checkout needs real Razorpay keys, so the simulation stops at that step. You can reset the data or simulate an API failure. State stays in memory. Billing makes no real charges. Other Pilot operations still use the real local bench. Stop the simulator and restore the original endpoint when finished.

版本与发布记录

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

版本发布日期距今
0.7.0latest2026/11/087 天前
0.6.12026/11/0312 天前
0.6.02026/11/0213 天前
0.5.02026/10/2719 天前
0.4.42026/10/2720 天前
0.4.32026/10/2620 天前

关于 @frappe/cloud-sdk 的常见问题

@frappe/cloud-sdk 是什么?

API client and dialog for Frappe Cloud site settings

如何安装 @frappe/cloud-sdk?

在项目目录运行 npm install @frappe/cloud-sdk,或使用 pnpm add / yarn add / bun add。

@frappe/cloud-sdk 支持 TypeScript 吗?

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

@frappe/cloud-sdk 支持 ESM 还是 CommonJS?

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

@frappe/cloud-sdk 可以商用吗?

@frappe/cloud-sdk 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@frappe/cloud-sdk 的下载量有多少?

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

@frappe/cloud-sdk 还在维护吗?

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