@frontfriend/sdk 0.0.0-stage → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +46 -0
  2. package/README.md +352 -2
  3. package/dist/THIRD_PARTY_NOTICES +44 -0
  4. package/dist/application-adoption-lock.d.ts +31 -0
  5. package/dist/application-adoption.d.ts +103 -0
  6. package/dist/browser.mjs +1 -0
  7. package/dist/cli.js +372 -0
  8. package/dist/cn.d.ts +2 -0
  9. package/dist/cn.js +1 -0
  10. package/dist/cn.mjs +1 -0
  11. package/dist/component-config.d.ts +330 -0
  12. package/dist/component-config.mjs +1 -0
  13. package/dist/component-recipes.d.ts +29 -0
  14. package/dist/components-config-schema.d.ts +2 -0
  15. package/dist/components-config-schema.js +1 -0
  16. package/dist/ffdc.d.ts +17 -0
  17. package/dist/ffdc.js +1 -0
  18. package/dist/ffdc.mjs +1 -0
  19. package/dist/foundation-contract.json +56 -0
  20. package/dist/index.js +1 -0
  21. package/dist/index.mjs +1 -0
  22. package/dist/lib/core/adoption.js +1 -0
  23. package/dist/lib/core/api-client.js +10 -0
  24. package/dist/lib/core/application-adoption-lock.js +6 -0
  25. package/dist/lib/core/application-adoption.js +28 -0
  26. package/dist/lib/core/cache-manager.js +1 -0
  27. package/dist/lib/core/cached-components-config.js +1 -0
  28. package/dist/lib/core/classes-source.js +1 -0
  29. package/dist/lib/core/component-config.js +1 -0
  30. package/dist/lib/core/component-recipes.js +8 -0
  31. package/dist/lib/core/components-config-schema.js +1 -0
  32. package/dist/lib/core/config-loader.js +1 -0
  33. package/dist/lib/core/constants.js +1 -0
  34. package/dist/lib/core/credentials.js +2 -0
  35. package/dist/lib/core/env-utils.js +2 -0
  36. package/dist/lib/core/errors.js +1 -0
  37. package/dist/lib/core/file-utils.js +2 -0
  38. package/dist/lib/core/nativeSource.d.ts +10 -0
  39. package/dist/lib/core/nativeSource.js +2 -0
  40. package/dist/lib/core/package-identity.js +1 -0
  41. package/dist/lib/core/path-utils.js +2 -0
  42. package/dist/lib/core/project-target.js +1 -0
  43. package/dist/lib/core/static-config.js +9 -0
  44. package/dist/lib/core/token-artifact-client.js +8 -0
  45. package/dist/lib/core/token-artifact.d.ts +39 -0
  46. package/dist/lib/core/token-artifact.js +1 -0
  47. package/dist/lib/core/token-processor.d.ts +23 -0
  48. package/dist/lib/core/token-processor.js +5 -0
  49. package/dist/lib/react/utils.d.ts +25 -0
  50. package/dist/lib/react/utils.mjs +1 -0
  51. package/dist/lib/vue/utils.d.ts +27 -0
  52. package/dist/lib/vue/utils.mjs +1 -0
  53. package/dist/mcp.cjs +226 -0
  54. package/dist/next.d.ts +11 -0
  55. package/dist/next.js +2 -0
  56. package/dist/next.mjs +1 -0
  57. package/dist/package.json +4 -0
  58. package/dist/project-target.d.ts +22 -0
  59. package/dist/runtime.d.ts +15 -0
  60. package/dist/runtime.js +1 -0
  61. package/dist/runtime.mjs +1 -0
  62. package/dist/scripts/generate-icon-types.js +38 -0
  63. package/dist/theme.css +3 -0
  64. package/dist/types/index.d.ts +68 -0
  65. package/dist/vite.d.mts +9 -0
  66. package/dist/vite.d.ts +8 -0
  67. package/dist/vite.js +9 -0
  68. package/dist/vite.mjs +1 -0
  69. package/package.json +202 -3
