synthos 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. package/README.md +1 -1
  2. package/default-pages/application/page.html +42 -0
  3. package/default-pages/application/page.json +10 -0
  4. package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
  5. package/default-pages/elevenlabs_effects_studio/page.json +11 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +801 -0
  7. package/default-pages/elevenlabs_voice_studio/page.json +11 -0
  8. package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
  9. package/default-pages/json_tools/page.json +10 -0
  10. package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
  11. package/default-pages/my_notes/page.html +132 -0
  12. package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
  13. package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
  14. package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
  15. package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
  16. package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
  17. package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
  18. package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
  19. package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
  20. package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
  21. package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
  22. package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
  23. package/default-pages/neon_asteroids/files/effects.json +74 -0
  24. package/default-pages/neon_asteroids/page.html +1822 -0
  25. package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
  26. package/default-pages/{oregon_trail.html → oregon_trail/page.html} +14 -12
  27. package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
  28. package/default-pages/retro_game_starter/page.html +1308 -0
  29. package/default-pages/retro_game_starter/page.json +12 -0
  30. package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
  31. package/default-pages/sidebar_page/page.json +10 -0
  32. package/default-pages/{solar_explorer.html → solar_explorer/page.html} +14 -11
  33. package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
  34. package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
  35. package/default-pages/solar_tutorial/page.json +10 -0
  36. package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
  37. package/default-pages/two-panel_page/page.json +10 -0
  38. package/default-pages/{us_map.html → us_map/page.html} +193 -192
  39. package/default-pages/{us_map.json → us_map/page.json} +12 -12
  40. package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
  41. package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
  42. package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
  43. package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
  44. package/default-themes/aurora-dawn.json +19 -0
  45. package/default-themes/aurora-dawn.v3.css +198 -0
  46. package/default-themes/aurora-dusk.json +19 -0
  47. package/default-themes/aurora-dusk.v3.css +200 -0
  48. package/default-themes/cosmos-dawn.json +19 -0
  49. package/default-themes/cosmos-dawn.v3.css +198 -0
  50. package/default-themes/cosmos-dusk.json +19 -0
  51. package/default-themes/cosmos-dusk.v3.css +200 -0
  52. package/default-themes/high-contrast-dark.json +19 -0
  53. package/default-themes/high-contrast-dark.v3.css +200 -0
  54. package/default-themes/high-contrast-light.json +19 -0
  55. package/default-themes/high-contrast-light.v3.css +198 -0
  56. package/default-themes/nebula-dawn.v2.css +110 -0
  57. package/default-themes/nebula-dawn.v3.css +199 -0
  58. package/default-themes/nebula-dusk.v2.css +104 -0
  59. package/default-themes/nebula-dusk.v3.css +201 -0
  60. package/default-themes/solar-flare-dawn.json +19 -0
  61. package/default-themes/solar-flare-dawn.v3.css +198 -0
  62. package/default-themes/solar-flare-dusk.json +19 -0
  63. package/default-themes/solar-flare-dusk.v3.css +200 -0
  64. package/dist/agents/index.d.ts +1 -1
  65. package/dist/agents/index.d.ts.map +1 -1
  66. package/dist/agents/index.js +2 -1
  67. package/dist/agents/index.js.map +1 -1
  68. package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
  69. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
  70. package/dist/agents/openclaw/gatewayManager.js +27 -11
  71. package/dist/agents/openclaw/gatewayManager.js.map +1 -1
  72. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
  73. package/dist/agents/openclaw/openclawProvider.js +2 -4
  74. package/dist/agents/openclaw/openclawProvider.js.map +1 -1
  75. package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
  76. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
  77. package/dist/agents/openclaw/sshTunnelManager.js +31 -12
  78. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
  79. package/dist/builders/anthropic.d.ts +31 -0
  80. package/dist/builders/anthropic.d.ts.map +1 -0
  81. package/dist/builders/anthropic.js +227 -0
  82. package/dist/builders/anthropic.js.map +1 -0
  83. package/dist/builders/fireworksai.d.ts +9 -0
  84. package/dist/builders/fireworksai.d.ts.map +1 -0
  85. package/dist/builders/fireworksai.js +57 -0
  86. package/dist/builders/fireworksai.js.map +1 -0
  87. package/dist/builders/index.d.ts +13 -0
  88. package/dist/builders/index.d.ts.map +1 -0
  89. package/dist/builders/index.js +31 -0
  90. package/dist/builders/index.js.map +1 -0
  91. package/dist/builders/openai.d.ts +8 -0
  92. package/dist/builders/openai.d.ts.map +1 -0
  93. package/dist/builders/openai.js +87 -0
  94. package/dist/builders/openai.js.map +1 -0
  95. package/dist/builders/types.d.ts +54 -0
  96. package/dist/builders/types.d.ts.map +1 -0
  97. package/dist/builders/types.js +211 -0
  98. package/dist/builders/types.js.map +1 -0
  99. package/dist/connectors/index.d.ts.map +1 -1
  100. package/dist/connectors/index.js +3 -2
  101. package/dist/connectors/index.js.map +1 -1
  102. package/dist/connectors/registry.d.ts +2 -1
  103. package/dist/connectors/registry.d.ts.map +1 -1
  104. package/dist/connectors/registry.js +31 -8
  105. package/dist/connectors/registry.js.map +1 -1
  106. package/dist/customizer/Customizer.d.ts +57 -0
  107. package/dist/customizer/Customizer.d.ts.map +1 -0
  108. package/dist/customizer/Customizer.js +124 -0
  109. package/dist/customizer/Customizer.js.map +1 -0
  110. package/dist/customizer/index.d.ts.map +1 -0
  111. package/dist/customizer/index.js +9 -0
  112. package/dist/customizer/index.js.map +1 -0
  113. package/dist/files.d.ts +16 -0
  114. package/dist/files.d.ts.map +1 -1
  115. package/dist/files.js +60 -1
  116. package/dist/files.js.map +1 -1
  117. package/dist/index.d.ts.map +1 -1
  118. package/dist/index.js +1 -0
  119. package/dist/index.js.map +1 -1
  120. package/dist/init.d.ts +10 -6
  121. package/dist/init.d.ts.map +1 -1
  122. package/dist/init.js +96 -113
  123. package/dist/init.js.map +1 -1
  124. package/dist/migrations.d.ts.map +1 -1
  125. package/dist/migrations.js +23 -10
  126. package/dist/migrations.js.map +1 -1
  127. package/dist/models/anthropic.d.ts +4 -2
  128. package/dist/models/anthropic.d.ts.map +1 -1
  129. package/dist/models/anthropic.js +33 -6
  130. package/dist/models/anthropic.js.map +1 -1
  131. package/dist/models/fireworksai.d.ts.map +1 -1
  132. package/dist/models/fireworksai.js +9 -1
  133. package/dist/models/fireworksai.js.map +1 -1
  134. package/dist/models/index.d.ts +1 -1
  135. package/dist/models/index.d.ts.map +1 -1
  136. package/dist/models/index.js +2 -1
  137. package/dist/models/index.js.map +1 -1
  138. package/dist/models/openai.d.ts +1 -1
  139. package/dist/models/openai.d.ts.map +1 -1
  140. package/dist/models/openai.js +24 -3
  141. package/dist/models/openai.js.map +1 -1
  142. package/dist/models/types.d.ts +20 -1
  143. package/dist/models/types.d.ts.map +1 -1
  144. package/dist/models/types.js +6 -1
  145. package/dist/models/types.js.map +1 -1
  146. package/dist/pages.d.ts +30 -7
  147. package/dist/pages.d.ts.map +1 -1
  148. package/dist/pages.js +177 -55
  149. package/dist/pages.js.map +1 -1
  150. package/dist/service/server.d.ts.map +1 -1
  151. package/dist/service/server.js +37 -8
  152. package/dist/service/server.js.map +1 -1
  153. package/dist/service/transformPage.d.ts +47 -20
  154. package/dist/service/transformPage.d.ts.map +1 -1
  155. package/dist/service/transformPage.js +514 -293
  156. package/dist/service/transformPage.js.map +1 -1
  157. package/dist/service/useAgentRoutes.d.ts +2 -1
  158. package/dist/service/useAgentRoutes.d.ts.map +1 -1
  159. package/dist/service/useAgentRoutes.js +5 -2
  160. package/dist/service/useAgentRoutes.js.map +1 -1
  161. package/dist/service/useApiRoutes.d.ts.map +1 -1
  162. package/dist/service/useApiRoutes.js +237 -136
  163. package/dist/service/useApiRoutes.js.map +1 -1
  164. package/dist/service/useConnectorRoutes.js +6 -6
  165. package/dist/service/useConnectorRoutes.js.map +1 -1
  166. package/dist/service/useFileRoutes.d.ts +4 -0
  167. package/dist/service/useFileRoutes.d.ts.map +1 -0
  168. package/dist/service/useFileRoutes.js +122 -0
  169. package/dist/service/useFileRoutes.js.map +1 -0
  170. package/dist/service/usePageRoutes.d.ts.map +1 -1
  171. package/dist/service/usePageRoutes.js +648 -67
  172. package/dist/service/usePageRoutes.js.map +1 -1
  173. package/dist/service/useSharedDataRoutes.d.ts +4 -0
  174. package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
  175. package/dist/service/useSharedDataRoutes.js +104 -0
  176. package/dist/service/useSharedDataRoutes.js.map +1 -0
  177. package/dist/service/useSharedFileRoutes.d.ts +4 -0
  178. package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
  179. package/dist/service/useSharedFileRoutes.js +121 -0
  180. package/dist/service/useSharedFileRoutes.js.map +1 -0
  181. package/dist/settings.d.ts +1 -0
  182. package/dist/settings.d.ts.map +1 -1
  183. package/dist/settings.js +1 -0
  184. package/dist/settings.js.map +1 -1
  185. package/dist/synthos-cli.d.ts.map +1 -1
  186. package/dist/synthos-cli.js +4 -3
  187. package/dist/synthos-cli.js.map +1 -1
  188. package/dist/themes.d.ts +1 -0
  189. package/dist/themes.d.ts.map +1 -1
  190. package/dist/themes.js +28 -15
  191. package/dist/themes.js.map +1 -1
  192. package/migration-rules/v1-to-v2.md +193 -0
  193. package/migration-rules/v2-to-v3.md +481 -0
  194. package/package.json +11 -10
  195. package/required-pages/builder/page.html +43 -0
  196. package/required-pages/builder/page.json +10 -0
  197. package/required-pages/{pages.html → pages/page.html} +238 -233
  198. package/required-pages/pages/page.json +10 -0
  199. package/required-pages/{settings.html → settings/page.html} +389 -275
  200. package/required-pages/settings/page.json +10 -0
  201. package/required-pages/synthos_apis/page.html +846 -0
  202. package/required-pages/synthos_apis/page.json +10 -0
  203. package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
  204. package/required-pages/synthos_scripts/page.json +10 -0
  205. package/src/agents/index.ts +1 -1
  206. package/src/agents/openclaw/gatewayManager.ts +22 -11
  207. package/src/agents/openclaw/openclawProvider.ts +2 -4
  208. package/src/agents/openclaw/sshTunnelManager.ts +19 -11
  209. package/src/builders/anthropic.ts +283 -0
  210. package/src/builders/fireworksai.ts +59 -0
  211. package/src/builders/index.ts +33 -0
  212. package/src/builders/openai.ts +89 -0
  213. package/src/builders/types.ts +261 -0
  214. package/src/connectors/index.ts +1 -1
  215. package/src/connectors/registry.ts +28 -8
  216. package/src/customizer/Customizer.ts +151 -0
  217. package/src/customizer/index.ts +5 -0
  218. package/src/files.ts +57 -0
  219. package/src/index.ts +2 -1
  220. package/src/init.ts +137 -123
  221. package/src/migrations.ts +30 -10
  222. package/src/models/anthropic.ts +40 -10
  223. package/src/models/fireworksai.ts +9 -2
  224. package/src/models/index.ts +1 -1
  225. package/src/models/openai.ts +26 -6
  226. package/src/models/types.ts +31 -1
  227. package/src/pages.ts +176 -54
  228. package/src/service/server.ts +36 -9
  229. package/src/service/transformPage.ts +557 -326
  230. package/src/service/useAgentRoutes.ts +7 -2
  231. package/src/service/useApiRoutes.ts +150 -41
  232. package/src/service/useConnectorRoutes.ts +7 -7
  233. package/src/service/useFileRoutes.ts +127 -0
  234. package/src/service/usePageRoutes.ts +720 -73
  235. package/src/service/useSharedDataRoutes.ts +106 -0
  236. package/src/service/useSharedFileRoutes.ts +126 -0
  237. package/src/settings.ts +2 -0
  238. package/src/synthos-cli.ts +4 -3
  239. package/src/themes.ts +25 -14
  240. package/static-files/favicon.svg +12 -0
  241. package/static-files/fluentlm-instructions.llmd +868 -0
  242. package/static-files/fluentlm-instructions.md +1595 -0
  243. package/static-files/fluentlm.css +4844 -0
  244. package/static-files/fluentlm.js +3602 -0
  245. package/static-files/fluentlm.min.css +1 -0
  246. package/static-files/fluentlm.min.js +1 -0
  247. package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
  248. package/static-files/page.v3.js +1290 -0
  249. package/static-files/recommended-frameworks.llmd +81 -0
  250. package/static-files/recommended-frameworks.md +137 -0
  251. package/static-files/retro-game.js +877 -0
  252. package/static-files/shell.css +797 -0
  253. package/static-files/theme-dark.css +169 -0
  254. package/static-files/theme-light.css +169 -0
  255. package/tests/builders.spec.ts +139 -0
  256. package/tests/pages.spec.ts +8 -8
  257. package/tests/transformPage.spec.ts +299 -360
  258. package/default-pages/application.html +0 -40
  259. package/default-pages/application.json +0 -1
  260. package/default-pages/json_tools.json +0 -1
  261. package/default-pages/my_notes.html +0 -33
  262. package/default-pages/neon_asteroids.html +0 -77
  263. package/default-pages/sidebar_page.json +0 -1
  264. package/default-pages/solar_tutorial.json +0 -1
  265. package/default-pages/two-panel_page.json +0 -1
  266. package/dist/agents/a2a/a2aProvider.d.ts +0 -3
  267. package/dist/agents/discovery.d.ts +0 -30
  268. package/dist/agents/openclaw/openclawProvider.d.ts +0 -3
  269. package/dist/agents/types.d.ts +0 -64
  270. package/dist/connectors/index.d.ts +0 -3
  271. package/dist/connectors/types.d.ts +0 -84
  272. package/dist/index.d.ts +0 -7
  273. package/dist/migrations.d.ts +0 -12
  274. package/dist/models/chainOfThought.d.ts +0 -12
  275. package/dist/models/fireworksai.d.ts +0 -30
  276. package/dist/models/logCompletePrompt.d.ts +0 -3
  277. package/dist/models/providers.d.ts +0 -8
  278. package/dist/models/utils.d.ts +0 -6
  279. package/dist/scripts.d.ts +0 -15
  280. package/dist/service/createCompletePrompt.d.ts +0 -5
  281. package/dist/service/debugLog.d.ts +0 -11
  282. package/dist/service/generateImage.d.ts +0 -32
  283. package/dist/service/index.d.ts +0 -8
  284. package/dist/service/modelInstructions.d.ts +0 -7
  285. package/dist/service/requiresSettings.d.ts +0 -3
  286. package/dist/service/server.d.ts +0 -4
  287. package/dist/service/useApiRoutes.d.ts +0 -4
  288. package/dist/service/useConnectorRoutes.d.ts +0 -4
  289. package/dist/service/useDataRoutes.d.ts +0 -4
  290. package/dist/service/useGatewayRoutes.d.ts +0 -4
  291. package/dist/service/useGatewayRoutes.d.ts.map +0 -1
  292. package/dist/service/useGatewayRoutes.js +0 -168
  293. package/dist/service/useGatewayRoutes.js.map +0 -1
  294. package/dist/service/usePageRoutes.d.ts +0 -5
  295. package/dist/synthos-cli.d.ts +0 -2
  296. package/page-scripts/page-v2.js +0 -656
  297. package/required-pages/builder.html +0 -48
  298. package/required-pages/builder.json +0 -1
  299. package/required-pages/pages.json +0 -1
  300. package/required-pages/settings.json +0 -1
  301. package/required-pages/synthos_apis.html +0 -327
  302. package/required-pages/synthos_apis.json +0 -1
  303. package/required-pages/synthos_scripts.json +0 -1
  304. package/src/connectors/airtable/connector.json +0 -27
  305. package/src/connectors/alpha-vantage/connector.json +0 -26
  306. package/src/connectors/brave-search/connector.json +0 -26
  307. package/src/connectors/cloudinary/connector.json +0 -27
  308. package/src/connectors/deepl/connector.json +0 -28
  309. package/src/connectors/elevenlabs/connector.json +0 -30
  310. package/src/connectors/giphy/connector.json +0 -27
  311. package/src/connectors/github/connector.json +0 -29
  312. package/src/connectors/huggingface/connector.json +0 -27
  313. package/src/connectors/imgur/connector.json +0 -29
  314. package/src/connectors/instagram/connector.json +0 -43
  315. package/src/connectors/jira/connector.json +0 -28
  316. package/src/connectors/mapbox/connector.json +0 -26
  317. package/src/connectors/nasa/connector.json +0 -27
  318. package/src/connectors/newsapi/connector.json +0 -27
  319. package/src/connectors/notion/connector.json +0 -28
  320. package/src/connectors/open-exchange-rates/connector.json +0 -27
  321. package/src/connectors/openweathermap/connector.json +0 -26
  322. package/src/connectors/pexels/connector.json +0 -27
  323. package/src/connectors/resend/connector.json +0 -29
  324. package/src/connectors/rss2json/connector.json +0 -27
  325. package/src/connectors/sendgrid/connector.json +0 -27
  326. package/src/connectors/spoonacular/connector.json +0 -28
  327. package/src/connectors/stability-ai/connector.json +0 -27
  328. package/src/connectors/twilio/connector.json +0 -28
  329. package/src/connectors/unsplash/connector.json +0 -27
  330. package/src/connectors/wolfram-alpha/connector.json +0 -26
  331. package/src/connectors/youtube-data/connector.json +0 -30
  332. /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
  333. /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
  334. /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
  335. /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
  336. /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
  337. /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
  338. /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
  339. /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
  340. /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
  341. /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
  342. /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
  343. /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
  344. /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
  345. /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
  346. /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
  347. /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
  348. /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
  349. /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
  350. /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
  351. /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
  352. /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
  353. /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
  354. /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
  355. /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
  356. /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
  357. /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
  358. /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
  359. /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
