getsyntux 0.1.2 → 0.2.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
@@ -1,72 +1,73 @@
1
1
  ![](https://raw.githubusercontent.com/puffinsoft/syntux/HEAD/docs/images/banner.png)
2
2
 
3
3
  <p align="center">
4
- <i>syntux</i> lets you build <b>personalized</b> generative UIs that are <i>secure</i> and <i>deterministic</i>.
4
+ <i>syntux</i> is the generative UI library for the web. It lets you build generative UIs that are <b><i>consistent</i></b> and <b><i>flexible</i></b>.
5
5
  </p>
6
6
 
7
7
  ---
8
- How it works:
9
8
 
10
- ![](https://raw.githubusercontent.com/puffinsoft/syntux/HEAD/docs/images/diagram_code.png)
11
- <br/><br/>
12
- `values` can be anything:
9
+ https://github.com/user-attachments/assets/f968d2c3-3b1e-4fc8-8e72-628f4361359b
13
10
 
14
- ![](https://raw.githubusercontent.com/puffinsoft/syntux/HEAD/docs/images/diagram_ui.png)
11
+ - ⚡ **Streamable** - display UI as you generate.
12
+ - 🎨 **Custom Components** - maintain aesthetics and reusability.
13
+ - 💾 **Cacheable** - reuse generated UIs with new values.
15
14
 
15
+ ⚠️ this library is still in **beta**. All npm versions are **stable**, but the API may change across versions.
16
16
 
17
17
  <h3 align="center" margin="0"><a href="https://github.com/puffinsoft/syntux/wiki">➡️ view documentation</a></h3>
18
18
 
19
19
  ---
20
20
 
21
- Features:
21
+ ### Examples
22
22
 
23
- - 💾 **Cacheable** - generated interfaces <b>can be reused</b> (*) with different values.
24
- - 🎨 **Consistency** - use and restrict custom components for reusability and consistent aesthetics.
25
- - 🔒 **Secure by default** - uses built-in component mapping engine. No `dangerouslySetInnerHTML`.
26
- - 🌐 **Server-sided** - for full SEO support and stronger first load performance.
23
+ Generate a UI based on `valueToDisplay` (can be anything, including arrays):
27
24
 
28
- <sup>* assuming same object structure (type). arrays are fully supported!</sup>
25
+ ```jsx
26
+ import { GeneratedUI } from "@/lib/getsyntux/GeneratedUI";
27
+ import { createAnthropic } from "@ai-sdk/anthropic";
29
28
 
30
- ---
29
+ /* this example uses Claude, but all models are supported! */
30
+ const anthropic = createAnthropic({ apiKey: ... })
31
31
 
32
- ### Examples
32
+ export default function Home(){
33
+ const valueToDisplay = { ... };
34
+ return <GeneratedUI model={anthropic("claude-sonnet-4-5")} value={valueToDisplay} hint="UI should look like..." />
35
+ }
36
+ ```
33
37
 
34
- Personalized analytics dashboard on Next.js:
38
+ Cache generated UI for different `value`s based on a user ID:
35
39
 
36
40
  ```jsx
37
- import { GeneratedPage, GeneratedContent } from 'getsyntux';
38
-
39
- const interest = "marketing";
40
- const statistics = [{ ... }, { ... }, { ... }];
41
-
42
- <GeneratedPage context={`Analytics dashboard. User interest: ${interest}`} schema={
43
- <div>
44
- <Navbar />
45
- <GeneratedContent
46
- value={statistics}
47
- allowedComponents={[ BarChart, LineChart, Histogram ]}
48
- hint="show charts related to user interest first"
49
- />
50
- <Footer />
51
- </div>
52
- } />
41
+ const cache: Map<number, string> = new Map();
42
+ export default function Home(){
43
+ const userID = 10;
44
+ const valueToDisplay = { ... };
45
+ return <GeneratedUI cached={cache.get(userID)} onGenerate={(result) => {
46
+ cache.set(userID, result)
47
+ }} model={anthropic("claude-sonnet-4-5")} value={valueToDisplay} />
48
+ }
53
49
  ```
54
- <sup><i>syntux</i> is tested for Next.js, but should support all React frameworks.</sup>
55
50
 
56
- <h3 align="center" margin="0"><a href="https://github.com/puffinsoft/syntux/wiki">➡️ view documentation</a></h3>
51
+ <sup>Note: <i>syntux</i> is built for Next.js. It likely works on other React frameworks, but isn't guaranteed.</sup>
57
52
 
58
53
  ---
54
+
59
55
  ### Installation
60
56
 
61
- We use the [Vercel AI SDK](https://github.com/vercel/ai) to provide support for all LLM providers.
57
+ In the root of your project:
62
58
 
63
- First, install via npm:
64
59
  ```
65
- npm i ai
66
- npm i getsyntux
60
+ $ npx getsyntux@latest
67
61
  ```
68
62
 
69
- That's not it though! See the [wiki](https://github.com/puffinsoft/syntux/wiki) on how to set it up. It takes less than 5 minutes.
63
+ This will automatically install the required components in the `lib/getsyntux` folder.
64
+
65
+ We use the [Vercel AI SDK](https://github.com/vercel/ai) to provide support for all LLM providers. To install the model providers:
66
+
67
+ ```
68
+ $ npm i ai
69
+ $ npm i @ai-sdk/anthropic (if you're using Claude)
70
+ ```
70
71
 
71
72
  ---
72
73
 
@@ -76,51 +77,21 @@ That's not it though! See the [wiki](https://github.com/puffinsoft/syntux/wiki)
76
77
 
77
78
  ![](https://raw.githubusercontent.com/puffinsoft/syntux/HEAD/docs/images/workflow.png)
78
79
 
79
- ---
80
80
 
81
81
  Generated designs are designed to be *reusable* and *cacheable*.
82
82
 
83
83
  To do this, *syntux* generates a "React Interface Schema" (RIS). It's essentially an Abstract Syntax Tree tailored to the `value` that you pass in. This schema is then hydrated by *syntux* and rendered.
84
84
 
85
- The RIS has built-in support for arrays, and thus can handle inputs of arbitrary lengths, making it cacheable. To get a better understanding, see the [LLM prompt itself](src/prompt.md).
85
+ The RIS has built-in support for arrays, and thus can handle inputs of arbitrary lengths, making it cacheable. To get a better understanding, see the [LLM prompt itself](src/templates/spec.md).
86
86
 
87
87
  \-
88
88
 
89
- <details>
90
- <summary>How does <i>syntux</i> understand how to use components?</summary>
91
-
92
- 👀 **tl:dr**: *syntux* is not designed to understand your codebase. It is only designed to know ***how to use*** your codebase.
93
-
94
- **The LLM never sees your source code.** The result? Better privacy, lower LLM costs, faster generation time.
95
-
96
- ---
97
-
98
- To do this, *syntux* automatically generates documentation (known as *llmContext*) for your components at compilation time.
99
-
100
- We use Babel to scan your code and attach *llmContext* to components (automatically). Additionally, for best results, developers should provide *user context* to reinforce LLM understanding.
101
-
102
- For instance:
103
-
104
- ```js
105
- const Profile = ({ username, imageURL }: { username: string, imageURL: string }) => { /* ... */ }
106
- console.log(Profile.llmContext) // "props: ({ username, imageURL }: { username: string, imageURL: string })"
107
- console.log(Profile.llmName) // "Profile"
108
-
109
- Profile.userContext = "Displays a small user profile"; // add further context
110
- ```
111
-
112
- > **Note**: The name of your components and props matter!
113
- >
114
- > That information is directly sent to the LLM for context on how to incorporate it into the UI.
115
-
116
- </details>
117
-
118
89
  <details>
119
90
  <summary>What about state? Can state be generated?</summary>
120
91
 
121
92
  Non-stateful components should be wrapped in stateful components, then passed to *syntux* to generate.
122
93
 
123
- Dynamic state generation violates the deterministic paradigm of <i>syntux</i>, and is thus not supported by design.
94
+ Dynamic state generation violates the semi-deterministic paradigm of <i>syntux</i>, and is thus not supported by design.
124
95
  </details>
125
96
 
126
97
  <details>
@@ -139,4 +110,4 @@ Profile.userContext = "Displays a small user profile"; // add further context
139
110
 
140
111
  ---
141
112
 
142
- *syntux* is open source software, licensed under the [MIT](LICENSE) license.
113
+ *syntux* is open source software, licensed under the [MIT](LICENSE) license.
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs-extra';
3
+ import path, { dirname } from 'path';
4
+ import { execSync } from 'child_process';
5
+ import prompts from 'prompts';
6
+ import chalk from 'chalk';
7
+ import { fileURLToPath } from 'url';
8
+
9
+ const __filename$1 = fileURLToPath(import.meta.url);
10
+ const __dirname$1 = dirname(__filename$1);
11
+
12
+ function getPackageManager(root) {
13
+ if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';
14
+ if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';
15
+ return 'npm';
16
+ }
17
+
18
+ function getInstallCommand(manager) {
19
+ if (manager === "yarn") return "yarn add getsyntux";
20
+ if (manager === "pnpm") return "pnpm add getsyntux";
21
+ return "npm install getsyntux";
22
+ }
23
+
24
+ const userRoot = process.cwd();
25
+ const packageJsonPath = path.join(userRoot, 'package.json');
26
+
27
+ if (!fs.existsSync(packageJsonPath)) {
28
+ console.log(chalk.magenta('getsyntux') + ': ' + chalk.red('Failed to find package.json. Run this command from your project root.'));
29
+ process.exit(1);
30
+ }
31
+
32
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
33
+ const allDeps = {
34
+ ...packageJson.dependencies,
35
+ ...packageJson.devDependencies
36
+ };
37
+
38
+ if (allDeps['getsyntux']) {
39
+ console.log(chalk.magenta('getsyntux') + `: library has already been installed. Continuing...`);
40
+ } else {
41
+ console.log(chalk.magenta('getsyntux') + `: library not detected in package.json. Please install to continue...`);
42
+ const packageManager = getPackageManager(userRoot);
43
+ const command = getInstallCommand(packageManager);
44
+ const response = await prompts({
45
+ type: 'select',
46
+ name: 'install',
47
+ message: `Run ${command}?`,
48
+ choices: [{ title: 'Yes' }, { title: 'No' }],
49
+ });
50
+
51
+ if (response.install !== 0) {
52
+ console.log(chalk.magenta('getsyntux') + ': installation cancelled.');
53
+ process.exit(0);
54
+ }
55
+
56
+ try {
57
+ execSync(command, { stdio: 'inherit' });
58
+ console.log(chalk.magenta('getsyntux') + ': installed from ' + chalk.green(packageManager) + ' successfully.');
59
+ } catch (error) {
60
+ console.log(chalk.magenta('getsyntux') + ': installation ' + chalk.red('failed') + ' from ' + packageManager + '.');
61
+ process.exit(1);
62
+ }
63
+ }
64
+
65
+ const templateDir = path.resolve(__dirname$1, '../templates');
66
+ const targetDir = path.resolve(process.cwd(), 'lib/getsyntux');
67
+
68
+ if (!fs.existsSync(templateDir)) {
69
+ console.log(chalk.magenta('getsyntux') + ': ' + chalk.red("failed to find template directory. This is not your fault."));
70
+ process.exit(1);
71
+ }
72
+
73
+ console.log(chalk.magenta('getsyntux') + ': generating files...');
74
+
75
+ if(fs.existsSync(targetDir)){
76
+ const files = fs.readdirSync(targetDir);
77
+ if(files.length > 0){
78
+ console.log(chalk.magenta('getsyntux') + `: target directory lib/getsyntux already contains files.`);
79
+ const response = await prompts({
80
+ type: 'select',
81
+ name: 'copy',
82
+ message: `Empty directory?`,
83
+ choices: [{ title: 'Yes' }, { title: 'No' }],
84
+ });
85
+
86
+ if (response.copy !== 0) {
87
+ console.log(chalk.magenta('getsyntux') + ': installation cancelled.');
88
+ process.exit(0);
89
+ }
90
+
91
+ fs.emptyDirSync(targetDir);
92
+ }
93
+ }
94
+
95
+ fs.copySync(templateDir, targetDir, {
96
+ overwrite: true,
97
+ errorOnExist: false
98
+ });
99
+ console.log(chalk.magenta('getsyntux') + ': ' + chalk.green('installation complete.'));
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ import n from"fs-extra";import s,{dirname as m}from"path";import{execSync as p}from"child_process";import r from"prompts";import e from"chalk";import{fileURLToPath as y}from"url";var d=y(import.meta.url),u=m(d);function f(t){return n.existsSync(s.join(t,"yarn.lock"))?"yarn":n.existsSync(s.join(t,"pnpm-lock.yaml"))?"pnpm":"npm"}function x(t){return t==="yarn"?"yarn add getsyntux":t==="pnpm"?"pnpm add getsyntux":"npm install getsyntux"}var l=process.cwd(),c=s.join(l,"package.json");n.existsSync(c)||(console.log(e.magenta("getsyntux")+": "+e.red("Failed to find package.json. Run this command from your project root.")),process.exit(1));var i=JSON.parse(n.readFileSync(c,"utf8")),h={...i.dependencies,...i.devDependencies};if(h.getsyntux)console.log(e.magenta("getsyntux")+": library has already been installed. Continuing...");else{console.log(e.magenta("getsyntux")+": library not detected in package.json. Please install to continue...");let t=f(l),a=x(t);(await r({type:"select",name:"install",message:`Run ${a}?`,choices:[{title:"Yes"},{title:"No"}]})).install!==0&&(console.log(e.magenta("getsyntux")+": installation cancelled."),process.exit(0));try{p(a,{stdio:"inherit"}),console.log(e.magenta("getsyntux")+": installed from "+e.green(t)+" successfully.")}catch{console.log(e.magenta("getsyntux")+": installation "+e.red("failed")+" from "+t+"."),process.exit(1)}}var g=s.resolve(u,"../templates"),o=s.resolve(process.cwd(),"lib/getsyntux");n.existsSync(g)||(console.log(e.magenta("getsyntux")+": "+e.red("failed to find template directory. This is not your fault.")),process.exit(1));console.log(e.magenta("getsyntux")+": generating files...");n.existsSync(o)&&n.readdirSync(o).length>0&&(console.log(e.magenta("getsyntux")+": target directory lib/getsyntux already contains files."),(await r({type:"select",name:"copy",message:"Empty directory?",choices:[{title:"Yes"},{title:"No"}]})).copy!==0&&(console.log(e.magenta("getsyntux")+": installation cancelled."),process.exit(0)),n.emptyDirSync(o));n.copySync(g,o,{overwrite:!0,errorOnExist:!1});console.log(e.magenta("getsyntux")+": "+e.green("installation complete."));
3
+ //# sourceMappingURL=cli.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/bin/cli.mjs"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport fs from 'fs-extra';\r\nimport path, { dirname } from 'path';\r\nimport { execSync } from 'child_process';\r\nimport prompts from 'prompts';\r\nimport chalk from 'chalk';\r\n\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\n\r\nfunction getPackageManager(root) {\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n return 'npm';\r\n}\r\n\r\nfunction getInstallCommand(manager) {\r\n if (manager === \"yarn\") return \"yarn add getsyntux\";\r\n if (manager === \"pnpm\") return \"pnpm add getsyntux\";\r\n return \"npm install getsyntux\";\r\n}\r\n\r\nconst userRoot = process.cwd();\r\nconst packageJsonPath = path.join(userRoot, 'package.json');\r\n\r\nif (!fs.existsSync(packageJsonPath)) {\r\n console.log(chalk.magenta('getsyntux') + ': ' + chalk.red('Failed to find package.json. Run this command from your project root.'));\r\n process.exit(1);\r\n}\r\n\r\nconst packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));\r\nconst allDeps = {\r\n ...packageJson.dependencies,\r\n ...packageJson.devDependencies\r\n};\r\n\r\nif (allDeps['getsyntux']) {\r\n console.log(chalk.magenta('getsyntux') + `: library has already been installed. Continuing...`);\r\n} else {\r\n console.log(chalk.magenta('getsyntux') + `: library not detected in package.json. Please install to continue...`);\r\n const packageManager = getPackageManager(userRoot);\r\n const command = getInstallCommand(packageManager);\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'install',\r\n message: `Run ${command}?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n\r\n if (response.install !== 0) {\r\n console.log(chalk.magenta('getsyntux') + ': installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n try {\r\n execSync(command, { stdio: 'inherit' });\r\n console.log(chalk.magenta('getsyntux') + ': installed from ' + chalk.green(packageManager) + ' successfully.');\r\n } catch (error) {\r\n console.log(chalk.magenta('getsyntux') + ': installation ' + chalk.red('failed') + ' from ' + packageManager + '.');\r\n process.exit(1);\r\n }\r\n}\r\n\r\nconst templateDir = path.resolve(__dirname, '../templates')\r\nconst targetDir = path.resolve(process.cwd(), 'lib/getsyntux');\r\n\r\nif (!fs.existsSync(templateDir)) {\r\n console.log(chalk.magenta('getsyntux') + ': ' + chalk.red(\"failed to find template directory. This is not your fault.\"));\r\n process.exit(1);\r\n}\r\n\r\nconsole.log(chalk.magenta('getsyntux') + ': generating files...');\r\n\r\nif(fs.existsSync(targetDir)){\r\n const files = fs.readdirSync(targetDir);\r\n if(files.length > 0){\r\n console.log(chalk.magenta('getsyntux') + `: target directory lib/getsyntux already contains files.`);\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'copy',\r\n message: `Empty directory?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n \r\n if (response.copy !== 0) {\r\n console.log(chalk.magenta('getsyntux') + ': installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n fs.emptyDirSync(targetDir);\r\n }\r\n}\r\n\r\nfs.copySync(templateDir, targetDir, {\r\n overwrite: true,\r\n errorOnExist: false\r\n})\r\nconsole.log(chalk.magenta('getsyntux') + ': ' + chalk.green('installation complete.'));"],"mappings":";AAEA,OAAOA,MAAQ,WACf,OAAOC,GAAQ,WAAAC,MAAe,OAC9B,OAAS,YAAAC,MAAgB,gBACzB,OAAOC,MAAa,UACpB,OAAOC,MAAW,QAElB,OAAS,iBAAAC,MAAqB,MAE9B,IAAMC,EAAaD,EAAc,YAAY,GAAG,EAC1CE,EAAYN,EAAQK,CAAU,EAEpC,SAASE,EAAkBC,EAAM,CAC7B,OAAIV,EAAG,WAAWC,EAAK,KAAKS,EAAM,WAAW,CAAC,EAAU,OACpDV,EAAG,WAAWC,EAAK,KAAKS,EAAM,gBAAgB,CAAC,EAAU,OACtD,KACX,CAEA,SAASC,EAAkBC,EAAS,CAChC,OAAIA,IAAY,OAAe,qBAC3BA,IAAY,OAAe,qBACxB,uBACX,CAEA,IAAMC,EAAW,QAAQ,IAAI,EACvBC,EAAkBb,EAAK,KAAKY,EAAU,cAAc,EAErDb,EAAG,WAAWc,CAAe,IAC9B,QAAQ,IAAIT,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,IAAI,uEAAuE,CAAC,EAClI,QAAQ,KAAK,CAAC,GAGlB,IAAMU,EAAc,KAAK,MAAMf,EAAG,aAAac,EAAiB,MAAM,CAAC,EACjEE,EAAU,CACZ,GAAGD,EAAY,aACf,GAAGA,EAAY,eACnB,EAEA,GAAIC,EAAQ,UACR,QAAQ,IAAIX,EAAM,QAAQ,WAAW,EAAI,qDAAqD,MAC3F,CACH,QAAQ,IAAIA,EAAM,QAAQ,WAAW,EAAI,uEAAuE,EAChH,IAAMY,EAAiBR,EAAkBI,CAAQ,EAC3CK,EAAUP,EAAkBM,CAAc,GAC/B,MAAMb,EAAQ,CAC3B,KAAM,SACN,KAAM,UACN,QAAS,OAAOc,CAAO,IACvB,QAAS,CAAC,CAAE,MAAO,KAAM,EAAG,CAAE,MAAO,IAAK,CAAC,CAC/C,CAAC,GAEY,UAAY,IACrB,QAAQ,IAAIb,EAAM,QAAQ,WAAW,EAAI,2BAA2B,EACpE,QAAQ,KAAK,CAAC,GAGlB,GAAI,CACAF,EAASe,EAAS,CAAE,MAAO,SAAU,CAAC,EACtC,QAAQ,IAAIb,EAAM,QAAQ,WAAW,EAAI,oBAAsBA,EAAM,MAAMY,CAAc,EAAI,gBAAgB,CACjH,MAAgB,CACZ,QAAQ,IAAIZ,EAAM,QAAQ,WAAW,EAAI,kBAAoBA,EAAM,IAAI,QAAQ,EAAI,SAAWY,EAAiB,GAAG,EAClH,QAAQ,KAAK,CAAC,CAClB,CACJ,CAEA,IAAME,EAAclB,EAAK,QAAQO,EAAW,cAAc,EACpDY,EAAYnB,EAAK,QAAQ,QAAQ,IAAI,EAAG,eAAe,EAExDD,EAAG,WAAWmB,CAAW,IAC1B,QAAQ,IAAId,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,IAAI,4DAA4D,CAAC,EACvH,QAAQ,KAAK,CAAC,GAGlB,QAAQ,IAAIA,EAAM,QAAQ,WAAW,EAAI,uBAAuB,EAE7DL,EAAG,WAAWoB,CAAS,GACRpB,EAAG,YAAYoB,CAAS,EAC7B,OAAS,IACd,QAAQ,IAAIf,EAAM,QAAQ,WAAW,EAAI,0DAA0D,GAClF,MAAMD,EAAQ,CAC3B,KAAM,SACN,KAAM,OACN,QAAS,mBACT,QAAS,CAAC,CAAE,MAAO,KAAM,EAAG,CAAE,MAAO,IAAK,CAAC,CAC/C,CAAC,GAEY,OAAS,IAClB,QAAQ,IAAIC,EAAM,QAAQ,WAAW,EAAI,2BAA2B,EACpE,QAAQ,KAAK,CAAC,GAGlBL,EAAG,aAAaoB,CAAS,GAIjCpB,EAAG,SAASmB,EAAaC,EAAW,CAChC,UAAW,GACX,aAAc,EAClB,CAAC,EACD,QAAQ,IAAIf,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,MAAM,wBAAwB,CAAC","names":["fs","path","dirname","execSync","prompts","chalk","fileURLToPath","__filename","__dirname","getPackageManager","root","getInstallCommand","manager","userRoot","packageJsonPath","packageJson","allDeps","packageManager","command","templateDir","targetDir"]}
@@ -0,0 +1,22 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { StreamableValue } from '@ai-sdk/rsc';
3
+ import react__default, { ComponentType } from 'react';
4
+ import { C as ComponentMap, b as ChildrenMap } from './types-DejIW5JZ.mjs';
5
+
6
+ declare function GeneratedClient({ value, allowedComponents, inputStream }: {
7
+ value: any;
8
+ allowedComponents: Record<string, react__default.ComponentType<any> | string>;
9
+ inputStream: StreamableValue<string>;
10
+ }): react_jsx_runtime.JSX.Element;
11
+
12
+ interface RendererProps {
13
+ id: string;
14
+ componentMap: ComponentMap;
15
+ childrenMap: ChildrenMap;
16
+ allowedComponents: Record<string, ComponentType<any> | string>;
17
+ global: any;
18
+ local: any;
19
+ }
20
+ declare function Renderer(props: RendererProps): react_jsx_runtime.JSX.Element;
21
+
22
+ export { GeneratedClient, Renderer, type RendererProps };
@@ -0,0 +1,3 @@
1
+ "use client";import{readStreamableValue as x}from"@ai-sdk/rsc";import{useEffect as N,useRef as _,useState as R}from"react";import{Fragment as k}from"react";import{Fragment as S,jsx as l,jsxs as v}from"react/jsx-runtime";import{createElement as U}from"react";var b=(t,n)=>n==="$"?t:n.split(".").reduce((e,o)=>e==null?void 0:e[o],t),y=(t,n,e)=>e.startsWith("$item.")?(e=e.slice(6),b(n,e)):e==="$item"?n:b(t,e),C=(t,n,e)=>e&&("$bind"in e?y(t,n,e.$bind):(Object.keys(e).forEach(o=>{let a=e[o];typeof a=="object"&&(e[o]=C(t,n,a))}),e)),M=(t,n,e)=>typeof e=="object"?y(t,n,e.$bind):e,T=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);function d(t){var g;let{id:n,componentMap:e,childrenMap:o,global:a,local:i,allowedComponents:f}=t,r=e[n];if(r.type==="TEXT")return l(S,{children:M(a,i,r.content)});let h=(g=r.props)==null?void 0:g.source;if(r.type==="__ForEach__"&&h){let p=y(a,i,h);if(!Array.isArray(p))return null;let c=o[r.id];return l(S,{children:c==null?void 0:c.map((w,P)=>l(k,{children:p.map((E,$)=>U(d,{...t,id:w,local:E,key:$}))},P))})}let s=f[r.type]||r.type,m=C(a,i,r.props);return typeof s=="string"&&T.has(s)?l(s,{...m}):v(s,{...m,children:[M(a,i,r.content),o[r.id]&&o[r.id].map((p,c)=>l(d,{...t,id:p},c))]})}var u=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(n){this.buffer+=n;let e=this.buffer.split(`
2
+ `);e.length>1&&(e.slice(0,e.length-1).forEach(o=>this.handleLine(o)),this.buffer=e[e.length-1])}handleLine(n){try{let e=JSON.parse(n),{childrenMap:o,componentMap:a}=this.schema;a[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 A,jsx as I}from"react/jsx-runtime";function B({value:t,allowedComponents:n,inputStream:e}){let[o,a]=R(""),[i,f]=R(),r=_(null);return N(()=>{r.current||(r.current=new u),(async()=>{for await(let s of x(e))a(m=>m+s),r.current&&s!==void 0&&(r.current.addDelta(s),f(r.current.schema))})()},[e]),I(A,{children:(i==null?void 0:i.root)&&I(d,{id:i.root.id,componentMap:i.componentMap,childrenMap:i.childrenMap,allowedComponents:n,global:t,local:t})})}export{B as GeneratedClient,d as Renderer};
3
+ //# sourceMappingURL=client.mjs.map
@@ -0,0 +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, { useEffect, useRef, useState } from 'react';\r\nimport { Renderer } from './Renderer';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { UISchema } from '../types';\r\n\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>\r\n}) {\r\n const [message, setMessage] = useState('');\r\n const [schema, setUISchema] = useState<UISchema | null>();\r\n const parser = useRef<ResponseParser | null>(null);\r\n\r\n useEffect(() => {\r\n if (!parser.current) {\r\n parser.current = new ResponseParser();\r\n }\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n setMessage((prev) => prev + delta);\r\n if (parser.current && delta !== undefined) {\r\n parser.current.addDelta(delta);\r\n setUISchema(parser.current.schema);\r\n }\r\n }\r\n };\r\n\r\n parseStream();\r\n }, [inputStream]);\r\n\r\n return (\r\n <>\r\n {schema?.root && <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={value} local={value} />}\r\n </>\r\n )\r\n}\r\n","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, SchemaNode } from '../types';\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\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\nconst resolveProps = (global: any, local: any, props: any) => {\r\n if (!props) return props;\r\n if (\"$bind\" in props) return get(global, local, props.$bind); // $bind may be falsy value\r\n Object.keys(props).forEach((key) => {\r\n const val = props[key];\r\n if (typeof val === \"object\") {\r\n props[key] = resolveProps(global, local, val);\r\n }\r\n })\r\n return props;\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}\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\nconst voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n])\r\n\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents\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);\r\n if(typeof Component === \"string\" && voidElements.has(Component)){\r\n return <Component {...componentProps} />\r\n }\r\n\r\n return <Component {...componentProps}>\r\n {renderContent(global, local, element.content)}\r\n {childrenMap[element.id] && 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 </Component>\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\nexport class ResponseParser {\r\n buffer = \"\";\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\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 }\r\n }\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 finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"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","names":["readStreamableValue","useEffect","useRef","useState","Fragment","jsx","jsxs","createElement","resolvePath","obj","path","acc","curr","get","global","local","resolveProps","props","key","val","renderContent","content","voidElements","Renderer","_a","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","message","setMessage","useState","schema","setUISchema","parser","useRef","useEffect","ResponseParser","delta","readStreamableValue","prev","Renderer"]}
package/dist/index.d.mts CHANGED
@@ -1,62 +1,36 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ComponentType } from 'react';
1
+ import { S as SyntuxComponent$1, U as UISchema } from './types-DejIW5JZ.mjs';
2
+ export { b as ChildrenMap, C as ComponentMap, a as SchemaNode } from './types-DejIW5JZ.mjs';
3
+ import * as react from 'react';
4
+ import { JSX } from 'react';
3
5
  import { LanguageModel } from 'ai';
4
-
5
- interface SchemaNode {
6
- type?: string;
7
- props?: Record<string, any>;
8
- children?: (SchemaNode | string)[];
9
- source?: string;
10
- template?: SchemaNode;
11
- $bind?: string;
12
- }
13
- interface RendererProps {
14
- schema: SchemaNode | string;
15
- global: any;
16
- local?: any;
17
- components: Record<string, ComponentType<any> | string>;
18
- }
19
- declare function Renderer({ schema, global, local, components }: RendererProps): react_jsx_runtime.JSX.Element;
20
-
21
- type SyntuxComponent<P = any> = React.ComponentType<P> & {
22
- userContext?: string;
23
- llmContext?: string;
24
- llmName?: string;
25
- identifier?: Symbol;
26
- };
27
- type SyntuxElement<P = any> = React.ReactElement<P, SyntuxComponent<P>>;
28
-
29
- interface GeneratedPageProps {
30
- context?: string;
31
- schema: SyntuxElement;
32
- onGenerate?: (result: SchemaNode[]) => void;
33
- cached?: (SchemaNode | string)[];
34
- }
6
+ import { SyntuxComponent } from 'getsyntux';
35
7
 
36
8
  interface GeneratedContentProps {
37
- values: any;
38
- components?: (SyntuxComponent<any> | string)[];
9
+ value: any;
10
+ model: LanguageModel;
11
+ components?: (SyntuxComponent | string)[];
39
12
  hint?: string;
13
+ placeholder?: JSX.Element;
14
+ cached?: string;
15
+ onGenerate?: (arg0: string) => void;
40
16
  }
17
+
41
18
  /**
42
- * Section of user interface for LLM to generate.
43
- * @param values The values (object, primitive, or array) to be displayed.
44
- * @param components List of allowed components that LLM can use.
45
- * @param hint Additional custom instructions for the LLM.
19
+ * Converts a list of components into a dictionary for fast-retrieval
20
+ * during rendering.
46
21
  */
47
- declare function GeneratedContent(props: GeneratedContentProps): react_jsx_runtime.JSX.Element;
48
- declare namespace GeneratedContent {
49
- var identifier: typeof SIGNATURE;
50
- }
51
- declare const SIGNATURE: unique symbol;
22
+ declare function generateComponentMap(allowedComponents: (SyntuxComponent$1 | string)[]): Record<string, string | react.ComponentType<any>>;
23
+ /**
24
+ * Creates LLM input in accordance to the spec
25
+ */
26
+ declare function constructInput({ value, components, hint }: GeneratedContentProps): string;
52
27
 
53
- interface SyntuxFactoryConfig {
54
- model: LanguageModel;
28
+ declare class ResponseParser {
29
+ buffer: string;
30
+ schema: UISchema;
31
+ addDelta(delta: string): void;
32
+ handleLine(line: string): void;
33
+ finish(): void;
55
34
  }
56
- declare const createSyntuxFactory: (config: SyntuxFactoryConfig) => {
57
- GeneratedPage: ({ context, schema, cached, onGenerate }: GeneratedPageProps) => Promise<react_jsx_runtime.JSX.Element>;
58
- GeneratedContent: typeof GeneratedContent;
59
- Renderer: typeof Renderer;
60
- };
61
35
 
62
- export { type GeneratedContentProps, type GeneratedPageProps, type SchemaNode, type SyntuxFactoryConfig, createSyntuxFactory };
36
+ export { ResponseParser, SyntuxComponent$1 as SyntuxComponent, UISchema, constructInput, generateComponentMap };