@silexlabs/silex 3.0.0-alpha.97 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/.env.default +2 -1
  2. package/README.md +31 -9
  3. package/dist/client/client/api.d.ts +5 -0
  4. package/dist/client/client/assetUrl.d.ts +3 -0
  5. package/dist/client/client/config.d.ts +31 -0
  6. package/dist/client/client/events.d.ts +7 -1
  7. package/dist/client/client/grapesjs/PublicationManager.d.ts +2 -1
  8. package/dist/client/client/grapesjs/css-props.d.ts +6 -0
  9. package/dist/client/client/grapesjs/img.d.ts +6 -0
  10. package/dist/client/client/grapesjs/index.d.ts +2 -2
  11. package/dist/client/client/grapesjs/new-page-dialog.d.ts +1 -1
  12. package/dist/client/client/grapesjs/page-panel.d.ts +1 -1
  13. package/dist/client/client/grapesjs/project-bar.d.ts +16 -0
  14. package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
  15. package/dist/client/client/grapesjs/rich-text.d.ts +4 -1
  16. package/dist/client/client/grapesjs/semantic.d.ts +1 -1
  17. package/dist/client/client/grapesjs/settings-sections.d.ts +15 -0
  18. package/dist/client/client/grapesjs/settings.d.ts +3 -1
  19. package/dist/client/client/grapesjs/symbolDialogs.d.ts +1 -1
  20. package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
  21. package/dist/client/client/index.d.ts +10 -0
  22. package/dist/client/client/publication-transformers.d.ts +4 -3
  23. package/dist/client/client/publish-custom-code-block.d.ts +4 -0
  24. package/dist/client/client/publish-fonts.d.ts +4 -0
  25. package/dist/client/client/utils.d.ts +4 -0
  26. package/dist/client/constants.d.ts +1 -0
  27. package/dist/client/css/admin.css +273 -32
  28. package/dist/client/index.html +2 -1
  29. package/dist/client/js/main.js +164 -123
  30. package/dist/client/js/main.js.LICENSE.txt +15 -1
  31. package/dist/client/types.d.ts +12 -7
  32. package/dist/plugins/client/client/events.d.ts +7 -1
  33. package/dist/plugins/client/client/events.js +7 -1
  34. package/dist/plugins/client/client/events.js.map +1 -1
  35. package/dist/plugins/client/plugins/client/template.js +108 -58
  36. package/dist/plugins/client/plugins/client/template.js.map +1 -1
  37. package/dist/plugins/client/types.d.ts +12 -7
  38. package/dist/plugins/client/types.js +6 -0
  39. package/dist/plugins/client/types.js.map +1 -1
  40. package/dist/plugins/server/constants.d.ts +1 -0
  41. package/dist/plugins/server/constants.js +2 -1
  42. package/dist/plugins/server/constants.js.map +1 -1
  43. package/dist/plugins/server/plugins/server/FtpConnector.d.ts +1 -0
  44. package/dist/plugins/server/plugins/server/FtpConnector.js +12 -1
  45. package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -1
  46. package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +3 -0
  47. package/dist/plugins/server/plugins/server/GitlabConnector.js +72 -35
  48. package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -1
  49. package/dist/plugins/server/server/config.js +3 -3
  50. package/dist/plugins/server/server/config.js.map +1 -1
  51. package/dist/plugins/server/server/connectors/FsHosting.d.ts +1 -0
  52. package/dist/plugins/server/server/connectors/FsHosting.js +13 -1
  53. package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -1
  54. package/dist/plugins/server/server/connectors/FsStorage.d.ts +2 -1
  55. package/dist/plugins/server/server/connectors/FsStorage.js +29 -25
  56. package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -1
  57. package/dist/plugins/server/server/connectors/connectors.d.ts +1 -0
  58. package/dist/plugins/server/server/jobs.js +4 -2
  59. package/dist/plugins/server/server/jobs.js.map +1 -1
  60. package/dist/plugins/server/types.d.ts +12 -7
  61. package/dist/plugins/server/types.js +7 -1
  62. package/dist/plugins/server/types.js.map +1 -1
  63. package/dist/server/constants.js +2 -1
  64. package/dist/server/server/api/publicationApi.js +3 -5
  65. package/dist/server/server/api/websiteApi.js +22 -3
  66. package/dist/server/server/cli.js +9 -6
  67. package/dist/server/server/config.js +3 -3
  68. package/dist/server/server/connectors/FsHosting.js +13 -1
  69. package/dist/server/server/connectors/FsStorage.js +28 -25
  70. package/dist/server/server/jobs.js +4 -2
  71. package/dist/server/types.js +7 -1
  72. package/package.json +34 -30
  73. package/public/assets/favicon.ico +0 -0
  74. package/public/assets/favicon.png +0 -0
  75. package/public/assets/logo-silex-small.png +0 -0
  76. package/src/css/_variables.scss +5 -3
  77. package/src/css/dialog.scss +22 -1
  78. package/src/css/fonts.scss +31 -0
  79. package/src/css/footer.scss +1 -1
  80. package/src/css/grapesjs-plugins.scss +34 -0
  81. package/src/css/grapesjs.scss +26 -11
  82. package/src/css/index.scss +1 -0
  83. package/src/css/project-bar.scss +11 -7
  84. package/src/css/silex.scss +58 -5
  85. package/src/html/index.pug +2 -2
  86. package/src/ts/client/api.ts +14 -9
  87. package/src/ts/client/assetUrl.test.ts +39 -0
  88. package/src/ts/client/assetUrl.ts +24 -5
  89. package/src/ts/client/config.ts +85 -4
  90. package/src/ts/client/events.ts +15 -9
  91. package/src/ts/client/grapesjs/PublicationManager.ts +71 -38
  92. package/src/ts/client/grapesjs/PublicationUi.ts +13 -11
  93. package/src/ts/client/grapesjs/css-props.ts +544 -0
  94. package/src/ts/client/grapesjs/eleventy.ts +2 -5
  95. package/src/ts/client/grapesjs/footer.ts +24 -9
  96. package/src/ts/client/grapesjs/img.ts +147 -0
  97. package/src/ts/client/grapesjs/index.ts +63 -25
  98. package/src/ts/client/grapesjs/internal-links.test.ts +2 -1
  99. package/src/ts/client/grapesjs/internal-links.ts +0 -1
  100. package/src/ts/client/grapesjs/new-page-dialog.ts +2 -3
  101. package/src/ts/client/grapesjs/page-panel.ts +28 -3
  102. package/src/ts/client/grapesjs/project-bar.ts +83 -64
  103. package/src/ts/client/grapesjs/resize-panel.ts +20 -0
  104. package/src/ts/client/grapesjs/rich-text.ts +21 -13
  105. package/src/ts/client/grapesjs/semantic.ts +3 -3
  106. package/src/ts/client/grapesjs/settings-sections.ts +117 -0
  107. package/src/ts/client/grapesjs/settings.ts +120 -77
  108. package/src/ts/client/grapesjs/symbolDialogs.ts +2 -3
  109. package/src/ts/client/grapesjs/view-buttons.ts +42 -0
  110. package/src/ts/client/index.ts +13 -6
  111. package/src/ts/client/publication-transformers.test.ts +13 -5
  112. package/src/ts/client/publication-transformers.ts +60 -47
  113. package/{dist/plugins/client/client/utils.js → src/ts/client/publish-custom-code-block.ts} +14 -8
  114. package/{dist/plugins/client/page.js → src/ts/client/publish-fonts.ts} +19 -14
  115. package/src/ts/client/utils.ts +18 -0
  116. package/src/ts/constants.ts +1 -0
  117. package/src/ts/plugins/client/template.ts +112 -60
  118. package/src/ts/plugins/server/FtpConnector.ts +14 -2
  119. package/src/ts/plugins/server/GitlabConnector.ts +71 -32
  120. package/src/ts/server/api/publicationApi.ts +5 -5
  121. package/src/ts/server/api/websiteApi.ts +39 -9
  122. package/src/ts/server/cli.ts +7 -5
  123. package/src/ts/server/config.ts +4 -4
  124. package/src/ts/server/connectors/FsHosting.ts +11 -5
  125. package/src/ts/server/connectors/FsStorage.ts +33 -4
  126. package/src/ts/server/connectors/connectors.ts +1 -1
  127. package/src/ts/server/jobs.ts +4 -2
  128. package/src/ts/types.ts +10 -7
  129. package/dist/plugins/client/client/api.d.ts +0 -85
  130. package/dist/plugins/client/client/api.js +0 -114
  131. package/dist/plugins/client/client/api.js.map +0 -1
  132. package/dist/plugins/client/client/assetUrl.d.ts +0 -51
  133. package/dist/plugins/client/client/assetUrl.js +0 -224
  134. package/dist/plugins/client/client/assetUrl.js.map +0 -1
  135. package/dist/plugins/client/client/config.d.ts +0 -58
  136. package/dist/plugins/client/client/config.js +0 -90
  137. package/dist/plugins/client/client/config.js.map +0 -1
  138. package/dist/plugins/client/client/grapesjs/LoginDialog.d.ts +0 -15
  139. package/dist/plugins/client/client/grapesjs/LoginDialog.js +0 -195
  140. package/dist/plugins/client/client/grapesjs/LoginDialog.js.map +0 -1
  141. package/dist/plugins/client/client/grapesjs/PublicationManager.d.ts +0 -72
  142. package/dist/plugins/client/client/grapesjs/PublicationManager.js +0 -356
  143. package/dist/plugins/client/client/grapesjs/PublicationManager.js.map +0 -1
  144. package/dist/plugins/client/client/grapesjs/PublicationUi.d.ts +0 -62
  145. package/dist/plugins/client/client/grapesjs/PublicationUi.js +0 -336
  146. package/dist/plugins/client/client/grapesjs/PublicationUi.js.map +0 -1
  147. package/dist/plugins/client/client/grapesjs/blocks.d.ts +0 -1
  148. package/dist/plugins/client/client/grapesjs/blocks.js +0 -37
  149. package/dist/plugins/client/client/grapesjs/blocks.js.map +0 -1
  150. package/dist/plugins/client/client/grapesjs/breadcrumbs.d.ts +0 -1
  151. package/dist/plugins/client/client/grapesjs/breadcrumbs.js +0 -75
  152. package/dist/plugins/client/client/grapesjs/breadcrumbs.js.map +0 -1
  153. package/dist/plugins/client/client/grapesjs/footer.d.ts +0 -2
  154. package/dist/plugins/client/client/grapesjs/footer.js +0 -28
  155. package/dist/plugins/client/client/grapesjs/footer.js.map +0 -1
  156. package/dist/plugins/client/client/grapesjs/index.d.ts +0 -5
  157. package/dist/plugins/client/client/grapesjs/index.js +0 -313
  158. package/dist/plugins/client/client/grapesjs/index.js.map +0 -1
  159. package/dist/plugins/client/client/grapesjs/internal-links.d.ts +0 -1
  160. package/dist/plugins/client/client/grapesjs/internal-links.js +0 -219
  161. package/dist/plugins/client/client/grapesjs/internal-links.js.map +0 -1
  162. package/dist/plugins/client/client/grapesjs/new-page-dialog.d.ts +0 -2
  163. package/dist/plugins/client/client/grapesjs/new-page-dialog.js +0 -83
  164. package/dist/plugins/client/client/grapesjs/new-page-dialog.js.map +0 -1
  165. package/dist/plugins/client/client/grapesjs/openImport.d.ts +0 -9
  166. package/dist/plugins/client/client/grapesjs/openImport.js +0 -74
  167. package/dist/plugins/client/client/grapesjs/openImport.js.map +0 -1
  168. package/dist/plugins/client/client/grapesjs/page-panel.d.ts +0 -3
  169. package/dist/plugins/client/client/grapesjs/page-panel.js +0 -113
  170. package/dist/plugins/client/client/grapesjs/page-panel.js.map +0 -1
  171. package/dist/plugins/client/client/grapesjs/project-bar.d.ts +0 -1
  172. package/dist/plugins/client/client/grapesjs/project-bar.js +0 -104
  173. package/dist/plugins/client/client/grapesjs/project-bar.js.map +0 -1
  174. package/dist/plugins/client/client/grapesjs/rich-text.d.ts +0 -1
  175. package/dist/plugins/client/client/grapesjs/rich-text.js +0 -31
  176. package/dist/plugins/client/client/grapesjs/rich-text.js.map +0 -1
  177. package/dist/plugins/client/client/grapesjs/semantic.d.ts +0 -1
  178. package/dist/plugins/client/client/grapesjs/semantic.js +0 -110
  179. package/dist/plugins/client/client/grapesjs/semantic.js.map +0 -1
  180. package/dist/plugins/client/client/grapesjs/settings.d.ts +0 -2
  181. package/dist/plugins/client/client/grapesjs/settings.js +0 -198
  182. package/dist/plugins/client/client/grapesjs/settings.js.map +0 -1
  183. package/dist/plugins/client/client/grapesjs/storage.d.ts +0 -1
  184. package/dist/plugins/client/client/grapesjs/storage.js +0 -126
  185. package/dist/plugins/client/client/grapesjs/storage.js.map +0 -1
  186. package/dist/plugins/client/client/grapesjs/symbolDialogs.d.ts +0 -3
  187. package/dist/plugins/client/client/grapesjs/symbolDialogs.js +0 -36
  188. package/dist/plugins/client/client/grapesjs/symbolDialogs.js.map +0 -1
  189. package/dist/plugins/client/client/publication-transformers.d.ts +0 -41
  190. package/dist/plugins/client/client/publication-transformers.js +0 -238
  191. package/dist/plugins/client/client/publication-transformers.js.map +0 -1
  192. package/dist/plugins/client/client/utils.d.ts +0 -2
  193. package/dist/plugins/client/client/utils.js.map +0 -1
  194. package/dist/plugins/client/constants.d.ts +0 -29
  195. package/dist/plugins/client/constants.js +0 -46
  196. package/dist/plugins/client/constants.js.map +0 -1
  197. package/dist/plugins/client/page.d.ts +0 -2
  198. package/dist/plugins/client/page.js.map +0 -1
  199. package/dist/plugins/client/plugins/client/11ty.d.ts +0 -17
  200. package/dist/plugins/client/plugins/client/11ty.js +0 -86
  201. package/dist/plugins/client/plugins/client/11ty.js.map +0 -1
  202. package/dist/plugins/client/plugins/client/publicationRenderer.d.ts +0 -2
  203. package/dist/plugins/client/plugins/client/publicationRenderer.js +0 -170
  204. package/dist/plugins/client/plugins/client/publicationRenderer.js.map +0 -1
  205. package/src/ts/plugins/client/11ty.ts +0 -104
  206. package/src/ts/plugins/client/publicationRenderer.ts +0 -174
