@silexlabs/silex 3.0.1-alpha.0 → 3.0.2

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 (323) hide show
  1. package/.env.default +20 -0
  2. package/.silex.js +67 -8
  3. package/LICENSE +661 -203
  4. package/README.md +37 -35
  5. package/dist/client/client/api.d.ts +90 -0
  6. package/dist/client/client/assetUrl.d.ts +54 -0
  7. package/dist/client/client/config.d.ts +102 -0
  8. package/dist/client/client/events.d.ts +23 -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 +73 -0
  12. package/dist/client/client/grapesjs/PublicationUi.d.ts +59 -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/css-props.d.ts +6 -0
  16. package/dist/client/client/grapesjs/footer.d.ts +2 -0
  17. package/dist/client/client/grapesjs/img.d.ts +6 -0
  18. package/dist/client/client/grapesjs/index.d.ts +9 -0
  19. package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
  20. package/dist/client/client/grapesjs/keymaps.d.ts +123 -0
  21. package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
  22. package/dist/client/client/grapesjs/openImport.d.ts +9 -0
  23. package/dist/client/client/grapesjs/page-panel.d.ts +9 -0
  24. package/dist/client/client/grapesjs/project-bar.d.ts +21 -0
  25. package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
  26. package/dist/client/client/grapesjs/rich-text.d.ts +4 -0
  27. package/dist/client/client/grapesjs/semantic.d.ts +1 -0
  28. package/dist/client/client/grapesjs/settings-sections.d.ts +16 -0
  29. package/dist/client/client/grapesjs/settings.d.ts +4 -0
  30. package/dist/client/client/grapesjs/storage.d.ts +2 -0
  31. package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
  32. package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
  33. package/dist/client/client/index.d.ts +10 -0
  34. package/dist/client/client/publication-transformers.d.ts +42 -0
  35. package/dist/client/client/publish-custom-code-block.d.ts +4 -0
  36. package/dist/client/client/publish-fonts.d.ts +4 -0
  37. package/dist/client/client/utils.d.ts +22 -0
  38. package/dist/client/constants.d.ts +32 -0
  39. package/dist/client/css/admin.css +1114 -328
  40. package/dist/client/css/admin.css.map +1 -0
  41. package/dist/client/grapesjs-filter-styles/dist/index.d.ts +4 -0
  42. package/dist/client/grapesjs-fonts/dist/index.d.ts +4 -0
  43. package/dist/client/grapesjs-fonts/src/commands.d.ts +3 -0
  44. package/dist/client/grapesjs-fonts/src/fonts.d.ts +4 -0
  45. package/dist/client/grapesjs-storage-rate-limit/dist/index.d.ts +4 -0
  46. package/dist/client/grapesjs-ui-suggest-classes/dist/index.d.ts +4 -0
  47. package/dist/client/index.html +3 -2
  48. package/dist/client/js/main.js +356 -131
  49. package/dist/client/js/main.js.LICENSE.txt +15 -1
  50. package/dist/client/page.d.ts +2 -0
  51. package/dist/client/silex-lib/src/ts/client/api.d.ts +90 -0
  52. package/dist/client/silex-lib/src/ts/client/assetUrl.d.ts +54 -0
  53. package/dist/client/silex-lib/src/ts/client/config.d.ts +102 -0
  54. package/dist/client/silex-lib/src/ts/client/events.d.ts +23 -0
  55. package/dist/client/silex-lib/src/ts/client/expose.d.ts +8 -0
  56. package/dist/client/silex-lib/src/ts/client/grapesjs/LoginDialog.d.ts +15 -0
  57. package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationManager.d.ts +73 -0
  58. package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationUi.d.ts +59 -0
  59. package/dist/client/silex-lib/src/ts/client/grapesjs/blocks.d.ts +1 -0
  60. package/dist/client/silex-lib/src/ts/client/grapesjs/breadcrumbs.d.ts +1 -0
  61. package/dist/client/silex-lib/src/ts/client/grapesjs/css-props.d.ts +6 -0
  62. package/dist/client/silex-lib/src/ts/client/grapesjs/footer.d.ts +2 -0
  63. package/dist/client/silex-lib/src/ts/client/grapesjs/img.d.ts +6 -0
  64. package/dist/client/silex-lib/src/ts/client/grapesjs/index.d.ts +9 -0
  65. package/dist/client/silex-lib/src/ts/client/grapesjs/internal-links.d.ts +1 -0
  66. package/dist/client/silex-lib/src/ts/client/grapesjs/keymaps.d.ts +123 -0
  67. package/dist/client/silex-lib/src/ts/client/grapesjs/new-page-dialog.d.ts +2 -0
  68. package/dist/client/silex-lib/src/ts/client/grapesjs/openImport.d.ts +9 -0
  69. package/dist/client/silex-lib/src/ts/client/grapesjs/page-panel.d.ts +9 -0
  70. package/dist/client/silex-lib/src/ts/client/grapesjs/project-bar.d.ts +21 -0
  71. package/dist/client/silex-lib/src/ts/client/grapesjs/resize-panel.d.ts +1 -0
  72. package/dist/client/silex-lib/src/ts/client/grapesjs/rich-text.d.ts +4 -0
  73. package/dist/client/silex-lib/src/ts/client/grapesjs/semantic.d.ts +1 -0
  74. package/dist/client/silex-lib/src/ts/client/grapesjs/settings-sections.d.ts +16 -0
  75. package/dist/client/silex-lib/src/ts/client/grapesjs/settings.d.ts +4 -0
  76. package/dist/client/silex-lib/src/ts/client/grapesjs/storage.d.ts +2 -0
  77. package/dist/client/silex-lib/src/ts/client/grapesjs/symbolDialogs.d.ts +3 -0
  78. package/dist/client/silex-lib/src/ts/client/grapesjs/view-buttons.d.ts +1 -0
  79. package/dist/client/silex-lib/src/ts/client/index.d.ts +10 -0
  80. package/dist/client/silex-lib/src/ts/client/publication-transformers.d.ts +42 -0
  81. package/dist/client/silex-lib/src/ts/client/publish-custom-code-block.d.ts +4 -0
  82. package/dist/client/silex-lib/src/ts/client/publish-fonts.d.ts +4 -0
  83. package/dist/client/silex-lib/src/ts/client/utils.d.ts +22 -0
  84. package/dist/client/silex-lib/src/ts/constants.d.ts +32 -0
  85. package/dist/client/silex-lib/src/ts/page.d.ts +2 -0
  86. package/dist/client/silex-lib/src/ts/types.d.ts +339 -0
  87. package/dist/client/types.d.ts +339 -0
  88. package/dist/plugins/client/client/events.d.ts +23 -0
  89. package/dist/plugins/client/client/events.js +43 -0
  90. package/dist/plugins/client/client/events.js.map +1 -0
  91. package/dist/plugins/client/plugins/client/template.d.ts +2 -0
  92. package/dist/plugins/client/plugins/client/template.js +234 -0
  93. package/dist/plugins/client/plugins/client/template.js.map +1 -0
  94. package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
  95. package/dist/plugins/client/plugins/client/website-info.js +72 -0
  96. package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
  97. package/dist/plugins/client/types.d.ts +339 -0
  98. package/dist/plugins/client/types.js +80 -0
  99. package/dist/plugins/client/types.js.map +1 -0
  100. package/dist/plugins/server/constants.d.ts +32 -0
  101. package/dist/plugins/server/constants.js +76 -0
  102. package/dist/plugins/server/constants.js.map +1 -0
  103. package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
  104. package/dist/plugins/server/plugins/server/Cache.js +36 -0
  105. package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
  106. package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
  107. package/dist/plugins/server/plugins/server/DownloadConnector.js +127 -0
  108. package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
  109. package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
  110. package/dist/plugins/server/plugins/server/FtpConnector.js +536 -0
  111. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
  112. package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +135 -0
  113. package/dist/plugins/server/plugins/server/GitlabConnector.js +649 -0
  114. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
  115. package/dist/plugins/server/plugins/server/GitlabHostingConnector.d.ts +16 -0
  116. package/dist/plugins/server/plugins/server/GitlabHostingConnector.js +209 -0
  117. package/dist/plugins/server/plugins/server/GitlabHostingConnector.js.map +1 -0
  118. package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
  119. package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
  120. package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
  121. package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
  122. package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
  123. package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
  124. package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +8 -0
  125. package/dist/plugins/server/plugins/server/StaticPlugin.js +45 -0
  126. package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
  127. package/dist/plugins/server/server/config.d.ts +59 -0
  128. package/dist/plugins/server/server/config.js +181 -0
  129. package/dist/plugins/server/server/config.js.map +1 -0
  130. package/dist/plugins/server/server/connectors/FsHosting.d.ts +14 -0
  131. package/dist/plugins/server/server/connectors/FsHosting.js +66 -0
  132. package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
  133. package/dist/plugins/server/server/connectors/FsStorage.d.ts +44 -0
  134. package/dist/plugins/server/server/connectors/FsStorage.js +261 -0
  135. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
  136. package/dist/plugins/server/server/connectors/connectors.d.ts +86 -0
  137. package/dist/plugins/server/server/connectors/connectors.js +126 -0
  138. package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
  139. package/dist/plugins/server/server/events.d.ts +26 -0
  140. package/dist/plugins/server/server/events.js +31 -0
  141. package/dist/plugins/server/server/events.js.map +1 -0
  142. package/dist/plugins/server/server/jobs.d.ts +12 -0
  143. package/dist/plugins/server/server/jobs.js +79 -0
  144. package/dist/plugins/server/server/jobs.js.map +1 -0
  145. package/dist/plugins/server/server/utils/validation.d.ts +7 -0
  146. package/dist/plugins/server/server/utils/validation.js +37 -0
  147. package/dist/plugins/server/server/utils/validation.js.map +1 -0
  148. package/dist/plugins/server/types.d.ts +339 -0
  149. package/dist/plugins/server/types.js +84 -0
  150. package/dist/plugins/server/types.js.map +1 -0
  151. package/dist/server/constants.js +55 -0
  152. package/dist/server/plugins/server/Cache.js +19 -0
  153. package/dist/server/server/api/api.js +20 -0
  154. package/dist/server/server/api/connectorApi.js +334 -0
  155. package/dist/server/server/api/publicationApi.js +106 -0
  156. package/dist/server/server/api/websiteApi.js +315 -0
  157. package/dist/server/server/cli.js +71 -0
  158. package/dist/server/server/config.js +120 -0
  159. package/dist/server/server/connectors/FsHosting.js +47 -0
  160. package/dist/server/server/connectors/FsStorage.js +228 -0
  161. package/dist/server/server/connectors/connectors.js +88 -0
  162. package/dist/server/server/events.js +14 -0
  163. package/dist/server/server/expose.js +27 -0
  164. package/dist/server/server/express.js +46 -0
  165. package/dist/server/server/index.js +92 -0
  166. package/dist/server/server/jobs.js +50 -0
  167. package/dist/server/server/utils/validation.js +14 -0
  168. package/dist/server/types.js +40 -0
  169. package/package.json +99 -49
  170. package/public/assets/download.png +0 -0
  171. package/public/assets/favicon.ico +0 -0
  172. package/public/assets/favicon.png +0 -0
  173. package/public/assets/ftp.png +0 -0
  174. package/public/assets/gitlab.png +0 -0
  175. package/public/assets/gitlab2.png +0 -0
  176. package/public/assets/laptop.png +0 -0
  177. package/public/assets/logo-silex-small.png +0 -0
  178. package/public/silex.js +22 -23
  179. package/src/css/_variables.scss +24 -20
  180. package/src/css/dialog.scss +35 -2
  181. package/src/css/fonts.scss +31 -0
  182. package/src/css/footer.scss +12 -0
  183. package/src/css/grapesjs-light.scss +180 -0
  184. package/src/css/grapesjs-plugins.scss +227 -0
  185. package/src/css/grapesjs.scss +159 -1
  186. package/src/css/index.scss +12 -1
  187. package/src/css/light.scss +7 -0
  188. package/src/css/loader.scss +2 -0
  189. package/src/css/project-bar.scss +32 -16
  190. package/src/css/silex.scss +79 -5
  191. package/src/css/website-info.scss +14 -0
  192. package/src/html/index.pug +3 -3
  193. package/src/html/templates/includes.pug +0 -1
  194. package/src/ts/client/api.ts +156 -0
  195. package/src/ts/client/assetUrl.test.ts +164 -0
  196. package/src/ts/client/assetUrl.ts +254 -0
  197. package/src/ts/client/config.ts +175 -13
  198. package/src/ts/client/events.ts +43 -0
  199. package/src/ts/client/expose.ts +27 -1
  200. package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
  201. package/src/ts/client/grapesjs/PublicationManager.ts +433 -0
  202. package/src/ts/client/grapesjs/PublicationUi.ts +366 -0
  203. package/src/ts/client/grapesjs/blocks.ts +17 -0
  204. package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
  205. package/src/ts/client/grapesjs/css-props.ts +910 -0
  206. package/src/ts/client/grapesjs/eleventy.ts +30 -7
  207. package/src/ts/client/grapesjs/footer.ts +42 -0
  208. package/src/ts/client/grapesjs/img.ts +147 -0
  209. package/src/ts/client/grapesjs/index.ts +311 -122
  210. package/src/ts/client/grapesjs/internal-links.test.ts +19 -1
  211. package/src/ts/client/grapesjs/internal-links.ts +31 -7
  212. package/src/ts/client/grapesjs/keymaps.ts +207 -0
  213. package/src/ts/client/grapesjs/new-page-dialog.ts +19 -3
  214. package/src/ts/client/grapesjs/openImport.ts +22 -0
  215. package/src/ts/client/grapesjs/page-panel.ts +109 -7
  216. package/src/ts/client/grapesjs/project-bar.ts +133 -72
  217. package/src/ts/client/grapesjs/resize-panel.ts +20 -0
  218. package/src/ts/client/grapesjs/rich-text.ts +38 -13
  219. package/src/ts/client/grapesjs/semantic.ts +20 -3
  220. package/src/ts/client/grapesjs/settings-sections.ts +117 -0
  221. package/src/ts/client/grapesjs/settings.ts +191 -96
  222. package/src/ts/client/grapesjs/storage.ts +187 -0
  223. package/src/ts/client/grapesjs/symbolDialogs.ts +21 -5
  224. package/src/ts/client/grapesjs/view-buttons.ts +42 -0
  225. package/src/ts/client/index.ts +80 -21
  226. package/src/ts/client/publication-transformers.test.ts +207 -0
  227. package/src/ts/client/publication-transformers.ts +280 -0
  228. package/src/ts/client/publish-custom-code-block.ts +31 -0
  229. package/src/ts/client/publish-fonts.ts +36 -0
  230. package/src/ts/client/utils.ts +70 -1
  231. package/src/ts/constants.ts +78 -0
  232. package/src/ts/externs.ts +17 -0
  233. package/src/ts/page.ts +20 -3
  234. package/src/ts/plugins/client/template.ts +246 -0
  235. package/src/ts/plugins/client/website-info.ts +84 -0
  236. package/src/ts/plugins/server/Cache.ts +32 -0
  237. package/src/ts/plugins/server/DownloadConnector.ts +146 -0
  238. package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
  239. package/src/ts/plugins/server/FtpConnector.ts +621 -0
  240. package/src/ts/plugins/server/GitlabConnector.ts +749 -0
  241. package/src/ts/plugins/server/GitlabHostingConnector.ts +215 -0
  242. package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
  243. package/src/ts/plugins/server/SslPlugin.ts +84 -0
  244. package/src/ts/plugins/server/StaticPlugin.ts +45 -0
  245. package/src/ts/server/api/api.ts +19 -0
  246. package/src/ts/server/api/connectorApi.ts +464 -0
  247. package/src/ts/server/api/publicationApi.ts +159 -0
  248. package/src/ts/server/api/websiteApi.ts +462 -0
  249. package/src/ts/server/cli.ts +48 -14
  250. package/src/ts/server/config.ts +158 -60
  251. package/src/ts/server/connectors/FsHosting.ts +66 -0
  252. package/src/ts/server/connectors/FsStorage.test.ts +51 -0
  253. package/src/ts/server/connectors/FsStorage.ts +290 -0
  254. package/src/ts/server/connectors/connectors.ts +203 -0
  255. package/src/ts/server/events.ts +37 -0
  256. package/src/ts/server/expose.ts +19 -0
  257. package/src/ts/server/express.ts +57 -5
  258. package/src/ts/server/index.ts +80 -19
  259. package/src/ts/server/jobs.test.ts +75 -0
  260. package/src/ts/server/jobs.ts +89 -0
  261. package/src/ts/server/utils/BackwardCompat.ts +546 -528
  262. package/src/ts/server/utils/validation.ts +34 -0
  263. package/src/ts/types.ts +295 -85
  264. package/.dockerignore +0 -5
  265. package/.editorconfig +0 -14
  266. package/.eslintrc.json +0 -43
  267. package/.github/FUNDING.yml +0 -13
  268. package/.github/workflows/docker-hub-publish.yml +0 -36
  269. package/.github/workflows/npm-publish.yml +0 -19
  270. package/.github/workflows/test.yml +0 -26
  271. package/.nvmrc +0 -1
  272. package/.silex/default/.silex.data.json +0 -1
  273. package/CODE_OF_CONDUCT.md +0 -128
  274. package/CONTRIBUTING.md +0 -131
  275. package/Dockerfile +0 -15
  276. package/directus.silex.js +0 -7
  277. package/dist/constants.js +0 -4
  278. package/dist/events.js +0 -5
  279. package/dist/page.js +0 -15
  280. package/dist/server/cli.js +0 -43
  281. package/dist/server/config.js +0 -70
  282. package/dist/server/express.js +0 -18
  283. package/dist/server/index.js +0 -58
  284. package/dist/types.js +0 -34
  285. package/jest.config.js +0 -10
  286. package/logos/logo_by_ceubri/silex-icon-2018@200px.png +0 -0
  287. package/logos/logo_by_ceubri/silex-icon-2018@4x.png +0 -0
  288. package/logos/logo_by_ceubri/silex-logo-2018-white-transp.pdf +0 -0
  289. package/logos/logo_by_ceubri/silex-logo-2018-white.jpg +0 -0
  290. package/logos/logo_by_ceubri/silex-logo-2018-white.pdf +0 -0
  291. package/logos/logo_by_ceubri/silex-logo-2018-white.png +0 -0
  292. package/logos/logo_by_ceubri/silex-logo-2018-white@0.5x.png +0 -0
  293. package/logos/logo_by_ceubri/silex-logo-2018-white@0.75x.png +0 -0
  294. package/logos/logo_by_ceubri/silex-logo-2018-white@4x.jpg +0 -0
  295. package/logos/logo_by_ceubri/silex-logo-2018-white@4x.png +0 -0
  296. package/logos/logo_by_ceubri/silex-logo-2018.ai +5 -2521
  297. package/logos/logo_by_ceubri/silex-logo-2018.jpg +0 -0
  298. package/logos/logo_by_ceubri/silex-logo-2018.pdf +0 -0
  299. package/logos/logo_by_ceubri/silex-logo-2018.png +0 -0
  300. package/logos/logo_by_ceubri/silex-logo-2018@0.5x.png +0 -0
  301. package/logos/logo_by_ceubri/silex-logo-2018@0.75x.png +0 -0
  302. package/logos/logo_by_ceubri/silex-logo-2018@4x.jpg +0 -0
  303. package/logos/logo_by_ceubri/silex-logo-2018@4x.png +0 -0
  304. package/logos/silexlabs.png +0 -0
  305. package/src/example-client-config.js +0 -47
  306. package/src/plugins/AuthPlugin.js +0 -21
  307. package/src/plugins/Cache.js +0 -11
  308. package/src/plugins/DefaultBackend.js +0 -149
  309. package/src/plugins/ExpressPlugin.js +0 -39
  310. package/src/plugins/HooksPlugin.js +0 -58
  311. package/src/plugins/PublishPlugin.js +0 -69
  312. package/src/plugins/SslPlugin.js +0 -66
  313. package/src/plugins/StaticPlugin.js +0 -48
  314. package/src/plugins/WebsitePlugin.js +0 -207
  315. package/src/ts/client/grapesjs/publish.ts +0 -386
  316. package/src/ts/client/grapesjs/template.ts +0 -166
  317. package/src/ts/events.ts +0 -2
  318. package/tsconfig-server-debug.json +0 -19
  319. package/tsconfig-server-release.json +0 -19
  320. package/tsconfig.jest.json +0 -9
  321. package/tsconfig.json +0 -26
  322. package/webpack.config.js +0 -28
  323. package/webpack.debug.config.js +0 -8
