synthos 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/default-pages/application/page.html +42 -0
- package/default-pages/application/page.json +10 -0
- package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
- package/default-pages/elevenlabs_effects_studio/page.json +11 -0
- package/default-pages/elevenlabs_voice_studio/page.html +801 -0
- package/default-pages/elevenlabs_voice_studio/page.json +11 -0
- package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
- package/default-pages/json_tools/page.json +10 -0
- package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
- package/default-pages/my_notes/page.html +132 -0
- package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
- package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
- package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
- package/default-pages/neon_asteroids/files/effects.json +74 -0
- package/default-pages/neon_asteroids/page.html +1803 -0
- package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
- package/default-pages/{oregon_trail.html → oregon_trail/page.html} +16 -30
- package/default-pages/{oregon_trail.json → oregon_trail/page.json} +2 -2
- package/default-pages/retro_game_starter/page.html +1308 -0
- package/default-pages/retro_game_starter/page.json +12 -0
- package/default-pages/{sidebar_page.html → sidebar_page/page.html} +12 -10
- package/default-pages/sidebar_page/page.json +10 -0
- package/default-pages/{solar_explorer.html → solar_explorer/page.html} +15 -12
- package/default-pages/{solar_explorer.json → solar_explorer/page.json} +2 -2
- package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
- package/default-pages/solar_tutorial/page.json +10 -0
- package/default-pages/{two-panel_page.html → two-panel_page/page.html} +13 -11
- package/default-pages/two-panel_page/page.json +10 -0
- package/default-pages/{us_map.html → us_map/page.html} +193 -192
- package/default-pages/{us_map.json → us_map/page.json} +12 -12
- package/default-pages/{us_map_1850.html → us_map_1850/page.html} +326 -325
- package/default-pages/{us_map_1850.json → us_map_1850/page.json} +12 -12
- package/default-pages/{western_cities_1850.html → western_cities_1850/page.html} +527 -526
- package/default-pages/{western_cities_1850.json → western_cities_1850/page.json} +12 -12
- package/default-themes/aurora-dawn.json +19 -0
- package/default-themes/aurora-dawn.v3.css +198 -0
- package/default-themes/aurora-dusk.json +19 -0
- package/default-themes/aurora-dusk.v3.css +200 -0
- package/default-themes/cosmos-dawn.json +19 -0
- package/default-themes/cosmos-dawn.v3.css +198 -0
- package/default-themes/cosmos-dusk.json +19 -0
- package/default-themes/cosmos-dusk.v3.css +200 -0
- package/default-themes/high-contrast-dark.json +19 -0
- package/default-themes/high-contrast-dark.v3.css +200 -0
- package/default-themes/high-contrast-light.json +19 -0
- package/default-themes/high-contrast-light.v3.css +198 -0
- package/default-themes/nebula-dawn.v2.css +110 -0
- package/default-themes/nebula-dawn.v3.css +199 -0
- package/default-themes/nebula-dusk.v2.css +104 -0
- package/default-themes/nebula-dusk.v3.css +201 -0
- package/default-themes/solar-flare-dawn.json +19 -0
- package/default-themes/solar-flare-dawn.v3.css +198 -0
- package/default-themes/solar-flare-dusk.json +19 -0
- package/default-themes/solar-flare-dusk.v3.css +200 -0
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +2 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/openclaw/gatewayManager.d.ts +4 -0
- package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -1
- package/dist/agents/openclaw/gatewayManager.js +27 -11
- package/dist/agents/openclaw/gatewayManager.js.map +1 -1
- package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -1
- package/dist/agents/openclaw/openclawProvider.js +2 -4
- package/dist/agents/openclaw/openclawProvider.js.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.d.ts +2 -0
- package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -1
- package/dist/agents/openclaw/sshTunnelManager.js +31 -12
- package/dist/agents/openclaw/sshTunnelManager.js.map +1 -1
- package/dist/builders/anthropic.d.ts +31 -0
- package/dist/builders/anthropic.d.ts.map +1 -0
- package/dist/builders/anthropic.js +227 -0
- package/dist/builders/anthropic.js.map +1 -0
- package/dist/builders/fireworksai.d.ts +9 -0
- package/dist/builders/fireworksai.d.ts.map +1 -0
- package/dist/builders/fireworksai.js +57 -0
- package/dist/builders/fireworksai.js.map +1 -0
- package/dist/builders/index.d.ts +13 -0
- package/dist/builders/index.d.ts.map +1 -0
- package/dist/builders/index.js +31 -0
- package/dist/builders/index.js.map +1 -0
- package/dist/builders/openai.d.ts +8 -0
- package/dist/builders/openai.d.ts.map +1 -0
- package/dist/builders/openai.js +87 -0
- package/dist/builders/openai.js.map +1 -0
- package/dist/builders/types.d.ts +54 -0
- package/dist/builders/types.d.ts.map +1 -0
- package/dist/builders/types.js +211 -0
- package/dist/builders/types.js.map +1 -0
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/registry.d.ts +2 -1
- package/dist/connectors/registry.d.ts.map +1 -1
- package/dist/connectors/registry.js +31 -8
- package/dist/connectors/registry.js.map +1 -1
- package/dist/customizer/Customizer.d.ts +62 -0
- package/dist/customizer/Customizer.d.ts.map +1 -0
- package/dist/customizer/Customizer.js +134 -0
- package/dist/customizer/Customizer.js.map +1 -0
- package/dist/customizer/index.d.ts +4 -0
- package/dist/customizer/index.d.ts.map +1 -0
- package/dist/customizer/index.js +9 -0
- package/dist/customizer/index.js.map +1 -0
- package/dist/files.d.ts +16 -0
- package/dist/files.d.ts.map +1 -1
- package/dist/files.js +60 -1
- package/dist/files.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +12 -6
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +150 -133
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +23 -10
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +4 -2
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +33 -6
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/fireworksai.d.ts.map +1 -1
- package/dist/models/fireworksai.js +9 -1
- package/dist/models/fireworksai.js.map +1 -1
- package/dist/models/index.d.ts +1 -1
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -1
- package/dist/models/index.js.map +1 -1
- package/dist/models/openai.d.ts +1 -1
- package/dist/models/openai.d.ts.map +1 -1
- package/dist/models/openai.js +24 -3
- package/dist/models/openai.js.map +1 -1
- package/dist/models/types.d.ts +20 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +6 -1
- package/dist/models/types.js.map +1 -1
- package/dist/pages.d.ts +34 -10
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +229 -79
- package/dist/pages.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts +2 -1
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +2 -2
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/requiresSettings.d.ts +2 -1
- package/dist/service/requiresSettings.d.ts.map +1 -1
- package/dist/service/requiresSettings.js +3 -3
- package/dist/service/requiresSettings.js.map +1 -1
- package/dist/service/server.d.ts +2 -1
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +37 -8
- package/dist/service/server.js.map +1 -1
- package/dist/service/transformPage.d.ts +47 -20
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +514 -293
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useAgentRoutes.d.ts +2 -1
- package/dist/service/useAgentRoutes.d.ts.map +1 -1
- package/dist/service/useAgentRoutes.js +17 -14
- package/dist/service/useAgentRoutes.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts +2 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +287 -172
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.js +17 -17
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useDataRoutes.d.ts.map +1 -1
- package/dist/service/useDataRoutes.js +13 -10
- package/dist/service/useDataRoutes.js.map +1 -1
- package/dist/service/useFileRoutes.d.ts +4 -0
- package/dist/service/useFileRoutes.d.ts.map +1 -0
- package/dist/service/useFileRoutes.js +122 -0
- package/dist/service/useFileRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts +2 -1
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +671 -74
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/service/useSharedDataRoutes.d.ts +4 -0
- package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
- package/dist/service/useSharedDataRoutes.js +107 -0
- package/dist/service/useSharedDataRoutes.js.map +1 -0
- package/dist/service/useSharedFileRoutes.d.ts +4 -0
- package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
- package/dist/service/useSharedFileRoutes.js +121 -0
- package/dist/service/useSharedFileRoutes.js.map +1 -0
- package/dist/settings.d.ts +5 -3
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +12 -10
- package/dist/settings.js.map +1 -1
- package/dist/storage/FsStorageProvider.d.ts +25 -0
- package/dist/storage/FsStorageProvider.d.ts.map +1 -0
- package/dist/storage/FsStorageProvider.js +103 -0
- package/dist/storage/FsStorageProvider.js.map +1 -0
- package/dist/storage/StorageProvider.d.ts +31 -0
- package/dist/storage/StorageProvider.d.ts.map +1 -0
- package/dist/storage/StorageProvider.js +3 -0
- package/dist/storage/StorageProvider.js.map +1 -0
- package/dist/storage/index.d.ts +3 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +6 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/synthos-cli.d.ts.map +1 -1
- package/dist/synthos-cli.js +4 -3
- package/dist/synthos-cli.js.map +1 -1
- package/dist/themes.d.ts +1 -0
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +65 -28
- package/dist/themes.js.map +1 -1
- package/migration-rules/v1-to-v2.md +193 -0
- package/migration-rules/v2-to-v3.md +481 -0
- package/package.json +11 -10
- package/required-pages/builder/page.html +43 -0
- package/required-pages/builder/page.json +10 -0
- package/required-pages/{pages.html → pages/page.html} +238 -233
- package/required-pages/pages/page.json +10 -0
- package/required-pages/{settings.html → settings/page.html} +389 -275
- package/required-pages/settings/page.json +10 -0
- package/required-pages/synthos_apis/page.html +846 -0
- package/required-pages/synthos_apis/page.json +10 -0
- package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
- package/required-pages/synthos_scripts/page.json +10 -0
- package/src/agents/index.ts +1 -1
- package/src/agents/openclaw/gatewayManager.ts +22 -11
- package/src/agents/openclaw/openclawProvider.ts +2 -4
- package/src/agents/openclaw/sshTunnelManager.ts +19 -11
- package/src/builders/anthropic.ts +283 -0
- package/src/builders/fireworksai.ts +59 -0
- package/src/builders/index.ts +33 -0
- package/src/builders/openai.ts +89 -0
- package/src/builders/types.ts +261 -0
- package/src/connectors/index.ts +1 -1
- package/src/connectors/registry.ts +28 -8
- package/src/customizer/Customizer.ts +163 -0
- package/src/customizer/index.ts +5 -0
- package/src/files.ts +57 -0
- package/src/index.ts +3 -1
- package/src/init.ts +195 -145
- package/src/migrations.ts +30 -10
- package/src/models/anthropic.ts +40 -10
- package/src/models/fireworksai.ts +9 -2
- package/src/models/index.ts +1 -1
- package/src/models/openai.ts +26 -6
- package/src/models/types.ts +31 -1
- package/src/pages.ts +230 -77
- package/src/service/createCompletePrompt.ts +3 -2
- package/src/service/requiresSettings.ts +4 -3
- package/src/service/server.ts +36 -9
- package/src/service/transformPage.ts +557 -326
- package/src/service/useAgentRoutes.ts +19 -14
- package/src/service/useApiRoutes.ts +208 -84
- package/src/service/useConnectorRoutes.ts +18 -18
- package/src/service/useDataRoutes.ts +13 -10
- package/src/service/useFileRoutes.ts +128 -0
- package/src/service/usePageRoutes.ts +730 -81
- package/src/service/useSharedDataRoutes.ts +109 -0
- package/src/service/useSharedFileRoutes.ts +127 -0
- package/src/settings.ts +14 -10
- package/src/storage/FsStorageProvider.ts +87 -0
- package/src/storage/StorageProvider.ts +34 -0
- package/src/storage/index.ts +2 -0
- package/src/synthos-cli.ts +4 -3
- package/src/themes.ts +64 -27
- package/static-files/favicon.svg +12 -0
- package/static-files/fluentlm-instructions.llmd +868 -0
- package/static-files/fluentlm-instructions.md +1595 -0
- package/static-files/fluentlm.css +4844 -0
- package/static-files/fluentlm.js +3602 -0
- package/static-files/fluentlm.min.css +1 -0
- package/static-files/fluentlm.min.js +1 -0
- package/{page-scripts/helpers-v2.js → static-files/helpers.v3.js} +82 -0
- package/static-files/page.v3.js +1290 -0
- package/static-files/recommended-frameworks.llmd +81 -0
- package/static-files/recommended-frameworks.md +137 -0
- package/static-files/retro-game.js +877 -0
- package/static-files/shell.css +797 -0
- package/static-files/theme-dark.css +169 -0
- package/static-files/theme-light.css +169 -0
- package/tests/builders.spec.ts +139 -0
- package/tests/pages.spec.ts +54 -84
- package/tests/transformPage.spec.ts +299 -360
- package/default-pages/application.html +0 -40
- package/default-pages/application.json +0 -1
- package/default-pages/json_tools.json +0 -1
- package/default-pages/my_notes.html +0 -33
- package/default-pages/neon_asteroids.html +0 -77
- package/default-pages/sidebar_page.json +0 -1
- package/default-pages/solar_tutorial.json +0 -1
- package/default-pages/two-panel_page.json +0 -1
- package/dist/service/useGatewayRoutes.d.ts +0 -4
- package/dist/service/useGatewayRoutes.d.ts.map +0 -1
- package/dist/service/useGatewayRoutes.js +0 -168
- package/dist/service/useGatewayRoutes.js.map +0 -1
- package/page-scripts/page-v2.js +0 -656
- package/required-pages/builder.html +0 -48
- package/required-pages/builder.json +0 -1
- package/required-pages/pages.json +0 -1
- package/required-pages/settings.json +0 -1
- package/required-pages/synthos_apis.html +0 -327
- package/required-pages/synthos_apis.json +0 -1
- package/required-pages/synthos_scripts.json +0 -1
- package/src/connectors/airtable/connector.json +0 -27
- package/src/connectors/alpha-vantage/connector.json +0 -26
- package/src/connectors/brave-search/connector.json +0 -26
- package/src/connectors/cloudinary/connector.json +0 -27
- package/src/connectors/deepl/connector.json +0 -28
- package/src/connectors/elevenlabs/connector.json +0 -30
- package/src/connectors/giphy/connector.json +0 -27
- package/src/connectors/github/connector.json +0 -29
- package/src/connectors/huggingface/connector.json +0 -27
- package/src/connectors/imgur/connector.json +0 -29
- package/src/connectors/instagram/connector.json +0 -43
- package/src/connectors/jira/connector.json +0 -28
- package/src/connectors/mapbox/connector.json +0 -26
- package/src/connectors/nasa/connector.json +0 -27
- package/src/connectors/newsapi/connector.json +0 -27
- package/src/connectors/notion/connector.json +0 -28
- package/src/connectors/open-exchange-rates/connector.json +0 -27
- package/src/connectors/openweathermap/connector.json +0 -26
- package/src/connectors/pexels/connector.json +0 -27
- package/src/connectors/resend/connector.json +0 -29
- package/src/connectors/rss2json/connector.json +0 -27
- package/src/connectors/sendgrid/connector.json +0 -27
- package/src/connectors/spoonacular/connector.json +0 -28
- package/src/connectors/stability-ai/connector.json +0 -27
- package/src/connectors/twilio/connector.json +0 -28
- package/src/connectors/unsplash/connector.json +0 -27
- package/src/connectors/wolfram-alpha/connector.json +0 -26
- package/src/connectors/youtube-data/connector.json +0 -30
- /package/{dist/connectors → service-connectors}/airtable/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/alpha-vantage/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/brave-search/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/cloudinary/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/deepl/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/elevenlabs/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/giphy/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/github/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/huggingface/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/imgur/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/instagram/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/jira/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/mapbox/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/nasa/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/newsapi/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/notion/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/open-exchange-rates/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/openweathermap/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/pexels/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/resend/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/rss2json/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/sendgrid/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/spoonacular/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/stability-ai/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/twilio/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/unsplash/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/wolfram-alpha/connector.json +0 -0
- /package/{dist/connectors → service-connectors}/youtube-data/connector.json +0 -0
|
@@ -2,7 +2,7 @@ import { Application } from 'express';
|
|
|
2
2
|
import { SynthOSConfig } from '../init';
|
|
3
3
|
import { loadSettings, saveSettings } from '../settings';
|
|
4
4
|
import {
|
|
5
|
-
|
|
5
|
+
getConnectorRegistry,
|
|
6
6
|
ConnectorSummary,
|
|
7
7
|
ConnectorDetail,
|
|
8
8
|
ConnectorCallRequest,
|
|
@@ -15,13 +15,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
15
15
|
// Also handles POST /api/connectors — Proxy call (see below)
|
|
16
16
|
app.get('/api/connectors', async (req, res) => {
|
|
17
17
|
try {
|
|
18
|
-
const settings = await loadSettings(config
|
|
18
|
+
const settings = await loadSettings(config);
|
|
19
19
|
const connectors = settings.connectors ?? {};
|
|
20
20
|
|
|
21
21
|
const categoryFilter = req.query.category as string | undefined;
|
|
22
22
|
const idFilter = req.query.id as string | undefined;
|
|
23
23
|
|
|
24
|
-
const list: ConnectorSummary[] =
|
|
24
|
+
const list: ConnectorSummary[] = getConnectorRegistry(config.serviceConnectorsFolders)
|
|
25
25
|
.filter(def => {
|
|
26
26
|
if (categoryFilter && def.category !== categoryFilter) return false;
|
|
27
27
|
if (idFilter && def.id !== idFilter) return false;
|
|
@@ -54,13 +54,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
54
54
|
app.get('/api/connectors/:id', async (req, res) => {
|
|
55
55
|
try {
|
|
56
56
|
const { id } = req.params;
|
|
57
|
-
const def =
|
|
57
|
+
const def = getConnectorRegistry(config.serviceConnectorsFolders).find(d => d.id === id);
|
|
58
58
|
if (!def) {
|
|
59
59
|
res.status(404).json({ error: `Connector "${id}" not found` });
|
|
60
60
|
return;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
const settings = await loadSettings(config
|
|
63
|
+
const settings = await loadSettings(config);
|
|
64
64
|
const cfg = (settings.connectors ?? {})[id];
|
|
65
65
|
const isOAuth = def.authStrategy === 'oauth2';
|
|
66
66
|
const oauthCfg = cfg as ConnectorOAuthConfig | undefined;
|
|
@@ -88,13 +88,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
88
88
|
app.post('/api/connectors/:id', async (req, res) => {
|
|
89
89
|
try {
|
|
90
90
|
const { id } = req.params;
|
|
91
|
-
const def =
|
|
91
|
+
const def = getConnectorRegistry(config.serviceConnectorsFolders).find(d => d.id === id);
|
|
92
92
|
if (!def) {
|
|
93
93
|
res.status(404).json({ error: `Connector "${id}" not found` });
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
const settings = await loadSettings(config
|
|
97
|
+
const settings = await loadSettings(config);
|
|
98
98
|
const existing = settings.connectors ?? {};
|
|
99
99
|
|
|
100
100
|
if (def.authStrategy === 'oauth2') {
|
|
@@ -121,7 +121,7 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
const updated = { ...existing, [id]: entry };
|
|
124
|
-
await saveSettings(config
|
|
124
|
+
await saveSettings(config, { connectors: updated });
|
|
125
125
|
} else {
|
|
126
126
|
const { apiKey, enabled } = req.body;
|
|
127
127
|
const resolvedKey = (typeof apiKey === 'string' && apiKey.length > 0)
|
|
@@ -132,7 +132,7 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
132
132
|
...existing,
|
|
133
133
|
[id]: { apiKey: resolvedKey, enabled: !!enabled }
|
|
134
134
|
};
|
|
135
|
-
await saveSettings(config
|
|
135
|
+
await saveSettings(config, { connectors: updated });
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
res.json({ saved: true });
|
|
@@ -146,13 +146,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
146
146
|
app.delete('/api/connectors/:id', async (req, res) => {
|
|
147
147
|
try {
|
|
148
148
|
const { id } = req.params;
|
|
149
|
-
const settings = await loadSettings(config
|
|
149
|
+
const settings = await loadSettings(config);
|
|
150
150
|
const existing = settings.connectors ?? {};
|
|
151
151
|
|
|
152
152
|
const updated = { ...existing };
|
|
153
153
|
delete updated[id];
|
|
154
154
|
|
|
155
|
-
await saveSettings(config
|
|
155
|
+
await saveSettings(config, { connectors: updated });
|
|
156
156
|
res.json({ deleted: true });
|
|
157
157
|
} catch (err: unknown) {
|
|
158
158
|
console.error(err);
|
|
@@ -164,13 +164,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
164
164
|
app.get('/api/connectors/:id/authorize', async (req, res) => {
|
|
165
165
|
try {
|
|
166
166
|
const { id } = req.params;
|
|
167
|
-
const def =
|
|
167
|
+
const def = getConnectorRegistry(config.serviceConnectorsFolders).find(d => d.id === id);
|
|
168
168
|
if (!def || def.authStrategy !== 'oauth2') {
|
|
169
169
|
res.status(400).json({ error: `Connector "${id}" is not an OAuth2 connector` });
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
const settings = await loadSettings(config
|
|
173
|
+
const settings = await loadSettings(config);
|
|
174
174
|
const cfg = (settings.connectors ?? {})[id] as ConnectorOAuthConfig | undefined;
|
|
175
175
|
if (!cfg?.clientId || !cfg?.clientSecret) {
|
|
176
176
|
res.status(400).json({ error: 'Client ID and Client Secret must be saved before authorizing' });
|
|
@@ -214,13 +214,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
214
214
|
const state = JSON.parse(stateRaw) as { connector: string };
|
|
215
215
|
const connectorId = state.connector;
|
|
216
216
|
|
|
217
|
-
const def =
|
|
217
|
+
const def = getConnectorRegistry(config.serviceConnectorsFolders).find(d => d.id === connectorId);
|
|
218
218
|
if (!def || def.authStrategy !== 'oauth2') {
|
|
219
219
|
res.status(400).json({ error: `Unknown OAuth2 connector: ${connectorId}` });
|
|
220
220
|
return;
|
|
221
221
|
}
|
|
222
222
|
|
|
223
|
-
const settings = await loadSettings(config
|
|
223
|
+
const settings = await loadSettings(config);
|
|
224
224
|
const cfg = (settings.connectors ?? {})[connectorId] as ConnectorOAuthConfig | undefined;
|
|
225
225
|
if (!cfg?.clientId || !cfg?.clientSecret) {
|
|
226
226
|
res.status(400).json({ error: 'Client credentials not found' });
|
|
@@ -307,7 +307,7 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
307
307
|
enabled: true
|
|
308
308
|
}
|
|
309
309
|
};
|
|
310
|
-
await saveSettings(config
|
|
310
|
+
await saveSettings(config, { connectors: updated });
|
|
311
311
|
|
|
312
312
|
res.redirect(`/settings?tab=connectors&connected=${encodeURIComponent(connectorId)}`);
|
|
313
313
|
} catch (err: unknown) {
|
|
@@ -326,13 +326,13 @@ export function useConnectorRoutes(config: SynthOSConfig, app: Application): voi
|
|
|
326
326
|
return;
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
const def =
|
|
329
|
+
const def = getConnectorRegistry(config.serviceConnectorsFolders).find(d => d.id === request.connector);
|
|
330
330
|
if (!def) {
|
|
331
331
|
res.status(404).json({ error: `Connector "${request.connector}" not found` });
|
|
332
332
|
return;
|
|
333
333
|
}
|
|
334
334
|
|
|
335
|
-
const settings = await loadSettings(config
|
|
335
|
+
const settings = await loadSettings(config);
|
|
336
336
|
const cfg = (settings.connectors ?? {})[request.connector];
|
|
337
337
|
|
|
338
338
|
if (def.authStrategy === 'oauth2') {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Application, Response } from 'express';
|
|
2
2
|
import { SynthOSConfig } from "../init";
|
|
3
|
-
import { checkIfExists, deleteFile, ensureFolderExists, listFiles, loadFile, saveFile } from "../files";
|
|
4
3
|
import path from "path";
|
|
5
4
|
import { v4 } from "uuid";
|
|
6
5
|
import { clearCachedScripts } from '../scripts';
|
|
@@ -17,19 +16,20 @@ export function useDataRoutes(config: SynthOSConfig, app: Application): void {
|
|
|
17
16
|
// ---------------------------------------------------------------------------
|
|
18
17
|
|
|
19
18
|
async function handleList(config: SynthOSConfig, page: string, table: string, query: Record<string, any>, res: Response): Promise<void> {
|
|
19
|
+
const sp = config.storageProvider;
|
|
20
20
|
const folder = tableFolder(config, page, table);
|
|
21
|
-
if (!(await checkIfExists(folder))) {
|
|
21
|
+
if (!(await sp.checkIfExists(folder))) {
|
|
22
22
|
res.status(404).json({ error: 'table_not_found', page, table });
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const ids = (await listFiles(folder)).filter(f => f.endsWith('.json')).map(f => f.replace('.json', ''));
|
|
26
|
+
const ids = (await sp.listFiles(folder)).filter(f => f.endsWith('.json')).map(f => f.replace('.json', ''));
|
|
27
27
|
|
|
28
28
|
const rows: Record<string, any>[] = [];
|
|
29
29
|
for (const id of ids) {
|
|
30
30
|
const file = recordFile(folder, id);
|
|
31
31
|
try {
|
|
32
|
-
const row = JSON.parse(await loadFile(file));
|
|
32
|
+
const row = JSON.parse(await sp.loadFile(file));
|
|
33
33
|
row.id = id;
|
|
34
34
|
rows.push(row);
|
|
35
35
|
} catch (err: unknown) {
|
|
@@ -49,15 +49,16 @@ async function handleList(config: SynthOSConfig, page: string, table: string, qu
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
async function handleGet(config: SynthOSConfig, page: string, table: string, id: string, res: Response): Promise<void> {
|
|
52
|
+
const sp = config.storageProvider;
|
|
52
53
|
const folder = tableFolder(config, page, table);
|
|
53
|
-
if (!(await checkIfExists(folder))) {
|
|
54
|
+
if (!(await sp.checkIfExists(folder))) {
|
|
54
55
|
res.status(404).json({ error: 'table_not_found', page, table });
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
const file = recordFile(folder, id);
|
|
59
60
|
try {
|
|
60
|
-
const row = JSON.parse(await loadFile(file));
|
|
61
|
+
const row = JSON.parse(await sp.loadFile(file));
|
|
61
62
|
row.id = id;
|
|
62
63
|
res.json(row);
|
|
63
64
|
} catch (err: unknown) {
|
|
@@ -66,13 +67,14 @@ async function handleGet(config: SynthOSConfig, page: string, table: string, id:
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
async function handleUpsert(config: SynthOSConfig, page: string, table: string, body: any, res: Response): Promise<void> {
|
|
70
|
+
const sp = config.storageProvider;
|
|
69
71
|
const id = body.id ?? v4();
|
|
70
72
|
const folder = tableFolder(config, page, table);
|
|
71
73
|
const file = recordFile(folder, id);
|
|
72
74
|
try {
|
|
73
75
|
const row = { ...body, id };
|
|
74
|
-
await ensureFolderExists(folder);
|
|
75
|
-
await saveFile(file, JSON.stringify(row, null, 4));
|
|
76
|
+
await sp.ensureFolderExists(folder);
|
|
77
|
+
await sp.saveFile(file, JSON.stringify(row, null, 4));
|
|
76
78
|
if (table === 'scripts') {
|
|
77
79
|
clearCachedScripts();
|
|
78
80
|
}
|
|
@@ -84,11 +86,12 @@ async function handleUpsert(config: SynthOSConfig, page: string, table: string,
|
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
async function handleDelete(config: SynthOSConfig, page: string, table: string, id: string, res: Response): Promise<void> {
|
|
89
|
+
const sp = config.storageProvider;
|
|
87
90
|
const folder = tableFolder(config, page, table);
|
|
88
91
|
const file = recordFile(folder, id);
|
|
89
92
|
try {
|
|
90
|
-
if (await checkIfExists(file)) {
|
|
91
|
-
await deleteFile(file);
|
|
93
|
+
if (await sp.checkIfExists(file)) {
|
|
94
|
+
await sp.deleteFile(file);
|
|
92
95
|
if (table === 'scripts') {
|
|
93
96
|
clearCachedScripts();
|
|
94
97
|
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Application } from 'express';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { SynthOSConfig } from '../init';
|
|
5
|
+
|
|
6
|
+
export function useFileRoutes(config: SynthOSConfig, app: Application): void {
|
|
7
|
+
const sp = config.storageProvider;
|
|
8
|
+
|
|
9
|
+
// List files in a page's files/ folder
|
|
10
|
+
app.get('/api/files/:page', async (req, res) => {
|
|
11
|
+
try {
|
|
12
|
+
const folder = filesFolder(config, req.params.page);
|
|
13
|
+
if (!(await sp.checkIfExists(folder))) {
|
|
14
|
+
res.json({ files: [] });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const entries = await sp.listFiles(folder);
|
|
19
|
+
const files: { name: string; size: number }[] = [];
|
|
20
|
+
for (const entry of entries) {
|
|
21
|
+
const stat = await sp.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 file
|
|
34
|
+
app.get('/api/files/:page/:filename', async (req, res) => {
|
|
35
|
+
try {
|
|
36
|
+
const filePath = safeFilePath(config, req.params.page, req.params.filename);
|
|
37
|
+
if (!filePath) {
|
|
38
|
+
res.status(400).json({ error: 'Invalid filename' });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (!(await sp.checkIfExists(filePath))) {
|
|
43
|
+
res.status(404).json({ error: 'File not found' });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
res.type(path.extname(req.params.filename));
|
|
48
|
+
sp.createReadStream(filePath).pipe(res);
|
|
49
|
+
} catch (err: unknown) {
|
|
50
|
+
console.error(err);
|
|
51
|
+
res.status(500).json({ error: (err as Error).message });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Upload a file (raw body + x-filename header)
|
|
56
|
+
app.post('/api/files/:page', express.raw({ type: '*/*', limit: '50mb' }), async (req, res) => {
|
|
57
|
+
try {
|
|
58
|
+
const filename = req.headers['x-filename'] as string | undefined;
|
|
59
|
+
if (!filename || filename.trim().length === 0) {
|
|
60
|
+
res.status(400).json({ error: 'x-filename header is required' });
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const filePath = safeFilePath(config, req.params.page, filename);
|
|
65
|
+
if (!filePath) {
|
|
66
|
+
res.status(400).json({ error: 'Invalid filename' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const folder = filesFolder(config, req.params.page);
|
|
71
|
+
await sp.ensureFolderExists(folder);
|
|
72
|
+
await sp.saveBuffer(filePath, req.body as Buffer);
|
|
73
|
+
|
|
74
|
+
const stat = await sp.stat(filePath);
|
|
75
|
+
res.status(201).json({ name: filename, size: stat.size });
|
|
76
|
+
} catch (err: unknown) {
|
|
77
|
+
console.error(err);
|
|
78
|
+
res.status(500).json({ error: (err as Error).message });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Delete a file
|
|
83
|
+
app.delete('/api/files/:page/:filename', async (req, res) => {
|
|
84
|
+
try {
|
|
85
|
+
const filePath = safeFilePath(config, req.params.page, req.params.filename);
|
|
86
|
+
if (!filePath) {
|
|
87
|
+
res.status(400).json({ error: 'Invalid filename' });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!(await sp.checkIfExists(filePath))) {
|
|
92
|
+
res.status(404).json({ error: 'File not found' });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
await sp.deleteFile(filePath);
|
|
97
|
+
res.json({ deleted: true });
|
|
98
|
+
} catch (err: unknown) {
|
|
99
|
+
console.error(err);
|
|
100
|
+
res.status(500).json({ error: (err as Error).message });
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
// Helpers
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
function filesFolder(config: SynthOSConfig, page: string): string {
|
|
110
|
+
return path.join(config.pagesFolder, 'pages', page, 'files');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Resolve a filename inside the page's files/ folder with path-traversal protection.
|
|
115
|
+
* Returns the absolute path if safe, or null if the filename is invalid.
|
|
116
|
+
*/
|
|
117
|
+
function safeFilePath(config: SynthOSConfig, page: string, filename: string): string | null {
|
|
118
|
+
// Reject obviously bad filenames
|
|
119
|
+
if (!filename || filename.includes('..') || filename.includes('/') || filename.includes('\\')) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
const folder = filesFolder(config, page);
|
|
123
|
+
const resolved = path.resolve(folder, filename);
|
|
124
|
+
if (!resolved.startsWith(path.resolve(folder))) {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
return resolved;
|
|
128
|
+
}
|