getsyntux 0.6.0 → 0.7.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.
package/README.md CHANGED
@@ -124,6 +124,24 @@ export default function Home(){
124
124
 
125
125
  Make sure components are marked with `"use client"`.
126
126
 
127
+ #### Update value (interactivity)
128
+
129
+ Use the `useSyntux` hook to retrieve and update the `value` inside a custom component:
130
+
131
+ ```jsx
132
+ "use client";
133
+
134
+ export default function CustomComponent(){
135
+ const { value, setValue } = useSyntux();
136
+
137
+ return (
138
+ <button onClick={() => {
139
+ setValue("new value!")
140
+ }}>${value}</button>
141
+ );
142
+ }
143
+ ```
144
+
127
145
  #### Custom actions
128
146
 
129
147
  Perform server actions, attached automatically to component events:
package/dist/client.d.mts CHANGED
@@ -1,17 +1,19 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { StreamableValue } from '@ai-sdk/rsc';
3
+ import * as react from 'react';
3
4
  import react__default, { JSX, ComponentType } from 'react';
4
- import { C as ContextfulAction, b as ComponentMap, c as ChildrenMap } from './types-CtXPasY-.mjs';
5
+ import { C as ContextfulAction, b as ComponentMap, a as ChildrenMap } from './types-B7z31wIq.mjs';
5
6
 
6
7
  /**
7
8
  * Client wrapper for Renderer that handles streaming and parsing with server.
8
9
  */
9
- declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder, actions }: {
10
+ declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder, actions, errorFallback }: {
10
11
  value: any;
11
12
  allowedComponents: Record<string, react__default.ComponentType<any> | string>;
12
13
  inputStream: StreamableValue<string>;
13
14
  placeholder?: JSX.Element;
14
15
  actions?: Record<string, ContextfulAction>;
16
+ errorFallback?: JSX.Element;
15
17
  }): react_jsx_runtime.JSX.Element;
16
18
 
