@inploi/forms

中文文档
1.7.9发布于 2026/11/01TypeScriptESM + CJS

Visual form renderer for inploi application flows.

原始使用文档
文档目录5 节
  1. Architecture
  2. Public API
  3. Placement
  4. Submit
  5. Runtime Behaviour

@inploi/forms

Visual form renderer for inploi application flows. It takes the same flow JSON that @inploi/plugin-chatbot renders sequentially and presents it as a classic, scrollable form. Forms can be rendered inline with the page or opened in a drawer, and are themed through the standard appearance options.

Deprecated (October 2026): use the Candidate widget's form mode. @inploi/forms is superseded and will receive no new features. Form-style applications are now delivered through the unified candidate widget (@inploi/plugin-candidate, Apply layout form), where conversational stays the default. For a new integration, use that.

The package stays in this repository and on npm as a design reference, and its CDN files stay up. It is still wired into Studio's SDK Form block and Form button action, which a few demo pages use, so it is not safe to remove yet. It has never been sold, and no customer domain was seen loading it in the Worker logs for the week to 28 Oct 2026 (the logs only reach back about 7 days).

Recent changes here (raw-error copy in PROD-7504, and shared-engine alignment in PROD-7448) came along with work on the shared flows engine and the widget. They aren't evidence of customer impact. Nothing else is fixed in place here: improvements go into the widget's form mode. The risk of its frame running on sdk.inploi.com is accepted while it stays up, and is revisited if a non-internal tenant starts submitting through it (PROD-7342 ADR, "Forms decision").

Architecture

  • Host plugin (forms.ts) creates and supervises an iframe, manages drawer open/close, scroll lock, theme propagation, submit transport and Talent Bank duplicate checks. It follows the same iframe scaffolding pattern as @inploi/plugin-kin.
  • Frame runtime (forms.runtime.tsx) is a Preact app rendered inside the iframe. It owns form state, validation, draft persistence, user interactions and the host RPC (submit, duplicate-check and address lookup requestId correlation, inlined — no separate bridge module).
  • Flow projection (form.projector.ts) walks the raw flow graph and produces renderable items plus a terminal state. It evaluates if-block, follows jump, applies add-submission, collects submit chains, exposes ready check-duplicate candidates, and gathers post-submit text/image/link content.
  • Shared logic is consumed from @inploi/flows for validation-adjacent flow helpers, conditions, interpolation, submit-response shapes, session keys and duplicate-check request building.

Forms is intentionally a projection-first renderer with a small forms executor, not a copy of the chatbot service interpreter.

  • Component library (src/library.ts): the unified candidate widget's form mode (PROD-7448) reuses Forms' Calendar, Combobox and floating primitives. It bundles them from source, so they share its Preact, and styles them through their markup (roles, aria state, data-active). The candidate widget draws its form from the conversation's engine (@inploi/flows/form), not from form.projector.ts. library.ts is workspace-internal and is not a published export. Forms also bundles identical icons from Candidate’s isolated kit through a workspace-only source alias.

Public API

import { formsPlugin } from '@inploi/forms';

const forms = formsPlugin({ appearance: { placement: 'drawer' } });
await forms.open({ flow, title: 'Apply now', context: { jobId: '...' } });

Placement

formsPlugin({
    appearance: { placement: 'embedded' },
    container: '#application-form',
});

drawer is the default placement. embedded mounts the iframe into the provided container and resizes it to fit the form content.

Submit

By default, the host plugin submits to /flow/submit using the SDK apiClient. Consumers can override this with onSubmit:

const forms = formsPlugin({
    onSubmit: async payload => {
        await submitApplication(payload);
        return { success: true };
    },
});

FormsSubmitPayload contains only the public submit data: integrationId, optional job, and filtered submissions.

See forms.protocol.ts for the full set of types (OpenFormsParams, FormsAppearance, FormsSubmitPayload, ...).