@@ -12,7 +12,7 @@ html(lang="en", translate="no")
12
12
  style.
13
13
  body {
14
14
  background-color: #444444;
15
- font-family: Helvetica,sans-serif;
15
+ font-family: "Ubuntu", "Helvetica Neue", Helvetica, Arial, sans-serif;
16
16
  }
17
17
  .silex-loader {
18
18
  display: none;
@@ -34,6 +34,6 @@ html(lang="en", translate="no")
34
34
  script(src='js/main.js')
35
35
 
36
36
  block silex-start
37
- // Here you can use silex.config to hook into silex options before silex starts
38
37
  script.
39
- window.silex.start()
38
+ silex.start()
39
+ // From here silex.config is available and Silex is getting started
@@ -1,2 +1 @@
1
1
  link(rel='stylesheet', type='text/css', href='css/admin.css')
2
-
@@ -0,0 +1,156 @@
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 { API_CONNECTOR_LIST, API_CONNECTOR_USER, API_CONNECTOR_LOGOUT, API_CONNECTOR_PATH, API_PATH, API_PUBLICATION_PATH, API_PUBLICATION_PUBLISH, API_PUBLICATION_STATUS, API_WEBSITE_ASSET_READ, API_WEBSITE_ASSETS_WRITE, API_WEBSITE_DELETE, API_WEBSITE_LIST, API_WEBSITE_PATH, API_WEBSITE_READ, API_WEBSITE_WRITE, API_WEBSITE_META_READ, API_WEBSITE_META_WRITE, API_WEBSITE_CREATE, API_WEBSITE_DUPLICATE } from '../constants'
19
+ import { ApiPublicationPublishBody, ApiPublicationPublishQuery, ApiPublicationPublishResponse, ApiPublicationStatusQuery, ApiPublicationStatusResponse, ConnectorId, JobData, JobId, PublicationJobData, WebsiteId, ApiConnectorListResponse, ApiConnectorListQuery, ConnectorData, ConnectorType, ApiWebsiteReadQuery, ApiWebsiteReadResponse, WebsiteData, ApiWebsiteWriteQuery, ApiWebsiteWriteBody, ApiWebsiteWriteResponse, ApiWebsiteDeleteQuery, ApiWebsiteAssetsReadQuery, ApiWebsiteAssetsReadResponse, ApiWebsiteAssetsWriteQuery, ApiWebsiteAssetsWriteBody, ApiWebsiteAssetsWriteResponse, ClientSideFile, PublicationData, ApiConnectorUserResponse, ConnectorUser, WebsiteMeta, ApiConnectorLogoutQuery, ApiConnectorUserQuery, ApiWebsiteListResponse, ApiWebsiteListQuery, WebsiteMetaFileContent, ApiWebsiteCreateQuery, ApiWebsiteCreateBody, ApiWebsiteCreateResponse, ApiWebsiteMetaWriteQuery, ApiWebsiteMetaWriteBody, ApiWebsiteMetaWriteResponse, ApiWebsiteMetaReadQuery, ApiWebsiteMetaReadResponse, ConnectorOptions, ApiError, ApiWebsiteDuplicateQuery } from '../types'
20
+
21
+ export enum ApiRoute {
22
+ PUBLICATION_PUBLISH = API_PATH + API_PUBLICATION_PATH + API_PUBLICATION_PUBLISH,
23
+ PUBLICATION_STATUS = API_PATH + API_PUBLICATION_PATH + API_PUBLICATION_STATUS,
24
+ CONNECTOR_USER = API_PATH + API_CONNECTOR_PATH + API_CONNECTOR_USER,
25
+ CONNECTOR_LOGOUT = API_PATH + API_CONNECTOR_PATH + API_CONNECTOR_LOGOUT,
26
+ CONNECTOR_LIST = API_PATH + API_CONNECTOR_PATH + API_CONNECTOR_LIST,
27
+ WEBSITE_READ = API_PATH + API_WEBSITE_PATH + API_WEBSITE_READ,
28
+ WEBSITE_WRITE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_WRITE,
29
+ WEBSITE_DELETE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_DELETE,
30
+ WEBSITE_DUPLICATE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_DUPLICATE,
31
+ WEBSITE_CREATE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_CREATE,
32
+ WEBSITE_LIST = API_PATH + API_WEBSITE_PATH + API_WEBSITE_LIST,
33
+ WEBSITE_ASSETS_READ = API_PATH + API_WEBSITE_PATH + API_WEBSITE_ASSET_READ,
34
+ WEBSITE_ASSETS_WRITE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_ASSETS_WRITE,
35
+ WEBSITE_META_READ = API_PATH + API_WEBSITE_PATH + API_WEBSITE_META_READ,
36
+ WEBSITE_META_WRITE = API_PATH + API_WEBSITE_PATH + API_WEBSITE_META_WRITE,
37
+ }
38
+
39
+ // Root URL of Silex server, should we use config.rootUrl ?
40
+ let serverUrl = window.location.origin + window.location.pathname.replace(/\/$/, '')
41
+ export function setServerUrl(url: string): void {
42
+ serverUrl = url
43
+ }
44
+ export function getServerUrl(): string {
45
+ return serverUrl
46
+ }
47
+
48
+ export async function getUser({type, connectorId}: {type: ConnectorType, connectorId?: ConnectorId}): Promise<ConnectorUser> {
49
+ return api<ApiConnectorUserQuery, null, ApiConnectorUserResponse>(ApiRoute.CONNECTOR_USER, 'GET', {
50
+ type,
51
+ connectorId,
52
+ }) as Promise<ConnectorUser>
53
+ }
54
+
55
+ export async function logout({type, connectorId}: {type: ConnectorType, connectorId?: ConnectorId}): Promise<void> {
56
+ return api<ApiConnectorLogoutQuery, null, null>(ApiRoute.CONNECTOR_LOGOUT, 'POST', { connectorId, type })
57
+ }
58
+
59
+ export async function publish({websiteId, hostingId, storageId, data, options}: {websiteId: WebsiteId, hostingId: ConnectorId, storageId: ConnectorId, data: PublicationData, options: ConnectorOptions}): Promise<[url: string, job: PublicationJobData]> {
60
+ const { url, job } = await api<ApiPublicationPublishQuery, ApiPublicationPublishBody, ApiPublicationPublishResponse>(
61
+ ApiRoute.PUBLICATION_PUBLISH,
62
+ 'POST',
63
+ { websiteId, hostingId, storageId, options },
64
+ data
65
+ ) as ApiPublicationPublishResponse
66
+ return [url, job]
67
+ }
68
+
69
+ export async function publicationStatus({jobId}: {jobId: JobId}): Promise<PublicationJobData> {
70
+ return api<ApiPublicationStatusQuery, null, ApiPublicationStatusResponse>(
71
+ ApiRoute.PUBLICATION_STATUS,
72
+ 'GET',
73
+ { jobId },
74
+ ) as Promise<PublicationJobData>
75
+ }
76
+
77
+ export async function connectorList({type}: {type: ConnectorType}): Promise<ConnectorData[]> {
78
+ const list = await api<ApiConnectorListQuery, null, ApiConnectorListResponse>(ApiRoute.CONNECTOR_LIST, 'GET', { type })
79
+ return list as ConnectorData[]
80
+ }
81
+
82
+ export async function websiteList({connectorId}: {connectorId?: ConnectorId}): Promise<WebsiteMeta[]> {
83
+ return api<ApiWebsiteListQuery, null, ApiWebsiteListResponse>(ApiRoute.WEBSITE_LIST, 'GET', { connectorId }) as Promise<WebsiteMeta[]>
84
+ }
85
+
86
+ export async function websiteLoad({websiteId, connectorId}: {websiteId: WebsiteId, connectorId?: ConnectorId}): Promise<WebsiteData> {
87
+ return api<ApiWebsiteReadQuery, null, ApiWebsiteReadResponse>(ApiRoute.WEBSITE_READ, 'GET', { websiteId, connectorId }) as Promise<WebsiteData>
88
+ }
89
+
90
+ export async function websiteSave({websiteId, data, connectorId}: {websiteId: WebsiteId, data: WebsiteData, connectorId?: ConnectorId}): Promise<void> {
91
+ const { message } = await api<ApiWebsiteWriteQuery, ApiWebsiteWriteBody, ApiWebsiteWriteResponse>(ApiRoute.WEBSITE_WRITE, 'POST', { websiteId, connectorId }, data)
92
+ }
93
+
94
+ export async function websiteDelete({websiteId, connectorId}: {websiteId: WebsiteId, connectorId?: ConnectorId}): Promise<void> {
95
+ await api<ApiWebsiteDeleteQuery, null, null>(ApiRoute.WEBSITE_DELETE, 'DELETE', { websiteId, connectorId })
96
+ }
97
+
98
+ export async function websiteDuplicate({websiteId, connectorId}: {websiteId: WebsiteId, connectorId?: ConnectorId}): Promise<void> {
99
+ await api<ApiWebsiteDuplicateQuery, null, null>(ApiRoute.WEBSITE_DUPLICATE, 'POST', { websiteId, connectorId })
100
+ }
101
+
102
+ export async function websiteCreate({websiteId, data, connectorId}: {websiteId: WebsiteId, data: WebsiteMetaFileContent, connectorId?: ConnectorId}): Promise<void> {
103
+ await api<ApiWebsiteCreateQuery, ApiWebsiteCreateBody, ApiWebsiteCreateResponse>(ApiRoute.WEBSITE_CREATE, 'PUT', { connectorId }, data)
104
+ }
105
+
106
+ export async function websiteMetaWrite({websiteId, data, connectorId}: {websiteId: WebsiteId, data: WebsiteMetaFileContent, connectorId?: ConnectorId}): Promise<void> {
107
+ await api<ApiWebsiteMetaWriteQuery, ApiWebsiteMetaWriteBody, ApiWebsiteMetaWriteResponse>(ApiRoute.WEBSITE_META_WRITE, 'POST', { websiteId, connectorId }, data)
108
+ }
109
+
110
+ export async function websiteMetaRead({websiteId, connectorId}: {websiteId: WebsiteId, connectorId?: ConnectorId}): Promise<WebsiteMeta> {
111
+ return api<ApiWebsiteMetaReadQuery, null, ApiWebsiteMetaReadResponse>(ApiRoute.WEBSITE_META_WRITE, 'GET', { websiteId, connectorId })
112
+ }
113
+
114
+ export async function websiteAssetsLoad({path, websiteId, connectorId}: {path: string, websiteId: WebsiteId, connectorId: ConnectorId}): Promise<string> {
115
+ return api<ApiWebsiteAssetsReadQuery, null, ApiWebsiteAssetsReadResponse>(`${ApiRoute.WEBSITE_ASSETS_READ}/${path}`, 'GET', { websiteId, connectorId })
116
+ }
117
+
118
+ /**
119
+ * Not used directly, grapesjs handles the upload
120
+ * @see assetManager in src/ts/client/grapesjs/index.ts
121
+ */
122
+ export async function websiteAssetsSave({websiteId, connectorId, files}: {websiteId: WebsiteId, connectorId: ConnectorId, files: ClientSideFile[]}): Promise<string[]> {
123
+ const { data } = await api<ApiWebsiteAssetsWriteQuery, ApiWebsiteAssetsWriteBody, ApiWebsiteAssetsWriteResponse>(ApiRoute.WEBSITE_ASSETS_WRITE, 'POST', { websiteId, connectorId }, files)
124
+ return data
125
+ }
126
+
127
+ export async function api<ReqQuery, ReqBody, ResBody>(route: ApiRoute | string, method: string, query?: ReqQuery, payload?: ReqBody): Promise<ResBody> {
128
+ const url = `${serverUrl}${route.toString()}?${
129
+ new URLSearchParams(
130
+ Object.entries(query)
131
+ .filter(([key, value]) => !!value)
132
+ .map(([key, value]) => [key, typeof value === 'string' ? value : JSON.stringify(value)])
133
+ ).toString()}`
134
+ const response = await fetch(url, {
135
+ method,
136
+ headers: {
137
+ 'Content-Type': 'application/json',
138
+ },
139
+ body: payload && JSON.stringify(payload), // assuming that the payload needs to be stringified
140
+ credentials: 'include', // sends the cookies with the request
141
+ })
142
+
143
+ if (!response.ok) {
144
+ let json
145
+ try {
146
+ json = await response.json()
147
+ } catch (err) {
148
+ // If the response is not JSON, throw a generic error
149
+ // This is the case when Silex backend has an uncatched error, e.g. expressjs 413 PayloadTooLargeError: request entity too large
150
+ throw new ApiError(response.statusText, response.status)
151
+ }
152
+ throw new ApiError(json.message, response.status)
153
+ }
154
+
155
+ return response.json()
156
+ }
@@ -0,0 +1,164 @@
1
+ import { jest, expect, describe, it, beforeEach } from '@jest/globals'
2
+ import { removeTempDataFromStyles } from './assetUrl'
3
+
4
+ describe('assetUrl', () => {
5
+ beforeEach(() => {
6
+ jest.resetModules()
7
+ Object.defineProperty(window, 'location', {
8
+ value: {
9
+ href: 'http://localhost:6800/',
10
+ pathname: '',
11
+ origin: 'http://localhost:6800',
12
+ },
13
+ })
14
+ Object.assign(window.location, {
15
+ href: 'http://localhost:6800/',
16
+ pathname: '',
17
+ origin: 'http://localhost:6800',
18
+ })
19
+ })
20
+
21
+ it('store url to display url', async () => {
22
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
23
+ // Convert a valid URL as stored
24
+ expect(storedToDisplayed('/assets/test.webp', 'test-id', 'test-connector'))
25
+ .toBe('/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
26
+ // Convert a URL which is already as displayed
27
+ expect(storedToDisplayed('/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector', 'test-id', 'test-connector'))
28
+ .toBe('/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
29
+ })
30
+
31
+ it('display url to store url', async () => {
32
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
33
+ // Convert a valid URL as displayed
34
+ expect(displayedToStored('/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector'))
35
+ .toBe('/assets/test.webp')
36
+ // Convert a URL which is already as stored
37
+ expect(displayedToStored('/assets/test.webp'))
38
+ .toBe('/assets/test.webp')
39
+ })
40
+
41
+ it('store url to display url with a root path', async () => {
42
+ Object.assign(window.location, {
43
+ href: 'http://localhost:6800/silex',
44
+ pathname: '/silex',
45
+ origin: 'http://localhost:6800',
46
+ })
47
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
48
+ // Convert a valid URL as stored
49
+ expect(storedToDisplayed('/assets/test.webp', 'test-id', 'test-connector'))
50
+ .toBe('/silex/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
51
+ // Convert a URL which is already as displayed
52
+ expect(storedToDisplayed('/silex/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector', 'test-id', 'test-connector'))
53
+ .toBe('/silex/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
54
+ })
55
+
56
+ it('display url to store url with a root path', async () => {
57
+ Object.assign(window.location, {
58
+ href: 'http://localhost:6800/silex',
59
+ pathname: '/silex',
60
+ origin: 'http://localhost:6800',
61
+ })
62
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
63
+ // Convert a valid URL as displayed
64
+ expect(displayedToStored('/silex/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector'))
65
+ .toBe('/assets/test.webp')
66
+ // Convert a URL which is already as stored
67
+ expect(displayedToStored('/assets/test.webp'))
68
+ .toBe('/assets/test.webp')
69
+ })
70
+
71
+ it('store url to display url with escapable chars', async () => {
72
+ Object.assign(window.location, {
73
+ href: 'http://localhost:6800/silex%20with%20spaces',
74
+ pathname: '/silex%20with%20spaces',
75
+ origin: 'http://localhost:6800',
76
+ })
77
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
78
+ // Convert a valid URL as displayed
79
+ expect(displayedToStored('/silex%20with%20spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector'))
80
+ .toBe('/assets/test.webp')
81
+ // Convert a URL which is already as stored
82
+ expect(displayedToStored('/assets/test.webp'))
83
+ .toBe('/assets/test.webp')
84
+ })
85
+
86
+ it('display url to store url with escapable chars', async () => {
87
+ Object.assign(window.location, {
88
+ href: 'http://localhost:6800/silex%20with%20spaces',
89
+ pathname: '/silex%20with%20spaces',
90
+ origin: 'http://localhost:6800',
91
+ })
92
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
93
+ // Convert a valid URL as stored
94
+ expect(storedToDisplayed('/assets/test.webp', 'test-id', 'test-connector'))
95
+ .toBe('/silex with spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
96
+ // Convert a URL which is already as displayed
97
+ expect(storedToDisplayed('/silex%20with%20spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector', 'test-id', 'test-connector'))
98
+ .toBe('/silex%20with%20spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
99
+ expect(storedToDisplayed('/silex with spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector', 'test-id', 'test-connector'))
100
+ .toBe('/silex with spaces/api/website/assets/test.webp?websiteId=test-id&connectorId=test-connector')
101
+ })
102
+
103
+ it('store url to display url with escapable website id and connector id', async () => {
104
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
105
+ // Convert a valid URL as displayed
106
+ expect(displayedToStored('/api/website/assets/test.webp?websiteId=test%20id&connectorId=test%20connector'))
107
+ .toBe('/assets/test.webp')
108
+ // Convert a URL which is already as stored
109
+ expect(displayedToStored('/assets/test.webp'))
110
+ .toBe('/assets/test.webp')
111
+ })
112
+
113
+ it('display url to store url with escapable website id and connector id', async () => {
114
+ const { displayedToStored, storedToDisplayed } = await import('./assetUrl')
115
+ const websiteId = 'test id'
116
+ const websiteIdEncoded = 'test+id'
117
+ const connectorId = 'test connector'
118
+ const connectorIdEncoded = 'test+connector'
119
+ // Convert a valid URL as stored
120
+ expect(storedToDisplayed('/assets/test.webp', websiteId, connectorId))
121
+ .toBe(`/api/website/assets/test.webp?websiteId=${websiteIdEncoded}&connectorId=${connectorIdEncoded}`)
122
+ // Convert a URL which is already as displayed
123
+ expect(storedToDisplayed(`/api/website/assets/test.webp?websiteId=${websiteIdEncoded}&connectorId=${connectorIdEncoded}`, websiteId, connectorId))
124
+ .toBe(`/api/website/assets/test.webp?websiteId=${websiteIdEncoded}&connectorId=${connectorIdEncoded}`)
125
+ })
126
+
127
+ it('multiple backgrounds', async () => {
128
+ // // FIXME: this should mock the functions but it doesnt
129
+ // const mocked = {
130
+ // displayedToStored: jest.fn((url: string) => url),
131
+ // storedToDisplayed: jest.fn((url: string) => url),
132
+ // }
133
+ // jest.mock('./assetUrl', () => (mocked))
134
+ //addTempDataToStyles([toStyle(bgImageDisplayed)], websiteId, connectorId)
135
+ //expect(mocked.displayedToStored).toBeCalledTimes(1)
136
+ const { addTempDataToStyles } = await import('./assetUrl')
137
+
138
+ const websiteId = 'test-id'
139
+ const connectorId = 'test-connector'
140
+ const bgImageDisplayed = `linear-gradient(to right, #1fb101 0%, #df1313 67%, rgba(234, 97, 97, 255) 78%, white 100%), url('/api/website/assets/qIg7JPRc.webp?websiteId=${websiteId}&connectorId=${connectorId}'), linear-gradient(#0ca311 0%, #0ca311 100%)`
141
+ const bgImageStored = 'linear-gradient(to right, #1fb101 0%, #df1313 67%, rgba(234, 97, 97, 255) 78%, white 100%), url(\'/assets/qIg7JPRc.webp\'), linear-gradient(#0ca311 0%, #0ca311 100%)'
142
+ const selectors = ['body']
143
+ function toStyle(bgImage: string) {
144
+ return {
145
+ style: {
146
+ 'background-image': bgImage,
147
+ },
148
+ selectors,
149
+ }
150
+ }
151
+ // From stored to displayed
152
+ expect(addTempDataToStyles([toStyle(bgImageStored)], websiteId, connectorId))
153
+ .toEqual([toStyle(bgImageDisplayed)])
154
+ // From displayed to displayed (error case)
155
+ expect(addTempDataToStyles([toStyle(bgImageDisplayed)], websiteId, connectorId))
156
+ .toEqual([toStyle(bgImageDisplayed)])
157
+ // From displayed to stored
158
+ expect(removeTempDataFromStyles([toStyle(bgImageDisplayed)]))
159
+ .toEqual([toStyle(bgImageStored)])
160
+ //// From stored to stored (error case)
161
+ expect(removeTempDataFromStyles([toStyle(bgImageStored)]))
162
+ .toEqual([toStyle(bgImageStored)])
163
+ })
164
+ })
@@ -0,0 +1,254 @@
1
+ import { API_PATH, API_WEBSITE_ASSET_READ, API_WEBSITE_PATH } from '../constants'
2
+ import { Asset, ClientSideFileType, Component, ConnectorId, Page, Style, WebsiteId } from '../types'
3
+
4
+ /**
5
+ * @fileoverview Helpers to manage assets URL
6
+ * Assets URLs are stored on storage in their "stored version": `/assets/image.webp`
7
+ * But the client side uses the "display version": `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
8
+ * After loading the site data we convert all URLs to the client side version
9
+ * Before saving the site data we convert all URLs to the storage version
10
+ * During publicationn we convert all URLs to the storage version and back
11
+ */
12
+
13
+ // Get the base URL where Silex is served
14
+ const baseUrl = window.location.pathname.replace(/\/$/, '')
15
+
16
+ // Orging and path, should we use config.rootUrl?
17
+ const SERVER_URL = window.location.origin
18
+
19
+ /**
20
+ * Function to convert a path from it stored version to the displayed version
21
+ * Stored version is like `/assets/image.webp`
22
+ * Grapesjs version is like `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
23
+ * Exported for unit tests
24
+ */
25
+ export function storedToDisplayed(path: string, websiteId: WebsiteId, storageId: ConnectorId): string {
26
+ // Check the path is a stored path
27
+ if (path.startsWith('/assets')) {
28
+ // Make an absolute URL
29
+ const url = new URL(path, SERVER_URL)
30
+ // Remove the assets folder as it is part of the saved path
31
+ url.pathname = url.pathname.replace(/^\/assets/, '')
32
+ // Add the API path and the connectorId and websiteId
33
+ url.pathname = `${baseUrl}${API_PATH}${API_WEBSITE_PATH}${API_WEBSITE_ASSET_READ}${url.pathname}`
34
+ // Add the GET params
35
+ url.searchParams.set('websiteId', websiteId)
36
+ url.searchParams.set('connectorId', storageId)
37
+ // Back to a relative URL, keep the path but not the origin
38
+ return `${decodeURIComponent(url.pathname)}${url.search}`
39
+ //const encodedPath = '/' + url.toString() // add a leading slash
40
+ // .replace(new RegExp(`^${SERVER_URL}`), '')
41
+ // .replace(/^\//, '') // remove the first slash if it exists
42
+ //return decodeURIComponent(encodedPath)
43
+ } else {
44
+ if(path.startsWith('<svg') || path.startsWith('data:image')) {
45
+ // SVG or data URL
46
+ return path
47
+ }
48
+ // Not a stored path, is there a problem?
49
+ console.warn('storedToDisplayed: path is not a stored path', path)
50
+ return path
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Function to convert a path from the one we give to grapesjs to the stored version
56
+ * Grapesjs version is like `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
57
+ * Stored version is like `/assets/image.webp`
58
+ * @param path the path to convert
59
+ * @returns the converted path
60
+ * Exported for unit tests
61
+ */
62
+ export function displayedToStored(path: string): string {
63
+ // The path to the assets API
64
+ const apiPath = `${baseUrl}${API_PATH}${API_WEBSITE_PATH}${API_WEBSITE_ASSET_READ}`
65
+ // Check the path is a displayed path
66
+ if (path.startsWith(apiPath)) {
67
+ const url = new URL(path, SERVER_URL)
68
+ url.pathname = url.pathname.replace(new RegExp(`^${apiPath}`), '')
69
+ url.pathname = `${baseUrl}/assets${url.pathname}`
70
+ url.searchParams.delete('websiteId')
71
+ url.searchParams.delete('connectorId')
72
+ const encodedPath = '/' + url.toString() // add a leading slash
73
+ .replace(new RegExp(`^${SERVER_URL}${baseUrl}`), '')
74
+ .replace(/^\//, '') // remove the first slash if it exists
75
+ return decodeURIComponent(encodedPath)
76
+ } else {
77
+ if(path.startsWith('<svg') || path.startsWith('data:image')) {
78
+ // SVG or data URL
79
+ return path
80
+ }
81
+ console.warn('displayedToStored: path is not a displayed path', path)
82
+ return path
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Publication transformer to convert the asset URL during publication
88
+ */
89
+ export const assetsPublicationTransformer = {
90
+ transformPath(path: string, type: ClientSideFileType): string {
91
+ if(type === ClientSideFileType.ASSET) {
92
+ const result = displayedToStored(path)
93
+ return result
94
+ }
95
+ return undefined
96
+ },
97
+ transformPermalink(path: string, type: ClientSideFileType): string {
98
+ if(type === ClientSideFileType.ASSET) {
99
+ const result = displayedToStored(path)
100
+ return result
101
+ }
102
+ return undefined
103
+ },
104
+ }
105
+
106
+ /**
107
+ * Update asset URL to use the current storage connector and website ID
108
+ * Assets URLs are stored in the project data in the form `/assets/image.webp`
109
+ * This function adds the API path and the connectorId and websiteId like so: `/api/website/assets/image.webp?websiteId=47868975&connectorId=gitlab`
110
+ */
111
+ export function addTempDataToAssetUrl(assets: Asset[], websiteId: WebsiteId, storageId: ConnectorId): Asset[] {
112
+ return assets.map((asset: Asset) => {
113
+ return asset.src ? {
114
+ ...asset,
115
+ src: storedToDisplayed(asset.src, websiteId, storageId),
116
+ } : asset
117
+ })
118
+ }
119
+
120
+ /**
121
+ * Remove the temporary data from the asset URL
122
+ * Remove the API path and the connectorId and websiteId like so: `/assets/image.webp`
123
+ */
124
+ export function removeTempDataFromAssetUrl(assets: Asset[]): Asset[] {
125
+ return assets.map((asset: Asset) => {
126
+ // Return the asset with the new URL
127
+ return asset.src ? {
128
+ ...asset,
129
+ src: displayedToStored(asset.src),
130
+ } : asset
131
+ })
132
+ }
133
+
134
+ /**
135
+ * Reucrsive function to update the asset URL in the components
136
+ */
137
+ function addTempDataToComponents(component: Component, websiteId: WebsiteId, storageId: ConnectorId): Component {
138
+ // Update the asset URL in the component
139
+ const newComponent = component.attributes?.src ? {
140
+ ...component,
141
+ attributes: {
142
+ ...component.attributes,
143
+ src: storedToDisplayed(component.attributes.src, websiteId, storageId),
144
+ },
145
+ } : component
146
+ // Update the asset URL in the children
147
+ if (newComponent.components) {
148
+ newComponent.components = newComponent.components.map((childComponent: Component) => {
149
+ return addTempDataToComponents(childComponent, websiteId, storageId)
150
+ })
151
+ }
152
+ return newComponent
153
+ }
154
+
155
+ /**
156
+ * Reucrsive function to update the asset URL in the components
157
+ */
158
+ function removeTempDataFromComponents(component: Component): Component {
159
+ // Update the asset URL in the component
160
+ const newComponent = component.attributes?.src ? {
161
+ ...component,
162
+ attributes: {
163
+ ...component.attributes,
164
+ src: displayedToStored(component.attributes.src),
165
+ },
166
+ } : component
167
+ // Update the asset URL in the children
168
+ if (newComponent.components) {
169
+ newComponent.components = newComponent.components.map((childComponent: Component) => {
170
+ return removeTempDataFromComponents(childComponent)
171
+ })
172
+ }
173
+ return newComponent
174
+ }
175
+
176
+ /**
177
+ * Add temp data to pages
178
+ */
179
+ export function addTempDataToPages(pages: Page[], websiteId: WebsiteId, storageId: ConnectorId): Page[] {
180
+ return pages.map((page: Page) => {
181
+ return {
182
+ ...page,
183
+ frames: page.frames.map(frame => ({
184
+ ...frame,
185
+ component: addTempDataToComponents(frame.component, websiteId, storageId),
186
+ }))
187
+ }
188
+ })
189
+ }
190
+
191
+ /**
192
+ * Remove temp data from asset URL in the components
193
+ */
194
+ export function removeTempDataFromPages(pages: Page[]): Page[] {
195
+ return pages.map((page: Page) => {
196
+ return {
197
+ ...page,
198
+ frames: page.frames.map(frame => ({
199
+ ...frame,
200
+ component: removeTempDataFromComponents(frame.component),
201
+ }))
202
+ }
203
+ })
204
+ }
205
+
206
+ /**
207
+ * Add data to stylesheets
208
+ * e.g. linear-gradient(to right, #1fb101 0%, #df1313 67%, rgba(234, 97, 97, 255) 78%, white 100%), url('/assets/qIg7JPRc.webp'), linear-gradient(#0ca311 0%, #0ca311 100%)
209
+ */
210
+ export function addTempDataToStyles(styles: Style[], websiteId: WebsiteId, storageId: ConnectorId): Style[] {
211
+ const regex = new RegExp(/(.*)(url\((["']?)([^"']+?)\1\))*(.*)/, 'g')
212
+
213
+ return styles.map((style: Style) => {
214
+ if (style.style && style.style['background-image']) {
215
+ const bgImage = style.style['background-image']
216
+ .replace(/url\((['"]?)([^'"]+)\1\)/g, (match, quote, url) => {
217
+ return `url(${quote}${storedToDisplayed(url, websiteId, storageId)}${quote})`
218
+ })
219
+ return {
220
+ ...style,
221
+ style: {
222
+ ...style.style,
223
+ 'background-image': bgImage,
224
+ },
225
+ }
226
+ }
227
+ return style
228
+ })
229
+ }
230
+
231
+ /**
232
+ * Remove temp data from stylesheets
233
+ * The property `background-image` contains the URLs of the assets and other values,
234
+ * e.g. `linear-gradient(to right, #1fb101 0%, #df1313 67%, rgba(234, 97, 97, 255) 78%, white 100%), url('/api/website/assets/qIg7JPRc.webp?websiteId=default&connectorId=fs-storage'), linear-gradient(#0ca311 0%, #0ca311 100%)`
235
+ */
236
+ export function removeTempDataFromStyles(styles: Style[]): Style[] {
237
+ const pattern = /url\((["']?)([^"']+?)\1\)/g
238
+ return styles.map((style: Style) => {
239
+ if (style.style && style.style['background-image']) {
240
+ const bgImage = style.style['background-image']
241
+ .replace(/url\((['"]?)([^'"]+)\1\)/g, (match, quote, url) => {
242
+ return `url(${quote}${displayedToStored(url)}${quote})`
243
+ })
244
+ return {
245
+ ...style,
246
+ style: {
247
+ ...style.style,
248
+ 'background-image': bgImage,
249
+ },
250
+ }
251
+ }
252
+ return style
253
+ })
254
+ }