@@ -0,0 +1,106 @@
1
+ import { Application, Response } from 'express';
2
+ import { SynthOSConfig } from "../init";
3
+ import { checkIfExists, deleteFile, ensureFolderExists, listFiles, loadFile, saveFile } from "../files";
4
+ import path from "path";
5
+ import { v4 } from "uuid";
6
+
7
+ export function useSharedDataRoutes(config: SynthOSConfig, app: Application): void {
8
+ app.get('/api/shared/data/:table', (req, res) => handleList(config, req.params.table, req.query, res));
9
+ app.get('/api/shared/data/:table/:id', (req, res) => handleGet(config, req.params.table, req.params.id, res));
10
+ app.post('/api/shared/data/:table', (req, res) => handleUpsert(config, req.params.table, req.body, res));
11
+ app.delete('/api/shared/data/:table/:id', (req, res) => handleDelete(config, req.params.table, req.params.id, res));
12
+ }
13
+
14
+ // ---------------------------------------------------------------------------
15
+ // Route handlers
16
+ // ---------------------------------------------------------------------------
17
+
18
+ async function handleList(config: SynthOSConfig, table: string, query: Record<string, any>, res: Response): Promise<void> {
19
+ const folder = sharedTableFolder(config, table);
20
+ if (!(await checkIfExists(folder))) {
21
+ res.status(404).json({ error: 'table_not_found', table });
22
+ return;
23
+ }
24
+
25
+ const ids = (await listFiles(folder)).filter(f => f.endsWith('.json')).map(f => f.replace('.json', ''));
26
+
27
+ const rows: Record<string, any>[] = [];
28
+ for (const id of ids) {
29
+ const file = recordFile(folder, id);
30
+ try {
31
+ const row = JSON.parse(await loadFile(file));
32
+ row.id = id;
33
+ rows.push(row);
34
+ } catch (err: unknown) {
35
+ console.error(err);
36
+ }
37
+ }
38
+
39
+ // Paginate when limit is provided
40
+ const limitParam = typeof query.limit === 'string' ? parseInt(query.limit, 10) : NaN;
41
+ if (!isNaN(limitParam) && limitParam > 0) {
42
+ const offset = Math.max(0, typeof query.offset === 'string' ? parseInt(query.offset, 10) || 0 : 0);
43
+ const items = rows.slice(offset, offset + limitParam);
44
+ res.json({ items, total: rows.length, offset, limit: limitParam, hasMore: offset + limitParam < rows.length });
45
+ } else {
46
+ res.json(rows);
47
+ }
48
+ }
49
+
50
+ async function handleGet(config: SynthOSConfig, table: string, id: string, res: Response): Promise<void> {
51
+ const folder = sharedTableFolder(config, table);
52
+ if (!(await checkIfExists(folder))) {
53
+ res.status(404).json({ error: 'table_not_found', table });
54
+ return;
55
+ }
56
+
57
+ const file = recordFile(folder, id);
58
+ try {
59
+ const row = JSON.parse(await loadFile(file));
60
+ row.id = id;
61
+ res.json(row);
62
+ } catch (err: unknown) {
63
+ res.json({});
64
+ }
65
+ }
66
+
67
+ async function handleUpsert(config: SynthOSConfig, table: string, body: any, res: Response): Promise<void> {
68
+ const id = body.id ?? v4();
69
+ const folder = sharedTableFolder(config, table);
70
+ const file = recordFile(folder, id);
71
+ try {
72
+ const row = { ...body, id };
73
+ await ensureFolderExists(folder);
74
+ await saveFile(file, JSON.stringify(row, null, 4));
75
+ res.json(row);
76
+ } catch (err: unknown) {
77
+ console.error(err);
78
+ res.status(500).send((err as Error).message);
79
+ }
80
+ }
81
+
82
+ async function handleDelete(config: SynthOSConfig, table: string, id: string, res: Response): Promise<void> {
83
+ const folder = sharedTableFolder(config, table);
84
+ const file = recordFile(folder, id);
85
+ try {
86
+ if (await checkIfExists(file)) {
87
+ await deleteFile(file);
88
+ }
89
+ res.json({ success: true });
90
+ } catch (err: unknown) {
91
+ console.error(err);
92
+ res.status(500).send((err as Error).message);
93
+ }
94
+ }
95
+
96
+ // ---------------------------------------------------------------------------
97
+ // Helpers
98
+ // ---------------------------------------------------------------------------
99
+
100
+ function sharedTableFolder(config: SynthOSConfig, table: string): string {
101
+ return path.join(config.pagesFolder, 'shared', table);
102
+ }
103
+
104
+ function recordFile(folder: string, id: string): string {
105
+ return path.join(folder, `${id}.json`);
106
+ }
@@ -0,0 +1,126 @@
1
+ import { Application } from 'express';
2
+ import express from 'express';
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { SynthOSConfig } from '../init';
6
+ import { checkIfExists, ensureFolderExists } from '../files';
7
+
8
+ export function useSharedFileRoutes(config: SynthOSConfig, app: Application): void {
9
+ // List files in the shared files folder
10
+ app.get('/api/shared/files', async (req, res) => {
11
+ try {
12
+ const folder = sharedFilesFolder(config);
13
+ if (!(await checkIfExists(folder))) {
14
+ res.json({ files: [] });
15
+ return;
16
+ }
17
+
18
+ const entries = await fs.readdir(folder);
19
+ const files: { name: string; size: number }[] = [];
20
+ for (const entry of entries) {
21
+ const stat = await fs.stat(path.join(folder, entry));
22
+ if (stat.isFile()) {
23
+ files.push({ name: entry, size: stat.size });
24
+ }
25
+ }
26
+ res.json({ files });
27
+ } catch (err: unknown) {
28
+ console.error(err);
29
+ res.status(500).json({ error: (err as Error).message });
30
+ }
31
+ });
32
+
33
+ // Download/serve a specific shared file
34
+ app.get('/api/shared/files/:filename', async (req, res) => {
35
+ try {
36
+ const filePath = safeFilePath(config, req.params.filename);
37
+ if (!filePath) {
38
+ res.status(400).json({ error: 'Invalid filename' });
39
+ return;
40
+ }
41
+
42
+ if (!(await checkIfExists(filePath))) {
43
+ res.status(404).json({ error: 'File not found' });
44
+ return;
45
+ }
46
+
47
+ res.sendFile(filePath);
48
+ } catch (err: unknown) {
49
+ console.error(err);
50
+ res.status(500).json({ error: (err as Error).message });
51
+ }
52
+ });
53
+
54
+ // Upload a shared file (raw body + x-filename header)
55
+ app.post('/api/shared/files', express.raw({ type: '*/*', limit: '50mb' }), async (req, res) => {
56
+ try {
57
+ const filename = req.headers['x-filename'] as string | undefined;
58
+ if (!filename || filename.trim().length === 0) {
59
+ res.status(400).json({ error: 'x-filename header is required' });
60
+ return;
61
+ }
62
+
63
+ const filePath = safeFilePath(config, filename);
64
+ if (!filePath) {
65
+ res.status(400).json({ error: 'Invalid filename' });
66
+ return;
67
+ }
68
+
69
+ const folder = sharedFilesFolder(config);
70
+ await ensureFolderExists(folder);
71
+ await fs.writeFile(filePath, req.body as Buffer);
72
+
73
+ const stat = await fs.stat(filePath);
74
+ res.status(201).json({ name: filename, size: stat.size });
75
+ } catch (err: unknown) {
76
+ console.error(err);
77
+ res.status(500).json({ error: (err as Error).message });
78
+ }
79
+ });
80
+
81
+ // Delete a shared file
82
+ app.delete('/api/shared/files/:filename', async (req, res) => {
83
+ try {
84
+ const filePath = safeFilePath(config, req.params.filename);
85
+ if (!filePath) {
86
+ res.status(400).json({ error: 'Invalid filename' });
87
+ return;
88
+ }
89
+
90
+ if (!(await checkIfExists(filePath))) {
91
+ res.status(404).json({ error: 'File not found' });
92
+ return;
93
+ }
94
+
95
+ await fs.unlink(filePath);
96
+ res.json({ deleted: true });
97
+ } catch (err: unknown) {
98
+ console.error(err);
99
+ res.status(500).json({ error: (err as Error).message });
100
+ }
101
+ });
102
+ }
103
+
104
+ // ---------------------------------------------------------------------------
105
+ // Helpers
106
+ // ---------------------------------------------------------------------------
107
+
108
+ function sharedFilesFolder(config: SynthOSConfig): string {
109
+ return path.join(config.pagesFolder, 'shared', 'files');
110
+ }
111
+
112
+ /**
113
+ * Resolve a filename inside the shared files folder with path-traversal protection.
114
+ * Returns the absolute path if safe, or null if the filename is invalid.
115
+ */
116
+ function safeFilePath(config: SynthOSConfig, filename: string): string | null {
117
+ if (!filename || filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
118
+ return null;
119
+ }
120
+ const folder = sharedFilesFolder(config);
121
+ const resolved = path.resolve(folder, filename);
122
+ if (!resolved.startsWith(path.resolve(folder))) {
123
+ return null;
124
+ }
125
+ return resolved;
126
+ }
package/src/settings.ts CHANGED
@@ -39,6 +39,7 @@ export interface SettingsV2 {
39
39
  services?: ServicesConfig;
40
40
  connectors?: ServicesConfig;
41
41
  agents?: AgentConfig[];
42
+ toolbarPosition?: 'left' | 'right';
42
43
  }
