@burdenoff/fluidgrids-fe-sdk
Operations with several credential adapters render a separate connection picker for each
adapter role. Selecting, replacing, creating, or removing one role's connection preserves
the other roles in args.connections, including when two roles share a provider or account.
Consumers opting into multiple can select several accounts per role without discarding
the other accounts; the builder's default remains one account per role.
Provider matching uses the declared provider key (or legacy adapter identity), not substring
or category matches. The builder does not assume every declared adapter is mandatory:
some operations declare alternative backends. Authentication and connection creation remain
in the shared @burdenoff/fe-libs/connections dialog for every supported method.
An explicitly selected operation is authoritative on every node card and in saved workflow state. Legacy graph-position defaults only initialize nodes without an operation; moving or connecting a configured node does not change its operation. Specialized property panels declare which operations they support; other operations use their manifest-driven form.
FluidGrids Workflow Builder SDK - Embeddable visual workflow automation for React applications.
Loop Compatibility
Loop Reset accepts a boolean or boolean expression. New nodes installed from the
updated registry persist batchSize: 1 and reset: false; saved explicit values
and legacy definitions omitting batch size keep their existing behavior (10).
The shared parameter editors distinguish missing return paths from possible
conditional exits without rejecting intentional exits. Reset clears the current
batch/results but not its safety budget. Existing output envelopes are unchanged.
BOFF-7415's cycle-authoring/continuation fix is required for general loop bodies;
these Reset controls do not replace that fix. Item-level lineage is not provided.
Installation
npm install @burdenoff/fluidgrids-fe-sdk
# or
bun add @burdenoff/fluidgrids-fe-sdk
Quick Start
Standalone Workflow Builder
Use WorkflowBuilder when you want a self-contained workflow builder with its own Apollo client:
import { WorkflowBuilder } from '@burdenoff/fluidgrids-fe-sdk';
import '@burdenoff/fluidgrids-fe-sdk/styles.css';
function App() {
return (
<WorkflowBuilder
apiGatewayUrl={process.env.NEXT_PUBLIC_FLUIDGRIDS_API_URL!}
authToken="your-auth-token"
workspaceId="your-workspace-id"
onSave={(workflow) => {
console.log('Workflow saved:', workflow);
}}
onExecute={(runId) => {
console.log('Execution started:', runId);
}}
/>
);
}
Full Workflow Module with Routing
Use FluidGridsRoot for complete workflow management including list, builder, runs, and credentials:
import { FluidGridsRoot } from '@burdenoff/fluidgrids-fe-sdk';
import '@burdenoff/fluidgrids-fe-sdk/styles.css';
import { useNavigate } from 'react-router-dom';
function App() {
const navigate = useNavigate();
return (
<FluidGridsRoot
basePath="/workflows"
apiGatewayUrl={process.env.NEXT_PUBLIC_FLUIDGRIDS_API_URL!}
authToken="your-auth-token"
workspaceId="your-workspace-id"
navigate={(path) => navigate(path)}
onWorkflowSave={(workflow) => {
console.log('Workflow saved:', workflow);
}}
/>
);
}
Core Builder (BYO Apollo Client)
Use WorkflowBuilderCore when you want to provide your own Apollo client:
import { WorkflowBuilderCore, FluidGridsProvider } from '@burdenoff/fluidgrids-fe-sdk';
import { ApolloProvider } from '@apollo/client';
import { yourApolloClient } from './apollo';
function App() {
return (
<FluidGridsProvider
apiGatewayUrl={process.env.NEXT_PUBLIC_FLUIDGRIDS_API_URL!}
authToken="your-auth-token"
workspaceId="your-workspace-id"
trustedOrigins={[window.location.origin]}
apolloClient={yourApolloClient}
>
<WorkflowBuilderCore
workflow={yourWorkflowData}
onSave={(workflow) => console.log('Saved:', workflow)}
/>
</FluidGridsProvider>
);
}
Mapping Input Data
The node detail view and quick-config mapper use the selected upstream node's
output from the loaded run, falling back to its declared output schema when no
output is available. Store/GraphQL operation-name wrappers remain part of mapping
paths; internal:* output stays flat. Switching sources also switches the data
used by the mapper. The node detail view keeps the target's post-mapping values
under Executed parameters (read-only); those values are not upstream paths.
Declared fields with oneOf or anyOf show each supported shape as an expandable
branch, including nested objects and array items. Shape labels are display-only:
dragging a child retains its actual operation-wrapped path, with no variant label
inserted into the expression. Once a run supplies output, the tree reflects that
actual value instead. This is schema visualization, not JSON Schema validation;
catalog field updates still require publication and a fresh node installation.
Optional Boolean Inputs
Both property panels provide Not set beside optional boolean checkboxes.
Choosing it removes that field from the node's fixed state; the operation's
existing omitted-input behavior then applies. Checking or unchecking still
stores explicit true or false. Rendering, opening and saving do not reset
existing values or defaults automatically. As with other fixed edits, unsetting
also clears that field's stale incoming mappings, without changing other fields'
mappings. Required booleans, expression controls and dynamic option controls
retain their existing behavior. Keyboard focus stays on the action after unset.
API Reference
WorkflowBuilder Props
| Prop | Type | Required | Description |
|---|---|---|---|
apiGatewayUrl | string | Yes | Workspace API Gateway URL |
authToken | string | No | Authentication token |
workspaceId | string | Yes | Current workspace ID |
tenantId | string | No | Current tenant ID |
workflowId | string | No | Workflow ID to load |
workflowVersion | string | No | Workflow version to load |
initialWorkflow | WorkflowData | No | Initial workflow data |
readonly | boolean | No | Disable editing |
hideHeader | boolean | No | Hide the header toolbar |
hideSidebar | boolean | No | Hide the sidebar |
hideLogsPanel | boolean | No | Hide the logs panel |
onSave | (workflow) => void | No | Save callback |
onExecute | (runId) => void | No | Execute callback |
onNodeClick | (node) => void | No | Node click callback |
onBack | () => void | No | Back button callback |
className | string | No | Custom CSS class |
FluidGridsRoot Props
| Prop | Type | Required | Description |
|---|---|---|---|
basePath | string | No | Base path for routing |
apiGatewayUrl | string | Yes | Workspace API Gateway URL |
authToken | string | No | Authentication token |
workspaceId | string | Yes | Current workspace ID |
tenantId | string | No | Current tenant ID |
currentUser | User | No | Current user info |
navigate | (path) => void | No | Navigation function |
readonly | boolean | No | Global readonly mode |
onWorkflowSave | (workflow) => void | No | Save callback |
onWorkflowExecute | (runId, workflowId) => void | No | Execute callback |
className | string | No | Custom CSS class |
JSON edge mappings
Incoming edge mappings support JSON values, including nested arrays/objects and
literal false, 0, and null. Both quick-config and Node Detail View preserve
these types and nested expressions. String mappings retain the expression editor.
For a JSON mapping, select Apply mapping before saving the workflow; Reset
discards the draft. Invalid or unapplied drafts do not replace the saved mapping.
Switching to fixed mode removes that field's mapping from all incoming edges.
Assistant page controls (optional)
Hosts that run an AI assistant can let people say "show failed runs" or "search workflows for invoices" and have the page do exactly what a click on its own control does. The SDK does not import any fe-libs assistant code (no new fe-libs version floor): the host mounts a small bridge and maps the page's description onto its own assistant.
import { FluidGridsAssistantBridge, type FgPageControlsSpec } from "@burdenoff/fluidgrids-fe-sdk/assistant";
// Stable identity (module constant or useCallback). Map the spec onto your
// assistant; return the function that removes exactly this registration.
const register = (spec: FgPageControlsSpec) => registerWithMyAssistant(spec);
<FluidGridsAssistantBridge register={register}>
<FluidGridsRoot ... />
</FluidGridsAssistantBridge>
- Import from the
/assistantsubpath: it is a tiny entry, so a host's main bundle does not pull the whole SDK in for a context provider. The pages share its chunk (one bridge per app). - With no
FluidGridsAssistantBridgeabove, nothing happens and the pages work as before. - Pages that describe their controls: Workflows list (search, Status when more than one status exists, Tag), Executions (search, Status, Workflow), Templates (From Store / My Templates tabs, search, Category on My Templates), History (search, Workflow). A page registers only what it shows right now and unregisters when it unmounts.
- A spec only holds tabs, single-choice filters and a search setter, and each setter is the page's own state setter. There is no create, save, delete, run, retry, duplicate or approve in a spec.
FgEnumFilterSpec/FgTabsSpecare structurally the fe-libsEnumFilterSpec/TabsSpec(fe-libs >= 2026.1004.6appControls), so a host can pass them straight toenumFilter/tabsOf.
Read-only workflow preview (optional)
WorkflowPreviewCanvas draws a stored workflow definition with the builder's own
node cards, read-only, and animates it as a workflow is built live (the AI
assistant's live preview). It needs no FluidGridsProvider, config, Apollo client
or node registry, and makes no request of its own.
import { WorkflowPreviewCanvas, previewCanvasFromDefinition, previewRevealOrder } from "@burdenoff/fluidgrids-fe-sdk/workflow-preview";
<div style={{ height: 520 }}>
<WorkflowPreviewCanvas
definition={workflow.definitionJson} // object or JSON string
visibleNodeIds={shown} // omit to show every node
freshNodeIds={justAdded} // highlighted with a ring
running={assistantIsWriting} // flow along edges, newest node pulses
/>
</div>
- The host drives the reveal:
previewRevealOrder(previewCanvasFromDefinition(def).nodes)gives the along-the-flow order. A node that becomes visible pops in, an edge draws in once both ends are visible, and the camera eases to keep every visible node in view (max zoom 1.5). resolveNodeMeta(nodeType)(optional, keep it stable) supplies registry names and icons; without it a card uses the node's saved manifest, then a name and icon derived from its type.- Edges follow the builder's rule: an edge whose source or target handle the builder's card for that node does not have (read from the node's stored data, as the builder reads it) is not drawn, so the preview never shows a connection the builder drops.
- Nodes cannot be dragged, connected, selected or deleted; pan and zoom work.
prefers-reduced-motion: reduceturns every animation off.
Styling
The SDK uses Tailwind CSS for styling. Make sure you have Tailwind configured in your project, or import the pre-built styles:
import '@burdenoff/fluidgrids-fe-sdk/styles.css';
Embedding: theme, token refresh and events (BOFF-9961)
FluidGridsProvider, FluidGridsRoot and WorkflowBuilder take three
embedding props (also settable with setFluidGridsConfig):
<FluidGridsProvider
workspaceId={workspaceId}
apiGatewayUrl={workspaceGraphqlUrl}
authToken={token}
theme={{ mode: 'light', colors: { primary: '#2563eb' }, radius: { base: '10px' } }}
auth={{ onTokenExpired: () => session.refresh() }}
onEvent={(name, payload) => {
if (name === 'run:completed') console.log(payload.runId, payload.status);
}}
>
{children}
</FluidGridsProvider>
theme—"light","dark"or{ mode?, colors?, radius?, font? }. Each token maps to fe-libs semantic CSS variables (FLUIDGRIDS_THEME_TOKEN_MAP); values are validated (themeToCssVariables) and applied document-wide as inline properties on<html>, restored on unmount (applyFluidGridsTheme,useFluidGridsTheme). The public embed viewer also readsaccent,radiusandfontquery parameters next totheme; its singleradiussetsradius.base,radius.card,radius.buttonandradius.input(builder node cards follow--radius-card).auth.onTokenExpired— called once per expired-session failure (401,UNAUTHENTICATED, expired/revoked credential); concurrent failures share one call; the request is retried once with the new token; on rejection the SDK emitsauth:failedand surfaces the original error. A failed refresh is reported once: requests already in flight with the expired token fail with their own error without a second call or event; a request sent after the failure may refresh again. Host-injected Apollo clients addcreateFluidGridsTokenRefreshLink()before their auth link.onEvent— typedFluidGridsEventMap:workflow:saved,workflow:activated,run:started,run:completed,node:selected,error,auth:failed. Contract versionFLUIDGRIDS_EVENTS_VERSION(semver: additive = minor, payload break = major). The standaloneWorkflowBuilder/WorkflowBuilderCorecanvas saves and runs locally (onSave/onExecute), so it emits onlynode:selected.FluidGridsRoot,WorkflowBuilderandWorkflowBuilderCorework without a hostThemeProvider; they reuse the host's when there is one.
Full guide: docs.fluidgrids.ai/developers/embedding.
Branding
Every workflow canvas the SDK renders — WorkflowBuilder, WorkflowBuilderCore,
the FluidGridsRoot builder and template-preview routes, and the public
WorkflowEmbedPage viewer — shows a small Powered by FluidGrids mark in its
top-right corner, linking to fluidgrids.ai. The
chrome props above (hideHeader, hideSidebar, hideLogsPanel, readonly)
hide toolbars and panels only.
FluidGrids is not offered as a white-label product: no prop, context, theme
option or URL parameter hides or replaces the mark. The embed viewer's old
badge=false parameter is ignored. Translations may reword the "Powered by"
phrase, but the FluidGrids name always stays.
Structured Node Parameters
The quick-config and full node editors use the selected operation's input_fields
schema for array and object values. Enter arrays and objects as JSON; string arrays
also accept comma-separated values. Blank inputs clear the field, while [] and
{} remain explicit empty values. Declared item/property types are validated.
Invalid drafts on enabled nodes stay visible for correction and cannot be saved or
executed. Disabled nodes retain their drafts when saved; re-enabling restores
validation. Saving
also normalizes legacy JSON strings from adaptive-card forms using the same schema.
Expression mappings remain separate from fixed values: switch the field to
Expression mode for whole-value templates such as {{ $vars.LIST }} or
${output.items}. Fixed JSON string items remain literal; the store-node runtime
does not generally evaluate templates in fixed args.state values.
Save the workflow before
execution to run the updated configuration; this does not change the existing
saved-version execution behavior or the operation-name output wrapper.
Absent fields remain unset so the engine can supply upstream inputs or defaults.
Security Notes
- Codegen's transitive
@graphql-tools/utilsis pinned to12.0.3for GHSA-7mx3-vvmw-hjmv;source-map-jsis pinned to1.2.2for GHSA-68fv-2mgg-jv7q. The utils override crosses older plugin ranges because even the current Apollo hook plugin retains an affected helper dependency. Keep the existing codegen contract tests and compare all four generated files when changing this pin; its GraphQL 17 execution-helper changes are not used by this repository's GraphQL 16 codegen path. Validate with a clean frozen-lockfile install: an incremental Bun install can leave old nested copies innode_modulesafter an override changes resolution. - Pass runtime URLs through environment variables instead of hardcoded localhost defaults.
- Use
trustedOriginswhen embedding the SDK into known host applications. - Avoid logging or persisting
authTokenvalues in app telemetry or error reports.
Loop Wiring
Connect a Loop's Loop Body output to the body nodes, then connect the last body node back to the Loop input. Connect Done to the following step. Canvas drag and click-to-connect accept this controlled cycle regardless of which edge is drawn last; ordinary cycles and cycles through Done remain rejected. SDK imperative connections, import and copy/paste preserve the same graph.
Return to the Loop input, not to an upstream trigger or ancestor. The validator uses workflow entry and Done paths to distinguish a controller's body, and rejects outside connections that would bypass an already-wired controller.
Loop Body classification follows the configured loopHandle in execution precedence: data, config, data.args.state, then args.state. Custom and swapped handle names retain controlled return validation and the guard against disabling an active controller, including saved/imported graphs. The default remains loop; configure matching output metadata and edge handles. This does not add new validation to arbitrary imported graphs or change runtime execution.
A controller cannot be disabled while it controls a loop cycle: disconnect the cycle first. The shared toggle action returns false without changing the graph or undo history, and the node toolbar explains why. Body-node toggles and undo for permitted changes remain available. This does not repair already-invalid imported graphs.
Body nodes may replace their output when the companion BOFF-7415 worker change is deployed: continuation is transported in execution context, not business fields. A workflow without a return edge does not request another batch. Reset/default parity and multiple-incoming-edge mapping are tracked separately in BOFF-9042 and BOFF-9041.
Development
bun run sanity: codegen, lint, format, type-check, the bun unit suite, the library build, the npm tarball check (scripts/verify-package-contents.sh) and the Storybook build.bun run storybook/bun run build-storybook: stories for the builder canvas, the node card, the workflow list card and the run list (src/stories/, fixture data, no backend). Stories are never packed.bun run test:e2e: read-only Playwright specs for the list, builder and runs pages through the fluidgrids-app shell, against alpha (Cloudflare Access) or prod. Seee2e/README.md.bun run schema:pullrefreshesgraphql/{wspace,global}.graphqlfrom the GraphQL Hive CDN;bun run schema:checkis the no-write drift check. Gateways are never introspected (seedocs/owned-codegen.md).
License
Proprietary - Copyright Algoshred Technologies Pvt Ltd.
Apollo 4 declaration migration (BOFF-9420)
The BOFF-9420 migration preserves the named operation/hook surface and fixes the packed public declarations using supported typed documents and owning Apollo 4 facades. Required query variables, skipped suspense results, lazy execution options and configured mutation variables now follow the actual Apollo 4 contract and require Apollo Client 4.2.0 or newer within major 4. This is an explicit type migration, not a transparent compatibility claim for invalid earlier signatures; existing published versions are unchanged.
See the migration contract for the correction table and verification limits. Package availability depends on its released version and verified release evidence. Host adoption and live workflow acceptance require separate verification.