17
19
  interface RendererProps {
@@ -28,4 +30,11 @@ interface RendererProps {
28
30
  */
29
31
  declare function Renderer(props: RendererProps): react_jsx_runtime.JSX.Element;
30
32
 
31
- export { GeneratedClient, Renderer, type RendererProps };
33
+ type SyntuxContextType = {
34
+ value: any;
35
+ setValue: (arg0: any) => void;
36
+ };
37
+ declare const SyntuxContext: react.Context<SyntuxContextType>;
38
+ declare function useSyntux(): SyntuxContextType;
39
+
40
+ export { GeneratedClient, Renderer, type RendererProps, SyntuxContext, type SyntuxContextType, useSyntux };
package/dist/client.mjs CHANGED
@@ -1,3 +1,3 @@
1
- "use client";import{readStreamableValue as J}from"@ai-sdk/rsc";import{useEffect as O,useReducer as U,useRef as V}from"react";import{Fragment as _}from"react";import{Fragment as A,jsx as d}from"react/jsx-runtime";import{createElement as F}from"react";var R=(r,t)=>t==="$"?r:t.split(".").reduce((e,i)=>e==null?void 0:e[i],r),p=(r,t,e)=>e.startsWith("$item.")?(e=e.slice(6),R(t,e)):e==="$item"?t:R(r,e),$=new Set(["dangerouslySetInnerHTML"]),P=(r,t,e,i)=>{if(!e)return e;if("$action"in e){let n=i[e.$action];if(!n)return()=>{};let s=e.args.map(o=>o&&typeof o=="object"&&"$bind"in o?p(r,t,o.$bind):o);return o=>{n.fn(...s)}}if("$bind"in e){let n=p(r,t,e.$bind);return Object.keys(n).forEach(s=>{$.has(s)&&delete n[s]}),n}return Object.keys(e).forEach(n=>{if($.has(n)){delete e[n];return}let s=e[n];typeof s=="object"&&(e[n]=P(r,t,s,i))}),e},x=(r,t,e)=>typeof e=="object"?p(r,t,e.$bind):e;function h(r){var M,S;let{id:t,componentMap:e,childrenMap:i,global:n,local:s,allowedComponents:o,actions:c}=r,a=e[t];if(a.type==="TEXT")return d(A,{children:x(n,s,a.content)});let f=(M=a.props)==null?void 0:M.source;if(a.type==="__ForEach__"&&f){let l=p(n,s,f);if(!Array.isArray(l))return null;let m=i[a.id];return d(A,{children:m==null?void 0:m.map((T,N)=>d(_,{children:l.map((v,L)=>F(h,{...r,id:T,local:v,key:L}))},N))})}let u=o[a.type]||a.type,g=P(n,s,a.props,c),E=x(n,s,a.content),I=((S=i[a.id])==null?void 0:S.map((l,m)=>d(h,{...r,id:l},m)))||[],C=[E,...I].filter(l=>l!=null);return C.length>0?d(u,{...g,children:C}):d(u,{...g})}var y=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(t){this.buffer+=t;let e=this.buffer.split(`
2
- `);return e.length>1?(e.slice(0,e.length-1).forEach(i=>this.handleLine(i)),this.buffer=e[e.length-1],!0):!1}handleLine(t){try{let e=JSON.parse(t),{childrenMap:i,componentMap:n}=this.schema;n[e.id]=e,e.parentId===null?this.schema.root=e:(i[e.parentId]||(i[e.parentId]=[]),i[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};import{Fragment as w,jsx as b}from"react/jsx-runtime";function ee({value:r,allowedComponents:t,inputStream:e,placeholder:i,actions:n}){var a;let[,s]=U(f=>f+1,0),o=V(null);O(()=>{o.current=new y,(async()=>{for await(let u of J(e))o.current&&u!==void 0&&o.current.addDelta(u)&&s()})().then(()=>{o.current.finish(),s()})},[e]);let c=(a=o==null?void 0:o.current)==null?void 0:a.schema;return b(w,{children:c!=null&&c.root?b(h,{id:c.root.id,componentMap:c.componentMap,childrenMap:c.childrenMap,allowedComponents:t,global:r,local:r,actions:n||{}}):b(w,{children:i})})}export{ee as GeneratedClient,h as Renderer};
1
+ "use client";import{readStreamableValue as O}from"@ai-sdk/rsc";import{useEffect as j,useMemo as k,useReducer as D,useRef as G,useState as I}from"react";var S=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(r){this.buffer+=r;let e=this.buffer.split(`
2
+ `);return e.length>1?(e.slice(0,e.length-1).forEach(o=>this.handleLine(o)),this.buffer=e[e.length-1],!0):!1}handleLine(r){try{let e=JSON.parse(r),{childrenMap:o,componentMap:n}=this.schema;n[e.id]=e,e.parentId===null?this.schema.root=e:(o[e.parentId]||(o[e.parentId]=[]),o[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};import{Fragment as U}from"react";import{Fragment as A,jsx as d}from"react/jsx-runtime";import{createElement as X}from"react";var P=(t,r)=>r==="$"?t:r.split(".").reduce((e,o)=>e==null?void 0:e[o],t),b=(t,r,e)=>e.startsWith("$item.")?(e=e.slice(6),P(r,e)):e==="$item"?r:P(t,e),$=new Set(["dangerouslySetInnerHTML"]),T=(t,r,e,o)=>{if(!e)return e;if("$action"in e){let n=o[e.$action];if(!n)return()=>{};let i=e.args.map(s=>s&&typeof s=="object"&&"$bind"in s?b(t,r,s.$bind):s);return s=>{n.fn(...i)}}if("$bind"in e){let n=b(t,r,e.$bind);return Object.keys(n).forEach(i=>{$.has(i)&&delete n[i]}),n}return Object.keys(e).forEach(n=>{if($.has(n)){delete e[n];return}let i=e[n];typeof i=="object"&&(e[n]=T(t,r,i,o))}),e},w=(t,r,e)=>typeof e=="object"?b(t,r,e.$bind):e;function g(t){var f,m;let{id:r,componentMap:e,childrenMap:o,global:n,local:i,allowedComponents:s,actions:M}=t,a=e[r];if(a.type==="TEXT")return d(A,{children:w(n,i,a.content)});let c=(f=a.props)==null?void 0:f.source;if(a.type==="__ForEach__"&&c){let l=b(n,i,c);if(!Array.isArray(l))return null;let p=o[a.id];return d(A,{children:p==null?void 0:p.map((V,N)=>d(U,{children:l.map((J,L)=>X(g,{...t,id:V,local:J,key:L}))},N))})}let h=s[a.type]||a.type,x=T(n,i,a.props,M),u=w(n,i,a.content),R=((m=o[a.id])==null?void 0:m.map((l,p)=>d(g,{...t,id:l},p)))||[],C=[u,...R].filter(l=>l!=null);return C.length>0?d(h,{...x,children:C}):d(h,{...x})}import{createContext as _,useContext as F}from"react";var v=_(null);function Y(){let t=F(v);if(!t)throw new Error("useSyntux must be used inside a GeneratedUI.");return t}import{Fragment as E,jsx as y}from"react/jsx-runtime";function ce({value:t,allowedComponents:r,inputStream:e,placeholder:o,actions:n,errorFallback:i}){var f;let[s,M]=I(t),[,a]=D(m=>m+1,0),c=G(null),[h,x]=I(!1);j(()=>{c.current=new S,(async()=>{for await(let l of O(e))c.current&&l!==void 0&&c.current.addDelta(l)&&a()})().then(()=>{c.current.finish(),a()}).catch(()=>{x(!0)})},[e]);let u=(f=c==null?void 0:c.current)==null?void 0:f.schema,R=k(()=>({value:s,setValue:M}),[s]),C=()=>h&&i?y(E,{children:i}):u!=null&&u.root?y(g,{id:u.root.id,componentMap:u.componentMap,childrenMap:u.childrenMap,allowedComponents:r,global:s,local:s,actions:n||{}}):y(E,{children:o});return y(E,{children:y(v.Provider,{value:R,children:C()})})}export{ce as GeneratedClient,g as Renderer,v as SyntuxContext,Y as useSyntux};
3
3
  //# sourceMappingURL=client.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/client/Renderer.tsx","../src/ResponseParser.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { JSX, useEffect, useReducer, useRef, useState } from 'react';\r\nimport { Renderer } from './Renderer';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { ContextfulAction } from 'src/types';\r\n\r\n/**\r\n * Client wrapper for Renderer that handles streaming and parsing with server.\r\n */\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream,\r\n placeholder,\r\n actions\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>,\r\n placeholder?: JSX.Element,\r\n actions?: Record<string, ContextfulAction>\r\n}) {\r\n const [, forceUpdate] = useReducer(x => x + 1, 0);\r\n const parser = useRef<ResponseParser | null>(null);\r\n\r\n useEffect(() => {\r\n // forcibly create a new one for HMR\r\n parser.current = new ResponseParser();\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n if (parser.current && delta !== undefined) {\r\n if (parser.current.addDelta(delta)) {\r\n forceUpdate();\r\n }\r\n }\r\n }\r\n };\r\n\r\n parseStream().then(() => {\r\n parser.current.finish();\r\n forceUpdate();\r\n });\r\n }, [inputStream]);\r\n\r\n const schema = parser?.current?.schema;\r\n\r\n return (\r\n <>\r\n {schema?.root ?\r\n <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={value} local={value} actions={actions || {}} />\r\n : <>{placeholder}</>}\r\n </>\r\n )\r\n}\r\n","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, ContextfulAction, SchemaNode } from '../types';\r\n\r\n/**\r\n * lightweight implementation of lodash.get\r\n */\r\nconst resolvePath = (obj: any, path: string) => {\r\n if (path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\n/**\r\n * parses binding protocol and performs property lookup w/ scope resolution\r\n */\r\nconst get = (global: any, local: any, path: string) => {\r\n if (path.startsWith(\"$item.\")) {\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if (path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\n\r\nconst blacklistedProps = new Set([\"dangerouslySetInnerHTML\"])\r\n/**\r\n * recursively parses props for bindings, replacing with true values\r\n */\r\nconst resolveProps = (global: any, local: any, props: any, actions: Record<string, ContextfulAction>) => {\r\n if (!props) return props;\r\n if (\"$action\" in props) {\r\n const action = actions[props.$action];\r\n if (!action) return () => { };\r\n\r\n const resolvedArgs = props.args.map((arg: any) => {\r\n if (arg && typeof arg === \"object\" && \"$bind\" in arg) {\r\n return get(global, local, arg.$bind);\r\n } else {\r\n return arg;\r\n }\r\n })\r\n\r\n return (e: any) => {\r\n action.fn(...resolvedArgs)\r\n }\r\n }\r\n\r\n if (\"$bind\" in props) { // $bind may be falsy value\r\n const resolved = get(global, local, props.$bind);\r\n Object.keys(resolved).forEach((key) => {\r\n if(blacklistedProps.has(key)){\r\n delete resolved[key];\r\n }\r\n })\r\n return resolved;\r\n }\r\n\r\n Object.keys(props).forEach((key) => {\r\n if (blacklistedProps.has(key)) {\r\n delete props[key];\r\n return;\r\n }\r\n\r\n const val = props[key];\r\n if (typeof val === \"object\") {\r\n props[key] = resolveProps(global, local, val, actions);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\n/**\r\n * output node.content, with check for $bind\r\n*/\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nexport interface RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n actions: Record<string, ContextfulAction>;\r\n}\r\n\r\n/**\r\n * Renders a UISchema recursively, in accordance to the spec.\r\n */\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents, actions\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props, actions);\r\n\r\n const contentNode = renderContent(global, local, element.content);\r\n const childNodes = childrenMap[element.id]?.map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n }) || []\r\n\r\n const nodesToRender = [contentNode, ...childNodes].filter(node => node !== null && node !== undefined) // 0 is falsy\r\n\r\n if (nodesToRender.length > 0) {\r\n return <Component {...componentProps}>\r\n {nodesToRender}\r\n </Component>\r\n }\r\n\r\n return <Component {...componentProps} />\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"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","names":["readStreamableValue","useEffect","useReducer","useRef","Fragment","jsx","createElement","resolvePath","obj","path","acc","curr","get","global","local","blacklistedProps","resolveProps","props","actions","action","resolvedArgs","arg","e","resolved","key","val","renderContent","content","Renderer","_a","_b","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","contentNode","childNodes","nodesToRender","node","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","placeholder","actions","_a","forceUpdate","useReducer","x","parser","useRef","useEffect","ResponseParser","delta","readStreamableValue","schema","Renderer"]}
1
+ {"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/ResponseParser.ts","../src/client/Renderer.tsx","../src/client/SyntuxContext.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { JSX, useEffect, useMemo, useReducer, useRef, useState } from 'react';\r\nimport { ContextfulAction } from 'src/types';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { Renderer } from './Renderer';\r\nimport { SyntuxContext } from './SyntuxContext';\r\n\r\n/**\r\n * Client wrapper for Renderer that handles streaming and parsing with server.\r\n */\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream,\r\n placeholder,\r\n actions,\r\n errorFallback\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>,\r\n placeholder?: JSX.Element,\r\n actions?: Record<string, ContextfulAction>,\r\n errorFallback?: JSX.Element\r\n}) {\r\n const [statefulValue, setStatefulValue] = useState(value); // stateful because changeable through context\r\n const [, forceUpdate] = useReducer(x => x + 1, 0);\r\n const parser = useRef<ResponseParser | null>(null);\r\n const [errored, setErrored] = useState(false)\r\n\r\n useEffect(() => {\r\n // forcibly create a new one for HMR\r\n parser.current = new ResponseParser();\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n if (parser.current && delta !== undefined) {\r\n if (parser.current.addDelta(delta)) {\r\n forceUpdate();\r\n }\r\n }\r\n }\r\n };\r\n\r\n parseStream().then(() => {\r\n parser.current.finish();\r\n forceUpdate();\r\n }).catch(() => {\r\n setErrored(true)\r\n });\r\n }, [inputStream]);\r\n\r\n const schema = parser?.current?.schema;\r\n\r\n const providerValue = useMemo(() => ({ value: statefulValue, setValue: setStatefulValue }), [statefulValue]);\r\n\r\n const renderContent = () => {\r\n if(errored && errorFallback) return <>{errorFallback}</>\r\n\r\n if(schema?.root){\r\n return <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={statefulValue} local={statefulValue} actions={actions || {}} /> \r\n } else {\r\n return <>{placeholder}</>\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n <SyntuxContext.Provider value={providerValue}>\r\n {renderContent()}\r\n </SyntuxContext.Provider >\r\n </>\r\n )\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * \r\n * @param delta delta from stream.\r\n * @returns true if update is warranted, false otherwise.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, ContextfulAction, SchemaNode } from '../types';\r\n\r\n/**\r\n * lightweight implementation of lodash.get\r\n */\r\nconst resolvePath = (obj: any, path: string) => {\r\n if (path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\n/**\r\n * parses binding protocol and performs property lookup w/ scope resolution\r\n */\r\nconst get = (global: any, local: any, path: string) => {\r\n if (path.startsWith(\"$item.\")) {\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if (path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\n\r\nconst blacklistedProps = new Set([\"dangerouslySetInnerHTML\"])\r\n/**\r\n * recursively parses props for bindings, replacing with true values\r\n */\r\nconst resolveProps = (global: any, local: any, props: any, actions: Record<string, ContextfulAction>) => {\r\n if (!props) return props;\r\n if (\"$action\" in props) {\r\n const action = actions[props.$action];\r\n if (!action) return () => { };\r\n\r\n const resolvedArgs = props.args.map((arg: any) => {\r\n if (arg && typeof arg === \"object\" && \"$bind\" in arg) {\r\n return get(global, local, arg.$bind);\r\n } else {\r\n return arg;\r\n }\r\n })\r\n\r\n return (e: any) => {\r\n action.fn(...resolvedArgs)\r\n }\r\n }\r\n\r\n if (\"$bind\" in props) { // $bind may be falsy value\r\n const resolved = get(global, local, props.$bind);\r\n Object.keys(resolved).forEach((key) => {\r\n if(blacklistedProps.has(key)){\r\n delete resolved[key];\r\n }\r\n })\r\n return resolved;\r\n }\r\n\r\n Object.keys(props).forEach((key) => {\r\n if (blacklistedProps.has(key)) {\r\n delete props[key];\r\n return;\r\n }\r\n\r\n const val = props[key];\r\n if (typeof val === \"object\") {\r\n props[key] = resolveProps(global, local, val, actions);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\n/**\r\n * output node.content, with check for $bind\r\n*/\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nexport interface RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n actions: Record<string, ContextfulAction>;\r\n}\r\n\r\n/**\r\n * Renders a UISchema recursively, in accordance to the spec.\r\n */\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents, actions\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props, actions);\r\n\r\n const contentNode = renderContent(global, local, element.content);\r\n const childNodes = childrenMap[element.id]?.map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n }) || []\r\n\r\n const nodesToRender = [contentNode, ...childNodes].filter(node => node !== null && node !== undefined) // 0 is falsy\r\n\r\n if (nodesToRender.length > 0) {\r\n return <Component {...componentProps}>\r\n {nodesToRender}\r\n </Component>\r\n }\r\n\r\n return <Component {...componentProps} />\r\n}\r\n","import { createContext, useContext } from \"react\";\r\n\r\nexport type SyntuxContextType = {\r\n value: any,\r\n setValue: (arg0: any) => void\r\n}\r\n\r\nexport const SyntuxContext = createContext<SyntuxContextType | null>(null)\r\n\r\nexport function useSyntux(){\r\n const context = useContext(SyntuxContext);\r\n if(!context) throw new Error(\"useSyntux must be used inside a GeneratedUI.\");\r\n return context;\r\n}"],"mappings":"aAEA,OAA0B,uBAAAA,MAA2B,cACrD,OAAqB,aAAAC,EAAW,WAAAC,EAAS,cAAAC,EAAY,UAAAC,EAAQ,YAAAC,MAAgB,QCEtE,IAAMC,EAAN,KAAqB,CACxB,OAAS,GAGT,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAUA,SAASC,EAAe,CACpB,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EACpC,OAAIA,EAAM,OAAS,GACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAC7B,IAEJ,EACX,CAMA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAKA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ,EC3DA,OAAwB,YAAAG,MAAgB,QAsGA,mBAAAA,EAAA,OAAAC,MAAA,oBASkB,wBAAAC,MAAA,QAzG1D,IAAMC,EAAc,CAACC,EAAUC,IACvBA,IAAS,IAAYD,EAClBC,EAAK,MAAM,GAAG,EAAE,OAAO,CAACC,EAAKC,IAASD,GAAA,YAAAA,EAAMC,GAAOH,CAAG,EAM3DI,EAAM,CAACC,EAAaC,EAAYL,IAC9BA,EAAK,WAAW,QAAQ,GACxBA,EAAOA,EAAK,MAAM,CAAC,EACZF,EAAYO,EAAOL,CAAI,GAE1BA,IAAS,QAAgBK,EACtBP,EAAYM,EAAQJ,CAAI,EAKjCM,EAAmB,IAAI,IAAI,CAAC,yBAAyB,CAAC,EAItDC,EAAe,CAACH,EAAaC,EAAYG,EAAYC,IAA8C,CACrG,GAAI,CAACD,EAAO,OAAOA,EACnB,GAAI,YAAaA,EAAO,CACpB,IAAME,EAASD,EAAQD,EAAM,OAAO,EACpC,GAAI,CAACE,EAAQ,MAAO,IAAM,CAAE,EAE5B,IAAMC,EAAeH,EAAM,KAAK,IAAKI,GAC7BA,GAAO,OAAOA,GAAQ,UAAY,UAAWA,EACtCT,EAAIC,EAAQC,EAAOO,EAAI,KAAK,EAE5BA,CAEd,EAED,OAAQC,GAAW,CACfH,EAAO,GAAG,GAAGC,CAAY,CAC7B,CACJ,CAEA,GAAI,UAAWH,EAAO,CAClB,IAAMM,EAAWX,EAAIC,EAAQC,EAAOG,EAAM,KAAK,EAC/C,cAAO,KAAKM,CAAQ,EAAE,QAASC,GAAQ,CAChCT,EAAiB,IAAIS,CAAG,GACvB,OAAOD,EAASC,CAAG,CAE3B,CAAC,EACMD,CACX,CAEA,cAAO,KAAKN,CAAK,EAAE,QAASO,GAAQ,CAChC,GAAIT,EAAiB,IAAIS,CAAG,EAAG,CAC3B,OAAOP,EAAMO,CAAG,EAChB,MACJ,CAEA,IAAMC,EAAMR,EAAMO,CAAG,EACjB,OAAOC,GAAQ,WACfR,EAAMO,CAAG,EAAIR,EAAaH,EAAQC,EAAOW,EAAKP,CAAO,EAE7D,CAAC,EACMD,CACX,EAKMS,EAAgB,CAACb,EAAaC,EAAYa,IACxC,OAAOA,GAAY,SACZf,EAAIC,EAAQC,EAAOa,EAAQ,KAAK,EAEhCA,EAiBR,SAASC,EAASX,EAAsB,CAlG/C,IAAAY,EAAAC,EAmGI,GAAM,CACF,GAAAC,EAAI,aAAAC,EAAc,YAAAC,EAAa,OAAApB,EAAQ,MAAAC,EAAO,kBAAAoB,EAAmB,QAAAhB,CACrE,EAAID,EACEkB,EAAUH,EAAaD,CAAE,EAE/B,GAAII,EAAQ,OAAS,OAAQ,OAAO9B,EAAAD,EAAA,CAAG,SAAAsB,EAAcb,EAAQC,EAAOqB,EAAQ,OAAO,EAAE,EAErF,IAAMC,GAAgBP,EAAAM,EAAQ,QAAR,YAAAN,EAAe,OACrC,GAAIM,EAAQ,OAAS,eAAiBC,EAAe,CACjD,IAAMC,EAAYzB,EAAIC,EAAQC,EAAOsB,CAAa,EAClD,GAAI,CAAC,MAAM,QAAQC,CAAS,EAAG,OAAO,KAEtC,IAAMC,EAAcL,EAAYE,EAAQ,EAAE,EAC1C,OAAO9B,EAAAD,EAAA,CAAG,SAAAkC,GAAA,YAAAA,EAAa,IAAI,CAACC,EAAiBC,IAAkBnC,EAACD,EAAA,CAC3D,SAAAiC,EAAU,IAAI,CAACI,EAAWC,IAAmBpC,EAACsB,EAAA,CAAU,GAAGX,EAAO,GAAIsB,EAAS,MAAOE,EAAM,IAAKC,EAAQ,CAAE,GADlCF,CAE9E,GAAa,CACjB,CAEA,IAAMG,EAAYT,EAAkBC,EAAQ,IAAI,GAAKA,EAAQ,KACvDS,EAAiB5B,EAAaH,EAAQC,EAAOqB,EAAQ,MAAOjB,CAAO,EAEnE2B,EAAcnB,EAAcb,EAAQC,EAAOqB,EAAQ,OAAO,EAC1DW,IAAahB,EAAAG,EAAYE,EAAQ,EAAE,IAAtB,YAAAL,EAAyB,IAAI,CAACS,EAAiBC,IACvDnC,EAACuB,EAAA,CAEH,GAAGX,EACJ,GAAIsB,GAFCC,CAGT,KACE,CAAC,EAEDO,EAAgB,CAACF,EAAa,GAAGC,CAAU,EAAE,OAAOE,GAAQA,GAAS,IAA0B,EAErG,OAAID,EAAc,OAAS,EAChB1C,EAACsC,EAAA,CAAW,GAAGC,EACjB,SAAAG,EACL,EAGG1C,EAACsC,EAAA,CAAW,GAAGC,EAAgB,CAC1C,CC1IA,OAAS,iBAAAK,EAAe,cAAAC,MAAkB,QAOnC,IAAMC,EAAgBF,EAAwC,IAAI,EAElE,SAASG,GAAW,CACvB,IAAMC,EAAUH,EAAWC,CAAa,EACxC,GAAG,CAACE,EAAS,MAAM,IAAI,MAAM,8CAA8C,EAC3E,OAAOA,CACX,CH8CwC,mBAAAC,EAAA,OAAAC,MAAA,oBA/CjC,SAASC,GAAgB,CAC9B,MAAAC,EACA,kBAAAC,EACA,YAAAC,EACA,YAAAC,EACA,QAAAC,EACA,cAAAC,CACF,EAOG,CA1BH,IAAAC,EA2BE,GAAM,CAACC,EAAeC,CAAgB,EAAIC,EAAST,CAAK,EAClD,CAAC,CAAEU,CAAW,EAAIC,EAAWC,GAAKA,EAAI,EAAG,CAAC,EAC1CC,EAASC,EAA8B,IAAI,EAC3C,CAACC,EAASC,CAAU,EAAIP,EAAS,EAAK,EAE5CQ,EAAU,IAAM,CAEdJ,EAAO,QAAU,IAAIK,GAED,SAAY,CAC9B,cAAiBC,KAASC,EAAoBlB,CAAW,EACnDW,EAAO,SAAWM,IAAU,QAC1BN,EAAO,QAAQ,SAASM,CAAK,GAC/BT,EAAY,CAIpB,GAEY,EAAE,KAAK,IAAM,CACvBG,EAAO,QAAQ,OAAO,EACtBH,EAAY,CACd,CAAC,EAAE,MAAM,IAAM,CACbM,EAAW,EAAI,CACjB,CAAC,CACH,EAAG,CAACd,CAAW,CAAC,EAEhB,IAAMmB,GAASf,EAAAO,GAAA,YAAAA,EAAQ,UAAR,YAAAP,EAAiB,OAE1BgB,EAAgBC,EAAQ,KAAO,CAAE,MAAOhB,EAAe,SAAUC,CAAiB,GAAI,CAACD,CAAa,CAAC,EAErGiB,EAAgB,IACjBT,GAAWV,EAAsBP,EAAAD,EAAA,CAAG,SAAAQ,EAAc,EAElDgB,GAAA,MAAAA,EAAQ,KACFvB,EAAC2B,EAAA,CAAS,GAAIJ,EAAO,KAAK,GAAI,aAAcA,EAAO,aAAc,YAAaA,EAAO,YAAa,kBAAmBpB,EAAmB,OAAQM,EAAe,MAAOA,EAAe,QAASH,GAAW,CAAC,EAAG,EAE7MN,EAAAD,EAAA,CAAG,SAAAM,EAAY,EAI1B,OACEL,EAAAD,EAAA,CACE,SAAAC,EAAC4B,EAAc,SAAd,CAAuB,MAAOJ,EAC5B,SAAAE,EAAc,EACjB,EACF,CAEJ","names":["readStreamableValue","useEffect","useMemo","useReducer","useRef","useState","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","createElement","resolvePath","obj","path","acc","curr","get","global","local","blacklistedProps","resolveProps","props","actions","action","resolvedArgs","arg","e","resolved","key","val","renderContent","content","Renderer","_a","_b","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","contentNode","childNodes","nodesToRender","node","createContext","useContext","SyntuxContext","useSyntux","context","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","placeholder","actions","errorFallback","_a","statefulValue","setStatefulValue","useState","forceUpdate","useReducer","x","parser","useRef","errored","setErrored","useEffect","ResponseParser","delta","readStreamableValue","schema","providerValue","useMemo","renderContent","Renderer","SyntuxContext"]}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as SyntuxComponent$1, C as ContextfulAction$1, U as UISchema } from './types-CtXPasY-.mjs';
2
- export { c as ChildrenMap, b as ComponentMap, a as SchemaNode } from './types-CtXPasY-.mjs';
1
+ import { C as ContextfulAction$1, S as SyntuxComponent$1, U as UISchema } from './types-B7z31wIq.mjs';
2
+ export { a as ChildrenMap, b as ComponentMap, c as SchemaNode } from './types-B7z31wIq.mjs';
3
3
  import * as react from 'react';
4
4
  import { JSX } from 'react';
5
5
  import { LanguageModel } from 'ai';
@@ -15,6 +15,8 @@ interface GeneratedContentProps {
15
15
  cached?: string;
16
16
  onGenerate?: (arg0: string) => void;
17
17
  skeletonize?: boolean;
18
+ onError?: (arg0: any) => void;
19
+ errorFallback?: JSX.Element;
18
20
  }
19
21
 
20
22
  /**
@@ -1 +1 @@
1
- {"inputs":{"src/types.ts":{"bytes":683,"imports":[],"format":"esm"},"src/util.ts":{"bytes":3487,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":1865,"imports":[{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":84,"imports":[{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"./ResponseParser"}],"format":"esm"},"src/client/Renderer.tsx":{"bytes":4350,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/GeneratedClient.tsx":{"bytes":1681,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./Renderer"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"../ResponseParser"},{"path":"src/types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/client.ts":{"bytes":92,"imports":[{"path":"src/client/GeneratedClient.tsx","kind":"import-statement","original":"./client/GeneratedClient"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./client/Renderer"}],"format":"esm"},"src/bin/cli_util.mjs":{"bytes":115,"imports":[{"path":"chalk","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/init.mjs":{"bytes":3700,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"},{"path":"url","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/generate.mjs":{"bytes":2933,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"}],"format":"esm"},"src/bin/cli.mjs":{"bytes":482,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"src/bin/commands/init.mjs","kind":"import-statement","original":"./commands/init.mjs"},{"path":"src/bin/commands/generate.mjs","kind":"import-statement","original":"./commands/generate.mjs"}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8268},"dist/index.mjs":{"imports":[],"exports":["ResponseParser","constructInput","create_skeleton","defineTool","generateComponentMap"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/util.ts":{"bytesInOutput":1050},"src/ResponseParser.ts":{"bytesInOutput":485}},"bytes":1647},"dist/client.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":13364},"dist/client.mjs":{"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"exports":["GeneratedClient","Renderer"],"entryPoint":"src/client.ts","inputs":{"src/client/GeneratedClient.tsx":{"bytesInOutput":675},"src/client/Renderer.tsx":{"bytesInOutput":1393},"src/ResponseParser.ts":{"bytesInOutput":485},"src/client.ts":{"bytesInOutput":0}},"bytes":2611},"dist/bin/cli.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":12417},"dist/bin/cli.mjs":{"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"url","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":250},"src/bin/commands/init.mjs":{"bytesInOutput":1851},"src/bin/cli_util.mjs":{"bytesInOutput":78},"src/bin/commands/generate.mjs":{"bytesInOutput":1443}},"bytes":3643}}}
1
+ {"inputs":{"src/types.ts":{"bytes":683,"imports":[],"format":"esm"},"src/util.ts":{"bytes":3487,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":1865,"imports":[{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":84,"imports":[{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"./ResponseParser"}],"format":"esm"},"src/client/Renderer.tsx":{"bytes":4350,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/SyntuxContext.tsx":{"bytes":407,"imports":[{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/GeneratedClient.tsx":{"bytes":2373,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/types","kind":"import-statement","external":true},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"../ResponseParser"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./SyntuxContext"},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/client.ts":{"bytes":133,"imports":[{"path":"src/client/GeneratedClient.tsx","kind":"import-statement","original":"./client/GeneratedClient"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./client/Renderer"},{"path":"src/client/SyntuxContext.tsx","kind":"import-statement","original":"./client/SyntuxContext"}],"format":"esm"},"src/bin/cli_util.mjs":{"bytes":115,"imports":[{"path":"chalk","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/init.mjs":{"bytes":3700,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"},{"path":"url","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/generate.mjs":{"bytes":2933,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"}],"format":"esm"},"src/bin/cli.mjs":{"bytes":482,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"src/bin/commands/init.mjs","kind":"import-statement","original":"./commands/init.mjs"},{"path":"src/bin/commands/generate.mjs","kind":"import-statement","original":"./commands/generate.mjs"}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8268},"dist/index.mjs":{"imports":[],"exports":["ResponseParser","constructInput","create_skeleton","defineTool","generateComponentMap"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/util.ts":{"bytesInOutput":1050},"src/ResponseParser.ts":{"bytesInOutput":485}},"bytes":1647},"dist/client.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":15341},"dist/client.mjs":{"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"exports":["GeneratedClient","Renderer","SyntuxContext","useSyntux"],"entryPoint":"src/client.ts","inputs":{"src/client/GeneratedClient.tsx":{"bytesInOutput":862},"src/ResponseParser.ts":{"bytesInOutput":485},"src/client/Renderer.tsx":{"bytesInOutput":1393},"src/client/SyntuxContext.tsx":{"bytesInOutput":171},"src/client.ts":{"bytesInOutput":0}},"bytes":3003},"dist/bin/cli.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":12417},"dist/bin/cli.mjs":{"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"url","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":250},"src/bin/commands/init.mjs":{"bytesInOutput":1851},"src/bin/cli_util.mjs":{"bytesInOutput":78},"src/bin/commands/generate.mjs":{"bytesInOutput":1443}},"bytes":3643}}}
@@ -9,20 +9,23 @@ import { ContextfulAction, ResponseParser, SyntuxComponent, UISchema, constructI
9
9
  import spec from './spec';
10
10
 
11
11
  export interface GeneratedContentProps {
12
- value: any;
13
- model: LanguageModel;
14
- components?: (SyntuxComponent | string)[];
15
- actions?: Record<string, ContextfulAction>;
16
- hint?: string;
17
- placeholder?: JSX.Element;
18
- cached?: string;
19
- /*
20
- * ^ this is a string for two reasons:
21
- * - it is easier to store
22
- * - it is parsed then mutated at runtime. This avoids unintended side effects.
23
- */
24
- onGenerate?: (arg0: string) => void;
25
- skeletonize?: boolean;
12
+ value: any;
13
+ model: LanguageModel;
14
+ components?: (SyntuxComponent | string)[];
15
+ actions?: Record<string, ContextfulAction>;
16
+ hint?: string;
17
+ placeholder?: JSX.Element;
18
+ cached?: string;
19
+ /*
20
+ * ^ this is a string for two reasons:
21
+ * - it is easier to store
22
+ * - it is parsed then mutated at runtime. This avoids unintended side effects.
23
+ */
24
+ onGenerate?: (arg0: string) => void;
25
+ skeletonize?: boolean;
26
+
27
+ onError?: (arg0: any) => void;
28
+ errorFallback?: JSX.Element;
26
29
  }
27
30
 
28
31
  /**
@@ -36,50 +39,66 @@ export interface GeneratedContentProps {
36
39
  * @param cached Schema returned from onGenerate, used for caching UI
37
40
  * @param onGenerate Callback which accepts a string, to be passed to `cached` to reuse same UI
38
41
  * @param skeletonize Compresses value for large inputs (arrays) or untrusted input
42
+ * @param onError Callback which accepts an error, invoked when necessary. If not provided, runtime error occurs.
43
+ * @param errorFallback An element fallback to show if an error occurs during generation.
39
44
  */
40
45
  export async function GeneratedUI(props: GeneratedContentProps) {
41
46
  const input = constructInput(props);
42
47
 
43
- const { value, model, components, placeholder, cached, onGenerate, actions } = props;
44
-
48
+ const { value, model, components, placeholder, cached, onGenerate, actions, onError, errorFallback } = props;
49
+
45
50
  const allowedComponents = generateComponentMap(components || []);
46
51
 
47
52
  // prerender if cached
48
- if(cached){
53
+ if (cached) {
49
54
  const parser = new ResponseParser();
50
55
  parser.addDelta(cached);
51
56
  parser.finish();
52
57
 
53
58
  const schema: UISchema = parser.schema;
54
59
 
55
- if(schema.root){
60
+ if (schema.root) {
56
61
  return <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap}
57
- allowedComponents={allowedComponents} global={value} local={value} actions={actions || {}}/>
62
+ allowedComponents={allowedComponents} global={value} local={value} actions={actions || {}} />
58
63
  } else {
59
64
  return <></>;
60
65
  }
61
66
  }
62
67
 
63
68
  const stream = createStreamableValue('');
64
-
65
69
  (async () => {
66
70
  let total = "";
71
+ let errored = false;
67
72
 
68
73
  const { textStream } = await streamText({
69
74
  model,
70
75
  system: spec,
71
- prompt: input
76
+ prompt: input,
77
+ onError: (err) => {
78
+ stream.error(err)
79
+ errored = true;
80
+
81
+ if (!onError) {
82
+ if (!errorFallback) {
83
+ throw err;
84
+ }
85
+ } else {
86
+ onError(err)
87
+ }
88
+ }
72
89
  })
73
90
 
74
- for await(const delta of textStream){
91
+ for await (const delta of textStream) {
75
92
  stream.update(delta);
76
93
  total += delta;
77
94
  }
78
95
 
79
- stream.done();
96
+ if (!errored) {
97
+ stream.done();
98
+ }
80
99
 
81
- if(onGenerate) onGenerate(total);
100
+ if (onGenerate) onGenerate(total);
82
101
  })()
83
102
 
84
- return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} placeholder={placeholder} actions={actions} />
103
+ return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} placeholder={placeholder} actions={actions} errorFallback={errorFallback} />
85
104
  }
@@ -26,4 +26,4 @@ type ContextfulAction = {
26
26
  context: string;
27
27
  };
28
28
 
29
- export type { ContextfulAction as C, SyntuxComponent as S, UISchema as U, SchemaNode as a, ComponentMap as b, ChildrenMap as c };
29
+ export type { ContextfulAction as C, SyntuxComponent as S, UISchema as U, ChildrenMap as a, ComponentMap as b, SchemaNode as c };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "getsyntux",
3
- "version": "0.6.0",
4
- "description": "The declarative generative-UI library.",
3
+ "version": "0.7.0",
4
+ "description": "Build generative UIs for the web.",
5
5
  "exports": {
6
6
  ".": {
7
7
  "types": "./dist/index.d.ts",