43
44
 
44
45
  export const DefaultSettings: SettingsV2 = {
@@ -66,6 +67,7 @@ export const DefaultSettings: SettingsV2 = {
66
67
  services: {},
67
68
  connectors: {},
68
69
  agents: [],
70
+ toolbarPosition: 'left',
69
71
  };
70
72
 
71
73
  /**
@@ -2,6 +2,7 @@ import yargs from "yargs";
2
2
  import { hideBin } from "yargs/helpers";
3
3
  import { server } from "./service";
4
4
  import { createConfig, init } from "./init";
5
+ import { customizer } from "./customizer";
5
6
 
6
7
  const dynamicImport = new Function('specifier', `return import(specifier)`);
7
8
 
@@ -16,7 +17,7 @@ export async function run() {
16
17
  default: 4242
17
18
  })
18
19
  .option('pages', {
19
- describe: `Include default pages when initializing a new .synthos folder.`,
20
+ describe: `Include default pages when initializing a new local folder.`,
20
21
  type: 'boolean',
21
22
  default: true
22
23
  })
@@ -32,9 +33,9 @@ export async function run() {
32
33
  })
33
34
  .demandOption([]);
34
35
  }, async (args) => {
35
- const config = createConfig('.synthos', { debug: args.debug, debugPageUpdates: args.debugPageUpdates });
36
+ const config = await createConfig(customizer.localFolder, { debug: args.debug, debugPageUpdates: args.debugPageUpdates }, customizer);
36
37
  await init(config, args.pages);
37
- await server(config).listen(args.port, async () => {
38
+ await server(config, customizer).listen(args.port, async () => {
38
39
  console.log(`SynthOS server is running on http://localhost:${args.port}`);
39
40
 
40
41
  // Open using default browser
package/src/themes.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { checkIfExists, listFiles, loadFile } from './files';
2
+ import { checkIfExists, findFileInFolders, listFiles, listFilesFromFolders, loadFile } from './files';
3
3
  import { SynthOSConfig } from './init';
4
4
 
5
5
  export const THEME_VERSION = 2;
@@ -46,6 +46,16 @@ async function findThemeCssFile(folder: string, name: string): Promise<{ path: s
46
46
  return best;
47
47
  }
48
48
 
49
+ export async function loadThemeVersion(name: string, config: SynthOSConfig): Promise<number> {
50
+ const local = await findThemeCssFile(userThemesFolder(config), name);
51
+ if (local) return local.version;
52
+ for (const folder of config.defaultThemesFolders) {
53
+ const def = await findThemeCssFile(folder, name);
54
+ if (def) return def.version;
55
+ }
56
+ return 1;
57
+ }
58
+
49
59
  export async function loadThemeInfo(name: string, config: SynthOSConfig): Promise<ThemeInfo | undefined> {
50
60
  // Check user's local themes first, then fall back to package defaults
51
61
  const localPath = path.join(userThemesFolder(config), `${name}.json`);
@@ -54,8 +64,8 @@ export async function loadThemeInfo(name: string, config: SynthOSConfig): Promis
54
64
  return raw ? JSON.parse(raw) : undefined;
55
65
  }
56
66
 
57
- const defaultPath = path.join(config.defaultThemesFolder, `${name}.json`);
58
- if (await checkIfExists(defaultPath)) {
67
+ const defaultPath = await findFileInFolders(config.defaultThemesFolders, `${name}.json`);
68
+ if (defaultPath) {
59
69
  const raw = await loadFile(defaultPath);
60
70
  return raw ? JSON.parse(raw) : undefined;
61
71
  }
@@ -70,9 +80,12 @@ export async function loadTheme(name: string, config: SynthOSConfig): Promise<st
70
80
  return await loadFile(local.path);
71
81
  }
72
82
 
73
- const def = await findThemeCssFile(config.defaultThemesFolder, name);
74
- if (def) {
75
- return await loadFile(def.path);
83
+ // Search all default theme folders
84
+ for (const folder of config.defaultThemesFolders) {
85
+ const def = await findThemeCssFile(folder, name);
86
+ if (def) {
87
+ return await loadFile(def.path);
88
+ }
76
89
  }
77
90
 
78
91
  return undefined;
@@ -91,13 +104,11 @@ export async function listThemes(config: SynthOSConfig): Promise<string[]> {
91
104
  }
92
105
  }
93
106
 
94
- // Collect from package defaults
95
- if (await checkIfExists(config.defaultThemesFolder)) {
96
- const files = await listFiles(config.defaultThemesFolder);
97
- for (const f of files) {
98
- const parsed = parseThemeFilename(f);
99
- if (parsed) names.add(parsed.name);
100
- }
107
+ // Collect from all default theme folders
108
+ const defaultFiles = await listFilesFromFolders(config.defaultThemesFolders);
109
+ for (const f of defaultFiles) {
110
+ const parsed = parseThemeFilename(f);
111
+ if (parsed) names.add(parsed.name);
101
112
  }
102
113
 
103
114
  return Array.from(names).sort();
@@ -110,7 +121,7 @@ export async function getOutdatedThemes(config: SynthOSConfig): Promise<string[]
110
121
  const localFolder = userThemesFolder(config);
111
122
  if (!await checkIfExists(localFolder)) return [];
112
123
 
113
- const defaultFiles = await listFiles(config.defaultThemesFolder);
124
+ const defaultFiles = await listFilesFromFolders(config.defaultThemesFolders);
114
125
  const localFiles = await listFiles(localFolder);
115
126
 
116
127
  // Build maps: theme name → highest version
@@ -0,0 +1,12 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
2
+ <defs>
3
+ <linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%">
4
+ <stop offset="0%" stop-color="#a855f7"/>
5
+ <stop offset="100%" stop-color="#3b82f6"/>
6
+ </linearGradient>
7
+ </defs>
8
+ <rect width="32" height="32" rx="7" fill="#0f0f13"/>
9
+ <path d="M9 11 C9 8.8 10.8 7 13 7 L20 7 C22.2 7 24 8.8 24 11 C24 13.2 22.2 15 20 15 L13 15 C10.8 15 9 16.8 9 19 C9 21.2 10.8 23 13 23 L20 23" stroke="url(#g)" stroke-width="3" stroke-linecap="round" fill="none"/>
10
+ <circle cx="9" cy="11" r="2" fill="#a855f7"/>
11
+ <circle cx="23" cy="23" r="2" fill="#3b82f6"/>
12
+ </svg>