@crvouga/mockingbird-service-formbricks

中文文档
3.11.0发布于 2026/11/11MITTypeScriptES Module构建来源已验证近 30 天下载 1.6万

Stateful emulator of open-source Formbricks: the client environment state (seeded with a synthetic survey corpus), response creation with upstream's validation and {code, message, details} errors, the v1 management API, the widget script, and signed respo

原始使用文档
文档目录8 节
  1. Install
  2. Usage
  3. Routes
  4. Webhooks
  5. Admin (beyond the standard contract)
  6. Namespaces
  7. Deliberately not modelled
  8. API

@crvouga/mockingbird-service-formbricks

Local emulators. Real API contracts. Part of Mockingbird.

Stateful emulator of open-source Formbricks (6.x) for test suites: the client environment state the JS SDK loads surveys from, response creation with upstream's validation and {code, message, details} errors, the v1 management API (responses and surveys, x-api-key), the widget script the web SDK loads, and the response pipeline's responseCreated / responseFinished webhooks. Every namespace is seeded with a small synthetic survey corpus (src/corpus/surveys.json: NPS, Onboarding, Product Feedback, a link survey and a paused survey; invented content).

  • Operation coverage: SUPPORT.md
  • The contract (openapi.yaml) is hand-authored from upstream Formbricks 6.0.0's route handlers and the docs.

Install

npm install -D @crvouga/mockingbird-service-formbricks

ESM only. Node >= 22 or Bun >= 1.2. No native dependencies. Serve it with npx mockingbird-formbricks serve, createServer from ./server (Node), or createRuntime with any Fetch server.

Usage

Point the SDK's appUrl (and your management API base URL) at the emulator, use the workspace id cworkspace000000000000001 (or its legacy environment id cenvironment0000000000001, as older SDKs send), and any management API key.

npx mockingbird-formbricks serve --port 8813 \
  --webhook-url http://127.0.0.1:3000/webhooks/formbricks \
  --webhook-secret "whsec_…"

Boot it with your own settings and surveys, without a wrapper process or a PUT after boot:

npx mockingbird-formbricks serve \
  --settings '{"workspaces": ["cworkspace000000000000002"], "legacyEnvironmentIds": {"cenvironment0000000000002": "cworkspace000000000000002"}}' \
  --surveys ./surveys.json

--settings <json|file> (or MOCKINGBIRD_SETTINGS, or a fleet entry's settings) takes the fields of GET|PUT /__admin/settings, checked with their types (a misspelled key is an error). They are every namespace's defaults, a reset returns to them, and a field you give replaces the built-in value whole (give legacyEnvironmentIds and the default environment alias is gone). --workspace-id adds to the booted workspaces. --surveys <file> (a list, or {surveys: [...]}) adds your surveys after the corpus ones for every namespace, and they survive a reset. A survey whose id the corpus (or an earlier row) already has is skipped, a survey with no workspaceId is served by every configured workspace, and type, status and a legacy environmentId are handled as PUT /__admin/surveys handles them. --surveys-mode replace uses the file as the whole corpus. In a fleet, set options: {"surveys": "surveys.json"}.

import { WORKSPACE_ID } from "@crvouga/mockingbird-service-formbricks"
import { createServer } from "@crvouga/mockingbird-service-formbricks/server"

// Test setup: the emulator, posting response webhooks to the app's handler.
const server = await createServer({
  webhooks: { url: "http://127.0.0.1:3000/webhooks/formbricks", secret: "whsec_…" },
})

// Application code: appUrl is server.url. Submit a response to the seeded NPS survey.
const appUrl = server.url
const created = await fetch(`${appUrl}/api/v2/client/${WORKSPACE_ID}/responses`, {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    surveyId: "csurveynps000000000000001",
    finished: true,
    data: { nps_score: 9 },
  }),
})
// → {data: {id, quotaFull: false}}. The emulator validates it, stores it, and posts
// responseFinished to the webhook.

// Test control: read what was stored.
const stored = await fetch(`${appUrl}/__admin/responses`)
await server.close()

Routes

Client routes take a workspace id or a legacy (pre-Formbricks-5) environment id in the path; both resolve to the same workspace.