@@ -21,6 +21,7 @@ import { ConnectorFile, ConnectorFileContent, StatusCallback, StorageConnector,
21
21
  import { ApiError, ConnectorType, ConnectorUser, WebsiteData, WebsiteId, WebsiteMeta, WebsiteMetaFileContent } from '../../types'
22
22
  import fetch from 'node-fetch'
23
23
  import crypto, { createHash } from 'crypto'
24
+ import { join } from 'path'
24
25
 
25
26
  /**
26
27
  * Gitlab connector
@@ -193,7 +194,7 @@ export default class GitlabConnector implements StorageConnector {
193
194
  // **
194
195
  // Convenience methods for the Gitlab API
195
196
  private getAssetPath(path: string): string {
196
- return encodeURIComponent(`${this.options.assetsFolder}${path}`)
197
+ return encodeURIComponent(join(this.options.assetsFolder, path))
197
198
  }
198
199
 
199
200
  private async createFile(session: GitlabSession, websiteId: WebsiteId, path: string, content: string, isBase64 = false): Promise<void> {
@@ -220,6 +221,24 @@ export default class GitlabConnector implements StorageConnector {
220
221
  })
221
222
  }
222
223
 
224
+ async readFile(session: GitlabSession, websiteId: string, fileName: string): Promise<Buffer> {
225
+ const safePath = fileName.replace(/^\//, '')
226
+ // Call the API
227
+ const url = `https://gitlab.com/api/v4/projects/${websiteId}/repository/files/${safePath}?ref=${this.options.branch}&access_token=${session.gitlab?.token?.access_token}`
228
+ const response = await fetch(url, {
229
+ method: 'GET',
230
+ headers: {
231
+ 'Content-Type': 'application/json',
232
+ },
233
+ })
234
+ const json = await response.json()
235
+ if(!response.ok) throw new ApiError(`Error reading file "${fileName}" from Gitlab: ${json?.message ?? json?.error ?? response.statusText}`, response.status)
236
+ // From base64 string to buffer
237
+ const buf = Buffer.from(json.content, 'base64')
238
+ // Return the image bytes
239
+ return buf
240
+ }
241
+
223
242
  /*
224
243
  * Get the meta repo path for the current user
225
244
  * The meta repo contains a JSON file which contains the list of websites
@@ -273,20 +292,10 @@ export default class GitlabConnector implements StorageConnector {
273
292
  let json: { message: string, error: string } | any
274
293
  // Handle the case when the server returns an non-JSON response (e.g. 400 Bad Request)
275
294
  const text = await response.text()
276
- try {
277
- json = JSON.parse(text)
278
- } catch (e) {
279
- if(!response.ok) {
280
- // A real error
281
- throw e
282
- } else {
283
- // Useless error linked to the fact that the response is not JSON
284
- console.error('Gitlab API error (3) - could not parse response', response.status, response.statusText, {url, method, body, params, text})
285
- return text
286
- }
287
- }
288
295
  if(!response.ok) {
289
- if (response.status === 401 && session?.gitlab?.token?.refresh_token) {
296
+ if (text.includes('A file with this name doesn\'t exist')) {
297
+ throw new ApiError('Gitlab API error (5): Not Found', 404)
298
+ } else if (response.status === 401 && session?.gitlab?.token?.refresh_token) {
290
299
  // Refresh the token
291
300
  const token = session?.gitlab?.token
292
301
  const body = {
@@ -320,10 +329,21 @@ export default class GitlabConnector implements StorageConnector {
320
329
  }
321
330
  } else {
322
331
  const message = typeof json?.message === 'object' ? Object.entries(json.message).map(entry => entry.join(' ')).join(' ') : json?.message ?? json?.error ?? response.statusText
323
- console.error('Gitlab API error (1)', response.status, response.statusText, {message})
324
332
  throw new ApiError(`Gitlab API error (1): ${message}`, response.status)
325
333
  }
326
334
  }
335
+ try {
336
+ json = JSON.parse(text)
337
+ } catch (e) {
338
+ if(!response.ok) {
339
+ // A real error
340
+ throw e
341
+ } else {
342
+ // Useless error linked to the fact that the response is not JSON
343
+ console.error('Gitlab API error (3) - could not parse response', response.status, response.statusText, {url, method, body, params, text})
344
+ return text
345
+ }
346
+ }
327
347
  return json
328
348
  }
329
349
 
@@ -501,7 +521,6 @@ export default class GitlabConnector implements StorageConnector {
501
521
  branch: this.options.branch,
502
522
  commit_message: 'Update website data from Silex',
503
523
  content: JSON.stringify(websiteData),
504
- file_path: WEBSITE_DATA_FILE,
505
524
  id: websiteId,
506
525
  })
507
526
  }
@@ -527,6 +546,37 @@ export default class GitlabConnector implements StorageConnector {
527
546
  //})
528
547
  }
529
548
 
549
+ async duplicateWebsite(session: GitlabSession, websiteId: string): Promise<void> {
550
+ // Get the repo meta data
551
+ const meta = await this.getWebsiteMeta(session, websiteId)
552
+ // List all the repository files
553
+ const blobs = await this.callApi(session, `api/v4/projects/${websiteId}/repository/tree`, 'GET', null, {
554
+ recursive: true,
555
+ })
556
+ const files = blobs
557
+ .filter(item => item.type === 'blob')
558
+ .map(item => item.path)
559
+ // Create a new repo
560
+ const newId = await this.createWebsite(session, {
561
+ ...meta,
562
+ name: meta.name + ' Copy ' + new Date().toISOString().replace(/T.*/, '') + ' ' + Math.random().toString(36).substring(2, 4),
563
+ })
564
+ // Upload all files
565
+ for(const file of files) {
566
+ const path = encodeURIComponent(file)
567
+ const content = await this.readFile(session, websiteId, path)
568
+ // From buffer to string
569
+ const contentStr = content.toString('base64')
570
+ switch(file) {
571
+ case WEBSITE_DATA_FILE:
572
+ await this.updateFile(session, newId, path, contentStr, true)
573
+ break
574
+ default:
575
+ await this.createFile(session, newId, path, contentStr, true)
576
+ }
577
+ }
578
+ }
579
+
530
580
  async getWebsiteMeta(session: GitlabSession, websiteId: WebsiteId): Promise<WebsiteMeta> {
531
581
  //const file = await this.callApi(session, `api/v4/projects/${this.getMetaRepoPath(session)}/repository/files/${this.options.metaRepoFile}`, 'GET', null, {
532
582
  // ref: this.options.branch,
@@ -598,12 +648,14 @@ export default class GitlabConnector implements StorageConnector {
598
648
  for (const file of files) {
599
649
  // Convert to base64
600
650
  const content = (await contentToBuffer(file.content)).toString('base64')
651
+ const path = this.getAssetPath(file.path)
652
+
601
653
  try {
602
- await this.updateFile(session, websiteId, this.getAssetPath(file.path), content, true)
654
+ await this.updateFile(session, websiteId, path, content, true)
603
655
  } catch (e) {
604
656
  // If the file does not exist, create it
605
657
  if (e.statusCode === 404 || e.httpStatusCode === 404 || e.message.endsWith('A file with this name doesn\'t exist')) {
606
- await this.createFile(session, websiteId, this.getAssetPath(file.path), content, true)
658
+ await this.createFile(session, websiteId, path, content, true)
607
659
  } else {
608
660
  throw e
609
661
  }
@@ -614,20 +666,7 @@ export default class GitlabConnector implements StorageConnector {
614
666
  async readAsset(session: GitlabSession, websiteId: string, fileName: string): Promise<ConnectorFileContent> {
615
667
  // Remove leading slash
616
668
  const finalPath = this.getAssetPath(fileName)
617
- // Call the API
618
- const url = `https://gitlab.com/api/v4/projects/${websiteId}/repository/files/${finalPath}?ref=${this.options.branch}&access_token=${session.gitlab?.token?.access_token}`
619
- const response = await fetch(url, {
620
- method: 'GET',
621
- headers: {
622
- 'Content-Type': 'application/json',
623
- },
624
- })
625
- const json = await response.json()
626
- if(!response.ok) throw new ApiError(`Gitlab API error: ${json?.message ?? json?.error ?? response.statusText}`, response.status)
627
- // From base64 string to buffer
628
- const buf = Buffer.from(json.content, 'base64')
629
- // Return the image bytes
630
- return buf
669
+ return this.readFile(session, websiteId, finalPath)
631
670
  }
632
671
 
633
672
  async deleteAssets(session: GitlabSession, websiteId: string, fileNames: string[]): Promise<void> {
@@ -124,15 +124,15 @@ export default function (config: ServerConfig): Router {
124
124
 
125
125
  // Load the content if necessary
126
126
  const filesList: ConnectorFile[] = await Promise.all(files.map(async (file: ClientSideFile) => {
127
- const prefix = API_WEBSITE_ASSET_READ
128
127
  const fileWithContent = file as ClientSideFileWithContent
129
128
  const fileWithSrc = file as ClientSideFileWithSrc
130
129
  if(!fileWithContent.content && !fileWithSrc.src) throw new PublicationError('Missing content or src in file', 400)
131
- const src = fileWithSrc.src?.startsWith(prefix) ? fileWithSrc.src.substring(prefix.length) : fileWithSrc.src
130
+ const src = fileWithSrc.src
132
131
  return {
133
- path: file.path,
134
- content: fileWithContent.content ??
135
- await storage.readAsset(session, websiteId, src),
132
+ // Destination
133
+ path: file.permalink ?? file.path,
134
+ // Content
135
+ content: fileWithContent.content ?? await storage.readAsset(session, websiteId, fileWithSrc.src),
136
136
  }
137
137
  }))
138
138
 
@@ -18,13 +18,13 @@
18
18
  import { Router } from 'express'
19
19
  import formidable from 'formidable'
20
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'
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, API_WEBSITE_DUPLICATE } from '../../constants'
22
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'
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, ApiWebsiteDuplicateQuery } from '../../types'
24
24
  import { ConnectorFile, ConnectorFileContent, ConnectorSession, StorageConnector, getConnector } from '../connectors/connectors'
25
25
  import { Readable } from 'stream'
26
26
  import { requiredParam } from '../utils/validation'
27
- import { basename } from 'path'
27
+ import { basename, join } from 'path'
28
28
  import { ServerConfig } from '../config'
29
29
  import { ServerEvent, WebsiteStoreEndEventType, WebsiteStoreStartEventType, WebsiteAssetStoreStartEventType, WebsiteAssetStoreEndEventType } from '../events'
30
30
 
@@ -226,6 +226,23 @@ export default function (config: ServerConfig, opts = {}): Router {
226
226
  }
227
227
  })
228
228
 
229
+ // Duplicate website
230
+ router.post(API_WEBSITE_DUPLICATE, async (req, res) => {
231
+ try {
232
+ const query: ApiWebsiteDuplicateQuery = req.query as any
233
+ const websiteId= requiredParam<WebsiteId>(query.websiteId, 'New website id')
234
+ await duplicateWebsite(req['session'], websiteId, query.connectorId)
235
+ res.status(200).json({ message: 'Website duplicated' } as ApiError)
236
+ } catch (e) {
237
+ console.error('Error duplicating website data', e)
238
+ if (e.httpStatusCode) {
239
+ res.status(e.httpStatusCode).json({ message: e.message } as ApiError)
240
+ } else {
241
+ res.status(500).json({ message: e.message } as ApiError)
242
+ }
243
+ }
244
+ })
245
+
229
246
  // Load assets
230
247
  router.get(API_WEBSITE_ASSET_READ + '/:path', async (req, res) => {
231
248
  {
@@ -261,11 +278,10 @@ export default function (config: ServerConfig, opts = {}): Router {
261
278
  try {
262
279
  // Check input
263
280
  const query: ApiWebsiteAssetsWriteQuery = req.query as any
264
- const websiteId= requiredParam<WebsiteId>(query.websiteId as WebsiteId, 'Website id')
281
+ const websiteId = requiredParam<WebsiteId>(query.websiteId as WebsiteId, 'Website id')
265
282
 
266
283
  // Get the file data from the request
267
284
  const form = formidable({
268
- filename: (name, ext, part, _form) => `${name}${ext}`,
269
285
  multiples: true,
270
286
  keepExtensions: true,
271
287
  })
@@ -278,7 +294,7 @@ export default function (config: ServerConfig, opts = {}): Router {
278
294
  console.error('Error parsing upload data', err)
279
295
  reject(new ApiError('Error parsing upload data: ' + err.message, 400))
280
296
  } else {
281
- const files = ([].concat(_files['files[]']) as PersistentFile[])
297
+ const files = ([].concat(_files['files[]'] as PersistentFile) as PersistentFile[])
282
298
  .map(file => file.toJSON())
283
299
  .map(file => ({
284
300
  path: `/${file.originalFilename}`,
@@ -301,9 +317,12 @@ export default function (config: ServerConfig, opts = {}): Router {
301
317
  // Return the file URLs to insert in the website
302
318
  // As expected by grapesjs (https://grapesjs.com/docs/modules/Assets.html#uploading-assets)
303
319
  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
320
+ join(
321
+ // We should return path without this line, as it is saved, not as it is displayed
322
+ // But this url is sent straight to grapesjs, so we need to return the url as it is displayed
323
+ baseUrl, API_PATH, API_WEBSITE_PATH, API_WEBSITE_ASSET_READ,
324
+ path,
325
+ )
307
326
  + `?websiteId=${websiteId}&connectorId=${connectorId ? connectorId : ''}` // As expected by wesite API (readAsset)
308
327
  )
309
328
 
@@ -388,6 +407,17 @@ export default function (config: ServerConfig, opts = {}): Router {
388
407
  return storageConnector.deleteWebsite(session, websiteId)
389
408
  }
390
409
 
410
+ /**
411
+ * Duplicate a website
412
+ */
413
+ async function duplicateWebsite(session: any, websiteId: string, connectorId?: string): Promise<void> {
414
+ // Get the desired connector
415
+ const storageConnector = await getStorageConnector(session, connectorId)
416
+
417
+ // Duplicate the website
418
+ return storageConnector.duplicateWebsite(session, websiteId)
419
+ }
420
+
391
421
  /**
392
422
  * Read an asset
393
423
  */
@@ -25,11 +25,12 @@ const options = parse({
25
25
  'host': ['', 'Sets the host param of the express module "cookie-session".', 'string'],
26
26
  'port': [ 'p', 'Port to listen to', 'int'],
27
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'],
28
+ 'server-config': [ 's', 'Path for the server side config file to load at startup', 'file'],
29
+ 'client-config': ['c', 'Path to client config file to be served on .silex-client.js', 'file'],
30
+ 'fs-root': ['', 'Path to the root folder where to store websites. Used by the default storage connector (fs).', 'string'],
31
+ 'fs-hosting-root': ['', 'Path to the root folder where to publish websites. Used by the default hosting connector (fs).', 'string'],
31
32
  'session-name': ['', 'Sets the name param of the express module "cookie-session".', 'string'],
32
- 'session-secret': ['s', 'Session secret', 'string'],
33
+ 'session-secret': ['', 'Session secret', 'string'],
33
34
  'ssl-port': [ false, 'Port to listen to for SSL/HTTPS', 'int'],
34
35
  'force-https': [ false, 'Force HTTPS', 'boolean'],
35
36
  'ssl-private-key': [ false, 'Path to private key for SSL', 'file'],
@@ -46,9 +47,10 @@ if(options['url']) process.env.SILEX_URL = options['url']
46
47
  if(options['host']) process.env.SILEX_HOST = options['host']
47
48
  if(options.port) process.env.SILEX_PORT = options.port
48
49
  if(options['protocol']) process.env.SILEX_PROTOCOL = options['protocol']
49
- if(options.config) process.env.SILEX_CONFIG = options.config
50
+ if(options['server-config']) process.env.SILEX_SERVER_CONFIG = options['server-config']
50
51
  if(options['client-config']) process.env.SILEX_CLIENT_CONFIG = options['client-config']
51
52
  if(options['fs-root']) process.env.SILEX_FS_ROOT = options['fs-root']
53
+ if(options['fs-hosting-root']) process.env.SILEX_FS_HOSTING_ROOT = options['fs-hosting-root']
52
54
  if(options['session-name']) process.env.SILEX_SESSION_NAME = options['session-name']
53
55
  if(options['session-secret']) process.env.SILEX_SESSION_SECRET = options['session-secret']
54
56
  if(options['ssl-port']) process.env.SILEX_SSL_PORT = options['ssl-port']
@@ -25,7 +25,7 @@
25
25
  */
26
26
 
27
27
  import { Config, Plugin } from '@silexlabs/silex-plugins'
28
- import { resolve } from 'path'
28
+ import { join, resolve } from 'path'
29
29
  import { CLIENT_CONFIG_FILE_NAME } from '../constants'
30
30
  import { Application, Request, Response, Router } from 'express'
31
31
  import { readFile } from 'fs/promises'
@@ -50,7 +50,7 @@ export class ServerConfig extends Config {
50
50
  public port = process.env.SILEX_PORT
51
51
  public debug = process.env.SILEX_DEBUG === 'true'
52
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
53
+ public userConfigPath: Plugin | undefined = process.env.SILEX_SERVER_CONFIG
54
54
  public configFilePath: Plugin = resolve(__dirname, '../../../.silex.js')
55
55
 
56
56
  // All connectors or just the storage or hosting connectors
@@ -176,13 +176,13 @@ export class ServerConfig extends Config {
176
176
  // Add default storage connectors
177
177
  if (!this.storageConnectors.length) {
178
178
  this.addStorageConnector(new FsStorage(null, {
179
- path: process.env.SILEX_FS_ROOT,
179
+ path: process.env.SILEX_FS_ROOT || join(process.cwd(), '/silex/storage'),
180
180
  }))
181
181
  }
182
182
  // Add default hosting connectors
183
183
  if (!this.hostingConnectors.length) {
184
184
  this.addHostingConnector(new FsHosting(null, {
185
- path: process.env.SILEX_FS_ROOT,
185
+ path: process.env.SILEX_FS_HOSTING_ROOT || join(process.cwd(), '/silex/hosting'),
186
186
  }))
187
187
  }
188
188
  }
@@ -15,6 +15,7 @@
15
15
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
  */
17
17
 
18
+ import fs from 'fs/promises'
18
19
  import { ConnectorFile, StorageConnector, HostingConnector, StatusCallback, ConnectorSession, contentToString, toConnectorData, ConnectorFileContent} from './connectors'
19
20
  import { join } from 'path'
20
21
  import { FsStorage } from './FsStorage'
@@ -23,21 +24,26 @@ import { JobManager } from '../jobs'
23
24
 
24
25
  type FsSession = ConnectorSession
25
26
 
26
- interface FsOptions {
27
- path?: string
28
- }
29
-
30
27
  export class FsHosting extends FsStorage implements HostingConnector<FsSession> {
31
28
  connectorId = 'fs-hosting'
32
29
  displayName = 'File system hosting'
33
30
  connectorType = ConnectorType.HOSTING
34
31
 
32
+ protected async initFs() {
33
+ const stat = await fs.stat(this.options.path).catch(() => null)
34
+ if (!stat) {
35
+ await fs.mkdir(join(this.options.path, 'assets'), { recursive: true })
36
+ await fs.mkdir(join(this.options.path, 'css'), { recursive: true })
37
+ console.info(`> [FsHosting] Created folders assets/ and css/ in ${this.options.path}`)
38
+ }
39
+ }
40
+
35
41
  async publish(session: FsSession, id: WebsiteId, files: ConnectorFile[], {startJob, jobSuccess, jobError}: JobManager): Promise<JobData> {
36
42
  const job = startJob(`Publishing to ${this.displayName}`) as PublicationJobData
37
43
  job.logs = [[`Publishing to ${this.displayName}`]]
38
44
  job.errors = [[]]
39
45
  // Call write without id or folder so that it goes in / (path will be modified by publication transformers)
40
- this.write(session, '', files, '', async ({status, message}) => {
46
+ await this.write(session, '', files, '', async ({status, message}) => {
41
47
  // Update the job status
42
48
  job.status = status
43
49
  job.message = message
@@ -15,7 +15,7 @@
15
15
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16
16
  */
17
17
 
18
- import fs, { stat } from 'fs/promises'
18
+ import fs from 'fs/promises'
19
19
  import { createWriteStream } from 'fs'
20
20
  import { ConnectorFile, StorageConnector, StatusCallback, ConnectorSession, toConnectorData, ConnectorFileContent} from './connectors'
21
21
  import { dirname, join } from 'path'
@@ -35,6 +35,22 @@ if(!globalThis.__dirname) {
35
35
  console.info('Redefining __dirname', globalThis.__dirname)
36
36
  }
37
37
 
38
+ // Copy a folder recursively
39
+ async function copyDir(src, dest) {
40
+ await fs.mkdir(dest, { recursive: true })
41
+ const entries = await fs.readdir(src, { withFileTypes: true })
42
+
43
+ for (const entry of entries) {
44
+ const srcPath = join(src, entry.name)
45
+ const destPath = join(dest, entry.name)
46
+
47
+ entry.isDirectory() ?
48
+ await copyDir(srcPath, destPath) :
49
+ await fs.copyFile(srcPath, destPath)
50
+ }
51
+ }
52
+
53
+
38
54
  type FsSession = ConnectorSession
39
55
 
40
56
  const USER_ICON = 'data:image/svg+xml,%3Csvg xmlns=\'http://www.w3.org/2000/svg\' height=\'1em\' viewBox=\'0 0 448 512\'%3E%3Cpath d=\'M304 128a80 80 0 1 0 -160 0 80 80 0 1 0 160 0zM96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM49.3 464H398.7c-8.9-63.3-63.3-112-129-112H178.3c-65.7 0-120.1 48.7-129 112zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3z\'/%3E%3C/svg%3E'
@@ -64,7 +80,7 @@ export class FsStorage implements StorageConnector<FsSession> {
64
80
  this.initFs()
65
81
  }
66
82
 
67
- private async initFs() {
83
+ protected async initFs() {
68
84
  const stat = await fs.stat(this.options.path).catch(() => null)
69
85
  if (!stat) {
70
86
  // create data folder with a default website
@@ -72,6 +88,7 @@ export class FsStorage implements StorageConnector<FsSession> {
72
88
  await fs.mkdir(join(this.options.path, id, this.options.assetsFolder), { recursive: true })
73
89
  await this.setWebsiteMeta({}, id, { name: 'Default website', connectorUserSettings: {} })
74
90
  await this.updateWebsite({}, id, defaultWebsiteData)
91
+ console.info(`> [FsStorage] Created ${id} in ${this.options.path}`)
75
92
  }
76
93
  }
77
94
 
@@ -136,7 +153,7 @@ export class FsStorage implements StorageConnector<FsSession> {
136
153
  async getWebsiteMeta(session: FsSession, id: WebsiteId): Promise<WebsiteMeta> {
137
154
  const websiteId = requiredParam<WebsiteId>(id, 'website id')
138
155
  // Get stats for website folder
139
- const fileStat = await stat(join(this.options.path, websiteId))
156
+ const fileStat = await fs.stat(join(this.options.path, websiteId))
140
157
  const path = join(this.options.path, websiteId, WEBSITE_META_DATA_FILE)
141
158
  // Get meta file
142
159
  const content = await fs.readFile(path)
@@ -182,6 +199,18 @@ export class FsStorage implements StorageConnector<FsSession> {
182
199
  return fs.rmdir(path, { recursive: true })
183
200
  }
184
201
 
202
+ async duplicateWebsite(session: FsSession, websiteId: WebsiteId): Promise<void> {
203
+ const newWebsiteId = uuid()
204
+ const from = join(this.options.path, websiteId)
205
+ const to = join(this.options.path, newWebsiteId)
206
+ await copyDir(from, to)
207
+ const meta = await this.getWebsiteMeta(session, websiteId)
208
+ await this.setWebsiteMeta(session, newWebsiteId, {
209
+ ...meta,
210
+ name: `${meta.name} copy`,
211
+ })
212
+ }
213
+
185
214
  async listWebsites(session: any): Promise<WebsiteMeta[]> {
186
215
  const list = await fs.readdir(this.options.path)
187
216
  return Promise.all(list.map(async fileName => {
@@ -210,7 +239,7 @@ export class FsStorage implements StorageConnector<FsSession> {
210
239
  fileStatus.message = 'Writing'
211
240
  this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
212
241
  try {
213
- await fs.writeFile(path, file.content, 'binary')
242
+ await fs.writeFile(path, file.content)
214
243
  } catch(err) {
215
244
  fileStatus.message = `Error (${err})`
216
245
  this.updateStatus(filesStatuses, JobStatus.IN_PROGRESS, statusCbk)
@@ -86,6 +86,7 @@ export interface StorageConnector<Session extends ConnectorSession = ConnectorSe
86
86
  createWebsite(session: Session, data: WebsiteMetaFileContent): Promise<WebsiteId>
87
87
  updateWebsite(session: Session, websiteId: WebsiteId, data: WebsiteData): Promise<void>
88
88
  deleteWebsite(session: Session, websiteId: WebsiteId): Promise<void>
89
+ duplicateWebsite(session: Session, websiteId: WebsiteId): Promise<void>
89
90
  // CRUD on assets
90
91
  writeAssets(session: Session, websiteId: WebsiteId, files: ConnectorFile[], status?: StatusCallback): Promise<string[] | void>
91
92
  readAsset(session: Session, websiteId: WebsiteId, fileName: string): Promise<ConnectorFileContent>
@@ -102,7 +103,6 @@ export interface StorageConnector<Session extends ConnectorSession = ConnectorSe
102
103
  export interface HostingConnector<Session extends ConnectorSession = ConnectorSession> extends Connector<Session> {
103
104
  publish(session: Session, websiteId: WebsiteId, files: ConnectorFile[], jobManager: JobManager): Promise<JobData> // Pass the jobManager as plugins do not neccessarily share the same module instance
104
105
  getUrl(session: Session, websiteId: WebsiteId): Promise<string>
105
-
106
106
  }
107
107
 
108
108
  export function toConnectorEnum(type: string | ConnectorType): ConnectorType {
@@ -22,6 +22,7 @@ const TIME_TO_KEEP_AFTER_STOP = 60*10*1000 // 10 min
22
22
 
23
23
  // Store the jobs in memory
24
24
  const jobs = new Array<JobData>()
25
+ const timers = new WeakMap<JobData, NodeJS.Timeout>()
25
26
 
26
27
  // Key which will change on server restart
27
28
  const processKey = Math.ceil(Math.random() * 1000000)
@@ -60,7 +61,8 @@ export function jobError(id: JobId, message = ''): boolean {
60
61
  // Remove a job from memory
61
62
  // This is also used in unit tests to avoid memory lea
62
63
  export function killJob(job: JobData) {
63
- clearTimeout(job._timeout)
64
+ clearTimeout(timers.get(job))
65
+ timers.delete(job)
64
66
  jobs.splice(jobs.findIndex(j => job.jobId === j.jobId), 1)
65
67
  }
66
68
 
@@ -70,7 +72,7 @@ function end(id: JobId, status: JobStatus, message = ''): boolean {
70
72
  if(job) {
71
73
  job.status = status
72
74
  if(message) job.message = message
73
- job._timeout = setTimeout(() => killJob(job), TIME_TO_KEEP_AFTER_STOP)
75
+ timers.set(job, setTimeout(() => killJob(job), TIME_TO_KEEP_AFTER_STOP))
74
76
  return true
75
77
  }
76
78
  return false
package/src/ts/types.ts CHANGED
@@ -58,6 +58,7 @@ export type ApiWebsiteCreateQuery = { connectorId?: ConnectorId }
58
58
  export type ApiWebsiteCreateBody = WebsiteMetaFileContent
59
59
  export type ApiWebsiteCreateResponse = { message: string }
60
60
  export type ApiWebsiteDeleteQuery = { websiteId: WebsiteId, connectorId?: ConnectorId }
61
+ export type ApiWebsiteDuplicateQuery = { websiteId: WebsiteId, connectorId?: ConnectorId }
61
62
  export type ApiWebsiteMetaReadQuery = { websiteId: WebsiteId, connectorId?: ConnectorId }
62
63
  export type ApiWebsiteMetaReadResponse = WebsiteMeta
63
64
  export type ApiWebsiteMetaWriteQuery = { websiteId: WebsiteId, connectorId?: ConnectorId }
@@ -201,6 +202,12 @@ export enum ClientSideFileType {
201
202
  HTML = 'html',
202
203
  ASSET = 'asset',
203
204
  CSS = 'css',
205
+ OTHER = 'other',
206
+ }
207
+
208
+ export enum Initiator {
209
+ HTML = 'html',
210
+ CSS = 'css',
204
211
  }
205
212
 
206
213
  /**
@@ -208,26 +215,22 @@ export enum ClientSideFileType {
208
215
  */
209
216
  export interface ClientSideFileWithPermalink {
210
217
  path: string, // Path in the connector
211
- permalink: string, // Used to link to the file
218
+ permalink?: string, // Defaults to path, this the path where the file is served, it is used to link to the file
212
219
  type: ClientSideFileType,
213
220
  }
214
221
 
215
222
  /**
216
223
  * Type for a client side file when the content is available as a string
217
224
  */
218
- export interface ClientSideFileWithContent {
219
- path: string,
225
+ export interface ClientSideFileWithContent extends ClientSideFileWithPermalink {
220
226
  content: string, // Not buffer because it's sent from the client in JSON
221
- type: ClientSideFileType
222
227
  }
223
228
 
224
229
  /**
225
230
  * Type for a client side file when the content is in the connector
226
231
  */
227
- export interface ClientSideFileWithSrc {
228
- path: string,
232
+ export interface ClientSideFileWithSrc extends ClientSideFileWithPermalink {
229
233
  src: string, // Where to download the file, a path for the storage connector
230
- type: ClientSideFileType
231
234
  }
232
235
 
233
236
  /**
@@ -1,85 +0,0 @@
1
- import { ConnectorId, JobId, PublicationJobData, WebsiteId, ConnectorData, ConnectorType, WebsiteData, ClientSideFile, PublicationData, ConnectorUser, WebsiteMeta, WebsiteMetaFileContent, ConnectorOptions } from '../types';
2
- export declare enum ApiRoute {
3
- PUBLICATION_PUBLISH = "/api/publication/",
4
- PUBLICATION_STATUS = "/api/publication/publication/status",
5
- CONNECTOR_USER = "/api/connector/user",
6
- CONNECTOR_LOGOUT = "/api/connector/logout",
7
- CONNECTOR_LIST = "/api/connector/",
8
- WEBSITE_READ = "/api/website/",
9
- WEBSITE_WRITE = "/api/website/",
10
- WEBSITE_DELETE = "/api/website/",
11
- WEBSITE_CREATE = "/api/website/",
12
- WEBSITE_LIST = "/api/website/",
13
- WEBSITE_ASSETS_READ = "/api/website/assets",
14
- WEBSITE_ASSETS_WRITE = "/api/website/assets",
15
- WEBSITE_META_READ = "/api/website/meta",
16
- WEBSITE_META_WRITE = "/api/website/meta"
17
- }
18
- export declare function setServerUrl(url: string): void;
19
- export declare function getServerUrl(): string;
20
- export declare function getUser({ type, connectorId }: {
21
- type: ConnectorType;
22
- connectorId?: ConnectorId;
23
- }): Promise<ConnectorUser>;
24
- export declare function logout({ type, connectorId }: {
25
- type: ConnectorType;
26
- connectorId?: ConnectorId;
27
- }): Promise<void>;
28
- export declare function publish({ websiteId, hostingId, storageId, data, options }: {
29
- websiteId: WebsiteId;
30
- hostingId: ConnectorId;
31
- storageId: ConnectorId;
32
- data: PublicationData;
33
- options: ConnectorOptions;
34
- }): Promise<[url: string, job: PublicationJobData]>;
35
- export declare function publicationStatus({ jobId }: {
36
- jobId: JobId;
37
- }): Promise<PublicationJobData>;
38
- export declare function connectorList({ type }: {
39
- type: ConnectorType;
40
- }): Promise<ConnectorData[]>;
41
- export declare function websiteList({ connectorId }: {
42
- connectorId?: ConnectorId;
43
- }): Promise<WebsiteMeta[]>;
44
- export declare function websiteLoad({ websiteId, connectorId }: {
45
- websiteId: WebsiteId;
46
- connectorId?: ConnectorId;
47
- }): Promise<WebsiteData>;
48
- export declare function websiteSave({ websiteId, data, connectorId }: {
49
- websiteId: WebsiteId;
50
- data: WebsiteData;
51
- connectorId?: ConnectorId;
52
- }): Promise<void>;
53
- export declare function websiteDelete({ websiteId, connectorId }: {
54
- websiteId: WebsiteId;
55
- connectorId?: ConnectorId;
56
- }): Promise<void>;
57
- export declare function websiteCreate({ websiteId, data, connectorId }: {
58
- websiteId: WebsiteId;
59
- data: WebsiteMetaFileContent;
60
- connectorId?: ConnectorId;
61
- }): Promise<void>;
62
- export declare function websiteMetaWrite({ websiteId, data, connectorId }: {
63
- websiteId: WebsiteId;
64
- data: WebsiteMetaFileContent;
65
- connectorId?: ConnectorId;
66
- }): Promise<void>;
67
- export declare function websiteMetaRead({ websiteId, connectorId }: {
68
- websiteId: WebsiteId;
69
- connectorId?: ConnectorId;
70
- }): Promise<WebsiteMeta>;
71
- export declare function websiteAssetsLoad({ path, websiteId, connectorId }: {
72
- path: string;
73
- websiteId: WebsiteId;
74
- connectorId: ConnectorId;
75
- }): Promise<string>;
76
- /**
77
- * Not used directly, grapesjs handles the upload
78
- * @see assetManager in src/ts/client/grapesjs/index.ts
79
- */
80
- export declare function websiteAssetsSave({ websiteId, connectorId, files }: {
81
- websiteId: WebsiteId;
82
- connectorId: ConnectorId;
83
- files: ClientSideFile[];
84
- }): Promise<string[]>;
85
- export declare function api<ReqQuery, ReqBody, ResBody>(route: ApiRoute | string, method: string, query?: ReqQuery, payload?: ReqBody): Promise<ResBody>;