Runtime Behaviour

  • Drafts are persisted by flow identity, flow keys and context hash. Closing, minimising, failed submit and successful submit preserve the draft. The header reset action is the explicit way to start over.
  • A candidate who opens a form with a saved draft that has an answer and was never submitted (the first time it is opened since the frame loaded) sees a banner above the form: "You have an unfinished application for this role. Continue where you left off?", with Continue (keep the answers) and Start again (clear the draft, as the header reset does). It sits in a live region that is always on the page, so its arrival is announced. A drawer moves focus to Continue; an embedded form never takes focus from the host page. Answering a question also dismisses it. A successful submit writes a submitted:<state key> marker to the same store, and the header reset or Start again removes it, so a submitted application is never offered for resuming (PROD-7338). Drafts live in this browser's IndexedDB only: another device or browser, a private window, cleared site data or Safari's seven-day storage expiry starts afresh.
  • Submit is disabled while required fields are missing, values are invalid, a duplicate check is pending, a submit is already in progress, or a submit cooldown is running.
  • Sequential integration-application-submit nodes are executed as a chain — FormApp awaits each step in order and short-circuits on the first failure or redirect. Redirect responses show the provider message and replace the footer submit button with a redirect CTA that opens the ATS in a new tab. There is no persistent submit cursor: before a successful submit, any field edit resets submit state, and the next click reruns the whole chain from step 0 (relies on integration idempotency).
  • A submit the API settles as a duplicate application, a closed role or an unknown verdict (the structured error.data from /flow/submit) shows our own informational message instead of the provider's text and the error tone. Submit stays available after these; only a success removes it. A duplicate within an hour of this candidate's own failed attempt on the same application most likely is that attempt landing, so it shows submission_duplicate_earlier_attempt and FLOW_SUBMIT records outcome: 'duplicate_after_own_attempt'. The host keeps that attempt history for the page's life, not across reloads.
  • Recovery after other failures follows the API's error.data (PROD-6846), decoded host-side with the chatbot's shared helpers from @inploi/flows/utils. A failure before the provider's submit step that the API marks retryable with verdict not_submitted shows submission_retryable. A failure marked retryable: false keeps the API's message and holds submit until the candidate changes an answer. An unreadable document (code: 'unreadable_document' with a field) clears that file answer, puts submission_unreadable_document on the file input and starts no wait. A thrown submit with no outcome to read (lost connection, gateway timeout, unreadable body, 5xx without an integration response) is an unconfirmed receipt and shows submission_unknown.
  • A failure the API labels reason: provider_maintenance (a provider's scheduled maintenance window, api#1713, PROD-7336) shows submission_provider_maintenance with the window's end (maintenance_until) in the candidate's local time, or submission_provider_maintenance_later when there is no usable end. Submit waits until that end (at most six hours), shown as "Submit will be available again at {time}." An unknown verdict inside the window may have reached the provider, so it keeps submission_unknown, though it still waits for the window to end.
  • Every other unsuccessful submit starts a cooldown with a countdown: consecutive throttles and temporary outages wait 20 s, 40 s, then 60 s (or the provider's longer Retry-After, capped at 120 s); anything else waits 30 s. The cooldown survives answer changes and the header reset, and is cleared when a different flow or job opens.
  • These fields are optional on forms:submit-result, so a CDN frame behind an older host behaves as before, and an older frame ignores them.
  • A submit the API accepts for later delivery (HTTP 202 with integration_response.data.outcome: 'pending') is a success: it shows the API's data.message, or submission_pending when there is none, in place of the flow's success message, and FLOW_SUBMIT records outcome: 'pending'. In a submit chain it continues to the next step like any success, and the latest pending message is kept when a later step plainly succeeds.
  • Post-submit text, image and link nodes are rendered after a successful final submit.
  • A successful final submit locks the inputs: they are wrapped in a disabled <fieldset>, so every control becomes non-editable and visibly muted, while labels, descriptions, informational nodes and links stay fully legible and clickable. The footer CTA and post-submit content remain interactive; the header reset clears the lock (and the draft).
  • end-flow before submit is treated as a terminal dead-end and hides the submit button.
  • check-duplicate runs through the host-side Talent Bank client and writes the result back as an integration submission for downstream conditions.
  • question-address supports manual entry plus host-side Mapbox suggestions. The regular address fields stay visible; selecting a suggestion fills them and users can still edit manually. When the question is required, every mapped part is required except line 2, which is required only when the node carries line2Required: true (the api sets it for ATSs that refuse a blank line 2); a required part holding only spaces counts as missing.
  • integration-workflow-get is expected to be materialized by the backend before runtime; if it reaches forms, the form fails closed instead of skipping integration-specific fields.

版本与发布记录

@inploi/forms 共发布 33 个版本,首次发布于 2026/05/18;过去 12 个月发布了 33 个版本。

版本发布日期距今
1.7.9latest2026/11/012 天前
1.7.82026/10/313 天前
1.7.72026/10/295 天前
1.7.62026/10/286 天前
1.7.52026/10/267 天前
1.7.42026/10/2113 天前

关于 @inploi/forms 的常见问题

@inploi/forms 是什么?

用于inploi应用程序流的可视化表单渲染器。

如何安装 @inploi/forms?

在项目目录运行 npm install @inploi/forms,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@inploi/sdk(>=2.1.5)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@inploi/forms 支持 TypeScript 吗?

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

@inploi/forms 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@inploi/forms 可以商用吗?

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

@inploi/forms 还在维护吗?

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