mirror of
				https://github.com/chartdb/chartdb.git
				synced 2025-11-04 05:53:15 +00:00 
			
		
		
		
	add export AI script functionality
This commit is contained in:
		
				
					committed by
					
						
						Jonathan Fishner
					
				
			
			
				
	
			
			
			
						parent
						
							15404fa113
						
					
				
				
					commit
					e380200a75
				
			@@ -5,6 +5,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<p align="center">
 | 
					<p align="center">
 | 
				
			||||||
  <b>Open-source database diagrams editor</b> <br />
 | 
					  <b>Open-source database diagrams editor</b> <br />
 | 
				
			||||||
 | 
					  <b>No installations • No Database password required.</b> <br />
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<h3 align="center">
 | 
					<h3 align="center">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										643
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										643
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -8,6 +8,7 @@
 | 
				
			|||||||
      "name": "chartdb",
 | 
					      "name": "chartdb",
 | 
				
			||||||
      "version": "0.0.0",
 | 
					      "version": "0.0.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/openai": "^0.0.51",
 | 
				
			||||||
        "@radix-ui/react-accordion": "^1.2.0",
 | 
					        "@radix-ui/react-accordion": "^1.2.0",
 | 
				
			||||||
        "@radix-ui/react-checkbox": "^1.1.1",
 | 
					        "@radix-ui/react-checkbox": "^1.1.1",
 | 
				
			||||||
        "@radix-ui/react-collapsible": "^1.1.0",
 | 
					        "@radix-ui/react-collapsible": "^1.1.0",
 | 
				
			||||||
@@ -27,6 +28,7 @@
 | 
				
			|||||||
        "@radix-ui/react-tooltip": "^1.1.2",
 | 
					        "@radix-ui/react-tooltip": "^1.1.2",
 | 
				
			||||||
        "@uidotdev/usehooks": "^2.4.1",
 | 
					        "@uidotdev/usehooks": "^2.4.1",
 | 
				
			||||||
        "@xyflow/react": "^12.0.4",
 | 
					        "@xyflow/react": "^12.0.4",
 | 
				
			||||||
 | 
					        "ai": "^3.3.14",
 | 
				
			||||||
        "class-variance-authority": "^0.7.0",
 | 
					        "class-variance-authority": "^0.7.0",
 | 
				
			||||||
        "clsx": "^2.1.1",
 | 
					        "clsx": "^2.1.1",
 | 
				
			||||||
        "cmdk": "^1.0.0",
 | 
					        "cmdk": "^1.0.0",
 | 
				
			||||||
