Skip to content

Commit 5cbe16b

Browse files
github-actions[bot]agentfront[bot]frontegg-david
authored
v0.6.2 (#160)
* chore(release): prepare v0.6.2 - Bump synchronized libs to v0.6.2 - Bump independent libs (Codex-analyzed) - Update CHANGELOGs for independent libs - Archive v0.6 docs to docs/live/docs/v/0.6 - Publish draft docs to live (docs/draft → docs/live) - Update docs/live/docs.json versioning Note: updates.mdx will be updated by Codex workflow * docs(codex): update Mintlify docs, CHANGELOG & READMEs [auto] (#162) Co-authored-by: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * fix: update model version to gpt-5.1-codex-mini in documentation workflows * docs(codex): update Mintlify docs, CHANGELOG & READMEs [auto] (#163) Co-authored-by: frontegg-david <69419539+frontegg-david@users.noreply.github.com> * feat: update mcp-from-openapi to version 2.1.1 and enhance version bump script to update dependencies across all packages --------- Co-authored-by: agentfront[bot] <agentfront[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: frontegg-david <69419539+frontegg-david@users.noreply.github.com> Co-authored-by: David Antoon <david@frontegg.com>
1 parent 2fef682 commit 5cbe16b

File tree

25 files changed

+571
-71
lines changed

25 files changed

+571
-71
lines changed

.github/workflows/codex-mintlify-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,7 @@ jobs:
611611
codex-home: ${{ steps.mcp.outputs.codex_home }}
612612
prompt-file: .github/codex/prompts/update-docs.md
613613
output-file: ${{ env.CODEX_OUT }}
614-
model: "gpt-5.1-codex"
614+
model: "gpt-5.1-codex-mini"
615615
sandbox: read-only
616616
safety-strategy: drop-sudo
617617
output-schema-file: .github/codex/codex-output-schema.json

.github/workflows/update-draft-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ jobs:
368368
codex-home: ${{ steps.mcp.outputs.codex_home }}
369369
prompt-file: .github/codex/prompts/update-draft-docs.md
370370
output-file: ${{ env.CODEX_OUT }}
371-
model: "gpt-5.1-codex"
371+
model: "gpt-5.1-codex-mini"
372372
sandbox: read-only
373373
safety-strategy: drop-sudo
374374
output-schema-file: .github/codex/codex-output-schema.json

CHANGELOG.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
1+
## [v0.6.2] - 2025-12-24
2+
3+
### feat
4+
5+
- Add static, dynamic, and hybrid UI build modes plus multi-platform bundling helpers so the same widget can hydrate differently on OpenAI, Claude, or Gemini without duplicate code.
6+
- Auto-enable transport persistence whenever `redis` is configured, wiring session storage without needing a separate `transport.persistence` block.
7+
- Teach `frontmcp build --adapter vercel` to detect npm, pnpm, yarn, or bun lockfiles, set the matching install/build commands, and emit Vercel Build Output API artifacts ready for deployment.
8+
9+
### fix
10+
11+
- Resolve dual-package hazards by lazily requiring `FrontMcpInstance` inside the decorator so runtime imports always reference the same module copy.
12+
- Default primary-auth transport options now reuse `DEFAULT_TRANSPORT_CONFIG`, eliminating drift between schema defaults and runtime behavior.
13+
- Serverless bundling loosens fully-specified import requirements, aliases optional React dependencies, and filters known rspack warnings so builds stay quiet but accurate.
14+
15+
### build
16+
17+
- All synchronized workspaces (sdk, cli, adapters, plugins) now publish dual CommonJS/ESM artifacts with `sideEffects: false` and shared typings for better tree-shaking.
18+
- Independent packages `json-schema-to-zod-v3@1.0.3` and `mcp-from-openapi@2.1.1` match the new export map layout, ensuring adapters and downstream CLIs consume a single source of truth.
19+
20+
### docs
21+
22+
- Published the Build Modes guide plus a new callout on the platforms page to explain when to reach for static, dynamic, or hybrid rendering.
23+
- Refreshed the live updates page with v0.6.2 highlights and links to the independent library releases.
24+
125
## [v0.6.1] - 2025-12-22
226

327
### feat
@@ -91,7 +115,7 @@
91115

92116
### feat
93117

94-
- Publish the standalone `mcp-from-openapi` generator and wire the OpenAPI adapter to it so every tool inherits request mappers, conflict-free schemas, and per-scheme authentication analysis.
118+
- Publish the standalone `mcp-from-openapi` generator and wire the OpenAPI adapter to it so every tool inherits conflict-free params, request mappers, and per-scheme authentication analysis.
95119
- Allow `@Tool` metadata to declare literal primitives, tuple-style arrays, and MCP resources (plus `rawInputSchema`) so clients get typed responses without wrapping outputs in placeholder objects.
96120
- Add a typed MCP error hierarchy and error handler so transports emit traceable IDs, consistent public/internal messages, and FlowControl-aware stop semantics.
97121
- Extract `json-schema-to-zod-v3` with built-in regex guards so adapters and apps can reuse the hardened JSON Schema → Zod converter.
Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
---
2+
title: Build Modes
3+
sidebarTitle: Build Modes
4+
icon: hammer
5+
description: Control how widget data is injected into HTML - static baking, dynamic subscription, or hybrid placeholder injection.
6+
---
7+
8+
## Overview
9+
10+
FrontMCP supports three build modes that control how tool input/output data is injected into the rendered HTML:
11+
12+
| Mode | Description | Best For |
13+
| ----------- | ---------------------------------------------------------------------------- | --------------------------------- |
14+
| **static** | Data baked into HTML at build time | Default, simple widgets |
15+
| **dynamic** | Platform-aware - subscribes to events (OpenAI) or uses placeholders (Claude) | Real-time updates, multi-platform |
16+
| **hybrid** | Pre-built shell with placeholders, replace at runtime | Caching, high-performance |
17+
18+
## Static Mode (Default)
19+
20+
Data is serialized and embedded directly in the HTML at build time.
21+
22+
```typescript
23+
const result = await bundler.bundleToStaticHTML({
24+
source: componentCode,
25+
toolName: 'get_weather',
26+
output: { temperature: 72, unit: 'F' },
27+
buildMode: 'static', // default
28+
});
29+
```
30+
31+
The generated HTML includes the data inline:
32+
33+
```html
34+
<script>
35+
window.__mcpToolOutput = {"temperature":72,"unit":"F"};
36+
window.__frontmcp.setState({
37+
toolName: "get_weather",
38+
output: window.__mcpToolOutput,
39+
loading: false,
40+
error: null
41+
});
42+
</script>
43+
```
44+
45+
**Use when:**
46+
47+
- Widget content doesn't change after initial render
48+
- Simple tool responses
49+
- No caching requirements
50+
51+
## Dynamic Mode
52+
53+
Dynamic mode is **platform-aware** - it behaves differently depending on the target platform:
54+
55+
### OpenAI (ESM)
56+
57+
For OpenAI, dynamic mode subscribes to the `window.openai.canvas.onToolResult` event for real-time updates:
58+
59+
```typescript
60+
const result = await bundler.bundleToStaticHTML({
61+
source: componentCode,
62+
toolName: 'get_weather',
63+
output: { temperature: 72 }, // Optional initial data
64+
buildMode: 'dynamic',
65+
dynamicOptions: {
66+
includeInitialData: true, // Include initial data (default: true)
67+
subscribeToUpdates: true, // Subscribe to events (default: true)
68+
},
69+
});
70+
```
71+
72+
Generated HTML subscribes to OpenAI events:
73+
74+
```html
75+
<script>
76+
// Initial data (if includeInitialData: true)
77+
window.__mcpToolOutput = {"temperature":72};
78+
79+
// Subscribe to updates
80+
if (window.openai?.canvas?.onToolResult) {
81+
window.openai.canvas.onToolResult(function(result) {
82+
window.__mcpToolOutput = result;
83+
window.__frontmcp.setState({ output: result, loading: false });
84+
});
85+
}
86+
</script>
87+
```
88+
89+
### Claude/Non-OpenAI (UMD)
90+
91+
For non-OpenAI platforms (Claude, etc.), dynamic mode uses **placeholders** since they can't subscribe to OpenAI events:
92+
93+
```html
94+
<script>
95+
window.__mcpToolOutput = "__FRONTMCP_OUTPUT_PLACEHOLDER__";
96+
window.__mcpToolInput = "__FRONTMCP_INPUT_PLACEHOLDER__";
97+
98+
// Parse placeholders if replaced with JSON
99+
if (window.__mcpToolOutput !== "__FRONTMCP_OUTPUT_PLACEHOLDER__") {
100+
window.__mcpToolOutput = JSON.parse(window.__mcpToolOutput);
101+
}
102+
</script>
103+
```
104+
105+
Use the `injectHybridDataFull` helper to replace placeholders before sending:
106+
107+
```typescript
108+
import { injectHybridDataFull } from '@frontmcp/uipack/build';
109+
110+
// Build once
111+
const shell = await bundler.bundleToStaticHTML({
112+
source: componentCode,
113+
toolName: 'get_weather',
114+
buildMode: 'dynamic',
115+
platform: 'claude',
116+
});
117+
118+
// Inject data before sending
119+
const html = injectHybridDataFull(
120+
shell.html,
121+
{ location: 'San Francisco' }, // input
122+
{ temperature: 72, unit: 'F' }, // output
123+
);
124+
```
125+
126+
### Dynamic Options
127+
128+
| Option | Type | Default | Description |
129+
| -------------------- | --------- | ------- | ------------------------------------------ |
130+
| `includeInitialData` | `boolean` | `true` | Include initial data in HTML |
131+
| `subscribeToUpdates` | `boolean` | `true` | Subscribe to platform events (OpenAI only) |
132+
133+
**Behavior when `includeInitialData: false`:**
134+
135+
- **OpenAI**: Shows loading state, waits for `onToolResult` event
136+
- **Claude**: Shows loading state if placeholder not replaced, error if expected data missing
137+
138+
## Hybrid Mode
139+
140+
Hybrid mode creates a pre-built shell with placeholders that you replace at runtime. This is ideal for caching - build the shell once, inject different data per request.
141+
142+
```typescript
143+
import { injectHybridData, injectHybridDataFull } from '@frontmcp/uipack/build';
144+
145+
// 1. Build shell ONCE at startup
146+
const shell = await bundler.bundleToStaticHTML({
147+
source: componentCode,
148+
toolName: 'get_weather',
149+
buildMode: 'hybrid',
150+
});
151+
152+
// Cache the shell
153+
const cachedShell = shell.html;
154+
155+
// 2. On each request, just inject data (no rebuild!)
156+
const html1 = injectHybridDataFull(cachedShell, input1, output1);
157+
const html2 = injectHybridDataFull(cachedShell, input2, output2);
158+
```
159+
160+
### Placeholders
161+
162+
| Placeholder | Purpose |
163+
| --------------------------------- | ------------------------------ |
164+
| `__FRONTMCP_OUTPUT_PLACEHOLDER__` | Replaced with tool output JSON |
165+
| `__FRONTMCP_INPUT_PLACEHOLDER__` | Replaced with tool input JSON |
166+
167+
### Helper Functions
168+
169+
```typescript
170+
import {
171+
injectHybridData,
172+
injectHybridDataFull,
173+
isHybridShell,
174+
HYBRID_DATA_PLACEHOLDER,
175+
HYBRID_INPUT_PLACEHOLDER,
176+
} from '@frontmcp/uipack/build';
177+
178+
// Inject output only
179+
const html = injectHybridData(shell, { temperature: 72 });
180+
181+
// Inject both input and output
182+
const html = injectHybridDataFull(shell, input, output);
183+
184+
// Check if HTML is a hybrid shell
185+
if (isHybridShell(html)) {
186+
// Contains placeholders - needs injection
187+
}
188+
```
189+
190+
### Error Handling
191+
192+
If placeholders are not replaced, the widget shows an error:
193+
194+
```javascript
195+
// If placeholder not replaced:
196+
window.__frontmcp.setState({
197+
loading: false,
198+
error: 'No data provided. The output placeholder was not replaced.'
199+
});
200+
```
201+
202+
## Multi-Platform Building
203+
204+
Build for multiple platforms at once with platform-specific behavior:
205+
206+
```typescript
207+
const result = await bundler.bundleForMultiplePlatforms({
208+
source: componentCode,
209+
toolName: 'get_weather',
210+
buildMode: 'dynamic',
211+
platforms: ['openai', 'claude'],
212+
});
213+
214+
// OpenAI HTML: subscribes to onToolResult events
215+
const openaiHtml = result.platforms.openai.html;
216+
217+
// Claude HTML: has placeholders - inject data before sending
218+
const claudeHtml = injectHybridDataFull(
219+
result.platforms.claude.html,
220+
input,
221+
output,
222+
);
223+
```
224+
225+
## Platform Behavior Summary
226+
227+
| Mode | OpenAI (ESM) | Claude (UMD) |
228+
| ----------- | ------------------ | ------------- |
229+
| **static** | Data baked in | Data baked in |
230+
| **dynamic** | Event subscription | Placeholders |
231+
| **hybrid** | Placeholders | Placeholders |
232+
233+
## Best Practices
234+
235+
1. **Use static mode** for simple, one-off widgets
236+
2. **Use dynamic mode** for multi-platform apps that need the same build mode everywhere
237+
3. **Use hybrid mode** for high-performance scenarios where you cache the shell
238+
4. **Always inject data** before sending hybrid/dynamic (Claude) HTML to clients
239+
240+
## TypeScript Types
241+
242+
```typescript
243+
import type { BuildMode, DynamicModeOptions, HybridModeOptions } from '@frontmcp/ui/bundler';
244+
245+
type BuildMode = 'static' | 'dynamic' | 'hybrid';
246+
247+
interface DynamicModeOptions {
248+
includeInitialData?: boolean; // default: true
249+
subscribeToUpdates?: boolean; // default: true
250+
}
251+
252+
interface HybridModeOptions {
253+
placeholder?: string; // default: '__FRONTMCP_OUTPUT_PLACEHOLDER__'
254+
inputPlaceholder?: string; // default: '__FRONTMCP_INPUT_PLACEHOLDER__'
255+
}
256+
```
257+
258+
## API Reference
259+
260+
### `bundleToStaticHTML(options)`
261+
262+
```typescript
263+
interface StaticHTMLOptions {
264+
// ... existing options ...
265+
266+
/** Build mode - controls data injection strategy */
267+
buildMode?: BuildMode;
268+
269+
/** Options for dynamic mode */
270+
dynamicOptions?: DynamicModeOptions;
271+
272+
/** Options for hybrid mode */
273+
hybridOptions?: HybridModeOptions;
274+
}
275+
276+
interface StaticHTMLResult {
277+
// ... existing fields ...
278+
279+
/** The build mode used */
280+
buildMode?: BuildMode;
281+
282+
/** Output placeholder (hybrid mode) */
283+
dataPlaceholder?: string;
284+
285+
/** Input placeholder (hybrid mode) */
286+
inputPlaceholder?: string;
287+
}
288+
```
289+
290+
### `injectHybridData(shell, data, placeholder?)`
291+
292+
Replaces the output placeholder with JSON data.
293+
294+
```typescript
295+
function injectHybridData(
296+
shell: string,
297+
data: unknown,
298+
placeholder?: string, // default: '__FRONTMCP_OUTPUT_PLACEHOLDER__'
299+
): string;
300+
```
301+
302+
### `injectHybridDataFull(shell, input, output)`
303+
304+
Replaces both input and output placeholders.
305+
306+
```typescript
307+
function injectHybridDataFull(
308+
shell: string,
309+
input: unknown,
310+
output: unknown,
311+
): string;
312+
```
313+
314+
### `isHybridShell(html, placeholder?)`
315+
316+
Checks if HTML contains the output placeholder.
317+
318+
```typescript
319+
function isHybridShell(
320+
html: string,
321+
placeholder?: string,
322+
): boolean;
323+
```

0 commit comments

Comments
 (0)