@silexlabs/silex 3.0.0-alpha.100

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 (282) hide show
  1. package/.env.default +19 -0
  2. package/.silex.js +37 -0
  3. package/LICENSE +661 -0
  4. package/README.md +96 -0
  5. package/dist/client/client/api.d.ts +85 -0
  6. package/dist/client/client/assetUrl.d.ts +51 -0
  7. package/dist/client/client/config.d.ts +58 -0
  8. package/dist/client/client/events.d.ts +14 -0
  9. package/dist/client/client/expose.d.ts +8 -0
  10. package/dist/client/client/grapesjs/LoginDialog.d.ts +15 -0
  11. package/dist/client/client/grapesjs/PublicationManager.d.ts +72 -0
  12. package/dist/client/client/grapesjs/PublicationUi.d.ts +62 -0
  13. package/dist/client/client/grapesjs/blocks.d.ts +1 -0
  14. package/dist/client/client/grapesjs/breadcrumbs.d.ts +1 -0
  15. package/dist/client/client/grapesjs/footer.d.ts +2 -0
  16. package/dist/client/client/grapesjs/index.d.ts +5 -0
  17. package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
  18. package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  19. package/dist/client/client/grapesjs/openImport.d.ts +9 -0
  20. package/dist/client/client/grapesjs/page-panel.d.ts +3 -0
  21. package/dist/client/client/grapesjs/project-bar.d.ts +1 -0
  22. package/dist/client/client/grapesjs/rich-text.d.ts +1 -0
  23. package/dist/client/client/grapesjs/semantic.d.ts +1 -0
  24. package/dist/client/client/grapesjs/settings.d.ts +2 -0
  25. package/dist/client/client/grapesjs/storage.d.ts +1 -0
  26. package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  27. package/dist/client/client/index.d.ts +5 -0
  28. package/dist/client/client/publication-transformers.d.ts +41 -0
  29. package/dist/client/client/utils.d.ts +2 -0
  30. package/dist/client/constants.d.ts +29 -0
  31. package/dist/client/css/admin.css +4491 -0
  32. package/dist/client/index.html +9 -0
  33. package/dist/client/js/main.js +321 -0
  34. package/dist/client/js/main.js.LICENSE.txt +24 -0
  35. package/dist/client/page.d.ts +2 -0
  36. package/dist/client/types.d.ts +334 -0
  37. package/dist/plugins/client/client/api.d.ts +85 -0
  38. package/dist/plugins/client/client/api.js +114 -0
  39. package/dist/plugins/client/client/api.js.map +1 -0
  40. package/dist/plugins/client/client/assetUrl.d.ts +51 -0
  41. package/dist/plugins/client/client/assetUrl.js +224 -0
  42. package/dist/plugins/client/client/assetUrl.js.map +1 -0
  43. package/dist/plugins/client/client/config.d.ts +58 -0
  44. package/dist/plugins/client/client/config.js +90 -0
  45. package/dist/plugins/client/client/config.js.map +1 -0
  46. package/dist/plugins/client/client/events.d.ts +14 -0
  47. package/dist/plugins/client/client/events.js +34 -0
  48. package/dist/plugins/client/client/events.js.map +1 -0
  49. package/dist/plugins/client/client/grapesjs/LoginDialog.d.ts +15 -0
  50. package/dist/plugins/client/client/grapesjs/LoginDialog.js +195 -0
  51. package/dist/plugins/client/client/grapesjs/LoginDialog.js.map +1 -0
  52. package/dist/plugins/client/client/grapesjs/PublicationManager.d.ts +72 -0
  53. package/dist/plugins/client/client/grapesjs/PublicationManager.js +356 -0
  54. package/dist/plugins/client/client/grapesjs/PublicationManager.js.map +1 -0
  55. package/dist/plugins/client/client/grapesjs/PublicationUi.d.ts +62 -0
  56. package/dist/plugins/client/client/grapesjs/PublicationUi.js +336 -0
  57. package/dist/plugins/client/client/grapesjs/PublicationUi.js.map +1 -0
  58. package/dist/plugins/client/client/grapesjs/blocks.d.ts +1 -0
  59. package/dist/plugins/client/client/grapesjs/blocks.js +37 -0
  60. package/dist/plugins/client/client/grapesjs/blocks.js.map +1 -0
  61. package/dist/plugins/client/client/grapesjs/breadcrumbs.d.ts +1 -0
  62. package/dist/plugins/client/client/grapesjs/breadcrumbs.js +75 -0
  63. package/dist/plugins/client/client/grapesjs/breadcrumbs.js.map +1 -0
  64. package/dist/plugins/client/client/grapesjs/footer.d.ts +2 -0
  65. package/dist/plugins/client/client/grapesjs/footer.js +28 -0
  66. package/dist/plugins/client/client/grapesjs/footer.js.map +1 -0
  67. package/dist/plugins/client/client/grapesjs/index.d.ts +5 -0
  68. package/dist/plugins/client/client/grapesjs/index.js +313 -0
  69. package/dist/plugins/client/client/grapesjs/index.js.map +1 -0
  70. package/dist/plugins/client/client/grapesjs/internal-links.d.ts +1 -0
  71. package/dist/plugins/client/client/grapesjs/internal-links.js +219 -0
  72. package/dist/plugins/client/client/grapesjs/internal-links.js.map +1 -0
  73. package/dist/plugins/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  74. package/dist/plugins/client/client/grapesjs/new-page-dialog.js +83 -0
  75. package/dist/plugins/client/client/grapesjs/new-page-dialog.js.map +1 -0
  76. package/dist/plugins/client/client/grapesjs/openImport.d.ts +9 -0
  77. package/dist/plugins/client/client/grapesjs/openImport.js +74 -0
  78. package/dist/plugins/client/client/grapesjs/openImport.js.map +1 -0
  79. package/dist/plugins/client/client/grapesjs/page-panel.d.ts +3 -0
  80. package/dist/plugins/client/client/grapesjs/page-panel.js +113 -0
  81. package/dist/plugins/client/client/grapesjs/page-panel.js.map +1 -0
  82. package/dist/plugins/client/client/grapesjs/project-bar.d.ts +1 -0
  83. package/dist/plugins/client/client/grapesjs/project-bar.js +104 -0
  84. package/dist/plugins/client/client/grapesjs/project-bar.js.map +1 -0
  85. package/dist/plugins/client/client/grapesjs/rich-text.d.ts +1 -0
  86. package/dist/plugins/client/client/grapesjs/rich-text.js +31 -0
  87. package/dist/plugins/client/client/grapesjs/rich-text.js.map +1 -0
  88. package/dist/plugins/client/client/grapesjs/semantic.d.ts +1 -0
  89. package/dist/plugins/client/client/grapesjs/semantic.js +110 -0
  90. package/dist/plugins/client/client/grapesjs/semantic.js.map +1 -0
  91. package/dist/plugins/client/client/grapesjs/settings.d.ts +2 -0
  92. package/dist/plugins/client/client/grapesjs/settings.js +198 -0
  93. package/dist/plugins/client/client/grapesjs/settings.js.map +1 -0
  94. package/dist/plugins/client/client/grapesjs/storage.d.ts +1 -0
  95. package/dist/plugins/client/client/grapesjs/storage.js +126 -0
  96. package/dist/plugins/client/client/grapesjs/storage.js.map +1 -0
  97. package/dist/plugins/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  98. package/dist/plugins/client/client/grapesjs/symbolDialogs.js +36 -0
  99. package/dist/plugins/client/client/grapesjs/symbolDialogs.js.map +1 -0
  100. package/dist/plugins/client/client/publication-transformers.d.ts +41 -0
  101. package/dist/plugins/client/client/publication-transformers.js +238 -0
  102. package/dist/plugins/client/client/publication-transformers.js.map +1 -0
  103. package/dist/plugins/client/client/utils.d.ts +2 -0
  104. package/dist/plugins/client/client/utils.js +25 -0
  105. package/dist/plugins/client/client/utils.js.map +1 -0
  106. package/dist/plugins/client/constants.d.ts +29 -0
  107. package/dist/plugins/client/constants.js +46 -0
  108. package/dist/plugins/client/constants.js.map +1 -0
  109. package/dist/plugins/client/page.d.ts +2 -0
  110. package/dist/plugins/client/page.js +31 -0
  111. package/dist/plugins/client/page.js.map +1 -0
  112. package/dist/plugins/client/plugins/client/11ty.d.ts +17 -0
  113. package/dist/plugins/client/plugins/client/11ty.js +86 -0
  114. package/dist/plugins/client/plugins/client/11ty.js.map +1 -0
  115. package/dist/plugins/client/plugins/client/publicationRenderer.d.ts +2 -0
  116. package/dist/plugins/client/plugins/client/publicationRenderer.js +170 -0
  117. package/dist/plugins/client/plugins/client/publicationRenderer.js.map +1 -0
  118. package/dist/plugins/client/plugins/client/template.d.ts +2 -0
  119. package/dist/plugins/client/plugins/client/template.js +183 -0
  120. package/dist/plugins/client/plugins/client/template.js.map +1 -0
  121. package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
  122. package/dist/plugins/client/plugins/client/website-info.js +72 -0
  123. package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
  124. package/dist/plugins/client/types.d.ts +334 -0
  125. package/dist/plugins/client/types.js +74 -0
  126. package/dist/plugins/client/types.js.map +1 -0
  127. package/dist/plugins/server/constants.d.ts +29 -0
  128. package/dist/plugins/server/constants.js +49 -0
  129. package/dist/plugins/server/constants.js.map +1 -0
  130. package/dist/plugins/server/plugins/server/AuthPlugin.d.ts +1 -0
  131. package/dist/plugins/server/plugins/server/AuthPlugin.js +40 -0
  132. package/dist/plugins/server/plugins/server/AuthPlugin.js.map +1 -0
  133. package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
  134. package/dist/plugins/server/plugins/server/Cache.js +32 -0
  135. package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
  136. package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
  137. package/dist/plugins/server/plugins/server/DownloadConnector.js +129 -0
  138. package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
  139. package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
  140. package/dist/plugins/server/plugins/server/FtpConnector.js +526 -0
  141. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
  142. package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +87 -0
  143. package/dist/plugins/server/plugins/server/GitlabConnector.js +564 -0
  144. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
  145. package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
  146. package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
  147. package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
  148. package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
  149. package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
  150. package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
  151. package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +1 -0
  152. package/dist/plugins/server/plugins/server/StaticPlugin.js +78 -0
  153. package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
  154. package/dist/plugins/server/server/config.d.ts +59 -0
  155. package/dist/plugins/server/server/config.js +181 -0
  156. package/dist/plugins/server/server/config.js.map +1 -0
  157. package/dist/plugins/server/server/connectors/FsHosting.d.ts +13 -0
  158. package/dist/plugins/server/server/connectors/FsHosting.js +54 -0
  159. package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
  160. package/dist/plugins/server/server/connectors/FsStorage.d.ts +43 -0
  161. package/dist/plugins/server/server/connectors/FsStorage.js +257 -0
  162. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
  163. package/dist/plugins/server/server/connectors/connectors.d.ts +87 -0
  164. package/dist/plugins/server/server/connectors/connectors.js +127 -0
  165. package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
  166. package/dist/plugins/server/server/events.d.ts +26 -0
  167. package/dist/plugins/server/server/events.js +31 -0
  168. package/dist/plugins/server/server/events.js.map +1 -0
  169. package/dist/plugins/server/server/jobs.d.ts +12 -0
  170. package/dist/plugins/server/server/jobs.js +77 -0
  171. package/dist/plugins/server/server/jobs.js.map +1 -0
  172. package/dist/plugins/server/server/utils/validation.d.ts +7 -0
  173. package/dist/plugins/server/server/utils/validation.js +38 -0
  174. package/dist/plugins/server/server/utils/validation.js.map +1 -0
  175. package/dist/plugins/server/types.d.ts +334 -0
  176. package/dist/plugins/server/types.js +78 -0
  177. package/dist/plugins/server/types.js.map +1 -0
  178. package/dist/server/constants.js +29 -0
  179. package/dist/server/plugins/server/Cache.js +15 -0
  180. package/dist/server/server/api/api.js +20 -0
  181. package/dist/server/server/api/connectorApi.js +216 -0
  182. package/dist/server/server/api/publicationApi.js +108 -0
  183. package/dist/server/server/api/websiteApi.js +296 -0
  184. package/dist/server/server/cli.js +68 -0
  185. package/dist/server/server/config.js +120 -0
  186. package/dist/server/server/connectors/FsHosting.js +35 -0
  187. package/dist/server/server/connectors/FsStorage.js +225 -0
  188. package/dist/server/server/connectors/connectors.js +89 -0
  189. package/dist/server/server/events.js +14 -0
  190. package/dist/server/server/expose.js +27 -0
  191. package/dist/server/server/express.js +47 -0
  192. package/dist/server/server/index.js +90 -0
  193. package/dist/server/server/jobs.js +48 -0
  194. package/dist/server/server/utils/validation.js +15 -0
  195. package/dist/server/types.js +34 -0
  196. package/package.json +209 -0
  197. package/public/assets/container.png +0 -0
  198. package/public/assets/favicon.png +0 -0
  199. package/public/assets/logo-silex-small.png +0 -0
  200. package/public/robots.txt +2 -0
  201. package/public/silex.js +24 -0
  202. package/src/css/_mixins.scss +8 -0
  203. package/src/css/_variables.scss +33 -0
  204. package/src/css/dialog.scss +41 -0
  205. package/src/css/footer.scss +12 -0
  206. package/src/css/grapesjs-light.scss +180 -0
  207. package/src/css/grapesjs.scss +152 -0
  208. package/src/css/index.scss +32 -0
  209. package/src/css/light.scss +7 -0
  210. package/src/css/loader.scss +12 -0
  211. package/src/css/page-panel.scss +65 -0
  212. package/src/css/project-bar.scss +102 -0
  213. package/src/css/silex.scss +189 -0
  214. package/src/css/website-info.scss +14 -0
  215. package/src/html/debug.pug +8 -0
  216. package/src/html/index.pug +39 -0
  217. package/src/html/templates/includes.pug +1 -0
  218. package/src/html/templates/workspace.pug +2 -0
  219. package/src/ts/client/api.ts +144 -0
  220. package/src/ts/client/assetUrl.test.ts +125 -0
  221. package/src/ts/client/assetUrl.ts +235 -0
  222. package/src/ts/client/config.ts +105 -0
  223. package/src/ts/client/events.ts +34 -0
  224. package/src/ts/client/expose.ts +30 -0
  225. package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
  226. package/src/ts/client/grapesjs/PublicationManager.ts +370 -0
  227. package/src/ts/client/grapesjs/PublicationUi.ts +342 -0
  228. package/src/ts/client/grapesjs/blocks.ts +37 -0
  229. package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
  230. package/src/ts/client/grapesjs/eleventy.ts +47 -0
  231. package/src/ts/client/grapesjs/footer.ts +27 -0
  232. package/src/ts/client/grapesjs/index.ts +335 -0
  233. package/src/ts/client/grapesjs/internal-links.test.ts +105 -0
  234. package/src/ts/client/grapesjs/internal-links.ts +225 -0
  235. package/src/ts/client/grapesjs/new-page-dialog.ts +90 -0
  236. package/src/ts/client/grapesjs/openImport.ts +81 -0
  237. package/src/ts/client/grapesjs/page-panel.ts +118 -0
  238. package/src/ts/client/grapesjs/project-bar.ts +107 -0
  239. package/src/ts/client/grapesjs/rich-text.ts +33 -0
  240. package/src/ts/client/grapesjs/semantic.ts +114 -0
  241. package/src/ts/client/grapesjs/settings.ts +208 -0
  242. package/src/ts/client/grapesjs/storage.ts +121 -0
  243. package/src/ts/client/grapesjs/symbolDialogs.ts +38 -0
  244. package/src/ts/client/index.ts +98 -0
  245. package/src/ts/client/publication-transformers.test.ts +199 -0
  246. package/src/ts/client/publication-transformers.ts +263 -0
  247. package/src/ts/client/utils.ts +28 -0
  248. package/src/ts/constants.ts +52 -0
  249. package/src/ts/externs.ts +18 -0
  250. package/src/ts/page.ts +31 -0
  251. package/src/ts/plugins/client/11ty.ts +104 -0
  252. package/src/ts/plugins/client/publicationRenderer.ts +174 -0
  253. package/src/ts/plugins/client/template.ts +192 -0
  254. package/src/ts/plugins/client/website-info.ts +84 -0
  255. package/src/ts/plugins/server/AuthPlugin.ts +38 -0
  256. package/src/ts/plugins/server/Cache.ts +28 -0
  257. package/src/ts/plugins/server/DownloadConnector.ts +148 -0
  258. package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
  259. package/src/ts/plugins/server/FtpConnector.ts +609 -0
  260. package/src/ts/plugins/server/GitlabConnector.ts +644 -0
  261. package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
  262. package/src/ts/plugins/server/SslPlugin.ts +84 -0
  263. package/src/ts/plugins/server/StaticPlugin.ts +79 -0
  264. package/src/ts/server/api/api.ts +19 -0
  265. package/src/ts/server/api/connectorApi.ts +345 -0
  266. package/src/ts/server/api/publicationApi.ts +159 -0
  267. package/src/ts/server/api/websiteApi.ts +432 -0
  268. package/src/ts/server/cli.ts +65 -0
  269. package/src/ts/server/config.ts +189 -0
  270. package/src/ts/server/connectors/FsHosting.ts +60 -0
  271. package/src/ts/server/connectors/FsStorage.test.ts +51 -0
  272. package/src/ts/server/connectors/FsStorage.ts +261 -0
  273. package/src/ts/server/connectors/connectors.ts +203 -0
  274. package/src/ts/server/events.ts +37 -0
  275. package/src/ts/server/expose.ts +19 -0
  276. package/src/ts/server/express.ts +70 -0
  277. package/src/ts/server/index.ts +100 -0
  278. package/src/ts/server/jobs.test.ts +75 -0
  279. package/src/ts/server/jobs.ts +87 -0
  280. package/src/ts/server/utils/BackwardCompat.ts +552 -0
  281. package/src/ts/server/utils/validation.ts +34 -0
  282. package/src/ts/types.ts +339 -0