@@ -69,6 +71,181 @@
 | 
				
			|||||||
        "vite": "^5.3.4"
 | 
					        "vite": "^5.3.4"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/openai": {
 | 
				
			||||||
 | 
					      "version": "0.0.51",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-0.0.51.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-e+badQnVzAuY0CXThjXZM4IdbztGnntz0Oo44jyklVsWjhJxnpr5m47ALR+0C/Wdakl5oHFGy4CZfiJ9K6ZyVw==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider": "0.0.21",
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "zod": "^3.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/provider": {
 | 
				
			||||||
 | 
					      "version": "0.0.21",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-0.0.21.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-9j95uaPRxwYkzQdkl4XO/MmWWW5c5vcVSXtqvALpD9SMB9fzH46dO3UN4VbOJR2J3Z84CZAqgZu5tNlkptT9qQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "json-schema": "0.4.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/provider-utils": {
 | 
				
			||||||
 | 
					      "version": "1.0.15",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-1.0.15.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-icZqf2kpV8XdSViei4pX9ylYcVn+pk9AnVquJJGjGQGnwZ/5OgShqnFcLYrMjQfQcSVkz0PxdQVsIhZHzlT9Og==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider": "0.0.21",
 | 
				
			||||||
 | 
					        "eventsource-parser": "1.1.2",
 | 
				
			||||||
 | 
					        "nanoid": "3.3.6",
 | 
				
			||||||
 | 
					        "secure-json-parse": "2.7.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "zod": "^3.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "zod": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/provider-utils/node_modules/nanoid": {
 | 
				
			||||||
 | 
					      "version": "3.3.6",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
 | 
				
			||||||
 | 
					      "funding": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "type": "github",
 | 
				
			||||||
 | 
					          "url": "https://github.com/sponsors/ai"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "bin": {
 | 
				
			||||||
 | 
					        "nanoid": "bin/nanoid.cjs"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/react": {
 | 
				
			||||||
 | 
					      "version": "0.0.48",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-0.0.48.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-KfW33Gj5/qDA6RWfJ42al3QsgIA2UO+x0gX1M6Kk6LY4bTFgy7+F4GLmo4eflM/9o2M7fUZrNddoOuJ15vbgZg==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "@ai-sdk/ui-utils": "0.0.35",
 | 
				
			||||||
 | 
					        "swr": "2.2.5"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": "^18 || ^19",
 | 
				
			||||||
 | 
					        "zod": "^3.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "react": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "zod": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/solid": {
 | 
				
			||||||
 | 
					      "version": "0.0.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/solid/-/solid-0.0.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-7pMW6leig8Y05UIL8jy/1dEDTjtfA2WG9qkVMWjnKSKiucT/Z5uOO3zWNHYq8EVwdJJnv+RR8gUASXcZLTh7og==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "@ai-sdk/ui-utils": "0.0.35"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "solid-js": "^1.7.7"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "solid-js": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/svelte": {
 | 
				
			||||||
 | 
					      "version": "0.0.40",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/svelte/-/svelte-0.0.40.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-S62aB2aT7gjrVY2uDhxwZFBg9hl4wNwu+kd31zsowByC/yyZp9MRIMXkDCkj0qQLFXvfUzaUuzk8v9gvuPOFCQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "@ai-sdk/ui-utils": "0.0.35",
 | 
				
			||||||
 | 
					        "sswr": "2.1.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "svelte": "^3.0.0 || ^4.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "svelte": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/ui-utils": {
 | 
				
			||||||
 | 
					      "version": "0.0.35",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/ui-utils/-/ui-utils-0.0.35.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-JZWp5gbH9K0/qmmqv0JFrH97JNMB9dU1xtrR2a8uzRE0wYtNmd3KsM9x3KW/f9OGjxUHzAkrboMvxKv/3uz24w==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider": "0.0.21",
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "json-schema": "0.4.0",
 | 
				
			||||||
 | 
					        "secure-json-parse": "2.7.0",
 | 
				
			||||||
 | 
					        "zod-to-json-schema": "3.22.5"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "zod": "^3.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "zod": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@ai-sdk/vue": {
 | 
				
			||||||
 | 
					      "version": "0.0.40",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@ai-sdk/vue/-/vue-0.0.40.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-01LuQT+Cx2e19fYB4nlMlQhmpJ826S1HfGcB4BY30+/XOJebdHRPPOZ3WV9BytBD7kha/tnngBruiYzegGR+Ug==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "@ai-sdk/ui-utils": "0.0.35",
 | 
				
			||||||
 | 
					        "swrv": "1.0.4"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "vue": "^3.3.4"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "vue": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@alloc/quick-lru": {
 | 
					    "node_modules/@alloc/quick-lru": {
 | 
				
			||||||
      "version": "5.2.0",
 | 
					      "version": "5.2.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
 | 
				
			||||||
@@ -85,7 +262,6 @@
 | 
				
			|||||||
      "version": "2.3.0",
 | 
					      "version": "2.3.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
 | 
					      "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "Apache-2.0",
 | 
					      "license": "Apache-2.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@jridgewell/gen-mapping": "^0.3.5",
 | 
					        "@jridgewell/gen-mapping": "^0.3.5",
 | 
				
			||||||
@@ -264,7 +440,6 @@
 | 
				
			|||||||
      "version": "7.24.8",
 | 
					      "version": "7.24.8",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
 | 
				
			||||||
      "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
 | 
					      "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=6.9.0"
 | 
					        "node": ">=6.9.0"
 | 
				
			||||||
@@ -274,7 +449,6 @@
 | 
				
			|||||||
      "version": "7.24.7",
 | 
					      "version": "7.24.7",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
 | 
				
			||||||
      "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
 | 
					      "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=6.9.0"
 | 
					        "node": ">=6.9.0"
 | 
				
			||||||
@@ -324,7 +498,6 @@
 | 
				
			|||||||
      "version": "7.25.3",
 | 
					      "version": "7.25.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz",
 | 
				
			||||||
      "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
 | 
					      "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@babel/types": "^7.25.2"
 | 
					        "@babel/types": "^7.25.2"
 | 
				
			||||||
@@ -418,7 +591,6 @@
 | 
				
			|||||||
      "version": "7.25.2",
 | 
					      "version": "7.25.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz",
 | 
				
			||||||
      "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
 | 
					      "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@babel/helper-string-parser": "^7.24.8",
 | 
					        "@babel/helper-string-parser": "^7.24.8",
 | 
				
			||||||
@@ -1156,6 +1328,14 @@
 | 
				
			|||||||
        "node": ">= 8"
 | 
					        "node": ">= 8"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@opentelemetry/api": {
 | 
				
			||||||
 | 
					      "version": "1.9.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=8.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@pkgjs/parseargs": {
 | 
					    "node_modules/@pkgjs/parseargs": {
 | 
				
			||||||
      "version": "0.11.0",
 | 
					      "version": "0.11.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
 | 
				
			||||||
@@ -2511,11 +2691,15 @@
 | 
				
			|||||||
        "@types/d3-selection": "*"
 | 
					        "@types/d3-selection": "*"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@types/diff-match-patch": {
 | 
				
			||||||
 | 
					      "version": "1.0.36",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@types/diff-match-patch/-/diff-match-patch-1.0.36.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-xFdR6tkm0MWvBfO8xXCSsinYxHcqkQUlcHeSpMC2ukzOb6lwQAfDmW+Qt0AvlGd8HpsS28qKsB+oPeJn9I39jg=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/estree": {
 | 
					    "node_modules/@types/estree": {
 | 
				
			||||||
      "version": "1.0.5",
 | 
					      "version": "1.0.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
 | 
				
			||||||
      "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
 | 
					      "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@types/hast": {
 | 
					    "node_modules/@types/hast": {
 | 
				
			||||||
@@ -2813,6 +2997,118 @@
 | 
				
			|||||||
        "vite": "^4.2.0 || ^5.0.0"
 | 
					        "vite": "^4.2.0 || ^5.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-core": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@babel/parser": "^7.24.7",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38",
 | 
				
			||||||
 | 
					        "entities": "^4.5.0",
 | 
				
			||||||
 | 
					        "estree-walker": "^2.0.2",
 | 
				
			||||||
 | 
					        "source-map-js": "^1.2.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-core/node_modules/estree-walker": {
 | 
				
			||||||
 | 
					      "version": "2.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
 | 
				
			||||||
 | 
					      "peer": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-dom": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/compiler-core": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-sfc": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@babel/parser": "^7.24.7",
 | 
				
			||||||
 | 
					        "@vue/compiler-core": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/compiler-dom": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/compiler-ssr": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38",
 | 
				
			||||||
 | 
					        "estree-walker": "^2.0.2",
 | 
				
			||||||
 | 
					        "magic-string": "^0.30.10",
 | 
				
			||||||
 | 
					        "postcss": "^8.4.40",
 | 
				
			||||||
 | 
					        "source-map-js": "^1.2.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
 | 
				
			||||||
 | 
					      "version": "2.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
 | 
				
			||||||
 | 
					      "peer": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/compiler-ssr": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/compiler-dom": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/reactivity": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/runtime-core": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/reactivity": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/runtime-dom": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/reactivity": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/runtime-core": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38",
 | 
				
			||||||
 | 
					        "csstype": "^3.1.3"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/server-renderer": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/compiler-ssr": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "vue": "3.4.38"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/shared": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==",
 | 
				
			||||||
 | 
					      "peer": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/@xobotyi/scrollbar-width": {
 | 
					    "node_modules/@xobotyi/scrollbar-width": {
 | 
				
			||||||
      "version": "1.9.5",
 | 
					      "version": "1.9.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz",
 | 
				
			||||||
@@ -2870,6 +3166,71 @@
 | 
				
			|||||||
        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
 | 
					        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/ai": {
 | 
				
			||||||
 | 
					      "version": "3.3.14",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/ai/-/ai-3.3.14.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-GF3CVS1rnOtgN68OQGlT/2quhg/D3sMFwak48OGXeqv4VRcDgGJx3UqSwT7ipFa9BncRqo7TIqDHHji3Doamaw==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ai-sdk/provider": "0.0.21",
 | 
				
			||||||
 | 
					        "@ai-sdk/provider-utils": "1.0.15",
 | 
				
			||||||
 | 
					        "@ai-sdk/react": "0.0.48",
 | 
				
			||||||
 | 
					        "@ai-sdk/solid": "0.0.38",
 | 
				
			||||||
 | 
					        "@ai-sdk/svelte": "0.0.40",
 | 
				
			||||||
 | 
					        "@ai-sdk/ui-utils": "0.0.35",
 | 
				
			||||||
 | 
					        "@ai-sdk/vue": "0.0.40",
 | 
				
			||||||
 | 
					        "@opentelemetry/api": "1.9.0",
 | 
				
			||||||
 | 
					        "eventsource-parser": "1.1.2",
 | 
				
			||||||
 | 
					        "json-schema": "0.4.0",
 | 
				
			||||||
 | 
					        "jsondiffpatch": "0.6.0",
 | 
				
			||||||
 | 
					        "nanoid": "3.3.6",
 | 
				
			||||||
 | 
					        "secure-json-parse": "2.7.0",
 | 
				
			||||||
 | 
					        "zod-to-json-schema": "3.22.5"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=18"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "openai": "^4.42.0",
 | 
				
			||||||
 | 
					        "react": "^18 || ^19",
 | 
				
			||||||
 | 
					        "sswr": "^2.1.0",
 | 
				
			||||||
 | 
					        "svelte": "^3.0.0 || ^4.0.0",
 | 
				
			||||||
 | 
					        "zod": "^3.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "openai": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "react": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "sswr": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "svelte": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "zod": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/ai/node_modules/nanoid": {
 | 
				
			||||||
 | 
					      "version": "3.3.6",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
 | 
				
			||||||
 | 
					      "funding": [
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          "type": "github",
 | 
				
			||||||
 | 
					          "url": "https://github.com/sponsors/ai"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
 | 
					      "bin": {
 | 
				
			||||||
 | 
					        "nanoid": "bin/nanoid.cjs"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/ajv": {
 | 
					    "node_modules/ajv": {
 | 
				
			||||||
      "version": "6.12.6",
 | 
					      "version": "6.12.6",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
 | 
				
			||||||
@@ -3449,6 +3810,11 @@
 | 
				
			|||||||
      "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
 | 
					      "integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/client-only": {
 | 
				
			||||||
 | 
					      "version": "0.0.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/clsx": {
 | 
					    "node_modules/clsx": {
 | 
				
			||||||
      "version": "2.1.1",
 | 
					      "version": "2.1.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
 | 
				
			||||||
@@ -3836,6 +4202,19 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/code-red": {
 | 
				
			||||||
 | 
					      "version": "1.0.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@jridgewell/sourcemap-codec": "^1.4.15",
 | 
				
			||||||
 | 
					        "@types/estree": "^1.0.1",
 | 
				
			||||||
 | 
					        "acorn": "^8.10.0",
 | 
				
			||||||
 | 
					        "estree-walker": "^3.0.3",
 | 
				
			||||||
 | 
					        "periscopic": "^3.1.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/color-convert": {
 | 
					    "node_modules/color-convert": {
 | 
				
			||||||
      "version": "1.9.3",
 | 
					      "version": "1.9.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
 | 
				
			||||||
@@ -4227,6 +4606,15 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/dequal": {
 | 
				
			||||||
 | 
					      "version": "2.0.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=6"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/detect-node-es": {
 | 
					    "node_modules/detect-node-es": {
 | 
				
			||||||
      "version": "1.1.0",
 | 
					      "version": "1.1.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
 | 
				
			||||||
@@ -4245,6 +4633,11 @@
 | 
				
			|||||||
      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
 | 
					      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
 | 
				
			||||||
      "license": "Apache-2.0"
 | 
					      "license": "Apache-2.0"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/diff-match-patch": {
 | 
				
			||||||
 | 
					      "version": "1.0.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/dir-glob": {
 | 
					    "node_modules/dir-glob": {
 | 
				
			||||||
      "version": "3.0.1",
 | 
					      "version": "3.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
 | 
				
			||||||
@@ -4294,6 +4687,18 @@
 | 
				
			|||||||
      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
 | 
					      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/entities": {
 | 
				
			||||||
 | 
					      "version": "4.5.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=0.12"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "url": "https://github.com/fb55/entities?sponsor=1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/error-stack-parser": {
 | 
					    "node_modules/error-stack-parser": {
 | 
				
			||||||
      "version": "2.1.4",
 | 
					      "version": "2.1.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz",
 | 
				
			||||||
@@ -5207,6 +5612,15 @@
 | 
				
			|||||||
        "node": ">=4.0"
 | 
					        "node": ">=4.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/estree-walker": {
 | 
				
			||||||
 | 
					      "version": "3.0.3",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@types/estree": "^1.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/esutils": {
 | 
					    "node_modules/esutils": {
 | 
				
			||||||
      "version": "2.0.3",
 | 
					      "version": "2.0.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
 | 
				
			||||||
@@ -5216,6 +5630,14 @@
 | 
				
			|||||||
        "node": ">=0.10.0"
 | 
					        "node": ">=0.10.0"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/eventsource-parser": {
 | 
				
			||||||
 | 
					      "version": "1.1.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=14.18"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/fast-deep-equal": {
 | 
					    "node_modules/fast-deep-equal": {
 | 
				
			||||||
      "version": "3.1.3",
 | 
					      "version": "3.1.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
 | 
				
			||||||
@@ -6159,6 +6581,15 @@
 | 
				
			|||||||
        "node": ">=8"
 | 
					        "node": ">=8"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/is-reference": {
 | 
				
			||||||
 | 
					      "version": "3.0.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@types/estree": "*"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/is-regex": {
 | 
					    "node_modules/is-regex": {
 | 
				
			||||||
      "version": "1.1.4",
 | 
					      "version": "1.1.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
 | 
				
			||||||
@@ -6383,6 +6814,11 @@
 | 
				
			|||||||
      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
 | 
					      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/json-schema": {
 | 
				
			||||||
 | 
					      "version": "0.4.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/json-schema-traverse": {
 | 
					    "node_modules/json-schema-traverse": {
 | 
				
			||||||
      "version": "0.4.1",
 | 
					      "version": "0.4.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
 | 
				
			||||||
@@ -6408,6 +6844,33 @@
 | 
				
			|||||||
        "node": ">=6"
 | 
					        "node": ">=6"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/jsondiffpatch": {
 | 
				
			||||||
 | 
					      "version": "0.6.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/jsondiffpatch/-/jsondiffpatch-0.6.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-3QItJOXp2AP1uv7waBkao5nCvhEv+QmJAd38Ybq7wNI74Q+BBmnLn4EDKz6yI9xGAIQoUF87qHt+kc1IVxB4zQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@types/diff-match-patch": "^1.0.36",
 | 
				
			||||||
 | 
					        "chalk": "^5.3.0",
 | 
				
			||||||
 | 
					        "diff-match-patch": "^1.0.5"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "bin": {
 | 
				
			||||||
 | 
					        "jsondiffpatch": "bin/jsondiffpatch.js"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": "^18.0.0 || >=20.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/jsondiffpatch/node_modules/chalk": {
 | 
				
			||||||
 | 
					      "version": "5.3.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": "^12.17.0 || ^14.13 || >=16.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "url": "https://github.com/chalk/chalk?sponsor=1"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/jsx-ast-utils": {
 | 
					    "node_modules/jsx-ast-utils": {
 | 
				
			||||||
      "version": "3.3.5",
 | 
					      "version": "3.3.5",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
 | 
				
			||||||
@@ -6481,6 +6944,12 @@
 | 
				
			|||||||
      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
 | 
					      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/locate-character": {
 | 
				
			||||||
 | 
					      "version": "3.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
 | 
				
			||||||
 | 
					      "peer": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/locate-path": {
 | 
					    "node_modules/locate-path": {
 | 
				
			||||||
      "version": "6.0.0",
 | 
					      "version": "6.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
 | 
				
			||||||
@@ -6547,6 +7016,15 @@
 | 
				
			|||||||
        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
 | 
					        "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/magic-string": {
 | 
				
			||||||
 | 
					      "version": "0.30.11",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@jridgewell/sourcemap-codec": "^1.5.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/mdn-data": {
 | 
					    "node_modules/mdn-data": {
 | 
				
			||||||
      "version": "2.0.14",
 | 
					      "version": "2.0.14",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
 | 
				
			||||||
@@ -6988,6 +7466,17 @@
 | 
				
			|||||||
        "node": ">=8"
 | 
					        "node": ">=8"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/periscopic": {
 | 
				
			||||||
 | 
					      "version": "3.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@types/estree": "^1.0.0",
 | 
				
			||||||
 | 
					        "estree-walker": "^3.0.0",
 | 
				
			||||||
 | 
					        "is-reference": "^3.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/picocolors": {
 | 
					    "node_modules/picocolors": {
 | 
				
			||||||
      "version": "1.0.1",
 | 
					      "version": "1.0.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
 | 
				
			||||||
@@ -7803,6 +8292,11 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/secure-json-parse": {
 | 
				
			||||||
 | 
					      "version": "2.7.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/semver": {
 | 
					    "node_modules/semver": {
 | 
				
			||||||
      "version": "7.6.3",
 | 
					      "version": "7.6.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
 | 
				
			||||||
@@ -7950,6 +8444,17 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/wooorm"
 | 
					        "url": "https://github.com/sponsors/wooorm"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/sswr": {
 | 
				
			||||||
 | 
					      "version": "2.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/sswr/-/sswr-2.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-Cqc355SYlTAaUt8iDPaC/4DPPXK925PePLMxyBKuWd5kKc5mwsG3nT9+Mq2tyguL5s7b4Jg+IRMpTRsNTAfpSQ==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "swrev": "^4.0.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "svelte": "^4.0.0 || ^5.0.0-next.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/stack-generator": {
 | 
					    "node_modules/stack-generator": {
 | 
				
			||||||
      "version": "2.0.10",
 | 
					      "version": "2.0.10",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/stack-generator/-/stack-generator-2.0.10.tgz",
 | 
				
			||||||
@@ -8370,6 +8875,93 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/ljharb"
 | 
					        "url": "https://github.com/sponsors/ljharb"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte": {
 | 
				
			||||||
 | 
					      "version": "4.2.18",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.18.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@ampproject/remapping": "^2.2.1",
 | 
				
			||||||
 | 
					        "@jridgewell/sourcemap-codec": "^1.4.15",
 | 
				
			||||||
 | 
					        "@jridgewell/trace-mapping": "^0.3.18",
 | 
				
			||||||
 | 
					        "@types/estree": "^1.0.1",
 | 
				
			||||||
 | 
					        "acorn": "^8.9.0",
 | 
				
			||||||
 | 
					        "aria-query": "^5.3.0",
 | 
				
			||||||
 | 
					        "axobject-query": "^4.0.0",
 | 
				
			||||||
 | 
					        "code-red": "^1.0.3",
 | 
				
			||||||
 | 
					        "css-tree": "^2.3.1",
 | 
				
			||||||
 | 
					        "estree-walker": "^3.0.3",
 | 
				
			||||||
 | 
					        "is-reference": "^3.0.1",
 | 
				
			||||||
 | 
					        "locate-character": "^3.0.0",
 | 
				
			||||||
 | 
					        "magic-string": "^0.30.4",
 | 
				
			||||||
 | 
					        "periscopic": "^3.1.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=16"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte/node_modules/aria-query": {
 | 
				
			||||||
 | 
					      "version": "5.3.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "dequal": "^2.0.3"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte/node_modules/axobject-query": {
 | 
				
			||||||
 | 
					      "version": "4.1.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">= 0.4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte/node_modules/css-tree": {
 | 
				
			||||||
 | 
					      "version": "2.3.1",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "mdn-data": "2.0.30",
 | 
				
			||||||
 | 
					        "source-map-js": "^1.0.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/svelte/node_modules/mdn-data": {
 | 
				
			||||||
 | 
					      "version": "2.0.30",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
 | 
				
			||||||
 | 
					      "peer": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/swr": {
 | 
				
			||||||
 | 
					      "version": "2.2.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/swr/-/swr-2.2.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-QtxqyclFeAsxEUeZIYmsaQ0UjimSq1RZ9Un7I68/0ClKK/U3LoyQunwkQfJZr2fc22DfIXLNDc2wFyTEikCUpg==",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "client-only": "^0.0.1",
 | 
				
			||||||
 | 
					        "use-sync-external-store": "^1.2.0"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "react": "^16.11.0 || ^17.0.0 || ^18.0.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/swrev": {
 | 
				
			||||||
 | 
					      "version": "4.0.0",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/swrev/-/swrev-4.0.0.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-LqVcOHSB4cPGgitD1riJ1Hh4vdmITOp+BkmfmXRh4hSF/t7EnS4iD+SOTmq7w5pPm/SiPeto4ADbKS6dHUDWFA=="
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/swrv": {
 | 
				
			||||||
 | 
					      "version": "1.0.4",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/swrv/-/swrv-1.0.4.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-zjEkcP8Ywmj+xOJW3lIT65ciY/4AL4e/Or7Gj0MzU3zBJNMdJiT8geVZhINavnlHRMMCcJLHhraLTAiDOTmQ9g==",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "vue": ">=3.2.26 < 4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/synckit": {
 | 
					    "node_modules/synckit": {
 | 
				
			||||||
      "version": "0.9.1",
 | 
					      "version": "0.9.1",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz",
 | 
				
			||||||
@@ -8501,7 +9093,6 @@
 | 
				
			|||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
 | 
				
			||||||
      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
 | 
					      "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
 | 
				
			||||||
      "dev": true,
 | 
					 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=4"
 | 
					        "node": ">=4"
 | 
				
			||||||
@@ -8865,6 +9456,27 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/vue": {
 | 
				
			||||||
 | 
					      "version": "3.4.38",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@vue/compiler-dom": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/compiler-sfc": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/runtime-dom": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/server-renderer": "3.4.38",
 | 
				
			||||||
 | 
					        "@vue/shared": "3.4.38"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "typescript": "*"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "typescript": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/which": {
 | 
					    "node_modules/which": {
 | 
				
			||||||
      "version": "2.0.2",
 | 
					      "version": "2.0.2",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 | 
				
			||||||
@@ -9143,6 +9755,23 @@
 | 
				
			|||||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
					        "url": "https://github.com/sponsors/sindresorhus"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/zod": {
 | 
				
			||||||
 | 
					      "version": "3.23.8",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
 | 
				
			||||||
 | 
					      "peer": true,
 | 
				
			||||||
 | 
					      "funding": {
 | 
				
			||||||
 | 
					        "url": "https://github.com/sponsors/colinhacks"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/zod-to-json-schema": {
 | 
				
			||||||
 | 
					      "version": "3.22.5",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.22.5.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-+akaPo6a0zpVCCseDed504KBJUQpEW5QZw7RMneNmKw+fGaML1Z9tUNLnHHAC8x6dzVRO1eB2oEMyZRnuBZg7Q==",
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "zod": "^3.22.4"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/zustand": {
 | 
					    "node_modules/zustand": {
 | 
				
			||||||
      "version": "4.5.4",
 | 
					      "version": "4.5.4",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.4.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.4.tgz",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@
 | 
				
			|||||||
    "preview": "vite preview"
 | 
					    "preview": "vite preview"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@ai-sdk/openai": "^0.0.51",
 | 
				
			||||||
    "@radix-ui/react-accordion": "^1.2.0",
 | 
					    "@radix-ui/react-accordion": "^1.2.0",
 | 
				
			||||||
    "@radix-ui/react-checkbox": "^1.1.1",
 | 
					    "@radix-ui/react-checkbox": "^1.1.1",
 | 
				
			||||||
    "@radix-ui/react-collapsible": "^1.1.0",
 | 
					    "@radix-ui/react-collapsible": "^1.1.0",
 | 
				
			||||||
@@ -30,6 +31,7 @@
 | 
				
			|||||||
    "@radix-ui/react-tooltip": "^1.1.2",
 | 
					    "@radix-ui/react-tooltip": "^1.1.2",
 | 
				
			||||||
    "@uidotdev/usehooks": "^2.4.1",
 | 
					    "@uidotdev/usehooks": "^2.4.1",
 | 
				
			||||||
    "@xyflow/react": "^12.0.4",
 | 
					    "@xyflow/react": "^12.0.4",
 | 
				
			||||||
 | 
					    "ai": "^3.3.14",
 | 
				
			||||||
    "class-variance-authority": "^0.7.0",
 | 
					    "class-variance-authority": "^0.7.0",
 | 
				
			||||||
    "clsx": "^2.1.1",
 | 
					    "clsx": "^2.1.1",
 | 
				
			||||||
    "cmdk": "^1.0.0",
 | 
					    "cmdk": "^1.0.0",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
import React, { useCallback, useMemo, useState } from 'react';
 | 
					import React, { useCallback, useMemo, useState } from 'react';
 | 
				
			||||||
import { DBTable } from '@/lib/domain/db-table';
 | 
					import { DBTable } from '@/lib/domain/db-table';
 | 
				
			||||||
import { generateId, randomHSLA } from '@/lib/utils';
 | 
					import { generateId } from '@/lib/utils';
 | 
				
			||||||
 | 
					import { randomColor } from '@/lib/colors';
 | 
				
			||||||
import { ChartDBContext, chartDBContext } from './chartdb-context';
 | 
					import { ChartDBContext, chartDBContext } from './chartdb-context';
 | 
				
			||||||
import { DatabaseType } from '@/lib/domain/database-type';
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
import { DBField } from '@/lib/domain/db-field';
 | 
					import { DBField } from '@/lib/domain/db-field';
 | 
				
			||||||
@@ -151,7 +152,7 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			|||||||
                },
 | 
					                },
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            indexes: [],
 | 
					            indexes: [],
 | 
				
			||||||
            color: randomHSLA(),
 | 
					            color: randomColor(),
 | 
				
			||||||
            createdAt: Date.now(),
 | 
					            createdAt: Date.now(),
 | 
				
			||||||
            isView: false,
 | 
					            isView: false,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
@@ -718,11 +719,18 @@ export const ChartDBProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			|||||||
                sourceFieldId,
 | 
					                sourceFieldId,
 | 
				
			||||||
                targetFieldId,
 | 
					                targetFieldId,
 | 
				
			||||||
            }) => {
 | 
					            }) => {
 | 
				
			||||||
                const sourceTableName = getTable(sourceTableId)?.name ?? '';
 | 
					                const sourceTable = getTable(sourceTableId);
 | 
				
			||||||
                const targetTableName = getTable(targetTableId)?.name ?? '';
 | 
					                const sourceTableName = sourceTable?.name ?? '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const sourceField = sourceTable?.fields.find(
 | 
				
			||||||
 | 
					                    (field: { id: string }) => field.id === sourceFieldId
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                const sourceFieldName = sourceField?.name ?? '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const relationship: DBRelationship = {
 | 
					                const relationship: DBRelationship = {
 | 
				
			||||||
                    id: generateId(),
 | 
					                    id: generateId(),
 | 
				
			||||||
                    name: `${sourceTableName}_${targetTableName}_fk`,
 | 
					                    name: `${sourceTableName}_${sourceFieldName}_fk`,
 | 
				
			||||||
                    sourceTableId,
 | 
					                    sourceTableId,
 | 
				
			||||||
                    targetTableId,
 | 
					                    targetTableId,
 | 
				
			||||||
                    sourceFieldId,
 | 
					                    sourceFieldId,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
import { createContext } from 'react';
 | 
					import { createContext } from 'react';
 | 
				
			||||||
import { emptyFn } from '@/lib/utils';
 | 
					import { emptyFn } from '@/lib/utils';
 | 
				
			||||||
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface DialogContext {
 | 
					export interface DialogContext {
 | 
				
			||||||
    // Create diagram dialog
 | 
					    // Create diagram dialog
 | 
				
			||||||
@@ -9,6 +10,10 @@ export interface DialogContext {
 | 
				
			|||||||
    // Open diagram dialog
 | 
					    // Open diagram dialog
 | 
				
			||||||
    openOpenDiagramDialog: () => void;
 | 
					    openOpenDiagramDialog: () => void;
 | 
				
			||||||
    closeOpenDiagramDialog: () => void;
 | 
					    closeOpenDiagramDialog: () => void;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Export SQL dialog
 | 
				
			||||||
 | 
					    openExportSQLDialog: (params: { targetDatabaseType: DatabaseType }) => void;
 | 
				
			||||||
 | 
					    closeExportSQLDialog: () => void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dialogContext = createContext<DialogContext>({
 | 
					export const dialogContext = createContext<DialogContext>({
 | 
				
			||||||
@@ -16,4 +21,6 @@ export const dialogContext = createContext<DialogContext>({
 | 
				
			|||||||
    closeCreateDiagramDialog: emptyFn,
 | 
					    closeCreateDiagramDialog: emptyFn,
 | 
				
			||||||
    openOpenDiagramDialog: emptyFn,
 | 
					    openOpenDiagramDialog: emptyFn,
 | 
				
			||||||
    closeOpenDiagramDialog: emptyFn,
 | 
					    closeOpenDiagramDialog: emptyFn,
 | 
				
			||||||
 | 
					    openExportSQLDialog: emptyFn,
 | 
				
			||||||
 | 
					    closeExportSQLDialog: emptyFn,
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,28 @@
 | 
				
			|||||||
import React, { useState } from 'react';
 | 
					import React, { useCallback, useState } from 'react';
 | 
				
			||||||
import { dialogContext } from './dialog-context';
 | 
					import { DialogContext, dialogContext } from './dialog-context';
 | 
				
			||||||
import { CreateDiagramDialog } from '@/dialogs/create-diagram-dialog/create-diagram-dialog';
 | 
					import { CreateDiagramDialog } from '@/dialogs/create-diagram-dialog/create-diagram-dialog';
 | 
				
			||||||
import { OpenDiagramDialog } from '@/dialogs/open-diagram-dialog/open-diagram-dialog';
 | 
					import { OpenDiagramDialog } from '@/dialogs/open-diagram-dialog/open-diagram-dialog';
 | 
				
			||||||
 | 
					import { ExportSQLDialog } from '@/dialogs/export-sql-dialog/export-sql-dialog';
 | 
				
			||||||
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
					export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			||||||
    children,
 | 
					    children,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const [openNewDiagramDialog, setOpenNewDiagramDialog] = useState(false);
 | 
					    const [openNewDiagramDialog, setOpenNewDiagramDialog] = useState(false);
 | 
				
			||||||
    const [openOpenDiagramDialog, setOpenOpenDiagramDialog] = useState(false);
 | 
					    const [openOpenDiagramDialog, setOpenOpenDiagramDialog] = useState(false);
 | 
				
			||||||
 | 
					    const [openExportSQLDialog, setOpenExportSQLDialog] = useState(false);
 | 
				
			||||||
 | 
					    const [openExportSQLDialogParams, setOpenExportSQLDialogParams] = useState<{
 | 
				
			||||||
 | 
					        targetDatabaseType: DatabaseType;
 | 
				
			||||||
 | 
					    }>({ targetDatabaseType: DatabaseType.GENERIC });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const openExportSQLDialogHandler: DialogContext['openExportSQLDialog'] =
 | 
				
			||||||
 | 
					        useCallback(
 | 
				
			||||||
 | 
					            ({ targetDatabaseType }) => {
 | 
				
			||||||
 | 
					                setOpenExportSQLDialog(true);
 | 
				
			||||||
 | 
					                setOpenExportSQLDialogParams({ targetDatabaseType });
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            [setOpenExportSQLDialog]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <dialogContext.Provider
 | 
					        <dialogContext.Provider
 | 
				
			||||||
@@ -16,11 +31,17 @@ export const DialogProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			|||||||
                closeCreateDiagramDialog: () => setOpenNewDiagramDialog(false),
 | 
					                closeCreateDiagramDialog: () => setOpenNewDiagramDialog(false),
 | 
				
			||||||
                openOpenDiagramDialog: () => setOpenOpenDiagramDialog(true),
 | 
					                openOpenDiagramDialog: () => setOpenOpenDiagramDialog(true),
 | 
				
			||||||
                closeOpenDiagramDialog: () => setOpenOpenDiagramDialog(false),
 | 
					                closeOpenDiagramDialog: () => setOpenOpenDiagramDialog(false),
 | 
				
			||||||
 | 
					                openExportSQLDialog: openExportSQLDialogHandler,
 | 
				
			||||||
 | 
					                closeExportSQLDialog: () => setOpenExportSQLDialog(false),
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            {children}
 | 
					            {children}
 | 
				
			||||||
            <CreateDiagramDialog dialog={{ open: openNewDiagramDialog }} />
 | 
					            <CreateDiagramDialog dialog={{ open: openNewDiagramDialog }} />
 | 
				
			||||||
            <OpenDiagramDialog dialog={{ open: openOpenDiagramDialog }} />
 | 
					            <OpenDiagramDialog dialog={{ open: openOpenDiagramDialog }} />
 | 
				
			||||||
 | 
					            <ExportSQLDialog
 | 
				
			||||||
 | 
					                dialog={{ open: openExportSQLDialog }}
 | 
				
			||||||
 | 
					                {...openExportSQLDialogParams}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
        </dialogContext.Provider>
 | 
					        </dialogContext.Provider>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,10 @@ export interface StorageContext {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Diagram operations
 | 
					    // Diagram operations
 | 
				
			||||||
    addDiagram: (params: { diagram: Diagram }) => Promise<void>;
 | 
					    addDiagram: (params: { diagram: Diagram }) => Promise<void>;
 | 
				
			||||||
    listDiagrams: () => Promise<Diagram[]>;
 | 
					    listDiagrams: (options?: {
 | 
				
			||||||
 | 
					        includeTables?: boolean;
 | 
				
			||||||
 | 
					        includeRelationships?: boolean;
 | 
				
			||||||
 | 
					    }) => Promise<Diagram[]>;
 | 
				
			||||||
    getDiagram: (
 | 
					    getDiagram: (
 | 
				
			||||||
        id: string,
 | 
					        id: string,
 | 
				
			||||||
        options?: {
 | 
					        options?: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -92,10 +92,33 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			|||||||
        await Promise.all(promises);
 | 
					        await Promise.all(promises);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const listDiagrams: StorageContext['listDiagrams'] = async (): Promise<
 | 
					    const listDiagrams: StorageContext['listDiagrams'] = async (
 | 
				
			||||||
        Diagram[]
 | 
					        options: {
 | 
				
			||||||
    > => {
 | 
					            includeTables?: boolean;
 | 
				
			||||||
        return await db.diagrams.toArray();
 | 
					            includeRelationships?: boolean;
 | 
				
			||||||
 | 
					        } = { includeRelationships: false, includeTables: false }
 | 
				
			||||||
 | 
					    ): Promise<Diagram[]> => {
 | 
				
			||||||
 | 
					        let diagrams = await db.diagrams.toArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (options.includeTables) {
 | 
				
			||||||
 | 
					            diagrams = await Promise.all(
 | 
				
			||||||
 | 
					                diagrams.map(async (diagram) => {
 | 
				
			||||||
 | 
					                    diagram.tables = await listTables(diagram.id);
 | 
				
			||||||
 | 
					                    return diagram;
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (options.includeRelationships) {
 | 
				
			||||||
 | 
					            diagrams = await Promise.all(
 | 
				
			||||||
 | 
					                diagrams.map(async (diagram) => {
 | 
				
			||||||
 | 
					                    diagram.relationships = await listRelationships(diagram.id);
 | 
				
			||||||
 | 
					                    return diagram;
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return diagrams;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const getDiagram: StorageContext['getDiagram'] = async (
 | 
					    const getDiagram: StorageContext['getDiagram'] = async (
 | 
				
			||||||
@@ -248,10 +271,15 @@ export const StorageProvider: React.FC<React.PropsWithChildren> = ({
 | 
				
			|||||||
    const listRelationships: StorageContext['listRelationships'] = async (
 | 
					    const listRelationships: StorageContext['listRelationships'] = async (
 | 
				
			||||||
        diagramId: string
 | 
					        diagramId: string
 | 
				
			||||||
    ): Promise<DBRelationship[]> => {
 | 
					    ): Promise<DBRelationship[]> => {
 | 
				
			||||||
        return await db.db_relationships
 | 
					        // Sort relationships alphabetically
 | 
				
			||||||
 | 
					        return await (
 | 
				
			||||||
 | 
					            await db.db_relationships
 | 
				
			||||||
                .where('diagramId')
 | 
					                .where('diagramId')
 | 
				
			||||||
                .equals(diagramId)
 | 
					                .equals(diagramId)
 | 
				
			||||||
            .toArray();
 | 
					                .toArray()
 | 
				
			||||||
 | 
					        ).sort((a, b) => {
 | 
				
			||||||
 | 
					            return a.name.localeCompare(b.name);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										107
									
								
								src/dialogs/export-sql-dialog/export-sql-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/dialogs/export-sql-dialog/export-sql-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					import { Button } from '@/components/button/button';
 | 
				
			||||||
 | 
					import { CodeSnippet } from '@/components/code-snippet/code-snippet';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    Dialog,
 | 
				
			||||||
 | 
					    DialogClose,
 | 
				
			||||||
 | 
					    DialogContent,
 | 
				
			||||||
 | 
					    DialogDescription,
 | 
				
			||||||
 | 
					    DialogFooter,
 | 
				
			||||||
 | 
					    DialogHeader,
 | 
				
			||||||
 | 
					    DialogTitle,
 | 
				
			||||||
 | 
					} from '@/components/dialog/dialog';
 | 
				
			||||||
 | 
					import { Label } from '@/components/label/label';
 | 
				
			||||||
 | 
					import { Spinner } from '@/components/spinner/spinner';
 | 
				
			||||||
 | 
					import { useChartDB } from '@/hooks/use-chartdb';
 | 
				
			||||||
 | 
					import { useDialog } from '@/hooks/use-dialog';
 | 
				
			||||||
 | 
					import {
 | 
				
			||||||
 | 
					    exportBaseSQL,
 | 
				
			||||||
 | 
					    exportSQL,
 | 
				
			||||||
 | 
					} from '@/lib/data/export-metadata/export-sql-script';
 | 
				
			||||||
 | 
					import { databaseTypeToLabelMap } from '@/lib/databases';
 | 
				
			||||||
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
 | 
					import { DialogProps } from '@radix-ui/react-dialog';
 | 
				
			||||||
 | 
					import { WandSparkles } from 'lucide-react';
 | 
				
			||||||
 | 
					import React, { useCallback, useEffect } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface ExportSQLDialogProps {
 | 
				
			||||||
 | 
					    dialog: DialogProps;
 | 
				
			||||||
 | 
					    targetDatabaseType: DatabaseType;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const ExportSQLDialog: React.FC<ExportSQLDialogProps> = ({
 | 
				
			||||||
 | 
					    dialog,
 | 
				
			||||||
 | 
					    targetDatabaseType,
 | 
				
			||||||
 | 
					}) => {
 | 
				
			||||||
 | 
					    const { closeExportSQLDialog } = useDialog();
 | 
				
			||||||
 | 
					    const { currentDiagram } = useChartDB();
 | 
				
			||||||
 | 
					    const [script, setScript] = React.useState<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const exportSQLScript = useCallback(async () => {
 | 
				
			||||||
 | 
					        if (targetDatabaseType === DatabaseType.GENERIC) {
 | 
				
			||||||
 | 
					            return Promise.resolve(exportBaseSQL(currentDiagram));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return exportSQL(currentDiagram, targetDatabaseType);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }, [targetDatabaseType, currentDiagram]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    useEffect(() => {
 | 
				
			||||||
 | 
					        setScript(undefined);
 | 
				
			||||||
 | 
					        const fetchScript = async () => {
 | 
				
			||||||
 | 
					            const script = await exportSQLScript();
 | 
				
			||||||
 | 
					            setScript(script);
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        fetchScript();
 | 
				
			||||||
 | 
					    }, [dialog.open, setScript, exportSQLScript]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const renderLoader = useCallback(
 | 
				
			||||||
 | 
					        () => (
 | 
				
			||||||
 | 
					            <div className="flex flex-col gap-2">
 | 
				
			||||||
 | 
					                <Spinner />
 | 
				
			||||||
 | 
					                <div className="flex items-center justify-center gap-1">
 | 
				
			||||||
 | 
					                    <WandSparkles className="h-5" />
 | 
				
			||||||
 | 
					                    <Label>
 | 
				
			||||||
 | 
					                        Generating SQL for{' '}
 | 
				
			||||||
 | 
					                        {databaseTypeToLabelMap[targetDatabaseType]}...
 | 
				
			||||||
 | 
					                    </Label>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        [targetDatabaseType]
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        <Dialog
 | 
				
			||||||
 | 
					            {...dialog}
 | 
				
			||||||
 | 
					            onOpenChange={(open) => {
 | 
				
			||||||
 | 
					                if (!open) {
 | 
				
			||||||
 | 
					                    closeExportSQLDialog();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }}
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					            <DialogContent
 | 
				
			||||||
 | 
					                className="flex flex-col min-w-[500px] xl:min-w-[75vw] max-h-[80vh] overflow-y-auto"
 | 
				
			||||||
 | 
					                showClose
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					                <DialogHeader>
 | 
				
			||||||
 | 
					                    <DialogTitle>Export SQL</DialogTitle>
 | 
				
			||||||
 | 
					                    <DialogDescription>
 | 
				
			||||||
 | 
					                        Export the SQL of the current diagram
 | 
				
			||||||
 | 
					                    </DialogDescription>
 | 
				
			||||||
 | 
					                </DialogHeader>
 | 
				
			||||||
 | 
					                <div className="flex flex-1 items-center justify-center">
 | 
				
			||||||
 | 
					                    {(script?.length ?? 0) === 0 ? (
 | 
				
			||||||
 | 
					                        renderLoader()
 | 
				
			||||||
 | 
					                    ) : (
 | 
				
			||||||
 | 
					                        <CodeSnippet code={script!} />
 | 
				
			||||||
 | 
					                    )}
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <DialogFooter className="flex !justify-between gap-2">
 | 
				
			||||||
 | 
					                    <div />
 | 
				
			||||||
 | 
					                    <DialogClose asChild>
 | 
				
			||||||
 | 
					                        <Button type="button">Close</Button>
 | 
				
			||||||
 | 
					                    </DialogClose>
 | 
				
			||||||
 | 
					                </DialogFooter>
 | 
				
			||||||
 | 
					            </DialogContent>
 | 
				
			||||||
 | 
					        </Dialog>
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
@@ -46,7 +46,7 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    useEffect(() => {
 | 
					    useEffect(() => {
 | 
				
			||||||
        const fetchDiagrams = async () => {
 | 
					        const fetchDiagrams = async () => {
 | 
				
			||||||
            const diagrams = await listDiagrams();
 | 
					            const diagrams = await listDiagrams({ includeTables: true });
 | 
				
			||||||
            setDiagrams(
 | 
					            setDiagrams(
 | 
				
			||||||
                diagrams.sort(
 | 
					                diagrams.sort(
 | 
				
			||||||
                    (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
 | 
					                    (a, b) => b.updatedAt.getTime() - a.updatedAt.getTime()
 | 
				
			||||||
@@ -87,6 +87,7 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
				
			|||||||
                                <TableHead>Name</TableHead>
 | 
					                                <TableHead>Name</TableHead>
 | 
				
			||||||
                                <TableHead>Created at</TableHead>
 | 
					                                <TableHead>Created at</TableHead>
 | 
				
			||||||
                                <TableHead>Last modified</TableHead>
 | 
					                                <TableHead>Last modified</TableHead>
 | 
				
			||||||
 | 
					                                <TableHead>Tables count</TableHead>
 | 
				
			||||||
                                <TableHead>Type</TableHead>
 | 
					                                <TableHead>Type</TableHead>
 | 
				
			||||||
                            </TableRow>
 | 
					                            </TableRow>
 | 
				
			||||||
                        </TableHeader>
 | 
					                        </TableHeader>
 | 
				
			||||||
@@ -120,6 +121,9 @@ export const OpenDiagramDialog: React.FC<OpenDiagramDialogProps> = ({
 | 
				
			|||||||
                                    <TableCell>
 | 
					                                    <TableCell>
 | 
				
			||||||
                                        {diagram.updatedAt.toLocaleString()}
 | 
					                                        {diagram.updatedAt.toLocaleString()}
 | 
				
			||||||
                                    </TableCell>
 | 
					                                    </TableCell>
 | 
				
			||||||
 | 
					                                    <TableCell>
 | 
				
			||||||
 | 
					                                        {diagram.tables?.length}
 | 
				
			||||||
 | 
					                                    </TableCell>
 | 
				
			||||||
                                    <TableCell>
 | 
					                                    <TableCell>
 | 
				
			||||||
                                        {
 | 
					                                        {
 | 
				
			||||||
                                            databaseTypeToLabelMap[
 | 
					                                            databaseTypeToLabelMap[
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								src/lib/colors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/lib/colors.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					export const randomColor = () => {
 | 
				
			||||||
 | 
					    const colors = [
 | 
				
			||||||
 | 
					        '#ff6363', // A brighter red.
 | 
				
			||||||
 | 
					        '#ff6b8a', // A vibrant pink.
 | 
				
			||||||
 | 
					        '#c05dcf', // A rich purple.
 | 
				
			||||||
 | 
					        '#b067e9', // A lighter purple.
 | 
				
			||||||
 | 
					        '#8a61f5', // A bold indigo.
 | 
				
			||||||
 | 
					        '#7175fa', // A lighter indigo.
 | 
				
			||||||
 | 
					        '#8eb7ff', // A sky blue.
 | 
				
			||||||
 | 
					        '#42e0c0', // A fresh aqua.
 | 
				
			||||||
 | 
					        '#4dee8a', // A mint green.
 | 
				
			||||||
 | 
					        '#9ef07a', // A lime green.
 | 
				
			||||||
 | 
					        '#ffe374', // A warm yellow.
 | 
				
			||||||
 | 
					        '#ff9f74', // A peachy orange.
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					    return colors[Math.floor(Math.random() * colors.length)];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const greyColor = '#b0b0b0'; // A Cloudy Grey.
 | 
				
			||||||
@@ -295,6 +295,12 @@ export const sqliteDataTypes = [
 | 
				
			|||||||
    // Date/Time Types (SQLite uses TEXT, REAL, or INTEGER types for dates and times)
 | 
					    // Date/Time Types (SQLite uses TEXT, REAL, or INTEGER types for dates and times)
 | 
				
			||||||
    'date',
 | 
					    'date',
 | 
				
			||||||
    'datetime',
 | 
					    'datetime',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    'int',
 | 
				
			||||||
 | 
					    'float',
 | 
				
			||||||
 | 
					    'boolean',
 | 
				
			||||||
 | 
					    'varchar',
 | 
				
			||||||
 | 
					    'decimal',
 | 
				
			||||||
] as const;
 | 
					] as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const dataTypes = [
 | 
					export const dataTypes = [
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,14 @@
 | 
				
			|||||||
import { Diagram } from "../domain/diagram";
 | 
					import { generateText } from 'ai';
 | 
				
			||||||
 | 
					import { createOpenAI } from '@ai-sdk/openai';
 | 
				
			||||||
 | 
					import { Diagram } from '../../domain/diagram';
 | 
				
			||||||
 | 
					import { OPENAI_API_KEY } from '@/lib/env';
 | 
				
			||||||
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const exportSQL = (diagram: Diagram): string => {
 | 
					const openai = createOpenAI({
 | 
				
			||||||
 | 
					    apiKey: OPENAI_API_KEY,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const exportBaseSQL = (diagram: Diagram): string => {
 | 
				
			||||||
    const { tables, relationships } = diagram;
 | 
					    const { tables, relationships } = diagram;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!tables || tables.length === 0) {
 | 
					    if (!tables || tables.length === 0) {
 | 
				
			||||||
@@ -8,26 +16,48 @@ export const exportSQL = (diagram: Diagram): string => {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Filter out the tables that are views
 | 
					    // Filter out the tables that are views
 | 
				
			||||||
    const nonViewTables = tables.filter(table => !table.isView);
 | 
					    const nonViewTables = tables.filter((table) => !table.isView);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Align the data types based on foreign key relationships
 | 
				
			||||||
 | 
					    alignForeignKeyDataTypes(diagram);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize the SQL script string
 | 
					    // Initialize the SQL script string
 | 
				
			||||||
    let sqlScript = '';
 | 
					    let sqlScript = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Loop through each non-view table to generate the SQL statements
 | 
					    // Loop through each non-view table to generate the SQL statements
 | 
				
			||||||
    nonViewTables.forEach(table => {
 | 
					    nonViewTables.forEach((table) => {
 | 
				
			||||||
        sqlScript += `CREATE TABLE ${table.name} (\n`;
 | 
					        sqlScript += `CREATE TABLE ${table.name} (\n`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        table.fields.forEach((field, index) => {
 | 
					        table.fields.forEach((field, index) => {
 | 
				
			||||||
            sqlScript += `  ${field.name} ${field.type}`;
 | 
					            sqlScript += `  ${field.name} ${field.type}`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (field.primaryKey) {
 | 
					            // Add size for character types
 | 
				
			||||||
                sqlScript += ' PRIMARY KEY';
 | 
					            if (field.characterMaximumLength) {
 | 
				
			||||||
 | 
					                sqlScript += `(${field.characterMaximumLength})`;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Add precision and scale for numeric types
 | 
				
			||||||
 | 
					            if (field.precision !== null && field.scale !== null) {
 | 
				
			||||||
 | 
					                sqlScript += `(${field.precision}, ${field.scale})`;
 | 
				
			||||||
 | 
					            } else if (field.precision !== null) {
 | 
				
			||||||
 | 
					                sqlScript += `(${field.precision})`;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Handle NOT NULL constraint
 | 
				
			||||||
            if (!field.nullable) {
 | 
					            if (!field.nullable) {
 | 
				
			||||||
                sqlScript += ' NOT NULL';
 | 
					                sqlScript += ' NOT NULL';
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Handle DEFAULT value
 | 
				
			||||||
 | 
					            if (field.default) {
 | 
				
			||||||
 | 
					                sqlScript += ` DEFAULT ${field.default}`;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Handle PRIMARY KEY constraint
 | 
				
			||||||
 | 
					            if (field.primaryKey) {
 | 
				
			||||||
 | 
					                sqlScript += ' PRIMARY KEY';
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Add a comma after each field except the last one
 | 
					            // Add a comma after each field except the last one
 | 
				
			||||||
            if (index < table.fields.length - 1) {
 | 
					            if (index < table.fields.length - 1) {
 | 
				
			||||||
                sqlScript += ',\n';
 | 
					                sqlScript += ',\n';
 | 
				
			||||||
@@ -35,17 +65,230 @@ export const exportSQL = (diagram: Diagram): string => {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sqlScript += '\n);\n\n';
 | 
					        sqlScript += '\n);\n\n';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Generate SQL for indexes
 | 
				
			||||||
 | 
					        table.indexes.forEach((index) => {
 | 
				
			||||||
 | 
					            const fieldNames = index.fieldIds
 | 
				
			||||||
 | 
					                .map(
 | 
				
			||||||
 | 
					                    (fieldId) =>
 | 
				
			||||||
 | 
					                        table.fields.find((field) => field.id === fieldId)?.name
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
 | 
					                .filter(Boolean)
 | 
				
			||||||
 | 
					                .join(', ');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (fieldNames) {
 | 
				
			||||||
 | 
					                sqlScript += `CREATE ${index.unique ? 'UNIQUE ' : ''}INDEX ${index.name} ON ${table.name} (${fieldNames});\n`;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Handle relationships (foreign keys) if needed
 | 
					        sqlScript += '\n';
 | 
				
			||||||
    relationships?.forEach(relationship => {
 | 
					    });
 | 
				
			||||||
        const sourceTable = nonViewTables.find(table => table.id === relationship.sourceTableId);
 | 
					 | 
				
			||||||
        const targetTable = nonViewTables.find(table => table.id === relationship.targetTableId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (sourceTable && targetTable) {
 | 
					    // Handle relationships (foreign keys)
 | 
				
			||||||
            sqlScript += `ALTER TABLE ${sourceTable.name} ADD CONSTRAINT ${relationship.name} FOREIGN KEY (${relationship.sourceFieldId}) REFERENCES ${targetTable.name} (${relationship.targetFieldId});\n`;
 | 
					    relationships?.forEach((relationship) => {
 | 
				
			||||||
 | 
					        const sourceTable = nonViewTables.find(
 | 
				
			||||||
 | 
					            (table) => table.id === relationship.sourceTableId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const targetTable = nonViewTables.find(
 | 
				
			||||||
 | 
					            (table) => table.id === relationship.targetTableId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const sourceTableField = sourceTable?.fields.find(
 | 
				
			||||||
 | 
					            (field) => field.id === relationship.sourceFieldId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        const targetTableField = targetTable?.fields.find(
 | 
				
			||||||
 | 
					            (field) => field.id === relationship.targetFieldId
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            sourceTable &&
 | 
				
			||||||
 | 
					            targetTable &&
 | 
				
			||||||
 | 
					            sourceTableField &&
 | 
				
			||||||
 | 
					            targetTableField
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            sqlScript += `ALTER TABLE ${sourceTable.name} ADD CONSTRAINT ${relationship.name} FOREIGN KEY (${sourceTableField.name}) REFERENCES ${targetTable.name} (${targetTableField.name});\n`;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return sqlScript;
 | 
					    return sqlScript;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const exportSQL = async (
 | 
				
			||||||
 | 
					    diagram: Diagram,
 | 
				
			||||||
 | 
					    databaseType: DatabaseType
 | 
				
			||||||
 | 
					): Promise<string> => {
 | 
				
			||||||
 | 
					    const sqlScript = exportBaseSQL(diagram);
 | 
				
			||||||
 | 
					    const prompt = generateSQLPrompt(databaseType, sqlScript);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const { text } = await generateText({
 | 
				
			||||||
 | 
					        model: openai('gpt-4o-mini-2024-07-18'),
 | 
				
			||||||
 | 
					        prompt: prompt,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return text;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function getMySQLDataTypeSize(type: string) {
 | 
				
			||||||
 | 
					    return (
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            tinyint: 1,
 | 
				
			||||||
 | 
					            smallint: 2,
 | 
				
			||||||
 | 
					            mediumint: 3,
 | 
				
			||||||
 | 
					            integer: 4,
 | 
				
			||||||
 | 
					            bigint: 8,
 | 
				
			||||||
 | 
					            float: 4,
 | 
				
			||||||
 | 
					            double: 8,
 | 
				
			||||||
 | 
					            decimal: 16,
 | 
				
			||||||
 | 
					            numeric: 16,
 | 
				
			||||||
 | 
					            // Add other relevant data types if needed
 | 
				
			||||||
 | 
					        }[type.toLowerCase()] || 0
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function alignForeignKeyDataTypes(diagram: Diagram) {
 | 
				
			||||||
 | 
					    const { tables, relationships } = diagram;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (
 | 
				
			||||||
 | 
					        !tables ||
 | 
				
			||||||
 | 
					        tables.length === 0 ||
 | 
				
			||||||
 | 
					        !relationships ||
 | 
				
			||||||
 | 
					        relationships.length === 0
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Convert tables to a map for quick lookup
 | 
				
			||||||
 | 
					    const tableMap = new Map();
 | 
				
			||||||
 | 
					    tables.forEach((table) => {
 | 
				
			||||||
 | 
					        tableMap.set(table.id, table);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Iterate through each relationship to update the child table column data types
 | 
				
			||||||
 | 
					    relationships.forEach((relationship) => {
 | 
				
			||||||
 | 
					        const { sourceTableId, sourceFieldId, targetTableId, targetFieldId } =
 | 
				
			||||||
 | 
					            relationship;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const sourceTable = tableMap.get(sourceTableId);
 | 
				
			||||||
 | 
					        const targetTable = tableMap.get(targetTableId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (sourceTable && targetTable) {
 | 
				
			||||||
 | 
					            const sourceField = sourceTable.fields.find(
 | 
				
			||||||
 | 
					                (field: { id: string }) => field.id === sourceFieldId
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            const targetField = targetTable.fields.find(
 | 
				
			||||||
 | 
					                (field: { id: string }) => field.id === targetFieldId
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (sourceField && targetField) {
 | 
				
			||||||
 | 
					                const sourceSize = getMySQLDataTypeSize(sourceField.type);
 | 
				
			||||||
 | 
					                const targetSize = getMySQLDataTypeSize(targetField.type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (sourceSize > targetSize) {
 | 
				
			||||||
 | 
					                    // Print a message indicating that the data type is being adjusted
 | 
				
			||||||
 | 
					                    console.log(
 | 
				
			||||||
 | 
					                        `Adjusting data type of '${targetTable.name}.${targetField.name}' from '${targetField.type}' to '${sourceField.type}' to match '${sourceTable.name}.${sourceField.name}'`
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Adjust the child field data type to the larger data type
 | 
				
			||||||
 | 
					                    targetField.type = sourceField.type;
 | 
				
			||||||
 | 
					                } else if (targetSize > sourceSize) {
 | 
				
			||||||
 | 
					                    // Print a message indicating that the data type is being adjusted
 | 
				
			||||||
 | 
					                    console.log(
 | 
				
			||||||
 | 
					                        `Adjusting data type of '${targetTable.name}.${sourceField.name}' from '${sourceField.type}' to '${targetField.type}' to match '${targetTable.name}.${targetField.name}' ('${targetField.type}')`
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    // Adjust the child field data type to the larger data type
 | 
				
			||||||
 | 
					                    sourceField.type = targetField.type;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    console.log(
 | 
				
			||||||
 | 
					                        `same data type '${targetField.type}' = '${sourceField.type}'.`
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const generateSQLPrompt = (databaseType: string, sqlScript: string) => {
 | 
				
			||||||
 | 
					    const basePrompt = `
 | 
				
			||||||
 | 
					        You are generating SQL scripts for creating database tables and sequences, handling primary keys, indices, and other table attributes.
 | 
				
			||||||
 | 
					        The following instructions will guide you in optimizing the scripts for the ${databaseType} dialect:
 | 
				
			||||||
 | 
					        - **Column Names**: Do **not** modify the names of columns. Ensure that all column names in the generated SQL script are exactly as provided in the input schema. If the input specifies a column name, it must appear in the output script unchanged.
 | 
				
			||||||
 | 
					        - **Column Name Conflicts**: When a column name conflicts with a data type or reserved keyword (e.g., fulltext), escape the column name by enclosing it.
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const dialectInstructions =
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            POSTGRESQL: `
 | 
				
			||||||
 | 
					        - **Sequence Creation**: Use \`CREATE SEQUENCE IF NOT EXISTS\` for sequence creation.
 | 
				
			||||||
 | 
					        - **Table and Index Creation**: Use \`CREATE TABLE IF NOT EXISTS\` and \`CREATE INDEX IF NOT EXISTS\` to avoid errors if the object already exists.
 | 
				
			||||||
 | 
					        - **Serial and Identity Columns**: For auto-increment columns, use \`SERIAL\` or \`GENERATED BY DEFAULT AS IDENTITY\`.
 | 
				
			||||||
 | 
					        - **Conditional Statements**: Utilize PostgreSQL’s support for \`IF NOT EXISTS\` in relevant \`CREATE\` statements.
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					            MYSQL: `
 | 
				
			||||||
 | 
					        - **Table Creation**: Use \`CREATE TABLE IF NOT EXISTS\` for creating tables. While creating the table structure, ensure that all foreign key columns use the correct data types as determined in the foreign key review.
 | 
				
			||||||
 | 
					        - **Auto-Increment**: Use \`AUTO_INCREMENT\` for auto-incrementing primary key columns.
 | 
				
			||||||
 | 
					        - **Index Creation**: Place all \`CREATE INDEX\` statements separately after the \`CREATE TABLE\` statement. Avoid using \`IF NOT EXISTS\` in \`CREATE INDEX\` statements.
 | 
				
			||||||
 | 
					        - **Indexing TEXT/BLOB Columns**: Do **not** create regular indexes on \`TEXT\` or \`BLOB\` columns. If indexing these types is required, use \`FULLTEXT\` indexes specifically for \`TEXT\` columns where appropriate, or consider alternative strategies.
 | 
				
			||||||
 | 
					        - **Date Column Defaults**: Avoid using \`CURRENT_DATE\` as a default for \`DATE\` columns. Instead, consider using \`DEFAULT NULL\` or handle default values programmatically.
 | 
				
			||||||
 | 
					        - **Timestamp Default Value**: Use \`DEFAULT CURRENT_TIMESTAMP\` for \`TIMESTAMP\` columns. Only one \`TIMESTAMP\` column can have \`CURRENT_TIMESTAMP\` as the default without specifying \`ON UPDATE\`.
 | 
				
			||||||
 | 
					        - **Boolean Columns**: Use \`TINYINT(1)\` instead of \`BOOLEAN\` for better compatibility with MySQL/MariaDB versions that might not fully support the \`BOOLEAN\` data type.
 | 
				
			||||||
 | 
					        - **TEXT and BLOB Constraints**: Do not use \`NOT NULL\` with \`TEXT\` or \`BLOB\` columns, as these types do not support the \`NOT NULL\` constraint in MariaDB.
 | 
				
			||||||
 | 
					        - **ENUM Data Type**: Ensure that default values are compatible and that the \`ENUM\` declaration adheres to MariaDB's syntax requirements.
 | 
				
			||||||
 | 
					        - **Default Values**: Ensure that default values for columns, especially \`DECIMAL\` and \`ENUM\`, are correctly formatted and comply with MariaDB's SQL syntax.
 | 
				
			||||||
 | 
					        - **Sequences**: Recognize that MySQL does not natively support sequences. Use \`AUTO_INCREMENT\` instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        **Reminder**: Ensure all column names that conflict with reserved keywords or data types (like \`fulltext\`) are escaped using backticks (\`).
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					            SQL_SERVER: `
 | 
				
			||||||
 | 
					        - **Sequence Creation**: Use \`CREATE SEQUENCE\` without \`IF NOT EXISTS\`, and employ conditional logic (\`IF NOT EXISTS\`) to check for sequence existence before creation.
 | 
				
			||||||
 | 
					        - **Identity Columns**: Always prefer using the \`IDENTITY\` keyword (e.g., \`INT IDENTITY(1,1)\`) for auto-incrementing primary key columns when possible.
 | 
				
			||||||
 | 
					        - **Conditional Logic**: Use a conditional block like \`IF NOT EXISTS (SELECT * FROM sys.objects WHERE ...)\` since SQL Server doesn’t support \`IF NOT EXISTS\` directly in \`CREATE\` statements.
 | 
				
			||||||
 | 
					        - **Avoid Unsupported Syntax**: Ensure the script does not include unsupported statements like \`CREATE TABLE IF NOT EXISTS\`.
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					            MARIADB: `
 | 
				
			||||||
 | 
					        - **Table Creation**: Use \`CREATE TABLE IF NOT EXISTS\` for creating tables. While creating the table structure, ensure that all foreign key columns use the correct data types as determined in the foreign key review.
 | 
				
			||||||
 | 
					        - **Auto-Increment**: Use \`AUTO_INCREMENT\` for auto-incrementing primary key columns.
 | 
				
			||||||
 | 
					        - **Index Creation**: Place all \`CREATE INDEX\` statements separately after the \`CREATE TABLE\` statement. Avoid using \`IF NOT EXISTS\` in \`CREATE INDEX\` statements.
 | 
				
			||||||
 | 
					        - **Indexing TEXT/BLOB Columns**: Do **not** create regular indexes on \`TEXT\` or \`BLOB\` columns. If indexing these types is required, use \`FULLTEXT\` indexes specifically for \`TEXT\` columns where appropriate, or consider alternative strategies.
 | 
				
			||||||
 | 
					        - **Date Column Defaults**: Avoid using \`CURRENT_DATE\` as a default for \`DATE\` columns. Instead, consider using \`DEFAULT NULL\` or handle default values programmatically.
 | 
				
			||||||
 | 
					        - **Timestamp Default Value**: Use \`DEFAULT CURRENT_TIMESTAMP\` for \`TIMESTAMP\` columns. Only one \`TIMESTAMP\` column can have \`CURRENT_TIMESTAMP\` as the default without specifying \`ON UPDATE\`.
 | 
				
			||||||
 | 
					        - **Boolean Columns**: Use \`TINYINT(1)\` instead of \`BOOLEAN\` for better compatibility with MySQL/MariaDB versions that might not fully support the \`BOOLEAN\` data type.
 | 
				
			||||||
 | 
					        - **TEXT and BLOB Constraints**: Do not use \`NOT NULL\` with \`TEXT\` or \`BLOB\` columns, as these types do not support the \`NOT NULL\` constraint in MariaDB.
 | 
				
			||||||
 | 
					        - **ENUM Data Type**: Ensure that default values are compatible and that the \`ENUM\` declaration adheres to MariaDB's syntax requirements.
 | 
				
			||||||
 | 
					        - **Default Values**: Ensure that default values for columns, especially \`DECIMAL\` and \`ENUM\`, are correctly formatted and comply with MariaDB's SQL syntax.
 | 
				
			||||||
 | 
					        - **Sequences**: Recognize that MySQL does not natively support sequences. Use \`AUTO_INCREMENT\` instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        **Reminder**: Ensure all column names that conflict with reserved keywords or data types (like \`fulltext\`) are escaped using backticks (\`).
 | 
				
			||||||
 | 
					        `,
 | 
				
			||||||
 | 
					            SQLITE: `
 | 
				
			||||||
 | 
					        - **Table Creation**: Use \`CREATE TABLE IF NOT EXISTS\`.
 | 
				
			||||||
 | 
					        - **Auto-Increment**: Use \`AUTOINCREMENT\` with \`INTEGER PRIMARY KEY\` for auto-increment functionality.
 | 
				
			||||||
 | 
					        - **No Sequence Support**: SQLite does not support sequences; rely solely on \`AUTOINCREMENT\` for similar functionality.
 | 
				
			||||||
 | 
					        - **Foreign Key Constraints**: Do not use \`ALTER TABLE\` to add foreign key constraints. SQLite does not support adding foreign keys to an existing table after it has been created. Always define foreign key constraints during the \`CREATE TABLE\` statement. Avoid using named constraints in foreign key definitions.
 | 
				
			||||||
 | 
					        - **Adding Foreign Keys to Existing Tables**: If adding a foreign key to an existing table is required, suggest creating a new table with the foreign key constraint, migrating the data, and renaming the new table to the original name.
 | 
				
			||||||
 | 
					        - **General SQLite Constraints**: Remember, \`ALTER TABLE\` in SQLite is limited and cannot add constraints after the table is created.
 | 
				
			||||||
 | 
					        - **Conditional Logic**: Ensure the script uses SQLite-compatible syntax and does not include unsupported features.
 | 
				
			||||||
 | 
					    `,
 | 
				
			||||||
 | 
					        }[databaseType] || '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const additionalInstructions = `
 | 
				
			||||||
 | 
					    Just answer with the script with no additional details. give the commands flat without markdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    No images are allowed. Do not try to generate or link images, including base64 data URLs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Feel free to suggest corrections for suspected typos.
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return `${basePrompt}\n${dialectInstructions}\n
 | 
				
			||||||
 | 
					        - **Validation**: After generating the script, validate it against the respective SQL dialect by attempting to execute it in a corresponding database environment.
 | 
				
			||||||
 | 
					        - **Syntax Checking**: Use SQL linting tools specific to each dialect to ensure the script is free from syntax errors.
 | 
				
			||||||
 | 
					        - **Manual Review**: Include a step where a knowledgeable developer reviews the generated script to ensure it meets the required specifications and adheres to best practices.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Here is the SQL script that needs to be optimized or generated according to the instructions above:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ${sqlScript}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ${additionalInstructions}
 | 
				
			||||||
 | 
					    `;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,5 +5,11 @@ export interface ColumnInfo {
 | 
				
			|||||||
    type: string;
 | 
					    type: string;
 | 
				
			||||||
    ordinal_position: number;
 | 
					    ordinal_position: number;
 | 
				
			||||||
    nullable: boolean;
 | 
					    nullable: boolean;
 | 
				
			||||||
    collation: string;
 | 
					    character_maximum_length?: string | null; // The maximum length of the column (if applicable), nullable
 | 
				
			||||||
 | 
					    precision?: {
 | 
				
			||||||
 | 
					        precision: number | null; // The precision for numeric types
 | 
				
			||||||
 | 
					        scale: number | null; // The scale for numeric types
 | 
				
			||||||
 | 
					    } | null; // Nullable, not all types have precision
 | 
				
			||||||
 | 
					    default?: string | null; // Default value for the column, nullable
 | 
				
			||||||
 | 
					    collation?: string | null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ export interface DatabaseMetadata {
 | 
				
			|||||||
    indexes: IndexInfo[];
 | 
					    indexes: IndexInfo[];
 | 
				
			||||||
    tables: TableInfo[];
 | 
					    tables: TableInfo[];
 | 
				
			||||||
    views: ViewInfo[];
 | 
					    views: ViewInfo[];
 | 
				
			||||||
    server_name: string;
 | 
					    database_name: string;
 | 
				
			||||||
    version: string;
 | 
					    version: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,11 @@ export interface DBField {
 | 
				
			|||||||
    unique: boolean;
 | 
					    unique: boolean;
 | 
				
			||||||
    nullable: boolean;
 | 
					    nullable: boolean;
 | 
				
			||||||
    createdAt: number;
 | 
					    createdAt: number;
 | 
				
			||||||
 | 
					    characterMaximumLength?: string;
 | 
				
			||||||
 | 
					    precision?: number;
 | 
				
			||||||
 | 
					    scale?: number;
 | 
				
			||||||
 | 
					    default?: string;
 | 
				
			||||||
 | 
					    collation?: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type FieldType = (typeof dataTypes)[number];
 | 
					export type FieldType = (typeof dataTypes)[number];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,10 +3,11 @@ import { DBField, FieldType } from './db-field';
 | 
				
			|||||||
import { TableInfo } from '../data/import-metadata/metadata-types/table-info';
 | 
					import { TableInfo } from '../data/import-metadata/metadata-types/table-info';
 | 
				
			||||||
import { ColumnInfo } from '../data/import-metadata/metadata-types/column-info';
 | 
					import { ColumnInfo } from '../data/import-metadata/metadata-types/column-info';
 | 
				
			||||||
import { IndexInfo } from '../data/import-metadata/metadata-types/index-info';
 | 
					import { IndexInfo } from '../data/import-metadata/metadata-types/index-info';
 | 
				
			||||||
import { generateId, greyColor, randomHSLA } from '@/lib/utils';
 | 
					import { greyColor, randomColor } from '@/lib/colors';
 | 
				
			||||||
import { DBRelationship } from './db-relationship';
 | 
					import { DBRelationship } from './db-relationship';
 | 
				
			||||||
import { PrimaryKeyInfo } from '../data/import-metadata/metadata-types/primary-key-info';
 | 
					import { PrimaryKeyInfo } from '../data/import-metadata/metadata-types/primary-key-info';
 | 
				
			||||||
import { ViewInfo } from '../data/import-metadata/metadata-types/view-info';
 | 
					import { ViewInfo } from '../data/import-metadata/metadata-types/view-info';
 | 
				
			||||||
 | 
					import { generateId } from '../utils';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface DBTable {
 | 
					export interface DBTable {
 | 
				
			||||||
    id: string;
 | 
					    id: string;
 | 
				
			||||||
@@ -38,7 +39,11 @@ export const createTablesFromMetadata = ({
 | 
				
			|||||||
        // Filter, make unique, and sort columns based on ordinal_position
 | 
					        // Filter, make unique, and sort columns based on ordinal_position
 | 
				
			||||||
        const uniqueColumns = new Map<string, ColumnInfo>();
 | 
					        const uniqueColumns = new Map<string, ColumnInfo>();
 | 
				
			||||||
        columns
 | 
					        columns
 | 
				
			||||||
            .filter((col) => col.table === tableInfo.table)
 | 
					            .filter(
 | 
				
			||||||
 | 
					                (col) =>
 | 
				
			||||||
 | 
					                    col.schema === tableInfo.schema &&
 | 
				
			||||||
 | 
					                    col.table === tableInfo.table
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
            .forEach((col) => {
 | 
					            .forEach((col) => {
 | 
				
			||||||
                if (!uniqueColumns.has(col.name)) {
 | 
					                if (!uniqueColumns.has(col.name)) {
 | 
				
			||||||
                    uniqueColumns.set(col.name, col);
 | 
					                    uniqueColumns.set(col.name, col);
 | 
				
			||||||
@@ -46,9 +51,7 @@ export const createTablesFromMetadata = ({
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const sortedColumns = Array.from(uniqueColumns.values()).sort(
 | 
					        const sortedColumns = Array.from(uniqueColumns.values()).sort(
 | 
				
			||||||
            (a, b) => {
 | 
					            (a, b) => a.ordinal_position - b.ordinal_position
 | 
				
			||||||
                return a.ordinal_position - b.ordinal_position;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const tablePrimaryKeys = primaryKeys.filter(
 | 
					        const tablePrimaryKeys = primaryKeys.filter(
 | 
				
			||||||
@@ -71,6 +74,16 @@ export const createTablesFromMetadata = ({
 | 
				
			|||||||
                    (idx) => idx.column === col.name && idx.unique
 | 
					                    (idx) => idx.column === col.name && idx.unique
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                nullable: col.nullable,
 | 
					                nullable: col.nullable,
 | 
				
			||||||
 | 
					                ...(col.character_maximum_length &&
 | 
				
			||||||
 | 
					                col.character_maximum_length !== 'null'
 | 
				
			||||||
 | 
					                    ? { character_maximum_length: col.character_maximum_length }
 | 
				
			||||||
 | 
					                    : {}),
 | 
				
			||||||
 | 
					                ...(col.precision?.precision
 | 
				
			||||||
 | 
					                    ? { precision: col.precision.precision }
 | 
				
			||||||
 | 
					                    : {}),
 | 
				
			||||||
 | 
					                ...(col.precision?.scale ? { scale: col.precision.scale } : {}),
 | 
				
			||||||
 | 
					                ...(col.default ? { default: col.default } : {}),
 | 
				
			||||||
 | 
					                ...(col.collation ? { collation: col.collation } : {}),
 | 
				
			||||||
                createdAt: Date.now(),
 | 
					                createdAt: Date.now(),
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
@@ -102,7 +115,7 @@ export const createTablesFromMetadata = ({
 | 
				
			|||||||
            y: Math.random() * 800, // Placeholder Y
 | 
					            y: Math.random() * 800, // Placeholder Y
 | 
				
			||||||
            fields,
 | 
					            fields,
 | 
				
			||||||
            indexes: dbIndexes,
 | 
					            indexes: dbIndexes,
 | 
				
			||||||
            color: isView ? greyColor : randomHSLA(),
 | 
					            color: isView ? greyColor : randomColor(),
 | 
				
			||||||
            isView: isView,
 | 
					            isView: isView,
 | 
				
			||||||
            createdAt: Date.now(),
 | 
					            createdAt: Date.now(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,9 @@ export const loadFromDatabaseMetadata = ({
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        id: generateId(),
 | 
					        id: generateId(),
 | 
				
			||||||
        name: databaseMetadata.server_name || `Diagram ${diagramNumber}`,
 | 
					        name:
 | 
				
			||||||
 | 
					            `${databaseMetadata.database_name}-db` ||
 | 
				
			||||||
 | 
					            `Diagram ${diagramNumber}`,
 | 
				
			||||||
        databaseType: databaseType ?? DatabaseType.GENERIC,
 | 
					        databaseType: databaseType ?? DatabaseType.GENERIC,
 | 
				
			||||||
        tables: sortedTables,
 | 
					        tables: sortedTables,
 | 
				
			||||||
        relationships,
 | 
					        relationships,
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								src/lib/env.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/lib/env.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					export const OPENAI_API_KEY = import.meta.env.VITE_OPENAI_API_KEY;
 | 
				
			||||||
@@ -2,7 +2,6 @@ import { type ClassValue, clsx } from 'clsx';
 | 
				
			|||||||
import { customAlphabet } from 'nanoid';
 | 
					import { customAlphabet } from 'nanoid';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const randomId = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 25);
 | 
					const randomId = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 25);
 | 
				
			||||||
const randonNumber = customAlphabet('1234567890', 18);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { twMerge } from 'tailwind-merge';
 | 
					import { twMerge } from 'tailwind-merge';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -10,16 +9,6 @@ export function cn(...inputs: ClassValue[]) {
 | 
				
			|||||||
    return twMerge(clsx(inputs));
 | 
					    return twMerge(clsx(inputs));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const convertToDecimal = (number: number) => {
 | 
					 | 
				
			||||||
    const digits = number.toString().length; // Get the number of digits
 | 
					 | 
				
			||||||
    return number / Math.pow(10, digits); // Divide the number by 10^digits
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const randomHSLA = () =>
 | 
					 | 
				
			||||||
    `hsla(${~~(360 * convertToDecimal(parseInt(randonNumber())))}, 70%, 72%, 0.8)`;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const greyColor = 'hsla(0, 0%, 65%, 1)';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
export const emptyFn = (): any => undefined;
 | 
					export const emptyFn = (): any => undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,12 +31,17 @@ import {
 | 
				
			|||||||
    databaseSecondaryLogoMap,
 | 
					    databaseSecondaryLogoMap,
 | 
				
			||||||
    databaseTypeToLabelMap,
 | 
					    databaseTypeToLabelMap,
 | 
				
			||||||
} from '@/lib/databases';
 | 
					} from '@/lib/databases';
 | 
				
			||||||
 | 
					import { DatabaseType } from '@/lib/domain/database-type';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface TopNavbarProps {}
 | 
					export interface TopNavbarProps {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
					export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
				
			||||||
    const { diagramName, updateDiagramName, currentDiagram } = useChartDB();
 | 
					    const { diagramName, updateDiagramName, currentDiagram } = useChartDB();
 | 
				
			||||||
    const { openCreateDiagramDialog, openOpenDiagramDialog } = useDialog();
 | 
					    const {
 | 
				
			||||||
 | 
					        openCreateDiagramDialog,
 | 
				
			||||||
 | 
					        openOpenDiagramDialog,
 | 
				
			||||||
 | 
					        openExportSQLDialog,
 | 
				
			||||||
 | 
					    } = useDialog();
 | 
				
			||||||
    const [editMode, setEditMode] = useState(false);
 | 
					    const [editMode, setEditMode] = useState(false);
 | 
				
			||||||
    const { exportImage } = useExportImage();
 | 
					    const { exportImage } = useExportImage();
 | 
				
			||||||
    const [editedDiagramName, setEditedDiagramName] =
 | 
					    const [editedDiagramName, setEditedDiagramName] =
 | 
				
			||||||
@@ -74,11 +79,6 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
				
			|||||||
        setEditMode(true);
 | 
					        setEditMode(true);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const exportSql = useCallback(() => {
 | 
					 | 
				
			||||||
        console.log('Export SQL');
 | 
					 | 
				
			||||||
        console.log({ currentDiagram });
 | 
					 | 
				
			||||||
    }, [currentDiagram]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const exportPNG = useCallback(() => {
 | 
					    const exportPNG = useCallback(() => {
 | 
				
			||||||
        exportImage('png');
 | 
					        exportImage('png');
 | 
				
			||||||
    }, [exportImage]);
 | 
					    }, [exportImage]);
 | 
				
			||||||
@@ -95,6 +95,13 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
				
			|||||||
        window.open('https://chartdb.io', '_blank');
 | 
					        window.open('https://chartdb.io', '_blank');
 | 
				
			||||||
    }, []);
 | 
					    }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const openJoinSlack = useCallback(() => {
 | 
				
			||||||
 | 
					        window.open(
 | 
				
			||||||
 | 
					            'https://join.slack.com/t/chartdb/shared_invite/zt-2ourrlh5e-mKIHCRML3_~m_gHjD5EcUg',
 | 
				
			||||||
 | 
					            '_blank'
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <nav className="flex flex-row items-center justify-between px-4 h-12 border-b">
 | 
					        <nav className="flex flex-row items-center justify-between px-4 h-12 border-b">
 | 
				
			||||||
            <div className="flex flex-1 justify-start gap-x-3">
 | 
					            <div className="flex flex-1 justify-start gap-x-3">
 | 
				
			||||||
@@ -125,9 +132,81 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
				
			|||||||
                                    Open
 | 
					                                    Open
 | 
				
			||||||
                                </MenubarItem>
 | 
					                                </MenubarItem>
 | 
				
			||||||
                                <MenubarSeparator />
 | 
					                                <MenubarSeparator />
 | 
				
			||||||
                                <MenubarItem onClick={exportSql}>
 | 
					                                <MenubarSub>
 | 
				
			||||||
                                    Export
 | 
					                                    <MenubarSubTrigger>
 | 
				
			||||||
 | 
					                                        Export SQL
 | 
				
			||||||
 | 
					                                    </MenubarSubTrigger>
 | 
				
			||||||
 | 
					                                    <MenubarSubContent>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.GENERIC,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {databaseTypeToLabelMap['generic']}
 | 
				
			||||||
                                        </MenubarItem>
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.POSTGRESQL,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                databaseTypeToLabelMap[
 | 
				
			||||||
 | 
					                                                    'postgresql'
 | 
				
			||||||
 | 
					                                                ]
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.MYSQL,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {databaseTypeToLabelMap['mysql']}
 | 
				
			||||||
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.SQL_SERVER,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {
 | 
				
			||||||
 | 
					                                                databaseTypeToLabelMap[
 | 
				
			||||||
 | 
					                                                    'sql_server'
 | 
				
			||||||
 | 
					                                                ]
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.MARIADB,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {databaseTypeToLabelMap['mariadb']}
 | 
				
			||||||
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                        <MenubarItem
 | 
				
			||||||
 | 
					                                            onClick={() =>
 | 
				
			||||||
 | 
					                                                openExportSQLDialog({
 | 
				
			||||||
 | 
					                                                    targetDatabaseType:
 | 
				
			||||||
 | 
					                                                        DatabaseType.SQLITE,
 | 
				
			||||||
 | 
					                                                })
 | 
				
			||||||
 | 
					                                            }
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {databaseTypeToLabelMap['sqlite']}
 | 
				
			||||||
 | 
					                                        </MenubarItem>
 | 
				
			||||||
 | 
					                                    </MenubarSubContent>
 | 
				
			||||||
 | 
					                                </MenubarSub>
 | 
				
			||||||
                                <MenubarSub>
 | 
					                                <MenubarSub>
 | 
				
			||||||
                                    <MenubarSubTrigger>
 | 
					                                    <MenubarSubTrigger>
 | 
				
			||||||
                                        Export as
 | 
					                                        Export as
 | 
				
			||||||
@@ -167,6 +246,9 @@ export const TopNavbar: React.FC<TopNavbarProps> = () => {
 | 
				
			|||||||
                                <MenubarItem onClick={openChartDBIO}>
 | 
					                                <MenubarItem onClick={openChartDBIO}>
 | 
				
			||||||
                                    Visit ChartDB
 | 
					                                    Visit ChartDB
 | 
				
			||||||
                                </MenubarItem>
 | 
					                                </MenubarItem>
 | 
				
			||||||
 | 
					                                <MenubarItem onClick={openJoinSlack}>
 | 
				
			||||||
 | 
					                                    Join us on Slack
 | 
				
			||||||
 | 
					                                </MenubarItem>
 | 
				
			||||||
                            </MenubarContent>
 | 
					                            </MenubarContent>
 | 
				
			||||||
                        </MenubarMenu>
 | 
					                        </MenubarMenu>
 | 
				
			||||||
                    </Menubar>
 | 
					                    </Menubar>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user