package/LICENSE ADDED
@@ -0,0 +1,46 @@
1
+ FrontFriend Proprietary License
2
+
3
+ Copyright (c) 2026 Donux
4
+
5
+ All Rights Reserved.
6
+
7
+ This software and associated documentation files (the "Software") are the
8
+ proprietary property of Donux. Public availability of the package does not
9
+ grant a license to use it.
10
+
11
+ LICENSE GRANT:
12
+ Subject to the terms and conditions of this license, Donux grants you
13
+ a limited, non-exclusive, non-transferable, non-sublicensable license to use
14
+ the Software as a registered Frontfriend client, including self-service
15
+ clients and clients who use only design contracts.
16
+
17
+ PROJECT OUTPUT:
18
+ Registered Frontfriend clients may use, modify, and include the component
19
+ source, tokens, and other project files delivered or generated by the Software
20
+ in their applications. Clients may bundle the SDK runtime with those
21
+ applications solely as needed to run them. Application users receive no right
22
+ to use the SDK separately. This permission does not grant a right to modify
23
+ the SDK implementation or redistribute the SDK as a standalone product.
24
+ Third-party materials remain subject to their own licenses and notices.
25
+
26
+ RESTRICTIONS (SDK IMPLEMENTATION):
27
+ Except for the application use and bundling permitted above, you may not:
28
+ - Distribute, sublicense, lease, rent, or lend the Software
29
+ - Modify, reverse engineer, decompile, or disassemble the Software
30
+ - Remove or alter any proprietary notices or labels on the Software
31
+ - Use the Software for any purpose other than as specifically authorized
32
+
33
+ TERMINATION:
34
+ This license is effective until terminated. Your rights under this license
35
+ will terminate automatically without notice if you fail to comply with any
36
+ term(s) of this license.
37
+
38
+ DISCLAIMER:
39
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
40
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
41
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
42
+ DONUX BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
43
+ AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
44
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
45
+
46
+ For licensing inquiries, please contact: frontfriend@donux.com
package/README.md CHANGED
@@ -1,3 +1,353 @@
1
- # Temporary Holding Version
1
+ # @frontfriend/sdk
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Connect your application to your Frontfriend Design System. Use design contracts on their own, or add generated tokens and components for React and Vue. The SDK includes the Frontfriend CLI, coding agent integrations, and runtime helpers.
4
+
5
+ [Documentation](https://frontfriend.dev/docs/introduction/) · [Component catalogue](https://frontfriend.dev/components/)
6
+
7
+ ## Install
8
+
9
+ Install `@frontfriend/sdk` to connect your application to Frontfriend. Follow the [installation guide](https://frontfriend.dev/docs/installation/) to get started.
10
+
11
+ `latest` is the stable SDK release. Use `@frontfriend/sdk@next` only when the Frontfriend team asks you to test a preview; the `next` tag may not be available. Pin a version when your project needs a fixed SDK version.
12
+
13
+ Use Node.js 20.19 or later. Web applications also need Tailwind CSS 4 and a compatible React or Vue 3 component library. Design contracts do not require Tailwind CSS, React, or Vue.
14
+
15
+ The SDK runtime supports React 16.8–19. The components you select can require a newer React version; follow their dependency requirements. Install TypeScript as a development dependency when importing or updating component sources (`npm install -D typescript`).
16
+
17
+ Every project starts from a Design System. Create one in Frontfriend, or open an existing one, and copy its ID (`ff-id`). For a web application, run these commands from the application root:
18
+
19
+ ```bash
20
+ npm install @frontfriend/sdk tw-animate-css
21
+ npm install -D typescript
22
+ npx frontfriend login
23
+ npx frontfriend setup --ff-id <ff-id> --framework react --primitive base
24
+ ```
25
+
26
+ Setup connects the Design System and asks which features to adopt: design rules, tokens, and components. It creates `frontfriend.config.js` and initializes the local configuration. Without `--ff-id`, setup asks for the ID in an interactive terminal. Setup never replaces the Design System or App of a project that is already connected; pass `--force` to replace them.
27
+
28
+ Use `setup` to configure a project and choose its features. Use `connect` for the complete flow, including sign-in, coding-agent installation, connection checks, and activation of reviewed design rules.
29
+
30
+ A **Release** is a published selection of tokens, components, and design rules. **Adoption** means applying that selection to your application and recording it in `frontfriend.lock.json` (the adoption lock). The **MCP bridge** connects your coding agent to Frontfriend and runs local checks.
31
+
32
+ Commands that work on the Design System, such as `init`, `migrate`, `update`, and `download`, check for the `ff-id` first. If the project has none, they stop and explain how to create or connect a Design System. They don't change the project. `npx frontfriend status` shows a missing Design System as the first problem.
33
+
34
+ Every command reads the Frontfriend URL in the same order: the `--api-url` flag, then `api-url` in `frontfriend.config.js`, then `FF_API_URL`, then the URL stored by `frontfriend login`, then the default platform. `update`, `init`, `check`, `design sync`, `import-shadcn` and `migrate` accept `--api-url` (`check` runs offline and only accepts it). `connect` writes `api-url` into an existing `frontfriend.config.js` that has none.
35
+
36
+ `frontfriend.config.js` holds data only. Setup writes `module.exports = {…}` for CommonJS and `const config = {…}; export default config;` for an ES module project. The CLI also reads `export default {…}` and `module.exports = config`.
37
+
38
+ ### Design contracts without tokens or components
39
+
40
+ Install the SDK and connect only the design contracts:
41
+
42
+ ```bash
43
+ npm install @frontfriend/sdk
44
+ npx frontfriend login
45
+ npx frontfriend setup --ff-id <ff-id> --adopt contracts
46
+ npx frontfriend design sync --contracts-only
47
+ ```
48
+
49
+ This setup does not require a web framework, CSS, or a build plugin. Contract synchronization writes `.frontfriend/design/`. If the application has adopted a design snapshot, synchronization uses that snapshot. Otherwise, it reads the working contracts without adopting a Release.
50
+
51
+ To adopt approved contracts and record the selection in the adoption lock (`frontfriend.lock.json`), preview and apply an update:
52
+
53
+ ```bash
54
+ npx frontfriend update --contracts-only --working-design --dry-run
55
+ npx frontfriend update --contracts-only --working-design --yes
56
+ ```
57
+
58
+ Tailwind CSS, React, and Vue are optional peer dependencies. Install the framework and renderer only when your application uses their integrations.
59
+
60
+ ### Existing shadcn projects
61
+
62
+ Create a Design System with the **shadcn** base. Connect the first application with its selected adoption levels:
63
+
64
+ ```bash
65
+ npx --yes @frontfriend/sdk@latest connect --ff-id <ff-id> --base-library shadcn --agent codex --adopt contracts,tokens,components
66
+ ```
67
+
68
+ On a shadcn base that is not initialized yet, `connect` runs its `import` step after the agent installation: `import-shadcn`, the adoption of the imported Release (its tokens and the installed components, as `update --release <id> --installed --tokens`), then `init`. The JSON result reports it in `import` (`status`, `release_id`). A source conflict stops the step with exit 12, names the files and the fix, and writes nothing; run `connect` again after you resolve them and it continues from the import. A second run changes nothing. `--no-import` skips the step. Later applications adopt the existing Release in the same step. The Design contract review and Connect activation still apply.
69
+
70
+ Without `connect`, run the same steps by hand. `init` exits 1 on a shadcn base that is not initialized and names them:
71
+
72
+ ```bash
73
+ npx frontfriend import-shadcn
74
+ npx frontfriend update --release <releaseId> --installed --tokens --dry-run
75
+ npx frontfriend update --release <releaseId> --installed --tokens --yes
76
+ npx frontfriend init
77
+ ```
78
+
79
+ `--installed` selects local components and their dependencies. `--tokens` also advances the token pin. Check any source conflict before you use `--replace`.
80
+
81
+ The first import keeps native light, dark, and custom tokens. With component adoption, it compares the actual UI sources with the pinned shadcn base. Changed components and local helpers become private versions at `1.0.0`. Explicit replacements have one file owner. Later applications adopt the configured Release. A repeated import does not publish local edits.
82
+
83
+ Native `init` writes the selected native CSS and foundation context. It uses the shadcn base without a Frontfriend runtime plugin.
84
+
85
+ To convert the same Design System to Frontfriend, run `npx frontfriend migrate`. It transforms token classes and preserves component logic. It publishes new private versions and adopts only this application's installed sources and tokens. Other applications keep their locks. If publication completes but local adoption fails, run `migrate` again to resume the saved adoption.
86
+
87
+ Choose one target per application:
88
+
89
+ | Framework | Primitive |
90
+ | --------- | -------------------------- |
91
+ | `react` | `base`, `radix`, or `aria` |
92
+ | `vue` | `reka` |
93
+
94
+ ### Connect an application with one command
95
+
96
+ Run inside an application in a Git work tree. Existing shadcn and shadcn-vue applications retain their target. For a new app, pass an explicit `--framework` and `--primitive` or copy the command from Studio’s Connect flow:
97
+
98
+ ```bash
99
+ npx --yes @frontfriend/sdk@latest connect --ff-id <design-system-id> --agent claude
100
+ ```
101
+
102
+ `connect` runs the operations of `login`, `setup`, `agents install` and `doctor` in order, says which files it will create or change before it writes them, and ends with checks of configuration, authentication, Design System access, Release selection, and the first data read, followed by onboarding. It never replaces an identity in `frontfriend.config.js`. A second run changes nothing and reports "already connected"; a run that failed continues from the failed step. When the installed Claude or Codex registration reads another Frontfriend URL than this run, `connect` registers it again for this URL and says so. The registration is user-level: every project that the agent opens reads the new URL.
103
+
104
+ | Flag | Meaning |
105
+ | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
106
+ | `--ff-id <id>` | Design System. Needed when there is no terminal. |
107
+ | `--base-library <base>` | The chosen Design System base: `frontfriend` or `shadcn`. |
108
+ | `--agent <agent>` | `claude`, `codex`, `cursor`, `hermes` or `openclaw`; repeat it or use commas. `connect` installs for Claude and Codex and prints the exact MCP registration for the other agents. |
109
+ | `--name`, `--adopt` | App name (default: the package name) and adoption levels (default: `contracts,tokens,components`). On an existing shadcn app the user may stop at `contracts`. On a connected project a different `--adopt` is written to `frontfriend.config.js` and `init` runs again. On a shadcn app, adopting components applies the Design System styling (`init --force`). |
110
+ | `--framework`, `--primitive` | Declare the target when no primitive package is installed yet. Evidence in the project can contradict the flag, never the reverse. |
111
+ | `--areas <a,b>` | Areas of the onboarding run: codebase areas, or the intended product areas of an app with no UI code yet. Used only while the App is not onboarded; without it, `connect` starts no run. |
112
+ | `--resume` | Continue the onboarding of a connected project (review, activation). It never starts a run, so it takes no `--areas` (exit 2). |
113
+ | `--no-activate` | Do not adopt the reviewed snapshot when the onboarding is ready to adopt, nor align the lock of a ready App. |
114
+ | `--no-import` | On a shadcn base, skip the native import step. |
115
+ | `--require-ready` | Exit 11 unless the App ends ready. |
116
+ | `--verification-id <id>` | Report the verification to the Studio Connect wizard. |
117
+ | `--login` | Start the device login when there is no terminal. A person approves the code in the browser. |
118
+ | `--no-install` | `init` adds `@frontfriend/sdk` to `package.json`; `connect` then installs it with the package manager your lockfile names. This flag prints the command instead. |
119
+ | `--dry-run`, `--yes`, `--force`, `--json` | Name the files (the activation included) and stop; do not ask before writing; run every step again; print one JSON result on stdout (progress goes to stderr). |
120
+
121
+ Without a terminal `connect` never prompts: it stops and names the missing flag.
122
+
123
+ #### Onboarding and activation
124
+
125
+ After the connection, `connect` reads the onboarding state of the App from Studio and acts on it:
126
+
127
+ | State | Waiting on | What `connect` does |
128
+ | ----------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
129
+ | `not_onboarded` | agent | With `--areas`, starts the setup run. Otherwise names the next step. |
130
+ | `onboarding` | agent | Reports the run progress: the agent runs ff-setup, which resumes the run. |
131
+ | `awaiting_review` | human (agent when changes were requested) | Prints the review URL in the Studio, and the comment when changes were requested. |
132
+ | `ready_to_adopt` | cli | Activation: adopts exactly the reviewed snapshot with its source Release (contracts only), lists the files, asks at a terminal unless `--yes`, reports the adoption, then runs doctor again until the selection is the adopted snapshot, and writes `.frontfriend/rules/` for it so `frontfriend check` can run. When `frontfriend.lock.json` already pins the reviewed snapshot, it only reports the adoption again. |
133
+ | `ready` | none | When `frontfriend.lock.json` is missing or pins neither the snapshot the platform reports as adopted nor the reviewed one, adopts that snapshot as in the activation (lock, `.frontfriend/design/`, `.frontfriend/rules/`) and reports it in `activation` (`reason`: `lock_missing` or `lock_mismatch`). Then prints the daily loop (design with ff-design, check with `frontfriend check`, update with `frontfriend update`) and how many contracts changed since the adopted snapshot (`daily_loop` in the JSON result). A second `connect` changes nothing. |
134
+
135
+ The approval in the Studio is the adoption decision, so without a terminal `connect` adopts without `--yes`. A human still commits the lock. States that wait on someone exit 0, with `state` and `waiting_on` in the JSON result. If the platform does not support the required onboarding API, `connect` reports an error. Check that the Frontfriend platform supports this SDK version.
136
+
137
+ `connect` also refreshes the installed `ff-*` skill stubs of Claude and Codex when this version renders them differently.
138
+
139
+ | Exit code | Meaning |
140
+ | --------- | ------------------------------------------------------------------------------------------------------------ |
141
+ | 0 | Connected, already connected, or dry run complete |
142
+ | 1 | Unexpected error, or the person declined |
143
+ | 2 | A required input is missing or invalid (the message names the flag) |
144
+ | 3 | Preflight refused: not a Git work tree, or several apps under this directory |
145
+ | 4 | Not a shadcn application, or not a Frontfriend Project target |
146
+ | 5 | Sign-in needed or failed |
147
+ | 6 | The project is connected to another Design System or App |
148
+ | 7 | Project configuration or agent installation failed |
149
+ | 8 | Not connected: a verification outcome failed, or the verification was not reported |
150
+ | 9 | Connected, but the onboarding status could not be read or the run could not be started |
151
+ | 10 | The activation failed (adoption, report or verification); run `connect` again to continue from it |
152
+ | 11 | The App is not ready (only with `--require-ready`) |
153
+ | 12 | The native shadcn import stopped (source conflicts, import or init); run `connect` again to continue from it |
154
+
155
+ `connect` pins the bridge version: the manual registration for Cursor, Hermes and OpenClaw pins `@frontfriend/sdk@<this version>` (set `FF_BRIDGE_VERSION` to pin another version or a tag), and `agents install` copies this version's runtime. The verification warns, and `result.bridge` lists the warning, when `.mcp.json` or the user-level runtime starts another version.
156
+
157
+ `frontfriend doctor` checks configuration, authentication, Design System access, Release selection, and the first data read (`frontfriend mcp doctor` is the same operation), the bridge and compliance engine versions with a warning for a registered bridge of another version, and an informational readiness line. When the platform reports the App as ready but `frontfriend.lock.json` does not pin its adopted snapshot, doctor fails the `Local adoption` line and exits 1: run `connect` to adopt it. `frontfriend onboard` prints the same onboarding state; `frontfriend onboard --areas <a,b>` starts the run while the App is not onboarded. `onboard` never adopts: `connect` activates.
158
+
159
+ ### Existing projects and updates
160
+
161
+ Rerun `agents install` to update the managed runtime and registrations. Other client settings and MCP servers are preserved. When run from an existing project, the installer removes an equivalent generated Frontfriend entry from that project's `.mcp.json` only after configuring the user-level Claude entry, deleting the file if no other settings remain. It reports and preserves customized entries, which may take precedence over the global connection. Review those overrides explicitly when migrating; the installer does not scan other repositories.
162
+
163
+ ```bash
164
+ # Refresh project rules and registry wiring without reinstalling the MCP.
165
+ npx --yes @frontfriend/sdk@latest agents configure
166
+ ```
167
+
168
+ `frontfriend setup` handles local adoption and calls `agents configure`. Project dependencies and generated `.frontfriend` artifacts remain local to each app. Global MCP installation does not add a package dependency to every repository.
169
+
170
+ ## Connect your build
171
+
172
+ Use these integrations when your application adopts tokens. They are not required for design contracts alone.
173
+
174
+ ### Vite
175
+
176
+ Add Frontfriend alongside your framework and Tailwind plugins:
177
+
178
+ ```ts
179
+ import { defineConfig } from "vite";
180
+ import react from "@vitejs/plugin-react";
181
+ import tailwindcss from "@tailwindcss/vite";
182
+ import frontfriend from "@frontfriend/sdk/vite";
183
+
184
+ export default defineConfig({
185
+ plugins: [react(), tailwindcss(), frontfriend()],
186
+ });
187
+ ```
188
+
189
+ For Vue, use your Vue plugin in place of `react()`.
190
+
191
+ When the App adopts tokens, `init` adds the import and `frontfriend()` to an existing `vite.config.{ts,js,mts,mjs}`. It changes nothing else in the file and does nothing when the plugin is already there. When the config is not an inline `export default` object (or `defineConfig(...)` of one), `init` leaves it untouched and prints the snippet to paste.
192
+
193
+ ### Next.js
194
+
195
+ Wrap your Next.js configuration:
196
+
197
+ ```js
198
+ import frontfriend from "@frontfriend/sdk/next";
199
+
200
+ export default frontfriend({
201
+ // Your Next.js configuration
202
+ });
203
+ ```
204
+
205
+ ### Styles
206
+
207
+ Import the theme in your application CSS:
208
+
209
+ ```css
210
+ @import "tailwindcss";
211
+ @import "@frontfriend/sdk/theme.css";
212
+ @import "tw-animate-css";
213
+ ```
214
+
215
+ Use design tokens as Tailwind utilities:
216
+
217
+ ```html
218
+ <div class="bg-brand-mid text-onbrand-strong border border-neutral-subtle">
219
+ Your content
220
+ </div>
221
+ ```
222
+
223
+ ## Add components
224
+
225
+ Preview a component from a Design System release, then apply it:
226
+
227
+ ```bash
228
+ npx frontfriend update button --release <release-id> --dry-run
229
+ npx frontfriend update button --release <release-id> --yes
230
+ ```
231
+
232
+ The command installs the component and its required components for your configured target. It records the selection in `frontfriend.lock.json`.
233
+
234
+ You can also select a release channel or add a private component:
235
+
236
+ ```bash
237
+ npx frontfriend update --channel latest --dry-run
238
+ npx frontfriend add custom/acme/data-grid --release <release-id> --dry-run
239
+ ```
240
+
241
+ Without a component or a selection flag, `frontfriend update` adopts what the App's `adopt` levels cover, in one lock: the approved contracts (`--working-design`), plus the Release tokens and the installed components (`--installed --tokens`) when the App adopts tokens or components. A contracts-only App gets `--contracts-only --working-design`. An applied adoption also writes `.frontfriend/rules/`, so `frontfriend check` reads the adopted rules.
242
+
243
+ An applied adoption installs the npm dependencies of the components it wrote that `package.json` lacks, with the package manager your lockfile names (`--no-install` prints the command instead). It then refreshes the token cache in `node_modules/.cache/frontfriend` when the token pin moved: a running Vite dev server reloads by itself, without a restart. With `--installed --replace`, a stock shadcn file that the Design System ships under another name (`sonner.tsx` → `toast`) is replaced by the Design System component and removed, and its imports point at the new module.
244
+
245
+ To apply the latest published Release of the App's tag in one step (lock, component source, npm dependencies, token cache), run:
246
+
247
+ ```bash
248
+ npx frontfriend adopt --dry-run
249
+ npx frontfriend adopt --yes
250
+ ```
251
+
252
+ `adopt` never adopts a draft: a component or foundation commit reaches the App once it is published in a Release.
253
+
254
+ Coding agents adopt through the MCP bridge instead: the local tool `adopt_design { project_path, dry_run?, scope? }` runs the same adoption without a prompt and returns a JSON summary (snapshot, Release, changed pins, files written, `npm_dependencies`, `token_cache`). It returns the install command for missing npm dependencies instead of running the package manager.
255
+
256
+ See the [CLI reference](https://frontfriend.dev/docs/cli-reference/) for all options.
257
+
258
+ ## Connect coding agents
259
+
260
+ Install the Frontfriend MCP connection and skills for Codex and Claude Code:
261
+
262
+ ```bash
263
+ npx --yes @frontfriend/sdk@latest agents install
264
+ ```
265
+
266
+ Restart your coding agent after installation. Use `--client codex` or `--client claude` to select one client. The connection is installed for your user account; each task uses the configuration of its application.
267
+
268
+ See [MCP connection](https://frontfriend.dev/docs/mcp/) and [Design Skills](https://frontfriend.dev/docs/design-skills/) for agent workflows.
269
+
270
+ ## Runtime helpers
271
+
272
+ ### Merge classes
273
+
274
+ Use `cn` to combine conditional classes and resolve Tailwind class conflicts:
275
+
276
+ ```ts
277
+ import { cn } from "@frontfriend/sdk/cn";
278
+
279
+ cn("px-2 py-1 bg-brand-mid", "px-4");
280
+ // 'py-1 bg-brand-mid px-4'
281
+ ```
282
+
283
+ ### Read component configuration
284
+
285
+ ```ts
286
+ import { config, ffdc, iconSet } from "@frontfriend/sdk";
287
+
288
+ const components = ffdc(config);
289
+ const button = ffdc(config, "button");
290
+ ```
291
+
292
+ `ffdc(config)` returns the runtime configuration. The optional component name applies that component's shared rules, such as using `main` for an unconfigured `default` variant. `iconSet` provides the configured icons.
293
+
294
+ The component form supports `badge`, `button`, `calendar`, `card`, `command`, `date-slider`, `input-group`, `popover`, `separator`, and `spinner`. Check for an absent result before use. Treat the result as read-only; save changes to the source configuration.
295
+
296
+ TypeScript declarations are included. Automatic Vite/Next configuration edits use TypeScript. In a JavaScript project without it, the SDK leaves your configuration unchanged and shows the manual integration step.
297
+
298
+ ## Maintain your project
299
+
300
+ | Command | Purpose |
301
+ | ---------------------------------- | -------------------------------------------------------------------------------------------- |
302
+ | `npx frontfriend status` | Check configuration and cache status. |
303
+ | `npx frontfriend init --force` | Fetch the current design tokens and configuration. |
304
+ | `npx frontfriend check` | Check local code against the adopted design rules. |
305
+ | `npx frontfriend diff` | Compare local component files with the adoption lock. |
306
+ | `npx frontfriend restore` | List snapshots from a shadcn conversion; pass a snapshot ID to restore its original sources. |
307
+ | `npx frontfriend logout` | Remove your saved Frontfriend login. |
308
+ | `npx frontfriend clean` | Remove the local cache. |
309
+ | `npx frontfriend design sync` | Refresh local design rules. |
310
+ | `npx frontfriend agents configure` | Refresh project integration for coding agents. |
311
+
312
+ If components have no styles, check the CSS imports and build plugin, then run `npx frontfriend init --force`. For installation errors, check your Design System access and application target, then preview the component with `--dry-run`.
313
+
314
+ See [Troubleshooting](https://frontfriend.dev/docs/troubleshooting/) for more help.
315
+
316
+ ## Token availability
317
+
318
+ `frontfriend init` requires a login (`frontfriend login` or `FF_AUTH_TOKEN`) and reads tokens from Studio. It uses the token Release in `frontfriend.lock.json`; you can also select a Release or tag:
319
+
320
+ ```sh
321
+ npx frontfriend init --version <release-id>
322
+ npx frontfriend init --tag <tag-name-or-id>
323
+ ```
324
+
325
+ `--version` takes a Release ID, not an SDK version. A Studio refusal, such as a missing login or no access to the Design System, stops initialization.
326
+
327
+ Every online `init` keeps a verified copy of the selected tokens in `.frontfriend/artifacts`. When Studio is unreachable (network failure, timeout or server error), a signed-in `init` restores that copy. A first install during an outage has no copy to restore.
328
+
329
+ ### Offline tokens
330
+
331
+ Offline tokens are a Workspace capability that Frontfriend enables on request; no plan includes them by default. With it, an online `init` also stores the Workspace's signed offline license next to the verified copies in `.frontfriend/artifacts`. Commit that directory to build and deploy without calling Frontfriend:
332
+
333
+ ```sh
334
+ npx frontfriend init --offline
335
+ ```
336
+
337
+ `--offline` makes no network request and needs no login: it verifies the license and the copy locally. The license does not expire; the next online `init` replaces it, or removes it if the Workspace no longer has offline tokens. With the capability, an `init` during a Studio outage also tries the token CDN before the local copy, so a first install can succeed with an explicit Release or tag. Without the capability, `--offline` fails and the CDN is never read.
338
+
339
+ The default API uses the production token CDN automatically. For a custom API, set `token-cdn-url`, `FF_TOKEN_CDN_URL`, or `--token-cdn-url`. Set `token-cdn-url: false` to disable CDN delivery.
340
+
341
+ Downloads validate artifact identity and integrity. Access refusals and invalid data stop initialization. Token delivery does not update component files, register the application, or publish changes. Run `connect` or `design sync` online for those operations. External fonts and images have their own availability.
342
+
343
+ ## CI authentication
344
+
345
+ Set `FF_AUTH_TOKEN` through your CI secret store for commands that need access to your workspace. Do not commit it to project configuration or print it in build logs. Online token delivery, private components and design rules require it; `init --offline` does not.
346
+
347
+ ## Existing Tailwind clients
348
+
349
+ `@frontfriend/sdk` is not backward compatible with `@frontfriend/tailwind`. Existing clients should use the [v3 documentation](https://frontfriend.dev/docs/legacy/v3/) and contact the Frontfriend team to arrange a migration. Do not replace the package directly.
350
+
351
+ ## License
352
+
353
+ Copyright © 2026 Donux. Use is restricted to registered Frontfriend clients. Clients may modify the component source and project files delivered by Frontfriend; the SDK implementation remains proprietary. See [LICENSE](LICENSE).
@@ -0,0 +1,44 @@
1
+ Notices for third-party code bundled with the SDK.
2
+
3
+ @modelcontextprotocol/client/dist/src-NAgB4Mp8.cjs:
4
+ /*!
5
+ * content-type
6
+ * Copyright(c) 2015 Douglas Christopher Wilson
7
+ * MIT Licensed
8
+ */
9
+
10
+ @modelcontextprotocol/server/dist/src-STyD_Vvf.cjs:
11
+ /*!
12
+ * content-type
13
+ * Copyright(c) 2015 Douglas Christopher Wilson
14
+ * MIT Licensed
15
+ */
16
+
17
+ smol-toml/dist/index.cjs:
18
+ /*!
19
+ * Copyright (c) Squirrel Chat et al., All rights reserved.
20
+ * SPDX-License-Identifier: BSD-3-Clause
21
+ *
22
+ * Redistribution and use in source and binary forms, with or without
23
+ * modification, are permitted provided that the following conditions are met:
24
+ *
25
+ * 1. Redistributions of source code must retain the above copyright notice, this
26
+ * list of conditions and the following disclaimer.
27
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
28
+ * this list of conditions and the following disclaimer in the
29
+ * documentation and/or other materials provided with the distribution.
30
+ * 3. Neither the name of the copyright holder nor the names of its contributors
31
+ * may be used to endorse or promote products derived from this software without
32
+ * specific prior written permission.
33
+ *
34
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
35
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
36
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
38
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
40
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44
+ */
@@ -0,0 +1,31 @@
1
+ import type { ProjectTarget } from "./project-target";
2
+ import type {
3
+ AdoptionComponent,
4
+ AdoptionDigestLock,
5
+ ApplicationLock,
6
+ } from "./application-adoption";
7
+
8
+ export type {
9
+ AdoptionFile,
10
+ AdoptionComponent,
11
+ DesignContractPin,
12
+ DesignAdoption,
13
+ AdoptionDigestLock,
14
+ ApplicationLock,
15
+ } from "./application-adoption";
16
+
17
+ export type ParsedApplicationLock =
18
+ | ApplicationLock
19
+ | {
20
+ schemaVersion: 1;
21
+ releaseId: string | null;
22
+ tokenVersionId: string;
23
+ projectTarget: ProjectTarget;
24
+ components: Record<string, AdoptionComponent>;
25
+ };
26
+
27
+ export function sortedObject<T>(value: Record<string, T>): Record<string, T>;
28
+ export function adoptionDigest(lock: AdoptionDigestLock): string;
29
+ export function normalizeLock(value: unknown): ParsedApplicationLock;
30
+ export function parseApplicationLock(content: unknown): ParsedApplicationLock;
31
+ export function serializeApplicationLock(lock: unknown): string;
@@ -0,0 +1,103 @@
1
+ import type { ProjectTarget } from "./project-target";
2
+
3
+ export type AdoptionFile = {
4
+ path: string;
5
+ installedHash: string | null;
6
+ baselineHash: string;
7
+ baseline: string;
8
+ };
9
+
10
+ export type AdoptionComponent = {
11
+ projectTarget?: ProjectTarget;
12
+ source: "canonical" | "private";
13
+ versionId: string;
14
+ semver: string;
15
+ manifestHash?: string | null;
16
+ sourceReleaseId?: string;
17
+ files?: AdoptionFile[];
18
+ };
19
+
20
+ export type DesignContractPin = {
21
+ revisionId: string;
22
+ contractId: string;
23
+ designSystemId: string;
24
+ slug: string;
25
+ kind: string;
26
+ version: number;
27
+ digest: string;
28
+ };
29
+
30
+ export type DesignAdoption = {
31
+ appId: string;
32
+ designSystemId: string;
33
+ snapshotId: string;
34
+ snapshotDigest: string;
35
+ sharedSourceReleaseId: string;
36
+ contracts: DesignContractPin[];
37
+ sharedContracts: DesignContractPin[];
38
+ };
39
+
40
+ export type AdoptionDigestLock = {
41
+ baseLibrary?: "frontfriend" | "shadcn";
42
+ baseProvenance?: Record<string, unknown>;
43
+ replacements?: Array<{
44
+ framework: string;
45
+ primitive: string;
46
+ canonicalName: string;
47
+ privateAddress: string;
48
+ }>;
49
+ schemaVersion?: 2 | 3;
50
+ design?: DesignAdoption;
51
+ designSystemId: string;
52
+ ffId: string;
53
+ releaseId?: string | null;
54
+ projectTarget: ProjectTarget | null;
55
+ tokenVersionId: string;
56
+ tokenSourceReleaseId?: string;
57
+ sourceReleaseIds?: string[];
58
+ components: Record<string, AdoptionComponent>;
59
+ adoptionDigest?: string;
60
+ };
61
+
62
+ export type ApplicationLock = AdoptionDigestLock & {
63
+ schemaVersion: 2 | 3;
64
+ releaseId: string | null;
65
+ tokenSourceReleaseId: string;
66
+ sourceReleaseIds: string[];
67
+ adoptionDigest: string;
68
+ };
69
+
70
+ export class AdoptionConflictError extends Error {
71
+ code: "ADOPTION_CONFLICT";
72
+ conflicts: readonly unknown[];
73
+ }
74
+
75
+ export function hashContent(content: string | Uint8Array): string;
76
+ export { parseApplicationLock } from "./application-adoption-lock";
77
+ export type { ParsedApplicationLock } from "./application-adoption-lock";
78
+ export function serializeApplicationLock(lock: unknown): string;
79
+ export function validateInstallationPath(value: unknown): string;
80
+ export function adoptionDigest(lock: AdoptionDigestLock): string;
81
+
82
+ export class ApplicationAdoption {
83
+ constructor(options?: {
84
+ root?: string;
85
+ readFile?: (relativePath: string) => string | null;
86
+ writeFile?: (relativePath: string, content: string) => void;
87
+ });
88
+ inspect(resolved: unknown, options?: Record<string, unknown>): unknown;
89
+ diff(lock: unknown): unknown[];
90
+ planUpdate(
91
+ resolved: unknown,
92
+ options?: Record<string, unknown>,
93
+ ): {
94
+ valid: true;
95
+ writes: Record<string, string>;
96
+ deletes: string[];
97
+ renames: Array<{ from: string; to: string }>;
98
+ nextLock: ApplicationLock;
99
+ changelogs: string[];
100
+ npmDependencies: string[];
101
+ };
102
+ apply(plan: unknown, hooks?: Record<string, unknown>): ApplicationLock;
103
+ }
@@ -0,0 +1 @@
1
+ var Q=Object.create;var y=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var ee=Object.getPrototypeOf,ne=Object.prototype.hasOwnProperty;var te=(e,n)=>()=>(e&&(n=e(e=0)),n);var v=(e,n)=>()=>(n||e((n={exports:{}}).exports,n),n.exports),oe=(e,n)=>{for(var t in n)y(e,t,{get:n[t],enumerable:!0})},k=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of Z(n))!ne.call(e,r)&&r!==t&&y(e,r,{get:()=>n[r],enumerable:!(o=Y(n,r))||o.enumerable});return e};var O=(e,n,t)=>(t=e!=null?Q(ee(e)):{},k(n||!e||!e.__esModule?y(t,"default",{value:e,enumerable:!0}):t,e)),se=e=>k(y({},"__esModule",{value:!0}),e);var z=v((Ae,j)=>{function p(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function _(e,n){if(!p(e)||!p(n))return n===void 0?e:n;let t={...e};for(let[o,r]of Object.entries(n))t[o]=o in t?_(t[o],r):r;return t}function R(e,n,t=[],o=[]){if(e===void 0||n===void 0)return o;if(!p(e)||!p(n))return o.push(t.join(".")),o;for(let r of Object.keys(e))r in n&&R(e[r],n[r],[...t,r],o);return o}function M(e){return p(e)&&("styles"in e||"behavior"in e)}function D(e,n="component"){if(!M(e)||!p(e.styles)||e.behavior!==void 0&&!p(e.behavior)||Object.keys(e).some(o=>!["styles","behavior"].includes(o)))throw new TypeError(`Component ${n} must use the styles/behavior envelope`);let t=R(e.styles,e.behavior,[n]);if(t.length>0)throw new Error(`Component config styles/behavior conflict at ${t.join(", ")}`);return _(e.styles||{},e.behavior||{})}function re(e){if(!p(e))return e;let n=!1,t={};for(let[o,r]of Object.entries(e))t[o]=D(r,o),t[o]!==r&&(n=!0);return n?t:e}j.exports={isPlainObject:p,deepMerge:_,findTreeConflicts:R,isComponentEnvelope:M,toRuntimeComponentConfig:D,toRuntimeComponentsConfig:re}});var T=v((Ge,F)=>{var ie={$id:"https://frontfriend.dev/schemas/components-config.schema.json",type:"object",additionalProperties:{$ref:"#/$defs/componentConfig"},$defs:{componentConfig:{$ref:"#/$defs/componentEnvelope"},styleTree:{anyOf:[{type:"string"},{type:"object",additionalProperties:{$ref:"#/$defs/styleTree"}}]},behaviorTree:{anyOf:[{type:["string","number","boolean","null"]},{type:"array",items:{$ref:"#/$defs/behaviorTree"}},{type:"object",additionalProperties:{$ref:"#/$defs/behaviorTree"}}]},componentEnvelope:{type:"object",additionalProperties:!1,required:["styles"],properties:{styles:{type:"object",additionalProperties:{$ref:"#/$defs/styleTree"}},behavior:{type:"object",additionalProperties:{$ref:"#/$defs/behaviorTree"}}}}}};function ae(e){return typeof e=="string"&&e.trim().length>0}F.exports={componentsConfigSchema:ie,isCSSClassString:ae}});var $={};oe($,{CONFIGURED_COMPONENTS:()=>xe,resolveComponentConfig:()=>Ne});function P(e){return typeof e=="object"&&e!==null||typeof e=="function"}function s(e,n){return P(e)?e[n]:void 0}function i(e,n){let t=P(e)?e:null,o=t?Object.create(t):{},r=(u,d)=>Object.defineProperty(o,u,{value:d,enumerable:!0,writable:!0,configurable:!0});if(t)for(let u of Object.keys(t))r(u,t[u]);for(let u of Object.keys(n))r(u,n[u]);return o}function le(e,n){let t={};for(let o of n){let r=s(e,o);r!==void 0&&(t[o]=r)}return t}function a(...e){return e.find(n=>n!=null)||""}function c(...e){return e.find(Boolean)||{}}function C(e,n,t){return e[n]||le(e,t)}function A(e){return i(e,{default:a(e.default,e.main),outline:a(e.outline,e.tertiary),linkDestructive:a(e.linkDestructive,e.linkdestructive)})}function ue(e){let n=s(e,"variants"),t=c(e.variant,s(n,"variant")),o=c(e.size,s(n,"size")),r=c(e.iconPosition,s(n,"iconPosition")),u=c(e.fullwidth,s(n,"fullwidth")),d=s(e.slots,"icon")||{},B=s(d,"variants"),l=c(d.size,s(B,"size")),X=c(d.color,s(B,"color")),S=H=>{let g=s(r,H);return i(g,{sm:a(s(g,"sm"),s(g,"small")),lg:a(s(g,"lg"),s(g,"large"))})};return i(e,{variant:A(t),size:i(o,{icon:a(o.icon,s(s(r,"default"),"default")),"icon-xs":a(o["icon-xs"],o.xs,o.small,o.sm),"icon-sm":a(o["icon-sm"],o.small,o.sm),"icon-lg":a(o["icon-lg"],o.large,o.lg)}),iconPosition:i(r,{prefix:S("prefix"),suffix:S("suffix"),default:S("default")}),fullwidth:u,slots:i(e.slots,{icon:i(d,{size:i(l,{icon:a(l.icon,l.default),"icon-xs":a(l["icon-xs"],l.xs,l.small,l.sm,l.default),"icon-sm":a(l["icon-sm"],l.sm,l.default),"icon-lg":a(l["icon-lg"],l.lg,l.default)}),color:A(X)})})})}function pe(e){let n=e.variant,t=s(n,"subtle");return i(e,{variant:i(n,{default:a(s(n,"default"),s(n,"main")),outline:a(s(n,"outline"),s(n,"tertiary")),ghost:a(s(n,"ghost"),s(n,"tertiary")),link:a(s(n,"link"),s(n,"tertiary")),subtle:i(t,{default:a(s(t,"default"),s(t,"main"))})})})}function de(e){let n=e.slots,t=s(n,"caption");return i(e,{slots:i(n,{caption:i(t,{overlay:s(t,"overlay")??s(t,"root")})})})}function ce(e,n={}){let t=s(e.slots,"calendar")??n.calendar,o=s(t,"slots"),r=s(o,"range");return i(e,{slots:i(e.slots,{calendar:i(t,{slots:i(o,{range:i(r,{root:s(r,"root")??s(o,"root"),container:s(r,"container")??s(o,"content"),row:s(r,"row")??s(o,"row")})})})})})}function me(e){return i(e,{slots:C(e,"slots",Ce),states:C(e,"states",fe),props:C(e,"props",ge)})}function Se(e){return i(e,{slots:C(e,"slots",ye)})}function Oe(e){return i(e,{slots:C(e,"slots",ve)})}function G(e){return i(e.props,{padding:s(e.props,"padding")||e.padding})}function _e(e){return i(e,{props:G(e)})}function be(e){return i(e,{slots:C(e,"slots",Re),props:G(e)})}function Pe(e){return i(e,{root:e.root,slots:i(e.slots,{track:s(e.slots,"track")})})}function Ne(e,n,...t){if(!Object.prototype.hasOwnProperty.call(b,e))throw new TypeError(`No component configuration policy for "${String(e)}".`);if(n==null)return n;if(!P(n))throw new TypeError("Component config must be an object.");let o=n;return b[e](o,t[0])}var Ce,fe,ge,ye,ve,Re,b,xe,V=te(()=>{Ce=["header","title","description","content","action","footer"],fe=["noContent","outside"],ge=["footerAlign"];ye=["dialog","input","list","empty","group","separator","item","shortcut","combobox"];ve=["addon","button","text","input","textarea"];Re=["horizontal","vertical","container"];b={button:ue,badge:pe,calendar:de,card:me,command:Se,"date-slider":ce,"input-group":Oe,popover:_e,separator:be,spinner:Pe};xe=Object.freeze(Object.keys(b))});var U=v(($e,L)=>{var N=Object.defineProperty,Ie=Object.getOwnPropertyDescriptor,he=Object.getOwnPropertyNames,we=Object.prototype.hasOwnProperty,Be=(e,n)=>{for(var t in n)N(e,t,{get:n[t],enumerable:!0})},ke=(e,n,t,o)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of he(n))!we.call(e,r)&&r!==t&&N(e,r,{get:()=>n[r],enumerable:!(o=Ie(n,r))||o.enumerable});return e},Me=e=>ke(N({},"__esModule",{value:!0}),e),K={};Be(K,{componentConfig:()=>De});L.exports=Me(K);var E=(V(),se($));function De(e,n){let t=e[n];return n==="date-slider"?(0,E.resolveComponentConfig)(n,t,{get calendar(){return e.calendar}}):(0,E.resolveComponentConfig)(n,t)}});var f=O(z(),1),J=O(T(),1),W=O(U(),1),je=typeof window<"u"&&typeof window.document<"u";function x(e){return typeof e!="string"?!1:e.startsWith("__v_")||e==="then"}function w(e=""){let n=new Map;return new Proxy({},{get(t,o){if(o===Symbol.toPrimitive||o==="valueOf")return()=>e;if(o==="toString"||o===Symbol.toStringTag)return()=>e;if(o==="constructor")return Object;if(!x(o))return n.has(o)||n.set(o,w(e)),n.get(o)},has(t,o){return!x(o)},ownKeys(){return[]},getOwnPropertyDescriptor(t,o){if(!x(o))return{enumerable:!0,configurable:!0}}})}var q=new Map;function ze(e){try{let n=e==="__FF_CONFIG__"?process.env.NEXT_PUBLIC_FF_CONFIG:process.env.NEXT_PUBLIC_FF_ICONS;if(!n)return null;let t=q.get(e);if(t?.serialized===n)return t.value;let o=JSON.parse(n);return(0,f.isPlainObject)(o)?(q.set(e,{serialized:n,value:o}),o):null}catch{return null}}function m(e){return e==="__FF_CONFIG__"&&typeof __FF_CONFIG__<"u"?__FF_CONFIG__:e==="__FF_ICONS__"&&typeof __FF_ICONS__<"u"?__FF_ICONS__:typeof globalThis<"u"&&globalThis[e]?globalThis[e]:je&&window[e]?window[e]:ze(e)}function Fe(e,n){return typeof n=="string"?(0,W.componentConfig)(Fe(e),n):!e||typeof e!="object"?w():(0,f.toRuntimeComponentsConfig)(e)}var I=new Map,h=new WeakMap,Ve=new Proxy({},{get(e,n){if(n===Symbol.toPrimitive||n==="valueOf")return()=>"";if(n==="toString"||n===Symbol.toStringTag)return()=>"[object Object]";if(n==="constructor")return Object;let t=m("__FF_CONFIG__");if(t&&n in t){let o=t[n];return h.has(o)||h.set(o,(0,f.toRuntimeComponentConfig)(o,String(n))),h.get(o)}return I.has(n)||I.set(n,w()),I.get(n)},has(){return!0},ownKeys(){return[]},getOwnPropertyDescriptor(){return{enumerable:!0,configurable:!0}}}),Ee=new Proxy({},{get(e,n){if(n===Symbol.toPrimitive||n==="valueOf")return()=>"";if(n==="toString"||n===Symbol.toStringTag)return()=>"[object Object]";if(n==="constructor")return Object;let t=m("__FF_ICONS__");return t&&n in t?t[n]:null},has(e,n){let t=m("__FF_ICONS__");return t?n in t:!1},ownKeys(){let e=m("__FF_ICONS__");return e?Object.keys(e):[]},getOwnPropertyDescriptor(e,n){let t=m("__FF_ICONS__");if(t&&n in t)return{enumerable:!0,configurable:!0,value:t[n]}}});var export_componentsConfigSchema=J.componentsConfigSchema;var export_isCSSClassString=J.isCSSClassString;export{export_componentsConfigSchema as componentsConfigSchema,Ve as config,Fe as ffdc,Ee as iconSet,export_isCSSClassString as isCSSClassString};