@@ -0,0 +1,432 @@
1
+ /*
2
+ * Silex website builder, free/libre no-code tool for makers.
3
+ * Copyright (c) 2023 lexoyo and Silex Labs foundation
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU Affero General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Affero General Public License
15
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ import { Router } from 'express'
19
+ import formidable from 'formidable'
20
+ import PersistentFile from 'formidable/src/PersistentFile'
21
+ import { API_WEBSITE_ASSET_READ, API_WEBSITE_ASSETS_WRITE, API_WEBSITE_READ, API_WEBSITE_WRITE, API_WEBSITE_DELETE, API_WEBSITE_META_READ, API_WEBSITE_META_WRITE, API_WEBSITE_LIST, API_WEBSITE_CREATE, API_PATH, API_WEBSITE_PATH } from '../../constants'
22
+ import { createReadStream } from 'fs'
23
+ import { ApiError, ApiWebsiteAssetsReadParams, ApiWebsiteAssetsReadQuery, ApiWebsiteAssetsReadResponse, ApiWebsiteAssetsWriteQuery, ApiWebsiteAssetsWriteResponse, ApiWebsiteDeleteQuery, ApiWebsiteReadQuery, ApiWebsiteReadResponse, ApiWebsiteWriteBody, ApiWebsiteWriteQuery, ConnectorId, ConnectorType, WebsiteMeta, WebsiteData, WebsiteId, ApiWebsiteListQuery, ApiWebsiteListResponse, ApiWebsiteMetaReadQuery, ApiWebsiteMetaReadResponse, ApiWebsiteMetaWriteQuery, ApiWebsiteMetaWriteBody, WebsiteMetaFileContent, ApiWebsiteMetaWriteResponse, ApiWebsiteWriteResponse, ApiWebsiteCreateQuery, ApiWebsiteCreateBody } from '../../types'
24
+ import { ConnectorFile, ConnectorFileContent, ConnectorSession, StorageConnector, getConnector } from '../connectors/connectors'
25
+ import { Readable } from 'stream'
26
+ import { requiredParam } from '../utils/validation'
27
+ import { basename } from 'path'
28
+ import { ServerConfig } from '../config'
29
+ import { ServerEvent, WebsiteStoreEndEventType, WebsiteStoreStartEventType, WebsiteAssetStoreStartEventType, WebsiteAssetStoreEndEventType } from '../events'
30
+
31
+ /**
32
+ * @fileoverview Website plugin for Silex
33
+ * This plugin provides the website API to Silex server
34
+ */
35
+
36
+ export default function (config: ServerConfig, opts = {}): Router {
37
+ // Options with defaults
38
+ const options = {
39
+ // Default constants
40
+ assetsPath: '/assets',
41
+ // Options
42
+ ...opts
43
+ }
44
+
45
+ // Create a new router
46
+ const router = Router()
47
+
48
+ // Load website data
49
+ router.get(API_WEBSITE_READ, async (req, res, next) => {
50
+ const query = req.query as ApiWebsiteReadQuery
51
+ const { websiteId, connectorId } = query
52
+ const session = req['session'] as ConnectorSession
53
+ if(!websiteId) {
54
+ // List websites
55
+ next()
56
+ return
57
+ }
58
+ try {
59
+ // Get website data
60
+ const websiteData: WebsiteData | Readable = await readWebsite(
61
+ session,
62
+ websiteId,
63
+ connectorId,
64
+ )
65
+ if (websiteData instanceof Readable) {
66
+ websiteData.pipe(res.type('application/json'))
67
+ } else {
68
+ res.json(websiteData as ApiWebsiteReadResponse)
69
+ }
70
+ } catch (e) {
71
+ if (e.httpStatusCode) {
72
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
73
+ } else {
74
+ res.status(500).json({ message: e.message } as ApiError)
75
+ }
76
+ }
77
+ })
78
+
79
+ // List websites
80
+ router.get(API_WEBSITE_LIST, async (req, res) => {
81
+ const query: ApiWebsiteListQuery = req.query
82
+ const { connectorId } = query
83
+ const session = req['session'] as ConnectorSession
84
+ try {
85
+ // List websites
86
+ const websites = await listWebsites(req['session'], query.connectorId as string | undefined)
87
+ res.json(websites as ApiWebsiteListResponse)
88
+ } catch (e) {
89
+ console.error('Error getting website data', e)
90
+ if (e.httpStatusCode) {
91
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
92
+ } else {
93
+ res.status(500).json({ message: e.message } as ApiError)
94
+ }
95
+ }
96
+ })
97
+
98
+ // Save website data
99
+ router.post(API_WEBSITE_WRITE, async (req, res) => {
100
+ try {
101
+ // Check input
102
+ const query: ApiWebsiteWriteQuery = req.query as any
103
+ const body: ApiWebsiteWriteBody = req.body
104
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'Website id')
105
+ const websiteData = requiredParam<WebsiteData>(body, 'Website data') as WebsiteData
106
+ const connectorId = query.connectorId // Optional
107
+ // Hook to modify the website data before saving
108
+ config.emit(ServerEvent.WEBSITE_STORE_START, { websiteId, websiteData, connectorId } as WebsiteStoreStartEventType)
109
+ // Save website data
110
+ await writeWebsite(
111
+ req['session'],
112
+ websiteId,
113
+ websiteData,
114
+ connectorId,
115
+ )
116
+ config.emit(ServerEvent.WEBSITE_STORE_END, null as WebsiteStoreEndEventType)
117
+ res.status(200).json({ message: 'Website saved' } as ApiWebsiteWriteResponse)
118
+ } catch (e) {
119
+ console.error('Error saving website data', e)
120
+ config.emit(ServerEvent.WEBSITE_STORE_END, e as WebsiteStoreEndEventType)
121
+ if (e.httpStatusCode) {
122
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
123
+ } else {
124
+ res.status(500).json({ message: e.message } as ApiError)
125
+ }
126
+ }
127
+ })
128
+
129
+ // Create website or update website meta
130
+ router.put(API_WEBSITE_CREATE, async (req, res) => {
131
+ try {
132
+ // Check input
133
+ const session = req['session'] as ConnectorSession
134
+ const query: ApiWebsiteCreateQuery = req.query as any
135
+ const body: ApiWebsiteCreateBody = req.body
136
+ const websiteMeta = requiredParam<WebsiteMetaFileContent>(body, 'Website meta') as WebsiteMeta
137
+ const connectorId = query.connectorId
138
+ const connector = await getConnector<StorageConnector>(config, session, ConnectorType.STORAGE, connectorId)
139
+ if(!connector) {
140
+ throw new ApiError(`Connector ${connectorId} not found`, 500)
141
+ }
142
+ // Create website
143
+ await connector.createWebsite(
144
+ session,
145
+ websiteMeta,
146
+ )
147
+ res.json({ message: 'Website meta saved' } as ApiWebsiteMetaWriteResponse)
148
+ } catch (e) {
149
+ console.error('Error saving website meta', e)
150
+ if (e.httpStatusCode) {
151
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
152
+ } else {
153
+ res.status(500).json({ message: e.message } as ApiError)
154
+ }
155
+ }
156
+ })
157
+
158
+ // Update website meta
159
+ router.post(API_WEBSITE_META_WRITE, async (req, res) => {
160
+ try {
161
+ // Check input
162
+ const session = req['session'] as ConnectorSession
163
+ const query: ApiWebsiteMetaWriteQuery = req.query as any
164
+ const body: ApiWebsiteMetaWriteBody = req.body
165
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'Website id')
166
+ const websiteMeta = requiredParam<WebsiteMetaFileContent>(body, 'Website meta') as WebsiteMeta
167
+ const connectorId = query.connectorId
168
+ const connector = await getConnector<StorageConnector>(config, session, ConnectorType.STORAGE, connectorId)
169
+ if(!connector) {
170
+ throw new ApiError(`Connector ${connectorId} not found`, 500)
171
+ }
172
+ // Update website meta
173
+ await connector.setWebsiteMeta(
174
+ session,
175
+ websiteId,
176
+ websiteMeta,
177
+ )
178
+ res.json({ message: 'Website meta saved' } as ApiWebsiteMetaWriteResponse)
179
+ } catch (e) {
180
+ console.error('Error saving website meta', e)
181
+ if (e.httpStatusCode) {
182
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
183
+ } else {
184
+ res.status(500).json({ message: e.message } as ApiError)
185
+ }
186
+ }
187
+ })
188
+
189
+ // Get website meta
190
+ router.get(API_WEBSITE_META_READ, async (req, res) => {
191
+ try {
192
+ const session = req['session'] as ConnectorSession
193
+ const query: ApiWebsiteMetaReadQuery = req.query as any
194
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'Website id')
195
+ const connectorId = query.connectorId
196
+ const connector = await getConnector<StorageConnector>(config, session, ConnectorType.STORAGE, connectorId)
197
+ if(!connector) {
198
+ throw new ApiError(`Connector ${connectorId} not found`, 500)
199
+ }
200
+ const websiteMeta: WebsiteMeta = await connector.getWebsiteMeta(session, websiteId)
201
+ res.json(websiteMeta as ApiWebsiteMetaReadResponse)
202
+ } catch (e) {
203
+ console.error('Error getting website meta', e)
204
+ if (e.httpStatusCode) {
205
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
206
+ } else {
207
+ res.status(500).json({ message: e.message } as ApiError)
208
+ }
209
+ }
210
+ })
211
+
212
+ // Delete website
213
+ router.delete(API_WEBSITE_DELETE, async (req, res) => {
214
+ try {
215
+ const query: ApiWebsiteDeleteQuery = req.query as any
216
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'Website id')
217
+ await deleteWebsite(req['session'], websiteId, query.connectorId)
218
+ res.status(200).json({ message: 'Website deleted' } as ApiError)
219
+ } catch (e) {
220
+ console.error('Error deleting website data', e)
221
+ if (e.httpStatusCode) {
222
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
223
+ } else {
224
+ res.status(500).json({ message: e.message } as ApiError)
225
+ }
226
+ }
227
+ })
228
+
229
+ // Load assets
230
+ router.get(API_WEBSITE_ASSET_READ + '/:path', async (req, res) => {
231
+ {
232
+ try {
233
+ const query: ApiWebsiteAssetsReadQuery = req.query as any
234
+ const params: ApiWebsiteAssetsReadParams = req.params as any
235
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'Website id')
236
+ const path = requiredParam<string>(params.path, 'path')
237
+ const asset: ConnectorFileContent = await readAsset(req['session'], websiteId, path, query.connectorId)
238
+ // Set content type
239
+ res.contentType(basename(path))
240
+ // Send the file
241
+ if (asset instanceof Readable) {
242
+ // Stream
243
+ asset.pipe(res)
244
+ } else {
245
+ // Buffer or string
246
+ res.send(asset as ApiWebsiteAssetsReadResponse)
247
+ }
248
+ } catch (e) {
249
+ console.error('Error getting asset', e)
250
+ if (e.httpStatusCode) {
251
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
252
+ } else {
253
+ res.status(500).json({ message: e.message } as ApiError)
254
+ }
255
+ }
256
+ }
257
+ })
258
+
259
+ // Upload assets
260
+ router.post(API_WEBSITE_ASSETS_WRITE, async (req, res) => {
261
+ try {
262
+ // Check input
263
+ const query: ApiWebsiteAssetsWriteQuery = req.query as any
264
+ const websiteId= requiredParam<WebsiteId>(query.websiteId as WebsiteId, 'Website id')
265
+
266
+ // Get the file data from the request
267
+ const form = formidable({
268
+ filename: (name, ext, part, _form) => `${name}${ext}`,
269
+ multiples: true,
270
+ keepExtensions: true,
271
+ })
272
+ const connectorId = query.connectorId // Optional
273
+
274
+ // Retrive the files
275
+ const files: ConnectorFile[] = await new Promise<ConnectorFile[]>((resolve, reject) => {
276
+ form.parse(req, async (err, fields, _files) => {
277
+ if (err) {
278
+ console.error('Error parsing upload data', err)
279
+ reject(new ApiError('Error parsing upload data: ' + err.message, 400))
280
+ } else {
281
+ const files = ([].concat(_files['files[]']) as PersistentFile[])
282
+ .map(file => file.toJSON())
283
+ .map(file => ({
284
+ path: `/${file.originalFilename}`,
285
+ content: createReadStream(file.filepath),
286
+ }))
287
+ resolve(files)
288
+ }
289
+ })
290
+ })
291
+
292
+ // Hook to modify the files
293
+ config.emit(ServerEvent.WEBSITE_ASSET_STORE_START, { files, websiteId, connectorId } as WebsiteAssetStoreStartEventType)
294
+
295
+ // Write the files
296
+ const result = await writeAssets(req['session'], websiteId, files, connectorId)
297
+
298
+ // Base URL of silex serve
299
+ const baseUrl = new URL(config.url).pathname.replace(/\/$/, '')
300
+
301
+ // Return the file URLs to insert in the website
302
+ // As expected by grapesjs (https://grapesjs.com/docs/modules/Assets.html#uploading-assets)
303
+ const data = result.map(path =>
304
+ // FIXME: We should return path without this line, as it is saved, not as it is displayed
305
+ baseUrl + API_PATH + API_WEBSITE_PATH + API_WEBSITE_ASSET_READ
306
+ + path
307
+ + `?websiteId=${websiteId}&connectorId=${connectorId ? connectorId : ''}` // As expected by wesite API (readAsset)
308
+ )
309
+
310
+ // Return the file URLs
311
+ res.json({
312
+ data,
313
+ } as ApiWebsiteAssetsWriteResponse)
314
+
315
+ // Hook for plugins
316
+ config.emit(ServerEvent.WEBSITE_ASSET_STORE_END, null as WebsiteAssetStoreEndEventType)
317
+ } catch (e) {
318
+ console.error('Error uploading assets', e)
319
+ if (e.httpStatusCode) {
320
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
321
+ } else {
322
+ res.status(500).json({ message: e.message } as ApiError)
323
+ }
324
+ // Hook for plugins
325
+ config.emit(ServerEvent.WEBSITE_ASSET_STORE_END, e as WebsiteAssetStoreEndEventType)
326
+ }
327
+ })
328
+
329
+ /**
330
+ * Get the desired connector
331
+ * Can be the default connector or a specific one
332
+ */
333
+ async function getStorageConnector(session: any, connectorId?: string): Promise<StorageConnector> {
334
+ const storageConnector = await getConnector(config, session, ConnectorType.STORAGE, connectorId) // ?? config.getStorageConnectors()[0]
335
+
336
+ if (!storageConnector) {
337
+ throw new ApiError('No storage connector found', 404)
338
+ }
339
+
340
+ if (!await storageConnector.isLoggedIn(session)) {
341
+ throw new ApiError('Not logged in', 401)
342
+ }
343
+
344
+ return storageConnector as StorageConnector
345
+ }
346
+
347
+ /**
348
+ * Read the website data
349
+ */
350
+ async function readWebsite(session: any, websiteId: string, connectorId?: string): Promise<WebsiteData | Readable> {
351
+ // Get the desired connector
352
+ const storageConnector = await getStorageConnector(session, connectorId)
353
+
354
+ // Return website data
355
+ return storageConnector.readWebsite(session, websiteId)
356
+ }
357
+
358
+ /**
359
+ * List existing websites
360
+ */
361
+ async function listWebsites(session: any, connectorId?: string): Promise<WebsiteMeta[]> {
362
+ // Get the desired connector
363
+ const storageConnector = await getStorageConnector(session, connectorId)
364
+
365
+ // List websites
366
+ return storageConnector.listWebsites(session)
367
+ }
368
+
369
+ /**
370
+ * Write the website data to the connector
371
+ */
372
+ async function writeWebsite(session: any, websiteId: WebsiteId, websiteData: WebsiteData, connectorId?: ConnectorId): Promise<void> {
373
+ // Get the desired connector
374
+ const storageConnector = await getStorageConnector(session, connectorId)
375
+
376
+ // Write the website data
377
+ await storageConnector.updateWebsite(session, websiteId, websiteData)
378
+ }
379
+
380
+ /**
381
+ * Delete a website
382
+ */
383
+ async function deleteWebsite(session: any, websiteId: string, connectorId?: string): Promise<void> {
384
+ // Get the desired connector
385
+ const storageConnector = await getStorageConnector(session, connectorId)
386
+
387
+ // Delete the website
388
+ return storageConnector.deleteWebsite(session, websiteId)
389
+ }
390
+
391
+ /**
392
+ * Read an asset
393
+ */
394
+ async function readAsset(session: any, websiteId: string, fileName: string, connectorId?: string): Promise<ConnectorFileContent> {
395
+ // Get the desired connector
396
+ const storageConnector = await getStorageConnector(session, connectorId)
397
+
398
+ // Read the asset from the connector
399
+ return storageConnector.readAsset(session, websiteId, `/${fileName}`)
400
+ }
401
+
402
+ /**
403
+ * Write an asset to the connector
404
+ * @returns File names on the storage connector, always starting with a slash
405
+ */
406
+ async function writeAssets(session: any, websiteId: string, files: ConnectorFile[], connectorId?: string): Promise<string[]> {
407
+ // Get the desired connector
408
+ const storageConnector = await getStorageConnector(session, connectorId)
409
+
410
+ // Clean up the path
411
+ const cleanPathFiles = files.map(file => ({
412
+ ...file,
413
+ path: file.path.replace('/assets/', '/'), // Remove the assets folder added by GrapesJS
414
+ }))
415
+
416
+ // Write the asset to the connector
417
+ const result = await storageConnector.writeAssets(
418
+ session,
419
+ websiteId,
420
+ cleanPathFiles,
421
+ )
422
+
423
+ // Return the files URLs with the website id
424
+ return files
425
+ // Use the original path or the one returned by the connector
426
+ .map(({ path }, idx) => result && result[idx] ? result[idx] : path)
427
+ // Make it an absolute path with the website id and the connector id as query params
428
+ //.map((path) => toAssetUrl(path, config.url, websiteId, connectorId))
429
+ }
430
+
431
+ return router
432
+ }
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env node
2
+
3
+ /*
4
+ * Silex website builder, free/libre no-code tool for makers.
5
+ * Copyright (c) 2023 lexoyo and Silex Labs foundation
6
+ *
7
+ * This program is free software: you can redistribute it and/or modify
8
+ * it under the terms of the GNU Affero General Public License as published by
9
+ * the Free Software Foundation, either version 3 of the License, or any later version.
10
+ *
11
+ * This program is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ * GNU Affero General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Affero General Public License
17
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
18
+ */
19
+
20
+ import silex from './index'
21
+ import { parse } from 'cli'
22
+
23
+ const options = parse({
24
+ 'url': ['', 'URL of your server', 'string'],
25
+ 'host': ['', 'Sets the host param of the express module "cookie-session".', 'string'],
26
+ 'port': [ 'p', 'Port to listen to', 'int'],
27
+ 'protocol': ['', 'Sets the protocol param of the express module "cookie-session".', 'string'],
28
+ 'config': [ 'c', 'Path for the server side config file to load at startup', 'file'],
29
+ 'client-config': ['', 'Path to client config file to be served on .silex-client.js', 'string'],
30
+ 'fs-root': ['', 'Path to the root folder where to store websites. Used by the default connector (fs).', 'string'],
31
+ 'session-name': ['', 'Sets the name param of the express module "cookie-session".', 'string'],
32
+ 'session-secret': ['s', 'Session secret', 'string'],
33
+ 'ssl-port': [ false, 'Port to listen to for SSL/HTTPS', 'int'],
34
+ 'force-https': [ false, 'Force HTTPS', 'boolean'],
35
+ 'ssl-private-key': [ false, 'Path to private key for SSL', 'file'],
36
+ 'ssl-certificate': [ false, 'Path to SSL certificate', 'file'],
37
+ 'force-https-trust-xfp-header': [ false, 'Sets the trustXFPHeader param of the express module "cookie-session". Use only with --force-https', 'boolean'],
38
+ 'cors-url': ['', 'Enable CORS for URL (can be "*")', 'string'],
39
+ 'express-json-limit': ['', 'Sets the limit param of the express module "json".', 'string'],
40
+ 'express-text-limit': ['', 'Sets the limit param of the express module "text".', 'string'],
41
+ 'express-urlencoded-limit': ['', 'Sets the limit param of the express module "urlencoded".', 'string'],
42
+ 'debug': [false, 'Debug mode, with live reload, source maps etc.', 'boolean'],
43
+ }, {})
44
+
45
+ if(options['url']) process.env.SILEX_URL = options['url']
46
+ if(options['host']) process.env.SILEX_HOST = options['host']
47
+ if(options.port) process.env.SILEX_PORT = options.port
48
+ if(options['protocol']) process.env.SILEX_PROTOCOL = options['protocol']
49
+ if(options.config) process.env.SILEX_CONFIG = options.config
50
+ if(options['client-config']) process.env.SILEX_CLIENT_CONFIG = options['client-config']
51
+ if(options['fs-root']) process.env.SILEX_FS_ROOT = options['fs-root']
52
+ if(options['session-name']) process.env.SILEX_SESSION_NAME = options['session-name']
53
+ if(options['session-secret']) process.env.SILEX_SESSION_SECRET = options['session-secret']
54
+ if(options['ssl-port']) process.env.SILEX_SSL_PORT = options['ssl-port']
55
+ if(options['force-https']) process.env.SILEX_FORCE_HTTPS = options['force-https']
56
+ if(options['ssl-private-key']) process.env.SILEX_SSL_PRIVATE_KEY = options['ssl-private-key']
57
+ if(options['ssl-certificate']) process.env.SILEX_SSL_CERTIFICATE = options['ssl-certificate']
58
+ if(options['force-https-trust-xfp-header']) process.env.SILEX_FORCE_HTTPS_TRUST_XFP_HEADER = options['force-https-trust-xfp-header']
59
+ if(options['cors-url']) process.env.SILEX_CORS_URL = options['cors-url']
60
+ if(options['express-json-limit']) process.env.SILEX_EXPRESS_JSON_LIMIT = options['express-json-limit']
61
+ if(options['express-text-limit']) process.env.SILEX_EXPRESS_TEXT_LIMIT = options['express-text-limit']
62
+ if(options['express-urlencoded-limit']) process.env.SILEX_EXPRESS_URLENCODED_LIMIT = options['express-urlencoded-limit']
63
+ if(options.debug) process.env.SILEX_DEBUG = options.debug
64
+
65
+ silex()
@@ -0,0 +1,189 @@
1
+ /*
2
+ * Silex website builder, free/libre no-code tool for makers.
3
+ * Copyright (c) 2023 lexoyo and Silex Labs foundation
4
+ *
5
+ * This program is free software: you can redistribute it and/or modify
6
+ * it under the terms of the GNU Affero General Public License as published by
7
+ * the Free Software Foundation, either version 3 of the License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ * GNU Affero General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Affero General Public License
15
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+ */
17
+
18
+ /**
19
+ * @fileoverview This is where the default config is defined. Also use this object as an event emitter to listen to Silex events
20
+ * The values can be overriden with env vars or before passing the config to Silex
21
+ */
22
+
23
+ /**
24
+ * @class default config for Silex server
25
+ */
26
+
27
+ import { Config, Plugin } from '@silexlabs/silex-plugins'
28
+ import { resolve } from 'path'
29
+ import { CLIENT_CONFIG_FILE_NAME } from '../constants'
30
+ import { Application, Request, Response, Router } from 'express'
31
+ import { readFile } from 'fs/promises'
32
+ import { HostingConnector, StorageConnector, toConnectorEnum } from './connectors/connectors'
33
+ import { FsStorage } from './connectors/FsStorage'
34
+ import { Connector } from './connectors/connectors'
35
+ import { ConnectorType } from '../types'
36
+ import { FsHosting } from './connectors/FsHosting'
37
+
38
+ /**
39
+ * Config types definitions
40
+ */
41
+ export class ServerConfig extends Config {
42
+ public expressOptions = {
43
+ jsonLimit: process.env.SILEX_EXPRESS_JSON_LIMIT,
44
+ textLimit: process.env.SILEX_EXPRESS_TEXT_LIMIT,
45
+ urlencodedLimit: process.env.SILEX_EXPRESS_URLENCODED_LIMIT,
46
+ sessionName: process.env.SILEX_SESSION_NAME,
47
+ sessionSecret: process.env.SILEX_SESSION_SECRET,
48
+ cors: process.env.SILEX_CORS_URL,
49
+ }
50
+ public port = process.env.SILEX_PORT
51
+ public debug = process.env.SILEX_DEBUG === 'true'
52
+ public url = process.env.SILEX_URL?.replace(/\/$/, '') ?? `${process.env.SILEX_PROTOCOL}://${process.env.SILEX_HOST}:${process.env.SILEX_PORT}`
53
+ public userConfigPath: Plugin | undefined = process.env.SILEX_CONFIG
54
+ public configFilePath: Plugin = resolve(__dirname, '../../../.silex.js')
55
+
56
+ // All connectors or just the storage or hosting connectors
57
+ getConnectors(type: ConnectorType | string | null = null): Connector[] {
58
+ // All connectors including storage and hosting connectors
59
+ if (!type) {
60
+ // Concat storage and hosting connectors
61
+ const allConnectors: Connector[] = (this.getStorageConnectors() as Connector[]).concat(this.getHostingConnectors())
62
+
63
+ // Remove duplicates (if a connector is both a storage and a hosting connector)
64
+ return [...new Set(allConnectors)]
65
+ }
66
+
67
+ // Convert to enum in case it is a string
68
+ const connectorType = toConnectorEnum(type.toString())
69
+
70
+ // Only one type of connector
71
+ switch(connectorType) {
72
+ case ConnectorType.HOSTING: return this.getHostingConnectors()
73
+ case ConnectorType.STORAGE: return this.getStorageConnectors()
74
+ default: throw new Error(`Unknown connector type ${type}`)
75
+ }
76
+ }
77
+
78
+ // Storage connectors to store the website data and assets
79
+ private storageConnectors: StorageConnector[] = []
80
+ addStorageConnector(storage: StorageConnector | StorageConnector[]) {
81
+ this.setStorageConnectors(this.storageConnectors.concat(storage))
82
+ }
83
+ setStorageConnectors(storageConnectors: StorageConnector[]) {
84
+ this.storageConnectors =storageConnectors
85
+ }
86
+ getStorageConnectors(): StorageConnector[] {
87
+ return this.storageConnectors
88
+ }
89
+
90
+ // Hosting connectors to publish the website online
91
+ private hostingConnectors: HostingConnector[] = []
92
+ addHostingConnector(hosting: HostingConnector | HostingConnector[]) {
93
+ this.setHostingConnectors(this.hostingConnectors.concat(hosting))
94
+ }
95
+ setHostingConnectors(hostings: HostingConnector[]) {
96
+ this.hostingConnectors = hostings
97
+ }
98
+ getHostingConnectors(): HostingConnector[] { return this.hostingConnectors }
99
+
100
+ /**
101
+ * Add routes to serve the client config file
102
+ */
103
+ async addRoutes(app: Application) {
104
+ const path = process.env.SILEX_CLIENT_CONFIG
105
+ if (path) {
106
+ console.info(`> Serving client side config ${path} at ${CLIENT_CONFIG_FILE_NAME}`)
107
+ try {
108
+ // Load the client config file
109
+ let clientConfig = (await readFile(path as string)).toString()
110
+ // Serve the config file
111
+ app.get(`/${CLIENT_CONFIG_FILE_NAME}`, async (req: Request, res: Response) => {
112
+ // Reload each time in debug mode
113
+ if (this.debug) {
114
+ console.info('[Debug mode] Reloading config file', path)
115
+ clientConfig = (await readFile(path)).toString()
116
+ }
117
+ // Send the config file
118
+ res
119
+ .contentType('application/javascript')
120
+ .send(clientConfig)
121
+ })
122
+ } catch (e) {
123
+ console.error(`Error loading client config file ${path}`, e)
124
+ throw new Error(`Error loading client config file ${path}: ${e.message}`)
125
+ }
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Load config files
131
+ * This is the main config file and the user config file
132
+ */
133
+ async loadConfigFiles() {
134
+ // Load the user config file
135
+ await this.loadUserConfig()
136
+ // Load the main config file
137
+ await this.loadSilexConfig()
138
+ }
139
+
140
+ /**
141
+ * Load user config file
142
+ * This is the config file passed as env var CONFIG
143
+ */
144
+ async loadUserConfig() {
145
+ if (this.userConfigPath) {
146
+ console.info('> Loading user config', this.userConfigPath)
147
+ try {
148
+ // Initiate the process with the config file which is just another plugin
149
+ await this.addPlugin(this.userConfigPath, {})
150
+ } catch (e) {
151
+ throw new Error(`\nUser config file ${this.userConfigPath} error:\n\n\t${e.message}\n\n`)
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Load .silex.js in the root folder
158
+ * This is the main config file
159
+ */
160
+ async loadSilexConfig() {
161
+ console.info('> Loading config', this.configFilePath)
162
+ try {
163
+ // Initiate the process with the config file which is just another plugin
164
+ await this.addPlugin(this.configFilePath, {})
165
+ } catch(e) {
166
+ // Check if the error is about the config file not found and not another module not found in the config file
167
+ if(e.code === 'MODULE_NOT_FOUND' && (!e.requireStack || !e.requireStack.find(path => path === this.configFilePath))) {
168
+ console.info('> /!\\ Config file not found', this.configFilePath)
169
+ } else {
170
+ throw new Error(`Error in config file ${this.configFilePath}: ${e.message}`)
171
+ }
172
+ }
173
+ }
174
+
175
+ async initDefaultConnectors() {
176
+ // Add default storage connectors
177
+ if (!this.storageConnectors.length) {
178
+ this.addStorageConnector(new FsStorage(null, {
179
+ path: process.env.SILEX_FS_ROOT,
180
+ }))
181
+ }
182
+ // Add default hosting connectors
183
+ if (!this.hostingConnectors.length) {
184
+ this.addHostingConnector(new FsHosting(null, {
185
+ path: process.env.SILEX_FS_ROOT,
186
+ }))
187
+ }
188
+ }
189
+ }