synthos 0.10.0 → 0.11.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 +5 -5
- package/default-pages/elevenlabs_effects_studio/chat-history.json +1 -0
- package/default-pages/elevenlabs_effects_studio/page.html +1345 -1363
- package/default-pages/elevenlabs_effects_studio/page.json +13 -11
- package/default-pages/elevenlabs_voice_studio/chat-history.json +1 -0
- package/default-pages/elevenlabs_voice_studio/page.html +782 -801
- package/default-pages/elevenlabs_voice_studio/page.json +13 -11
- package/default-pages/json_tools/chat-history.json +1 -0
- package/default-pages/json_tools/page.html +70 -90
- package/default-pages/json_tools/page.json +12 -10
- package/default-pages/my_notes/chat-history.json +1 -0
- package/default-pages/my_notes/page.html +115 -131
- package/default-pages/my_notes/page.json +14 -12
- package/default-pages/neon_asteroids/chat-history.json +1 -0
- package/default-pages/neon_asteroids/page.html +1777 -1803
- package/default-pages/neon_asteroids/page.json +14 -12
- package/default-pages/oregon_trail/chat-history.json +1 -0
- package/default-pages/oregon_trail/page.html +290 -307
- package/default-pages/oregon_trail/page.json +14 -12
- package/default-pages/solar_explorer/chat-history.json +1 -0
- package/default-pages/solar_explorer/page.html +1929 -1951
- package/default-pages/solar_explorer/page.json +14 -12
- package/default-pages/solar_tutorial/chat-history.json +1 -0
- package/default-pages/solar_tutorial/page.html +464 -478
- package/default-pages/solar_tutorial/page.json +12 -10
- package/default-pages/us_map/chat-history.json +1 -0
- package/default-pages/us_map/page.html +170 -193
- package/default-pages/us_map/page.json +14 -12
- package/default-pages/us_map/page.light.png +0 -0
- package/default-pages/us_map_1850/chat-history.json +1 -0
- package/default-pages/us_map_1850/page.html +302 -326
- package/default-pages/us_map_1850/page.json +14 -12
- package/default-pages/western_cities_1850/chat-history.json +1 -0
- package/default-pages/western_cities_1850/page.html +503 -527
- package/default-pages/western_cities_1850/page.json +14 -12
- package/default-themes/aurora-dawn.v3.css +15 -14
- package/default-themes/aurora-dusk.v3.css +26 -26
- package/default-themes/cosmos-dawn.v3.css +15 -14
- package/default-themes/cosmos-dusk.v3.css +26 -26
- package/default-themes/elemental-dawn.v3.css +200 -0
- package/default-themes/nebula-dawn.v3.css +15 -14
- package/default-themes/nebula-dusk.v3.css +24 -24
- package/default-themes/solar-flare-dawn.v3.css +15 -14
- package/default-themes/solar-flare-dusk.v3.css +26 -26
- package/dist/builders/anthropic.d.ts +26 -2
- package/dist/builders/anthropic.d.ts.map +1 -1
- package/dist/builders/anthropic.js +132 -31
- package/dist/builders/anthropic.js.map +1 -1
- package/dist/builders/claudecode.d.ts +13 -0
- package/dist/builders/claudecode.d.ts.map +1 -0
- package/dist/builders/claudecode.js +253 -0
- package/dist/builders/claudecode.js.map +1 -0
- package/dist/builders/index.d.ts +2 -1
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +8 -1
- package/dist/builders/index.js.map +1 -1
- package/dist/builders/openai.js +2 -1
- package/dist/builders/openai.js.map +1 -1
- package/dist/builders/types.d.ts +31 -7
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +60 -28
- package/dist/builders/types.js.map +1 -1
- package/dist/connectors/types.d.ts +8 -0
- package/dist/connectors/types.d.ts.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +13 -6
- package/dist/init.js.map +1 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +161 -14
- package/dist/migrations.js.map +1 -1
- package/dist/models/anthropic.d.ts +1 -0
- package/dist/models/anthropic.d.ts.map +1 -1
- package/dist/models/anthropic.js +129 -29
- package/dist/models/anthropic.js.map +1 -1
- package/dist/models/chainOfThought.d.ts.map +1 -1
- package/dist/models/chainOfThought.js +32 -19
- package/dist/models/chainOfThought.js.map +1 -1
- package/dist/models/index.d.ts +2 -2
- 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/providers.d.ts +1 -0
- package/dist/models/providers.d.ts.map +1 -1
- package/dist/models/providers.js +12 -4
- package/dist/models/providers.js.map +1 -1
- package/dist/models/types.d.ts +15 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js.map +1 -1
- package/dist/pages.d.ts +57 -8
- package/dist/pages.d.ts.map +1 -1
- package/dist/pages.js +258 -45
- package/dist/pages.js.map +1 -1
- package/dist/service/createCompletePrompt.d.ts.map +1 -1
- package/dist/service/createCompletePrompt.js +5 -0
- package/dist/service/createCompletePrompt.js.map +1 -1
- package/dist/service/mediaCache.d.ts +36 -0
- package/dist/service/mediaCache.d.ts.map +1 -0
- package/dist/service/mediaCache.js +182 -0
- package/dist/service/mediaCache.js.map +1 -0
- package/dist/service/pageValidator.d.ts +25 -0
- package/dist/service/pageValidator.d.ts.map +1 -0
- package/dist/service/pageValidator.js +315 -0
- package/dist/service/pageValidator.js.map +1 -0
- package/dist/service/server.d.ts.map +1 -1
- package/dist/service/server.js +4 -0
- package/dist/service/server.js.map +1 -1
- package/dist/service/sharedTableSchema.d.ts +73 -0
- package/dist/service/sharedTableSchema.d.ts.map +1 -0
- package/dist/service/sharedTableSchema.js +206 -0
- package/dist/service/sharedTableSchema.js.map +1 -0
- package/dist/service/transformPage.d.ts +49 -11
- package/dist/service/transformPage.d.ts.map +1 -1
- package/dist/service/transformPage.js +354 -241
- package/dist/service/transformPage.js.map +1 -1
- package/dist/service/useApiRoutes.d.ts.map +1 -1
- package/dist/service/useApiRoutes.js +288 -34
- package/dist/service/useApiRoutes.js.map +1 -1
- package/dist/service/useConnectorRoutes.d.ts.map +1 -1
- package/dist/service/useConnectorRoutes.js +170 -32
- package/dist/service/useConnectorRoutes.js.map +1 -1
- package/dist/service/useDataRoutes.d.ts.map +1 -1
- package/dist/service/useDataRoutes.js +59 -2
- package/dist/service/useDataRoutes.js.map +1 -1
- package/dist/service/useExtractRoutes.d.ts +4 -0
- package/dist/service/useExtractRoutes.d.ts.map +1 -0
- package/dist/service/useExtractRoutes.js +304 -0
- package/dist/service/useExtractRoutes.js.map +1 -0
- package/dist/service/usePageRoutes.d.ts +17 -0
- package/dist/service/usePageRoutes.d.ts.map +1 -1
- package/dist/service/usePageRoutes.js +1385 -483
- package/dist/service/usePageRoutes.js.map +1 -1
- package/dist/service/useSharedDataRoutes.d.ts.map +1 -1
- package/dist/service/useSharedDataRoutes.js +54 -2
- package/dist/service/useSharedDataRoutes.js.map +1 -1
- package/dist/settings.d.ts +27 -0
- package/dist/settings.d.ts.map +1 -1
- package/dist/settings.js +40 -1
- package/dist/settings.js.map +1 -1
- package/dist/themes.d.ts +0 -5
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js +3 -95
- package/dist/themes.js.map +1 -1
- package/migration-rules/v2-to-v3.md +277 -119
- package/package.json +5 -1
- package/{default-pages/application → required-pages/_shell}/page.html +56 -42
- package/required-pages/_shell/page.json +14 -0
- package/required-pages/_starters/page.html +534 -0
- package/required-pages/_starters/page.json +12 -0
- package/required-pages/builder/page.html +353 -43
- package/required-pages/builder/page.json +12 -10
- package/required-pages/pages/page.html +697 -924
- package/required-pages/pages/page.json +12 -10
- package/required-pages/settings/page.html +1879 -1753
- package/required-pages/settings/page.json +12 -10
- package/required-pages/synthos_apis/page.html +834 -845
- package/required-pages/synthos_apis/page.json +12 -10
- package/required-pages/synthos_scripts/page.html +74 -88
- package/required-pages/synthos_scripts/page.json +12 -10
- package/scripts/append-instructions.py +90 -0
- package/scripts/audit-instructions.py +76 -0
- package/scripts/cleanup-shell-markup.mjs +112 -0
- package/service-connectors/buffer/connector.json +46 -0
- package/service-connectors/canva/connector.json +67 -0
- package/service-connectors/elevenlabs/connector.json +1 -1
- package/src/builders/anthropic.ts +155 -30
- package/src/builders/claudecode.ts +310 -0
- package/src/builders/index.ts +7 -1
- package/src/builders/openai.ts +2 -1
- package/src/builders/types.ts +93 -32
- package/src/connectors/types.ts +8 -0
- package/src/init.ts +13 -7
- package/src/migrations.ts +187 -16
- package/src/models/anthropic.ts +140 -30
- package/src/models/chainOfThought.ts +33 -18
- package/src/models/index.ts +2 -2
- package/src/models/providers.ts +12 -3
- package/src/models/types.ts +21 -1
- package/src/pages.ts +271 -35
- package/src/service/createCompletePrompt.ts +6 -0
- package/src/service/mediaCache.ts +206 -0
- package/src/service/pageValidator.ts +337 -0
- package/src/service/server.ts +4 -0
- package/src/service/sharedTableSchema.ts +236 -0
- package/src/service/transformPage.ts +370 -260
- package/src/service/useApiRoutes.ts +282 -32
- package/src/service/useConnectorRoutes.ts +189 -34
- package/src/service/useDataRoutes.ts +198 -116
- package/src/service/useExtractRoutes.ts +331 -0
- package/src/service/usePageRoutes.ts +1411 -394
- package/src/service/useSharedDataRoutes.ts +184 -109
- package/src/settings.ts +65 -0
- package/src/themes.ts +78 -180
- package/starters/blank_starter/chat-history.json +1 -0
- package/starters/blank_starter/page.dark.png +0 -0
- package/starters/blank_starter/page.html +47 -0
- package/starters/blank_starter/page.json +13 -0
- package/starters/blank_starter/page.light.png +0 -0
- package/starters/calculator_starter/chat-history.json +1 -0
- package/starters/calculator_starter/page.dark.png +0 -0
- package/starters/calculator_starter/page.html +232 -0
- package/starters/calculator_starter/page.json +13 -0
- package/starters/calculator_starter/page.light.png +0 -0
- package/starters/calendar_starter/chat-history.json +1 -0
- package/starters/calendar_starter/page.dark.png +0 -0
- package/starters/calendar_starter/page.html +495 -0
- package/starters/calendar_starter/page.json +13 -0
- package/starters/calendar_starter/page.light.png +0 -0
- package/starters/chat_starter/chat-history.json +1 -0
- package/starters/chat_starter/page.dark.png +0 -0
- package/starters/chat_starter/page.html +351 -0
- package/starters/chat_starter/page.json +13 -0
- package/starters/chat_starter/page.light.png +0 -0
- package/starters/checklist_starter/chat-history.json +1 -0
- package/starters/checklist_starter/page.dark.png +0 -0
- package/starters/checklist_starter/page.html +437 -0
- package/starters/checklist_starter/page.json +13 -0
- package/starters/checklist_starter/page.light.png +0 -0
- package/starters/dashboard_starter/chat-history.json +1 -0
- package/starters/dashboard_starter/page.dark.png +0 -0
- package/starters/dashboard_starter/page.html +195 -0
- package/starters/dashboard_starter/page.json +13 -0
- package/starters/dashboard_starter/page.light.png +0 -0
- package/starters/form_starter/chat-history.json +1 -0
- package/starters/form_starter/page.dark.png +0 -0
- package/starters/form_starter/page.html +313 -0
- package/starters/form_starter/page.json +13 -0
- package/starters/form_starter/page.light.png +0 -0
- package/starters/gallery_starter/chat-history.json +1 -0
- package/starters/gallery_starter/page.dark.png +0 -0
- package/starters/gallery_starter/page.html +418 -0
- package/starters/gallery_starter/page.json +13 -0
- package/starters/gallery_starter/page.light.png +0 -0
- package/starters/generator_starter/chat-history.json +1 -0
- package/starters/generator_starter/page.dark.png +0 -0
- package/starters/generator_starter/page.html +261 -0
- package/starters/generator_starter/page.json +13 -0
- package/starters/generator_starter/page.light.png +0 -0
- package/starters/index.html +538 -0
- package/starters/kanban_starter/chat-history.json +1 -0
- package/starters/kanban_starter/page.dark.png +0 -0
- package/starters/kanban_starter/page.html +432 -0
- package/starters/kanban_starter/page.json +13 -0
- package/starters/kanban_starter/page.light.png +0 -0
- package/starters/presentation_builder/chat-history.json +1 -0
- package/starters/presentation_builder/page.dark.png +0 -0
- package/starters/presentation_builder/page.html +970 -0
- package/starters/presentation_builder/page.json +15 -0
- package/starters/presentation_builder/page.light.png +0 -0
- package/starters/presentation_builder/presentation_voice/voice_config.json +9 -0
- package/starters/pulse_starter/chat-history.json +1 -0
- package/starters/pulse_starter/page.dark.png +0 -0
- package/starters/pulse_starter/page.html +698 -0
- package/starters/pulse_starter/page.json +13 -0
- package/starters/pulse_starter/page.light.png +0 -0
- package/starters/quiz_starter/chat-history.json +1 -0
- package/starters/quiz_starter/page.dark.png +0 -0
- package/starters/quiz_starter/page.html +292 -0
- package/starters/quiz_starter/page.json +13 -0
- package/starters/quiz_starter/page.light.png +0 -0
- package/starters/reference_starter/chat-history.json +1 -0
- package/starters/reference_starter/page.dark.png +0 -0
- package/starters/reference_starter/page.html +250 -0
- package/starters/reference_starter/page.json +13 -0
- package/starters/reference_starter/page.light.png +0 -0
- package/starters/retro_game_starter/chat-history.json +1 -0
- package/starters/retro_game_starter/page.dark.png +0 -0
- package/{default-pages → starters}/retro_game_starter/page.html +1281 -1308
- package/starters/retro_game_starter/page.json +15 -0
- package/starters/retro_game_starter/page.light.png +0 -0
- package/starters/roster_starter/chat-history.json +1 -0
- package/starters/roster_starter/page.dark.png +0 -0
- package/starters/roster_starter/page.html +600 -0
- package/starters/roster_starter/page.json +13 -0
- package/starters/roster_starter/page.light.png +0 -0
- package/starters/server.js +182 -0
- package/starters/start.cmd +1 -0
- package/starters/timeline_starter/chat-history.json +1 -0
- package/starters/timeline_starter/page.dark.png +0 -0
- package/starters/timeline_starter/page.html +446 -0
- package/starters/timeline_starter/page.json +13 -0
- package/starters/timeline_starter/page.light.png +0 -0
- package/starters/tutorial_starter/chat-history.json +1 -0
- package/starters/tutorial_starter/page.dark.png +0 -0
- package/starters/tutorial_starter/page.html +283 -0
- package/starters/tutorial_starter/page.json +13 -0
- package/starters/tutorial_starter/page.light.png +0 -0
- package/static-files/agent.v3.js +122 -0
- package/static-files/connector.v3.js +48 -0
- package/static-files/extract.v3.js +188 -0
- package/static-files/helpers.v3.js +50 -6
- package/static-files/page-bridge.js +114 -0
- package/static-files/page.v3.js +1292 -1290
- package/static-files/script.v3.js +32 -0
- package/static-files/server.v3.js +89 -0
- package/static-files/shell-bridge.v3.js +174 -0
- package/static-files/shell-modals.v3.js +521 -0
- package/static-files/{shell.css → shell.v3.css} +271 -22
- package/static-files/shell.v3.js +1865 -0
- package/static-files/storage.v3.js +176 -0
- package/tests/anthropic.spec.ts +42 -7
- package/tests/builders.spec.ts +72 -4
- package/tests/pageValidator.spec.ts +548 -0
- package/tests/profiles.spec.ts +122 -0
- package/tests/providers.spec.ts +1 -1
- package/tests/sharedTableSchema.spec.ts +242 -0
- package/tests/transformPage.spec.ts +62 -81
- package/default-pages/application/page.json +0 -10
- package/default-pages/retro_game_starter/page.json +0 -12
- package/default-pages/sidebar_page/page.html +0 -51
- package/default-pages/sidebar_page/page.json +0 -10
- package/default-pages/two-panel_page/page.html +0 -68
- package/default-pages/two-panel_page/page.json +0 -10
|
@@ -1,109 +1,184 @@
|
|
|
1
|
-
import { Application, Response } from 'express';
|
|
2
|
-
import { SynthOSConfig } from "../init";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { v4 } from "uuid";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
const folder = sharedTableFolder(config, table);
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
function
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
1
|
+
import { Application, Response } from 'express';
|
|
2
|
+
import { SynthOSConfig } from "../init";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { v4 } from "uuid";
|
|
5
|
+
import {
|
|
6
|
+
deleteSchema,
|
|
7
|
+
isValidSchemaPayload,
|
|
8
|
+
listTables,
|
|
9
|
+
loadSchema,
|
|
10
|
+
mergeSchema,
|
|
11
|
+
newSchemaWrapper,
|
|
12
|
+
saveSchema,
|
|
13
|
+
updateSchemaWrapper,
|
|
14
|
+
MergeMode,
|
|
15
|
+
} from "./sharedTableSchema";
|
|
16
|
+
|
|
17
|
+
export function useSharedDataRoutes(config: SynthOSConfig, app: Application): void {
|
|
18
|
+
// Schema sidecar + table-list endpoints are registered FIRST so the
|
|
19
|
+
// literal `_schema` and `_tables` segments don't get captured by the
|
|
20
|
+
// generic `:table` / `:table/:id` patterns below.
|
|
21
|
+
app.get('/api/shared/data/_tables', (req, res) => handleListTables(config, res));
|
|
22
|
+
app.get('/api/shared/data/:table/_schema', (req, res) => handleGetSchema(config, req.params.table, res));
|
|
23
|
+
app.put('/api/shared/data/:table/_schema', (req, res) => handlePutSchema(config, req.params.table, req.query, req.body, res));
|
|
24
|
+
app.delete('/api/shared/data/:table/_schema', (req, res) => handleDeleteSchema(config, req.params.table, res));
|
|
25
|
+
|
|
26
|
+
app.get('/api/shared/data/:table', (req, res) => handleList(config, req.params.table, req.query, res));
|
|
27
|
+
app.get('/api/shared/data/:table/:id', (req, res) => handleGet(config, req.params.table, req.params.id, res));
|
|
28
|
+
app.post('/api/shared/data/:table', (req, res) => handleUpsert(config, req.params.table, req.body, res));
|
|
29
|
+
app.delete('/api/shared/data/:table/:id', (req, res) => handleDelete(config, req.params.table, req.params.id, res));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Route handlers — records
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
async function handleList(config: SynthOSConfig, table: string, query: Record<string, any>, res: Response): Promise<void> {
|
|
37
|
+
const sp = config.storageProvider;
|
|
38
|
+
const folder = sharedTableFolder(config, table);
|
|
39
|
+
if (!(await sp.checkIfExists(folder))) {
|
|
40
|
+
res.status(404).json({ error: 'table_not_found', table });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const ids = (await sp.listFiles(folder)).filter(f => f.endsWith('.json')).map(f => f.replace('.json', ''));
|
|
45
|
+
|
|
46
|
+
const rows: Record<string, any>[] = [];
|
|
47
|
+
for (const id of ids) {
|
|
48
|
+
const file = recordFile(folder, id);
|
|
49
|
+
try {
|
|
50
|
+
const row = JSON.parse(await sp.loadFile(file));
|
|
51
|
+
row.id = id;
|
|
52
|
+
rows.push(row);
|
|
53
|
+
} catch (err: unknown) {
|
|
54
|
+
console.error(err);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Paginate when limit is provided
|
|
59
|
+
const limitParam = typeof query.limit === 'string' ? parseInt(query.limit, 10) : NaN;
|
|
60
|
+
if (!isNaN(limitParam) && limitParam > 0) {
|
|
61
|
+
const offset = Math.max(0, typeof query.offset === 'string' ? parseInt(query.offset, 10) || 0 : 0);
|
|
62
|
+
const items = rows.slice(offset, offset + limitParam);
|
|
63
|
+
res.json({ items, total: rows.length, offset, limit: limitParam, hasMore: offset + limitParam < rows.length });
|
|
64
|
+
} else {
|
|
65
|
+
res.json(rows);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function handleGet(config: SynthOSConfig, table: string, id: string, res: Response): Promise<void> {
|
|
70
|
+
const sp = config.storageProvider;
|
|
71
|
+
const folder = sharedTableFolder(config, table);
|
|
72
|
+
if (!(await sp.checkIfExists(folder))) {
|
|
73
|
+
res.status(404).json({ error: 'table_not_found', table });
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const file = recordFile(folder, id);
|
|
78
|
+
try {
|
|
79
|
+
const row = JSON.parse(await sp.loadFile(file));
|
|
80
|
+
row.id = id;
|
|
81
|
+
res.json(row);
|
|
82
|
+
} catch (err: unknown) {
|
|
83
|
+
res.json({});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async function handleUpsert(config: SynthOSConfig, table: string, body: any, res: Response): Promise<void> {
|
|
88
|
+
const sp = config.storageProvider;
|
|
89
|
+
const id = body.id ?? v4();
|
|
90
|
+
const folder = sharedTableFolder(config, table);
|
|
91
|
+
const file = recordFile(folder, id);
|
|
92
|
+
try {
|
|
93
|
+
const row = { ...body, id };
|
|
94
|
+
await sp.ensureFolderExists(folder);
|
|
95
|
+
await sp.saveFile(file, JSON.stringify(row, null, 4));
|
|
96
|
+
res.json(row);
|
|
97
|
+
} catch (err: unknown) {
|
|
98
|
+
console.error(err);
|
|
99
|
+
res.status(500).send((err as Error).message);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function handleDelete(config: SynthOSConfig, table: string, id: string, res: Response): Promise<void> {
|
|
104
|
+
const sp = config.storageProvider;
|
|
105
|
+
const folder = sharedTableFolder(config, table);
|
|
106
|
+
const file = recordFile(folder, id);
|
|
107
|
+
try {
|
|
108
|
+
if (await sp.checkIfExists(file)) {
|
|
109
|
+
await sp.deleteFile(file);
|
|
110
|
+
}
|
|
111
|
+
res.json({ success: true });
|
|
112
|
+
} catch (err: unknown) {
|
|
113
|
+
console.error(err);
|
|
114
|
+
res.status(500).send((err as Error).message);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Route handlers — schema sidecar
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
|
|
122
|
+
async function handleGetSchema(config: SynthOSConfig, table: string, res: Response): Promise<void> {
|
|
123
|
+
const wrapper = await loadSchema(config, sharedNamespace(config), table);
|
|
124
|
+
if (!wrapper) {
|
|
125
|
+
res.status(404).json({ error: 'schema_not_found', table });
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
res.json(wrapper);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async function handlePutSchema(
|
|
132
|
+
config: SynthOSConfig,
|
|
133
|
+
table: string,
|
|
134
|
+
query: Record<string, any>,
|
|
135
|
+
body: any,
|
|
136
|
+
res: Response,
|
|
137
|
+
): Promise<void> {
|
|
138
|
+
const incoming = body && typeof body === 'object' && body.schema ? body.schema : body;
|
|
139
|
+
if (!isValidSchemaPayload(incoming)) {
|
|
140
|
+
res.status(400).json({ error: 'invalid_schema', message: 'Body must be a JSON Schema object (or { schema: ... } wrapper).' });
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const merge: MergeMode = query.merge === 'replace' ? 'replace' : 'additive';
|
|
144
|
+
const definedBy = typeof body?.definedBy === 'string' ? body.definedBy : undefined;
|
|
145
|
+
const namespace = sharedNamespace(config);
|
|
146
|
+
const existing = await loadSchema(config, namespace, table);
|
|
147
|
+
const { merged, conflicts } = mergeSchema(existing?.schema, incoming, merge);
|
|
148
|
+
if (conflicts.length > 0) {
|
|
149
|
+
res.status(409).json({ error: 'schema_conflict', conflicts });
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
const now = new Date().toISOString();
|
|
153
|
+
const wrapper = existing
|
|
154
|
+
? updateSchemaWrapper(existing, merged, now, definedBy)
|
|
155
|
+
: newSchemaWrapper(merged, now, definedBy);
|
|
156
|
+
await saveSchema(config, namespace, table, wrapper);
|
|
157
|
+
res.json(wrapper);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async function handleDeleteSchema(config: SynthOSConfig, table: string, res: Response): Promise<void> {
|
|
161
|
+
await deleteSchema(config, sharedNamespace(config), table);
|
|
162
|
+
res.status(204).end();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async function handleListTables(config: SynthOSConfig, res: Response): Promise<void> {
|
|
166
|
+
const tables = await listTables(config, sharedNamespace(config));
|
|
167
|
+
res.json({ tables });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
// Helpers
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
function sharedNamespace(config: SynthOSConfig): string {
|
|
175
|
+
return path.join(config.pagesFolder, 'shared');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function sharedTableFolder(config: SynthOSConfig, table: string): string {
|
|
179
|
+
return path.join(sharedNamespace(config), table);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function recordFile(folder: string, id: string): string {
|
|
183
|
+
return path.join(folder, `${id}.json`);
|
|
184
|
+
}
|
package/src/settings.ts
CHANGED
|
@@ -31,6 +31,28 @@ export interface SettingsV1 {
|
|
|
31
31
|
/**
|
|
32
32
|
* V2 settings shape with versioned models array.
|
|
33
33
|
*/
|
|
34
|
+
export interface CacheSettings {
|
|
35
|
+
enabled: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface PersonalInfo {
|
|
39
|
+
name?: string;
|
|
40
|
+
address?: string;
|
|
41
|
+
details?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface BusinessInfo {
|
|
45
|
+
name?: string;
|
|
46
|
+
locations?: string;
|
|
47
|
+
hours?: string;
|
|
48
|
+
details?: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface UserProfile {
|
|
52
|
+
personal?: PersonalInfo;
|
|
53
|
+
business?: BusinessInfo;
|
|
54
|
+
}
|
|
55
|
+
|
|
34
56
|
export interface SettingsV2 {
|
|
35
57
|
version: 2;
|
|
36
58
|
theme: string;
|
|
@@ -40,6 +62,8 @@ export interface SettingsV2 {
|
|
|
40
62
|
connectors?: ServicesConfig;
|
|
41
63
|
agents?: AgentConfig[];
|
|
42
64
|
toolbarPosition?: 'left' | 'right';
|
|
65
|
+
cache?: CacheSettings;
|
|
66
|
+
profile?: UserProfile;
|
|
43
67
|
}
|
|
44
68
|
|
|
45
69
|
export const DefaultSettings: SettingsV2 = {
|
|
@@ -181,3 +205,44 @@ export async function saveSettings(config: SynthOSConfig, settings: Partial<Sett
|
|
|
181
205
|
_settings.version = 2;
|
|
182
206
|
await sp.saveFile(path.join(config.pagesFolder, 'settings.json'), JSON.stringify(_settings, null, 4));
|
|
183
207
|
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Render the user profile as markdown for injection into the builder's
|
|
211
|
+
* <USER_PROFILE> context section. Each field is optional; sections with no
|
|
212
|
+
* filled fields are omitted entirely. Returns an empty string when nothing
|
|
213
|
+
* would be rendered.
|
|
214
|
+
*/
|
|
215
|
+
export function renderUserProfile(profile: UserProfile | undefined): string {
|
|
216
|
+
if (!profile) return '';
|
|
217
|
+
|
|
218
|
+
const blocks: string[] = [];
|
|
219
|
+
|
|
220
|
+
const personalFields: Array<{ label: string; value?: string }> = [
|
|
221
|
+
{ label: 'Name', value: profile.personal?.name },
|
|
222
|
+
{ label: 'Address', value: profile.personal?.address },
|
|
223
|
+
{ label: 'Details', value: profile.personal?.details },
|
|
224
|
+
];
|
|
225
|
+
const personalBody = renderProfileSection(personalFields);
|
|
226
|
+
if (personalBody) blocks.push(`## Personal Information\n\n${personalBody}`);
|
|
227
|
+
|
|
228
|
+
const businessFields: Array<{ label: string; value?: string }> = [
|
|
229
|
+
{ label: 'Name', value: profile.business?.name },
|
|
230
|
+
{ label: 'Locations', value: profile.business?.locations },
|
|
231
|
+
{ label: 'Hours', value: profile.business?.hours },
|
|
232
|
+
{ label: 'Details', value: profile.business?.details },
|
|
233
|
+
];
|
|
234
|
+
const businessBody = renderProfileSection(businessFields);
|
|
235
|
+
if (businessBody) blocks.push(`## Business Information\n\n${businessBody}`);
|
|
236
|
+
|
|
237
|
+
return blocks.join('\n\n');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function renderProfileSection(fields: Array<{ label: string; value?: string }>): string {
|
|
241
|
+
const parts: string[] = [];
|
|
242
|
+
for (const { label, value } of fields) {
|
|
243
|
+
if (value && value.trim().length > 0) {
|
|
244
|
+
parts.push(`**${label}:**\n${value.trim()}`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return parts.join('\n\n');
|
|
248
|
+
}
|
package/src/themes.ts
CHANGED
|
@@ -1,180 +1,78 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { SynthOSConfig } from './init';
|
|
4
|
-
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const sp = config.storageProvider;
|
|
80
|
-
|
|
81
|
-
// Check user's local themes first (user storage)
|
|
82
|
-
const localPath = path.join(userThemesFolder(config), `${name}.json`);
|
|
83
|
-
if (await sp.checkIfExists(localPath)) {
|
|
84
|
-
const raw = await sp.loadFile(localPath);
|
|
85
|
-
return raw ? JSON.parse(raw) : undefined;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Fall back to package defaults (local fs)
|
|
89
|
-
const defaultPath = await findFileInFolders(config.defaultThemesFolders, `${name}.json`);
|
|
90
|
-
if (defaultPath) {
|
|
91
|
-
const raw = await loadFile(defaultPath);
|
|
92
|
-
return raw ? JSON.parse(raw) : undefined;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return undefined;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export async function loadTheme(name: string, config: SynthOSConfig): Promise<string | undefined> {
|
|
99
|
-
const sp = config.storageProvider;
|
|
100
|
-
|
|
101
|
-
// Check user's local themes first (user storage)
|
|
102
|
-
const local = await findUserThemeCssFile(config, userThemesFolder(config), name);
|
|
103
|
-
if (local) {
|
|
104
|
-
return await sp.loadFile(local.path);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Search all default theme folders (local fs)
|
|
108
|
-
for (const folder of config.defaultThemesFolders) {
|
|
109
|
-
const def = await findDefaultThemeCssFile(folder, name);
|
|
110
|
-
if (def) {
|
|
111
|
-
return await loadFile(def.path);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
return undefined;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export async function listThemes(config: SynthOSConfig): Promise<string[]> {
|
|
119
|
-
const sp = config.storageProvider;
|
|
120
|
-
const names = new Set<string>();
|
|
121
|
-
|
|
122
|
-
// Collect from user's local themes folder (user storage)
|
|
123
|
-
const localFolder = userThemesFolder(config);
|
|
124
|
-
if (await sp.checkIfExists(localFolder)) {
|
|
125
|
-
const files = await sp.listFiles(localFolder);
|
|
126
|
-
for (const f of files) {
|
|
127
|
-
const parsed = parseThemeFilename(f);
|
|
128
|
-
if (parsed) names.add(parsed.name);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Collect from all default theme folders (local fs)
|
|
133
|
-
const defaultFiles = await listFilesFromFolders(config.defaultThemesFolders);
|
|
134
|
-
for (const f of defaultFiles) {
|
|
135
|
-
const parsed = parseThemeFilename(f);
|
|
136
|
-
if (parsed) names.add(parsed.name);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return Array.from(names).sort();
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Compare local theme versions against defaults and return themes that need upgrading.
|
|
144
|
-
*/
|
|
145
|
-
export async function getOutdatedThemes(config: SynthOSConfig): Promise<string[]> {
|
|
146
|
-
const sp = config.storageProvider;
|
|
147
|
-
const localFolder = userThemesFolder(config);
|
|
148
|
-
if (!await sp.checkIfExists(localFolder)) return [];
|
|
149
|
-
|
|
150
|
-
const defaultFiles = await listFilesFromFolders(config.defaultThemesFolders);
|
|
151
|
-
const localFiles = await sp.listFiles(localFolder);
|
|
152
|
-
|
|
153
|
-
// Build maps: theme name → highest version
|
|
154
|
-
const defaultVersions = new Map<string, number>();
|
|
155
|
-
for (const f of defaultFiles) {
|
|
156
|
-
const parsed = parseThemeFilename(f);
|
|
157
|
-
if (parsed) {
|
|
158
|
-
const cur = defaultVersions.get(parsed.name) ?? 0;
|
|
159
|
-
if (parsed.version > cur) defaultVersions.set(parsed.name, parsed.version);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const localVersions = new Map<string, number>();
|
|
164
|
-
for (const f of localFiles) {
|
|
165
|
-
const parsed = parseThemeFilename(f);
|
|
166
|
-
if (parsed) {
|
|
167
|
-
const cur = localVersions.get(parsed.name) ?? 0;
|
|
168
|
-
if (parsed.version > cur) localVersions.set(parsed.name, parsed.version);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const outdated: string[] = [];
|
|
173
|
-
for (const [name, defVer] of defaultVersions) {
|
|
174
|
-
const localVer = localVersions.get(name) ?? 0;
|
|
175
|
-
if (localVer < defVer) {
|
|
176
|
-
outdated.push(name);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return outdated;
|
|
180
|
-
}
|
|
1
|
+
import { checkIfExists, findFileInFolders, listFiles, listFilesFromFolders, loadFile } from './files';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { SynthOSConfig } from './init';
|
|
4
|
+
|
|
5
|
+
export interface ThemeInfo {
|
|
6
|
+
mode: 'light' | 'dark';
|
|
7
|
+
colors: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extract the base theme name and version from a CSS filename.
|
|
12
|
+
* e.g. "nebula-dusk.v2.css" → { name: "nebula-dusk", version: 2 }
|
|
13
|
+
* "nebula-dusk.css" → { name: "nebula-dusk", version: 1 }
|
|
14
|
+
*/
|
|
15
|
+
export function parseThemeFilename(filename: string): { name: string; version: number } | undefined {
|
|
16
|
+
if (!filename.endsWith('.css')) return undefined;
|
|
17
|
+
const versionedMatch = filename.match(/^(.+)\.v(\d+)\.css$/);
|
|
18
|
+
if (versionedMatch) {
|
|
19
|
+
return { name: versionedMatch[1], version: parseInt(versionedMatch[2], 10) };
|
|
20
|
+
}
|
|
21
|
+
return { name: filename.replace(/\.css$/, ''), version: 1 };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Find the CSS file for a theme by name in a local-fs folder (package defaults).
|
|
26
|
+
* Prefers the highest-versioned file (e.g. name.v2.css over name.css).
|
|
27
|
+
*/
|
|
28
|
+
async function findDefaultThemeCssFile(folder: string, name: string): Promise<{ path: string; version: number } | undefined> {
|
|
29
|
+
if (!await checkIfExists(folder)) return undefined;
|
|
30
|
+
const files = await listFiles(folder);
|
|
31
|
+
let best: { path: string; version: number } | undefined;
|
|
32
|
+
for (const f of files) {
|
|
33
|
+
const parsed = parseThemeFilename(f);
|
|
34
|
+
if (parsed && parsed.name === name) {
|
|
35
|
+
if (!best || parsed.version > best.version) {
|
|
36
|
+
best = { path: path.join(folder, f), version: parsed.version };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return best;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export async function loadThemeVersion(name: string, config: SynthOSConfig): Promise<number> {
|
|
44
|
+
for (const folder of config.defaultThemesFolders) {
|
|
45
|
+
const def = await findDefaultThemeCssFile(folder, name);
|
|
46
|
+
if (def) return def.version;
|
|
47
|
+
}
|
|
48
|
+
return 1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function loadThemeInfo(name: string, config: SynthOSConfig): Promise<ThemeInfo | undefined> {
|
|
52
|
+
const defaultPath = await findFileInFolders(config.defaultThemesFolders, `${name}.json`);
|
|
53
|
+
if (defaultPath) {
|
|
54
|
+
const raw = await loadFile(defaultPath);
|
|
55
|
+
return raw ? JSON.parse(raw) : undefined;
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function loadTheme(name: string, config: SynthOSConfig): Promise<string | undefined> {
|
|
61
|
+
for (const folder of config.defaultThemesFolders) {
|
|
62
|
+
const def = await findDefaultThemeCssFile(folder, name);
|
|
63
|
+
if (def) {
|
|
64
|
+
return await loadFile(def.path);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function listThemes(config: SynthOSConfig): Promise<string[]> {
|
|
71
|
+
const names = new Set<string>();
|
|
72
|
+
const defaultFiles = await listFilesFromFolders(config.defaultThemesFolders);
|
|
73
|
+
for (const f of defaultFiles) {
|
|
74
|
+
const parsed = parseThemeFilename(f);
|
|
75
|
+
if (parsed) names.add(parsed.name);
|
|
76
|
+
}
|
|
77
|
+
return Array.from(names).sort();
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"role":"assistant","content":"Welcome to the Blank starter — an empty page ready to be shaped into anything. Tell me what you'd like to build and I'll lay out the structure, styles, and behavior from scratch."}]
|
|
Binary file
|