From fc01d9799312ff89db03df7bb522f89c8ae977c9 Mon Sep 17 00:00:00 2001 From: Piotr Blaszczyk Date: Tue, 21 Jul 2026 12:42:54 +0200 Subject: [PATCH 1/2] feat(sdk): reduce required peer dependencies --- .changeset/slim-peer-dependencies.md | 5 ++ README.md | 9 +-- apps/ai-studio/package.json | 2 - apps/demo/package.json | 3 - .../quick-start/wb-as-react-component.mdx | 13 ++- packages/sdk/README.md | 37 +++++---- packages/sdk/package.json | 18 ++--- packages/sdk/vite.config.mts | 25 +++--- pnpm-lock.yaml | 80 ++++++------------- 9 files changed, 78 insertions(+), 114 deletions(-) create mode 100644 .changeset/slim-peer-dependencies.md diff --git a/.changeset/slim-peer-dependencies.md b/.changeset/slim-peer-dependencies.md new file mode 100644 index 000000000..1832d723d --- /dev/null +++ b/.changeset/slim-peer-dependencies.md @@ -0,0 +1,5 @@ +--- +'@workflowbuilder/sdk': minor +--- + +Reduce the required peer dependencies from ten to four. `@jsonforms/core`, `@jsonforms/react`, `i18next`, `react-i18next`, `i18next-browser-languagedetector` and `immer` are now regular dependencies that install automatically, so the full install is `@workflowbuilder/sdk @xyflow/react zustand` on any package manager (`react`/`react-dom` stay peers but are already in any React app). diff --git a/README.md b/README.md index 3b8ad4e2e..c8aa662ff 100644 --- a/README.md +++ b/README.md @@ -49,14 +49,11 @@ Don't want to install or clone anything yet? [Try the live demo](https://app.wor Use Workflow Builder inside your own React app. No clone, no Docker. Install the SDK and its peer dependencies from npm: ```bash -npm install @workflowbuilder/sdk \ - react react-dom \ - @xyflow/react \ - @jsonforms/core @jsonforms/react \ - i18next react-i18next i18next-browser-languagedetector \ - immer zustand +npm install @workflowbuilder/sdk @xyflow/react zustand ``` +Requires React 18 or 19. + Render the editor: ```tsx diff --git a/apps/ai-studio/package.json b/apps/ai-studio/package.json index 243eec574..747ed5079 100644 --- a/apps/ai-studio/package.json +++ b/apps/ai-studio/package.json @@ -13,8 +13,6 @@ "test:watch": "vitest --passWithNoTests" }, "dependencies": { - "@jsonforms/core": "^3.4.1", - "@jsonforms/react": "^3.4.1", "@phosphor-icons/react": "^2.1.7", "@synergycodes/overflow-ui": "1.0.0-beta.27", "@workflow-builder/types": "workspace:*", diff --git a/apps/demo/package.json b/apps/demo/package.json index db77ad2cd..4869d045b 100644 --- a/apps/demo/package.json +++ b/apps/demo/package.json @@ -16,8 +16,6 @@ "test:watch": "vitest" }, "dependencies": { - "@jsonforms/core": "^3.4.1", - "@jsonforms/react": "^3.4.1", "@microsoft/clarity": "^1.0.0", "@phosphor-icons/react": "^2.1.7", "@synergycodes/overflow-ui": "1.0.0-beta.27", @@ -27,7 +25,6 @@ "elkjs": "^0.9.3", "html-to-image": "1.11.11", "i18next": "^24.2.3", - "i18next-browser-languagedetector": "^8.0.5", "immer": "^10.1.1", "jspdf": "^3.0.1", "libavoid-js": "0.4.0-beta.1", diff --git a/apps/docs/src/content/docs/get-started/quick-start/wb-as-react-component.mdx b/apps/docs/src/content/docs/get-started/quick-start/wb-as-react-component.mdx index cbdd336c7..6fe69ef3b 100644 --- a/apps/docs/src/content/docs/get-started/quick-start/wb-as-react-component.mdx +++ b/apps/docs/src/content/docs/get-started/quick-start/wb-as-react-component.mdx @@ -27,31 +27,28 @@ Install the SDK along with its peer dependencies: ```bash -npm install @workflowbuilder/sdk react react-dom @xyflow/react @jsonforms/core @jsonforms/react i18next react-i18next i18next-browser-languagedetector immer zustand +npm install @workflowbuilder/sdk @xyflow/react zustand ``` ```bash -pnpm add @workflowbuilder/sdk react react-dom @xyflow/react @jsonforms/core @jsonforms/react i18next react-i18next i18next-browser-languagedetector immer zustand +pnpm add @workflowbuilder/sdk @xyflow/react zustand ``` ```bash -yarn add @workflowbuilder/sdk react react-dom @xyflow/react @jsonforms/core @jsonforms/react i18next react-i18next i18next-browser-languagedetector immer zustand +yarn add @workflowbuilder/sdk @xyflow/react zustand ``` -The SDK ships its non-peer dependencies bundled inside `dist/`, so the -peer list above is everything you need to install yourself. React, -xyflow, JsonForms, i18next, immer and zustand are kept external because -they expose singletons (store identity, i18next instance, frozen-object -caches) — your app and the SDK must share a single copy of each. +Requires React 18 or 19. Everything else the SDK uses (JsonForms, +i18next, immer, …) is a regular dependency and installs automatically. ## Usage diff --git a/packages/sdk/README.md b/packages/sdk/README.md index 63246491e..63da8066b 100644 --- a/packages/sdk/README.md +++ b/packages/sdk/README.md @@ -27,15 +27,10 @@ Battle-tested in production by teams shipping AI workflow products. ## Install ```bash -npm install @workflowbuilder/sdk \ - react react-dom \ - @xyflow/react \ - @jsonforms/core @jsonforms/react \ - i18next react-i18next i18next-browser-languagedetector \ - immer zustand +npm install @workflowbuilder/sdk @xyflow/react zustand ``` -The SDK ships its non-peer dependencies bundled in `dist/`. React, xyflow, JsonForms, i18next, immer, and zustand are declared as `peerDependencies` so your app and the SDK share a single copy of each. See [Peer dependencies](#peer-dependencies) below. +Requires React 18 or 19. Everything else the SDK needs (JsonForms, i18next, immer, …) is a regular dependency and installs automatically. See [Peer dependencies](#peer-dependencies) below. ## Quick start @@ -271,18 +266,22 @@ Full API reference: - EXTERNAL_PEER_PACKAGES.some((peer) => id === peer || id.startsWith(`${peer}/`)); +const isExternalPackage = (id: string) => + EXTERNAL_PACKAGES.some((packageName) => id === packageName || id.startsWith(`${packageName}/`)); export default defineConfig(({ command }) => ({ plugins: [ @@ -59,10 +69,7 @@ export default defineConfig(({ command }) => ({ '@/assets': path.resolve(import.meta.dirname, 'src/assets'), '@': path.resolve(import.meta.dirname, 'src'), // overflow-ui doesn't export ./dist/index.css in its package.json exports field - 'overflow-ui-css': path.resolve( - import.meta.dirname, - 'node_modules/@synergycodes/overflow-ui/dist/index.css', - ), + 'overflow-ui-css': path.resolve(import.meta.dirname, 'node_modules/@synergycodes/overflow-ui/dist/index.css'), }, }, // Inline `process.env.NODE_ENV` at SDK build time. The SDK bundles deps @@ -87,7 +94,7 @@ export default defineConfig(({ command }) => ({ cssFileName: 'style', }, rollupOptions: { - external: isExternalPeer, + external: isExternalPackage, }, outDir: './dist', emptyOutDir: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f18eda6ba..0812c5f9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,12 +95,6 @@ importers: apps/ai-studio: dependencies: - '@jsonforms/core': - specifier: ^3.4.1 - version: 3.5.1 - '@jsonforms/react': - specifier: ^3.4.1 - version: 3.5.1(@jsonforms/core@3.5.1)(react@19.1.0) '@phosphor-icons/react': specifier: ^2.1.7 version: 2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -217,12 +211,6 @@ importers: apps/demo: dependencies: - '@jsonforms/core': - specifier: ^3.4.1 - version: 3.5.1 - '@jsonforms/react': - specifier: ^3.4.1 - version: 3.5.1(@jsonforms/core@3.5.1)(react@19.1.0) '@microsoft/clarity': specifier: ^1.0.0 version: 1.0.2 @@ -250,9 +238,6 @@ importers: i18next: specifier: ^24.2.3 version: 24.2.3(typescript@5.9.3) - i18next-browser-languagedetector: - specifier: ^8.0.5 - version: 8.0.5 immer: specifier: ^10.1.1 version: 10.1.1 @@ -459,6 +444,12 @@ importers: '@fontsource/poppins': specifier: ^5.2.7 version: 5.2.7 + '@jsonforms/core': + specifier: ^3.4.0 + version: 3.5.1 + '@jsonforms/react': + specifier: ^3.4.0 + version: 3.5.1(@jsonforms/core@3.5.1)(react@19.1.0) '@phosphor-icons/react': specifier: ^2.1.7 version: 2.1.7(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -480,6 +471,15 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 + i18next: + specifier: ^24.0.0 + version: 24.2.3(typescript@5.9.3) + i18next-browser-languagedetector: + specifier: ^8.0.0 + version: 8.0.5 + immer: + specifier: ^10.0.0 + version: 10.1.1 notistack: specifier: ^3.0.1 version: 3.0.2(csstype@3.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -492,6 +492,9 @@ importers: react-dom: specifier: ^18.0.0 || ^19.0.0 version: 19.1.0(react@19.1.0) + react-i18next: + specifier: ^15.0.0 + version: 15.4.1(i18next@24.2.3(typescript@5.9.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) react-mentions-ts: specifier: ^5.4.7 version: 5.4.7(class-variance-authority@0.7.1)(clsx@2.1.1)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(tailwind-merge@3.5.0) @@ -499,12 +502,6 @@ importers: specifier: ^2.19.2 version: 2.20.0 devDependencies: - '@jsonforms/core': - specifier: ^3.4.1 - version: 3.5.1 - '@jsonforms/react': - specifier: ^3.4.1 - version: 3.5.1(@jsonforms/core@3.5.1)(react@19.1.0) '@testing-library/react': specifier: ^16.3.0 version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.1.1(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) @@ -529,27 +526,15 @@ importers: eslint-plugin-tsdoc: specifier: ^0.4.0 version: 0.4.0 - i18next: - specifier: ^24.2.3 - version: 24.2.3(typescript@5.6.3) - i18next-browser-languagedetector: - specifier: ^8.0.5 - version: 8.0.5 - immer: - specifier: ^10.1.1 - version: 10.1.1 - react-i18next: - specifier: ^15.4.1 - version: 15.4.1(i18next@24.2.3(typescript@5.6.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) vite: specifier: ^6.0.7 version: 6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4) vite-plugin-dts: specifier: ^4.5.0 - version: 4.5.4(@types/node@22.12.0)(rollup@4.57.1)(typescript@5.6.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.5.4(@types/node@22.12.0)(rollup@4.57.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)) vite-plugin-svgr: specifier: ^4.3.0 - version: 4.3.0(rollup@4.57.1)(typescript@5.6.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)) + version: 4.3.0(rollup@4.57.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)) vitest: specifier: ^3.0.4 version: 3.0.4(@types/debug@4.1.12)(@types/node@22.12.0)(jiti@2.6.1)(jsdom@26.0.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4) @@ -10523,7 +10508,7 @@ snapshots: de-indent: 1.0.2 he: 1.2.0 - '@vue/language-core@2.2.0(typescript@5.6.3)': + '@vue/language-core@2.2.0(typescript@5.9.3)': dependencies: '@volar/language-core': 2.4.28 '@vue/compiler-dom': 3.5.33 @@ -10534,7 +10519,7 @@ snapshots: muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: - typescript: 5.6.3 + typescript: 5.9.3 '@vue/shared@3.5.33': {} @@ -12869,12 +12854,6 @@ snapshots: dependencies: '@babel/runtime': 7.27.0 - i18next@24.2.3(typescript@5.6.3): - dependencies: - '@babel/runtime': 7.27.0 - optionalDependencies: - typescript: 5.6.3 - i18next@24.2.3(typescript@5.9.3): dependencies: '@babel/runtime': 7.27.0 @@ -14478,15 +14457,6 @@ snapshots: react: 19.1.0 scheduler: 0.26.0 - react-i18next@15.4.1(i18next@24.2.3(typescript@5.6.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): - dependencies: - '@babel/runtime': 7.27.0 - html-parse-stringify: 3.0.1 - i18next: 24.2.3(typescript@5.6.3) - react: 19.1.0 - optionalDependencies: - react-dom: 19.1.0(react@19.1.0) - react-i18next@15.4.1(i18next@24.2.3(typescript@5.9.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@babel/runtime': 7.27.0 @@ -15789,18 +15759,18 @@ snapshots: - tsx - yaml - vite-plugin-dts@4.5.4(@types/node@22.12.0)(rollup@4.57.1)(typescript@5.6.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)): + vite-plugin-dts@4.5.4(@types/node@22.12.0)(rollup@4.57.1)(typescript@5.9.3)(vite@6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4)): dependencies: '@microsoft/api-extractor': 7.58.7(@types/node@22.12.0) '@rollup/pluginutils': 5.3.0(rollup@4.57.1) '@volar/typescript': 2.4.28 - '@vue/language-core': 2.2.0(typescript@5.6.3) + '@vue/language-core': 2.2.0(typescript@5.9.3) compare-versions: 6.1.1 debug: 4.4.3 kolorist: 1.8.0 local-pkg: 1.1.2 magic-string: 0.30.21 - typescript: 5.6.3 + typescript: 5.9.3 optionalDependencies: vite: 6.4.1(@types/node@22.12.0)(jiti@2.6.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.4) transitivePeerDependencies: From 6e144cd119febfa3668ed7741b9389036d86afc7 Mon Sep 17 00:00:00 2001 From: Piotr Blaszczyk Date: Thu, 23 Jul 2026 09:11:37 +0200 Subject: [PATCH 2/2] feat(sdk): re-export JsonForms authoring primitives --- .changeset/slim-peer-dependencies.md | 2 +- .../content/docs/get-started/side-effects.md | 2 +- .../content/docs/guides/add-a-custom-node.mdx | 15 +- .../docs/guides/custom-jsonforms-control.md | 31 +-- apps/docs/src/landing-pages/api-index.md | 2 +- packages/sdk/README.md | 9 +- .../sdk/src/features/json-form/authoring.ts | 177 ++++++++++++++++++ packages/sdk/src/index.ts | 8 + 8 files changed, 216 insertions(+), 30 deletions(-) create mode 100644 packages/sdk/src/features/json-form/authoring.ts diff --git a/.changeset/slim-peer-dependencies.md b/.changeset/slim-peer-dependencies.md index 1832d723d..9e1f3f21d 100644 --- a/.changeset/slim-peer-dependencies.md +++ b/.changeset/slim-peer-dependencies.md @@ -2,4 +2,4 @@ '@workflowbuilder/sdk': minor --- -Reduce the required peer dependencies from ten to four. `@jsonforms/core`, `@jsonforms/react`, `i18next`, `react-i18next`, `i18next-browser-languagedetector` and `immer` are now regular dependencies that install automatically, so the full install is `@workflowbuilder/sdk @xyflow/react zustand` on any package manager (`react`/`react-dom` stay peers but are already in any React app). +Slimmer install: the base install is now `@workflowbuilder/sdk @xyflow/react zustand`. `@jsonforms/core`, `@jsonforms/react`, `i18next`, `react-i18next`, `i18next-browser-languagedetector` and `immer` moved from peer to regular dependencies and install automatically. JsonForms authoring primitives (`withJsonFormsControlProps`, `rankWith`, `useJsonForms`, `RuleEffect`, `ControlProps`, …) are now re-exported from `@workflowbuilder/sdk`, so custom renderers need no extra installs. diff --git a/apps/docs/src/content/docs/get-started/side-effects.md b/apps/docs/src/content/docs/get-started/side-effects.md index ea8f686a8..dfaa61b8b 100644 --- a/apps/docs/src/content/docs/get-started/side-effects.md +++ b/apps/docs/src/content/docs/get-started/side-effects.md @@ -9,7 +9,7 @@ Importing `@workflowbuilder/sdk` runs a handful of module-level side effects on ## Side effects on import -- **`immer`** — calls `setAutoFreeze(false)`. ReactFlow mutates the objects produced by the SDK's `produce` calls (size, position, internal flags), so the SDK's drafts must not be auto-frozen. Because `immer` is a singleton peer, this disables auto-freeze **globally** for the host app — any of your own reducers, RTK slices, or libraries that rely on frozen drafts lose that protection. If you have your own immer flows that depend on frozen drafts, treat it as a known caveat. +- **`immer`** — calls `setAutoFreeze(false)`. ReactFlow mutates the objects produced by the SDK's `produce` calls (size, position, internal flags), so the SDK's drafts must not be auto-frozen. Because `immer` is a shared, deduped dependency, this disables auto-freeze **globally** for the host app — any of your own reducers, RTK slices, or libraries that rely on frozen drafts lose that protection. If you have your own immer flows that depend on frozen drafts, treat it as a known caveat. - **`i18next`** — initialises the i18next instance with `react-i18next`, the language detector, and the SDK's bundled `en` / `pl` translations. If your app already configured i18next before importing the SDK, the SDK's `i18n.init(...)` is a no-op for the second `init` per i18next's contract — the registry is shared. ## Known limitations diff --git a/apps/docs/src/content/docs/guides/add-a-custom-node.mdx b/apps/docs/src/content/docs/guides/add-a-custom-node.mdx index 8f3b34d38..8dd8d34e9 100644 --- a/apps/docs/src/content/docs/guides/add-a-custom-node.mdx +++ b/apps/docs/src/content/docs/guides/add-a-custom-node.mdx @@ -151,16 +151,9 @@ To render a property with a custom React component, split the renderer into two `renderers/color-picker.tsx`: ```tsx -import { withJsonFormsControlProps } from '@jsonforms/react'; +import { type ControlProps, withJsonFormsControlProps } from '@workflowbuilder/sdk'; -type Props = { - data: string; - handleChange: (path: string, value: string) => void; - path: string; - label?: string; -}; - -function ColorPickerControl({ data, handleChange, path, label }: Props) { +function ColorPickerControl({ data, handleChange, path, label }: ControlProps) { return (