RouteBehaviour
GET /api/v1/client/{workspace}/environment{data: {data: {surveys, actionClasses, workspace, project}, expiresAt}} (project is upstream's legacy alias of workspace). Only app surveys inProgress, with the SDK's survey fields and projectOverwrites mirroring workspaceOverwrites. A malformed id is 400 Invalid ID format; an unknown one 404 Workspace not found.
POST /api/v2/client/{workspace}/responses{surveyId, finished, data, contactId?, meta?, …} → {data: {id, quotaFull: false}}. An unknown workspace is 404; input errors are 400 Fields are missing or incorrectly formatted with zod 4 details ({surveyId: "Invalid cuid2", finished: "Invalid input: expected boolean, received undefined"}; userId is not part of the v2 input and is ignored); a contactId while contacts are off is 403 (Enterprise); an unknown survey 404; a survey of another workspace 400 Survey is part of another workspace; a survey not inProgress 403 Survey is not accepting submissions. data keeps only element ids and declared hidden fields (hiddenFields.fieldIds); other keys are dropped. Before element validation, a multipleChoiceSingle or multipleChoiceMulti value (a string, or any string in an array) that equals no choice label in the response language — the body's language, or the label's default when it is omitted; getLocalizedValue does not fall back — and is longer than 250 characters is 400 Response exceeds character limit with details: {questionId}, and nothing is stored. An exact label match is not length-checked; an unmatched entry of 250 characters or fewer passes this check. Element validation defaults to the elements present in data (finished or not). validation: "finished-validates-all" (pre-#7292 Formbricks) checks every element when finished is true and only the present ones when it is false; a failure is 400 and stores nothing. Either way: required → Please fill out this field; a choice outside a choice element's options (when it has no "other") → Please enter a valid format; openText email / url / phone → Please enter a valid …; 400 Validation failed with details: {"response.data.<elementId>": "<messages joined by '; '>"}. meta keeps source, url, action and the auto-captured page / UTM / screen keys, plus userAgent and country (from CF-IPCountry). language is canonicalized (en → en-US); a finished response's ttc gains _total.
GET /api/v1/management/responses?surveyId=&limit=&skip={data: [response]}, newest first; an unknown surveyId is 404.
GET /api/v1/management/responses/{id}{data: response} or 404.
GET /api/v1/management/surveys?limit=&offset={data: [survey]}, most recently updated first.
POST /api/v1/management/surveys{workspaceId (or legacy environmentId), name, type?, status?, blocks | questions} → {data: survey}. Legacy questions become one block each; both or neither is 400; a missing workspace id is 400 workspaceId must be provided, an unknown one 404.
GET /api/v1/management/surveys/{id}{data: survey} or 404.
GET /js/formbricks.umd.cjsA no-op script defining window.formbricks (every SDK method resolves).

Management surveys carry questions derived from blocks (block button labels on the block's last element), workspaceId, the legacy environmentId, and projectOverwrites. Management routes need x-api-key (any non-empty key, unless apiKeys is set), else 401 {code: "not_authenticated", message: "Not authenticated", details: {"x-Api-Key": "…"}}.

Webhooks

POST <webhook-url> with {webhookId, event, data: {...response, survey: {title, type, status, createdAt, updatedAt}}}, headers webhook-id, webhook-timestamp and, when the endpoint has a whsec_… secret, webhook-signature: v1,<base64 HMAC-SHA256> (Standard Webhooks). Only events an endpoint subscribes to are sent: responseFinished by default (events: ["responseCreated", "responseFinished"] for both). --webhook-token appends a ?token= for receivers that check one. Retries, GET /__admin/webhooks, …/events, …/replay, …/flush and PUT /__admin/webhook-endpoints work as usual.

Admin (beyond the standard contract)

RouteEffect
GET /__admin/responses?surveyId=Stored responses, oldest first.
GET|PUT /__admin/surveysRead, or add / replace surveys ([{id, name, type?, status?, workspaceId?, blocks?, questions?, …}]; no workspaceId = served by every configured workspace).
GET|PUT /__admin/contactsRead, or add contacts ([{id, userId?, attributes?, workspaceId?}]) for contactId responses.
GET|PUT /__admin/settings{workspaces?, legacyEnvironmentIds?, apiKeys?, webhookId?, contactsEnabled?, validation?}. validation is present-only (default, Formbricks after #7292) or finished-validates-all (before #7292: a finished response validates every element). createRuntime({settings}) accepts the same fields.

Fault presets (POST /__admin/faults {"preset": "<name>", "count"?: n}; GET /__admin/faults/presets): rate_limited (429 too_many_requests), server_error (500), missing_response_id (stored, but no id in the answer), environment_unavailable, data_as_string (management data as a JSON string), management_unauthorized, connection_drop, duplicate (the next webhook twice), webhook_drop, webhook_reorder.

Namespaces

x-mockingbird-namespace, a /__admin/ns/<name> prefix on the app URL, or by credential: the workspace (or legacy environment) id in the client paths (the SDK cannot add headers) or the management x-api-key, through PUT /__admin/credentials {"credentials": {"<workspace id or key>": "<namespace>"}}.

Deliberately not modelled

  • Displays, contacts / identify, user and storage routes of the client API (the widget script is a no-op, so the SDK never calls them); response updates (PUT …/responses/{id}).
  • Quotas (always quotaFull: false), single-use links, PIN protection, reCAPTCHA, email verification, file-upload checks, custom validation.rules, survey logic, and the full survey schema on create (only the shapes above are checked).
  • The Embedded Data ingest contract beyond its allow-list (locked fields, coercion, size limits), userAgent parsing (always {device: "desktop"}), and language canonicalization beyond common bare codes.
  • Organizations, API-key permissions (unauthorized), and the rest of the management API; the Formbricks UI.

API

ExportKindDescription
FormbricksAPIclassThe in-process emulator: fetch(request), reset(), responses(), render(record), wireSurvey(survey), pipeline(event, record, survey), state. Options: sqlite, now, namespace, surveys, settings, onWebhook.
createRuntimefunctionThe emulator with the full service contract (health, admin, namespaces, credentials, presets, webhooks). Options: webhooks: {url, secret?, events?, retryDelaysMs?, fetch?}, surveys (replaces the corpus; serve --surveys appends), settings, clock, seed, adminKey, onLog, sqlite.
FORMBRICKS_PRESETSobjectEvery named fault preset.
FORMBRICKS_NAMESPACEstringThe service name, "formbricks".
WEBHOOK_PATHstringA conventional receiver path for examples, /webhooks/formbricks.
formbricksCredentialfunctionThe workspace id or API key a request carries.
formbricksErrorfunctionBuild Formbricks' {code, message, details} error response.
validateResponseDatafunctionUpstream's element validation: (survey, data, language?, {validation?, finished?}) → {elementId: messages} or null.
CORPUS_SURVEYSvalueThe synthetic survey corpus every namespace is seeded with.
WORKSPACE_ID, ENVIRONMENT_ID, DEFAULT_SETTINGSvaluesThe default workspace, its legacy environment id, and the default settings.
document, operationIds, supportedOperationIdsvaluesThe vendored OpenAPI contract and its operation ids.
createServer, serveTarget, DEFAULT_PORT (./server)NodeServe over node:http; the serve CLI target; port 8813.

Part of mockingbird.

版本与发布记录

@crvouga/mockingbird-service-formbricks 共发布 42 个版本,首次发布于 2026/09/23;过去 12 个月发布了 42 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
3.11.0latest2026/11/11今天
3.10.92026/11/038 天前
3.10.82026/11/038 天前
3.10.72026/11/038 天前
3.10.62026/11/038 天前
3.10.52026/11/038 天前

关于 @crvouga/mockingbird-service-formbricks 的常见问题

@crvouga/mockingbird-service-formbricks 是什么?

Stateful emulator of open-source Formbricks: the client environment state (seeded with a synthetic survey corpus), response creation with upstream's validation and {code, message, details} errors, the v1 management API, the widget script, and signed respo

如何安装 @crvouga/mockingbird-service-formbricks?

在项目目录运行 npm install @crvouga/mockingbird-service-formbricks,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 mockingbird-formbricks,可以用 npx mockingbird-formbricks 直接运行。

@crvouga/mockingbird-service-formbricks 支持 TypeScript 吗?

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

@crvouga/mockingbird-service-formbricks 支持 ESM 还是 CommonJS?

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

@crvouga/mockingbird-service-formbricks 可以商用吗?

@crvouga/mockingbird-service-formbricks 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@crvouga/mockingbird-service-formbricks 的下载量有多少?

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

@crvouga/mockingbird-service-formbricks 还在维护吗?

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