@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.
- package/.env.default +20 -0
- package/.silex.js +67 -8
- package/LICENSE +661 -203
- package/README.md +37 -35
- package/dist/client/client/api.d.ts +90 -0
- package/dist/client/client/assetUrl.d.ts +54 -0
- package/dist/client/client/config.d.ts +102 -0
- package/dist/client/client/events.d.ts +23 -0
- package/dist/client/client/expose.d.ts +8 -0
- package/dist/client/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/client/client/grapesjs/PublicationManager.d.ts +73 -0
- package/dist/client/client/grapesjs/PublicationUi.d.ts +59 -0
- package/dist/client/client/grapesjs/blocks.d.ts +1 -0
- package/dist/client/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/client/grapesjs/img.d.ts +6 -0
- package/dist/client/client/grapesjs/index.d.ts +9 -0
- package/dist/client/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/client/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/client/client/grapesjs/openImport.d.ts +9 -0
- package/dist/client/client/grapesjs/page-panel.d.ts +9 -0
- package/dist/client/client/grapesjs/project-bar.d.ts +21 -0
- package/dist/client/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/client/grapesjs/rich-text.d.ts +4 -0
- package/dist/client/client/grapesjs/semantic.d.ts +1 -0
- package/dist/client/client/grapesjs/settings-sections.d.ts +16 -0
- package/dist/client/client/grapesjs/settings.d.ts +4 -0
- package/dist/client/client/grapesjs/storage.d.ts +2 -0
- package/dist/client/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/client/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/client/index.d.ts +10 -0
- package/dist/client/client/publication-transformers.d.ts +42 -0
- package/dist/client/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/client/publish-fonts.d.ts +4 -0
- package/dist/client/client/utils.d.ts +22 -0
- package/dist/client/constants.d.ts +32 -0
- package/dist/client/css/admin.css +1114 -328
- package/dist/client/css/admin.css.map +1 -0
- package/dist/client/grapesjs-filter-styles/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-fonts/src/commands.d.ts +3 -0
- package/dist/client/grapesjs-fonts/src/fonts.d.ts +4 -0
- package/dist/client/grapesjs-storage-rate-limit/dist/index.d.ts +4 -0
- package/dist/client/grapesjs-ui-suggest-classes/dist/index.d.ts +4 -0
- package/dist/client/index.html +3 -2
- package/dist/client/js/main.js +356 -131
- package/dist/client/js/main.js.LICENSE.txt +15 -1
- package/dist/client/page.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/api.d.ts +90 -0
- package/dist/client/silex-lib/src/ts/client/assetUrl.d.ts +54 -0
- package/dist/client/silex-lib/src/ts/client/config.d.ts +102 -0
- package/dist/client/silex-lib/src/ts/client/events.d.ts +23 -0
- package/dist/client/silex-lib/src/ts/client/expose.d.ts +8 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/LoginDialog.d.ts +15 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationManager.d.ts +73 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/PublicationUi.d.ts +59 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/blocks.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/breadcrumbs.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/css-props.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/footer.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/img.d.ts +6 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/index.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/internal-links.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/keymaps.d.ts +123 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/new-page-dialog.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/openImport.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/page-panel.d.ts +9 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/project-bar.d.ts +21 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/resize-panel.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/rich-text.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/semantic.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings-sections.d.ts +16 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/settings.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/storage.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/symbolDialogs.d.ts +3 -0
- package/dist/client/silex-lib/src/ts/client/grapesjs/view-buttons.d.ts +1 -0
- package/dist/client/silex-lib/src/ts/client/index.d.ts +10 -0
- package/dist/client/silex-lib/src/ts/client/publication-transformers.d.ts +42 -0
- package/dist/client/silex-lib/src/ts/client/publish-custom-code-block.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/publish-fonts.d.ts +4 -0
- package/dist/client/silex-lib/src/ts/client/utils.d.ts +22 -0
- package/dist/client/silex-lib/src/ts/constants.d.ts +32 -0
- package/dist/client/silex-lib/src/ts/page.d.ts +2 -0
- package/dist/client/silex-lib/src/ts/types.d.ts +339 -0
- package/dist/client/types.d.ts +339 -0
- package/dist/plugins/client/client/events.d.ts +23 -0
- package/dist/plugins/client/client/events.js +43 -0
- package/dist/plugins/client/client/events.js.map +1 -0
- package/dist/plugins/client/plugins/client/template.d.ts +2 -0
- package/dist/plugins/client/plugins/client/template.js +234 -0
- package/dist/plugins/client/plugins/client/template.js.map +1 -0
- package/dist/plugins/client/plugins/client/website-info.d.ts +1 -0
- package/dist/plugins/client/plugins/client/website-info.js +72 -0
- package/dist/plugins/client/plugins/client/website-info.js.map +1 -0
- package/dist/plugins/client/types.d.ts +339 -0
- package/dist/plugins/client/types.js +80 -0
- package/dist/plugins/client/types.js.map +1 -0
- package/dist/plugins/server/constants.d.ts +32 -0
- package/dist/plugins/server/constants.js +76 -0
- package/dist/plugins/server/constants.js.map +1 -0
- package/dist/plugins/server/plugins/server/Cache.d.ts +2 -0
- package/dist/plugins/server/plugins/server/Cache.js +36 -0
- package/dist/plugins/server/plugins/server/Cache.js.map +1 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.d.ts +29 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js +127 -0
- package/dist/plugins/server/plugins/server/DownloadConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/FtpConnector.d.ts +86 -0
- package/dist/plugins/server/plugins/server/FtpConnector.js +536 -0
- package/dist/plugins/server/plugins/server/FtpConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.d.ts +135 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.js +649 -0
- package/dist/plugins/server/plugins/server/GitlabConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.d.ts +16 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js +209 -0
- package/dist/plugins/server/plugins/server/GitlabHostingConnector.js.map +1 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.d.ts +0 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.js +14 -0
- package/dist/plugins/server/plugins/server/PublicationOptimizer.js.map +1 -0
- package/dist/plugins/server/plugins/server/SslPlugin.d.ts +1 -0
- package/dist/plugins/server/plugins/server/SslPlugin.js +86 -0
- package/dist/plugins/server/plugins/server/SslPlugin.js.map +1 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.d.ts +8 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.js +45 -0
- package/dist/plugins/server/plugins/server/StaticPlugin.js.map +1 -0
- package/dist/plugins/server/server/config.d.ts +59 -0
- package/dist/plugins/server/server/config.js +181 -0
- package/dist/plugins/server/server/config.js.map +1 -0
- package/dist/plugins/server/server/connectors/FsHosting.d.ts +14 -0
- package/dist/plugins/server/server/connectors/FsHosting.js +66 -0
- package/dist/plugins/server/server/connectors/FsHosting.js.map +1 -0
- package/dist/plugins/server/server/connectors/FsStorage.d.ts +44 -0
- package/dist/plugins/server/server/connectors/FsStorage.js +261 -0
- package/dist/plugins/server/server/connectors/FsStorage.js.map +1 -0
- package/dist/plugins/server/server/connectors/connectors.d.ts +86 -0
- package/dist/plugins/server/server/connectors/connectors.js +126 -0
- package/dist/plugins/server/server/connectors/connectors.js.map +1 -0
- package/dist/plugins/server/server/events.d.ts +26 -0
- package/dist/plugins/server/server/events.js +31 -0
- package/dist/plugins/server/server/events.js.map +1 -0
- package/dist/plugins/server/server/jobs.d.ts +12 -0
- package/dist/plugins/server/server/jobs.js +79 -0
- package/dist/plugins/server/server/jobs.js.map +1 -0
- package/dist/plugins/server/server/utils/validation.d.ts +7 -0
- package/dist/plugins/server/server/utils/validation.js +37 -0
- package/dist/plugins/server/server/utils/validation.js.map +1 -0
- package/dist/plugins/server/types.d.ts +339 -0
- package/dist/plugins/server/types.js +84 -0
- package/dist/plugins/server/types.js.map +1 -0
- package/dist/server/constants.js +55 -0
- package/dist/server/plugins/server/Cache.js +19 -0
- package/dist/server/server/api/api.js +20 -0
- package/dist/server/server/api/connectorApi.js +334 -0
- package/dist/server/server/api/publicationApi.js +106 -0
- package/dist/server/server/api/websiteApi.js +315 -0
- package/dist/server/server/cli.js +71 -0
- package/dist/server/server/config.js +120 -0
- package/dist/server/server/connectors/FsHosting.js +47 -0
- package/dist/server/server/connectors/FsStorage.js +228 -0
- package/dist/server/server/connectors/connectors.js +88 -0
- package/dist/server/server/events.js +14 -0
- package/dist/server/server/expose.js +27 -0
- package/dist/server/server/express.js +46 -0
- package/dist/server/server/index.js +92 -0
- package/dist/server/server/jobs.js +50 -0
- package/dist/server/server/utils/validation.js +14 -0
- package/dist/server/types.js +40 -0
- package/package.json +99 -49
- package/public/assets/download.png +0 -0
- package/public/assets/favicon.ico +0 -0
- package/public/assets/favicon.png +0 -0
- package/public/assets/ftp.png +0 -0
- package/public/assets/gitlab.png +0 -0
- package/public/assets/gitlab2.png +0 -0
- package/public/assets/laptop.png +0 -0
- package/public/assets/logo-silex-small.png +0 -0
- package/public/silex.js +22 -23
- package/src/css/_variables.scss +24 -20
- package/src/css/dialog.scss +35 -2
- package/src/css/fonts.scss +31 -0
- package/src/css/footer.scss +12 -0
- package/src/css/grapesjs-light.scss +180 -0
- package/src/css/grapesjs-plugins.scss +227 -0
- package/src/css/grapesjs.scss +159 -1
- package/src/css/index.scss +12 -1
- package/src/css/light.scss +7 -0
- package/src/css/loader.scss +2 -0
- package/src/css/project-bar.scss +32 -16
- package/src/css/silex.scss +79 -5
- package/src/css/website-info.scss +14 -0
- package/src/html/index.pug +3 -3
- package/src/html/templates/includes.pug +0 -1
- package/src/ts/client/api.ts +156 -0
- package/src/ts/client/assetUrl.test.ts +164 -0
- package/src/ts/client/assetUrl.ts +254 -0
- package/src/ts/client/config.ts +175 -13
- package/src/ts/client/events.ts +43 -0
- package/src/ts/client/expose.ts +27 -1
- package/src/ts/client/grapesjs/LoginDialog.ts +204 -0
- package/src/ts/client/grapesjs/PublicationManager.ts +433 -0
- package/src/ts/client/grapesjs/PublicationUi.ts +366 -0
- package/src/ts/client/grapesjs/blocks.ts +17 -0
- package/src/ts/client/grapesjs/breadcrumbs.ts +79 -0
- package/src/ts/client/grapesjs/css-props.ts +910 -0
- package/src/ts/client/grapesjs/eleventy.ts +30 -7
- package/src/ts/client/grapesjs/footer.ts +42 -0
- package/src/ts/client/grapesjs/img.ts +147 -0
- package/src/ts/client/grapesjs/index.ts +311 -122
- package/src/ts/client/grapesjs/internal-links.test.ts +19 -1
- package/src/ts/client/grapesjs/internal-links.ts +31 -7
- package/src/ts/client/grapesjs/keymaps.ts +207 -0
- package/src/ts/client/grapesjs/new-page-dialog.ts +19 -3
- package/src/ts/client/grapesjs/openImport.ts +22 -0
- package/src/ts/client/grapesjs/page-panel.ts +109 -7
- package/src/ts/client/grapesjs/project-bar.ts +133 -72
- package/src/ts/client/grapesjs/resize-panel.ts +20 -0
- package/src/ts/client/grapesjs/rich-text.ts +38 -13
- package/src/ts/client/grapesjs/semantic.ts +20 -3
- package/src/ts/client/grapesjs/settings-sections.ts +117 -0
- package/src/ts/client/grapesjs/settings.ts +191 -96
- package/src/ts/client/grapesjs/storage.ts +187 -0
- package/src/ts/client/grapesjs/symbolDialogs.ts +21 -5
- package/src/ts/client/grapesjs/view-buttons.ts +42 -0
- package/src/ts/client/index.ts +80 -21
- package/src/ts/client/publication-transformers.test.ts +207 -0
- package/src/ts/client/publication-transformers.ts +280 -0
- package/src/ts/client/publish-custom-code-block.ts +31 -0
- package/src/ts/client/publish-fonts.ts +36 -0
- package/src/ts/client/utils.ts +70 -1
- package/src/ts/constants.ts +78 -0
- package/src/ts/externs.ts +17 -0
- package/src/ts/page.ts +20 -3
- package/src/ts/plugins/client/template.ts +246 -0
- package/src/ts/plugins/client/website-info.ts +84 -0
- package/src/ts/plugins/server/Cache.ts +32 -0
- package/src/ts/plugins/server/DownloadConnector.ts +146 -0
- package/src/ts/plugins/server/FtpConnector.test.ts +82 -0
- package/src/ts/plugins/server/FtpConnector.ts +621 -0
- package/src/ts/plugins/server/GitlabConnector.ts +749 -0
- package/src/ts/plugins/server/GitlabHostingConnector.ts +215 -0
- package/src/ts/plugins/server/PublicationOptimizer.ts +14 -0
- package/src/ts/plugins/server/SslPlugin.ts +84 -0
- package/src/ts/plugins/server/StaticPlugin.ts +45 -0
- package/src/ts/server/api/api.ts +19 -0
- package/src/ts/server/api/connectorApi.ts +464 -0
- package/src/ts/server/api/publicationApi.ts +159 -0
- package/src/ts/server/api/websiteApi.ts +462 -0
- package/src/ts/server/cli.ts +48 -14
- package/src/ts/server/config.ts +158 -60
- package/src/ts/server/connectors/FsHosting.ts +66 -0
- package/src/ts/server/connectors/FsStorage.test.ts +51 -0
- package/src/ts/server/connectors/FsStorage.ts +290 -0
- package/src/ts/server/connectors/connectors.ts +203 -0
- package/src/ts/server/events.ts +37 -0
- package/src/ts/server/expose.ts +19 -0
- package/src/ts/server/express.ts +57 -5
- package/src/ts/server/index.ts +80 -19
- package/src/ts/server/jobs.test.ts +75 -0
- package/src/ts/server/jobs.ts +89 -0
- package/src/ts/server/utils/BackwardCompat.ts +546 -528
- package/src/ts/server/utils/validation.ts +34 -0
- package/src/ts/types.ts +295 -85
- package/.dockerignore +0 -5
- package/.editorconfig +0 -14
- package/.eslintrc.json +0 -43
- package/.github/FUNDING.yml +0 -13
- package/.github/workflows/docker-hub-publish.yml +0 -36
- package/.github/workflows/npm-publish.yml +0 -19
- package/.github/workflows/test.yml +0 -26
- package/.nvmrc +0 -1
- package/.silex/default/.silex.data.json +0 -1
- package/CODE_OF_CONDUCT.md +0 -128
- package/CONTRIBUTING.md +0 -131
- package/Dockerfile +0 -15
- package/directus.silex.js +0 -7
- package/dist/constants.js +0 -4
- package/dist/events.js +0 -5
- package/dist/page.js +0 -15
- package/dist/server/cli.js +0 -43
- package/dist/server/config.js +0 -70
- package/dist/server/express.js +0 -18
- package/dist/server/index.js +0 -58
- package/dist/types.js +0 -34
- package/jest.config.js +0 -10
- package/logos/logo_by_ceubri/silex-icon-2018@200px.png +0 -0
- package/logos/logo_by_ceubri/silex-icon-2018@4x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white-transp.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@0.5x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@0.75x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@4x.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018-white@4x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.ai +5 -2521
- package/logos/logo_by_ceubri/silex-logo-2018.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.pdf +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@0.5x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@0.75x.png +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@4x.jpg +0 -0
- package/logos/logo_by_ceubri/silex-logo-2018@4x.png +0 -0
- package/logos/silexlabs.png +0 -0
- package/src/example-client-config.js +0 -47
- package/src/plugins/AuthPlugin.js +0 -21
- package/src/plugins/Cache.js +0 -11
- package/src/plugins/DefaultBackend.js +0 -149
- package/src/plugins/ExpressPlugin.js +0 -39
- package/src/plugins/HooksPlugin.js +0 -58
- package/src/plugins/PublishPlugin.js +0 -69
- package/src/plugins/SslPlugin.js +0 -66
- package/src/plugins/StaticPlugin.js +0 -48
- package/src/plugins/WebsitePlugin.js +0 -207
- package/src/ts/client/grapesjs/publish.ts +0 -386
- package/src/ts/client/grapesjs/template.ts +0 -166
- package/src/ts/events.ts +0 -2
- package/tsconfig-server-debug.json +0 -19
- package/tsconfig-server-release.json +0 -19
- package/tsconfig.jest.json +0 -9
- package/tsconfig.json +0 -26
- package/webpack.config.js +0 -28
- package/webpack.debug.config.js +0 -8
|
@@ -0,0 +1,203 @@
|
|
|
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 { Readable } from 'stream'
|
|
19
|
+
import { ServerConfig } from '../config'
|
|
20
|
+
import { JobStatus, JobData, ConnectorData, ConnectorId, WebsiteId, ConnectorType, ConnectorUser, WebsiteMeta, WebsiteMetaFileContent, WebsiteData, ConnectorOptions } from '../../types'
|
|
21
|
+
import { JobManager } from '../jobs'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @fileoverview define types for Silex connectors
|
|
25
|
+
* Bakends can provide storage for website data and assets, and/or hosting to publish the website online
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Connector data stored in the website meta file
|
|
30
|
+
*/
|
|
31
|
+
export type ConnectorFileContent = string | Buffer | Readable
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Files are stored in connector as a File object
|
|
35
|
+
* @see types/ClientSideFile
|
|
36
|
+
* @see contentToString()
|
|
37
|
+
*/
|
|
38
|
+
export interface ConnectorFile {
|
|
39
|
+
path: string,
|
|
40
|
+
content: ConnectorFileContent,
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Callback to update the publication status
|
|
45
|
+
*/
|
|
46
|
+
export type StatusCallback = ({message, status}: {message: string, status: JobStatus}) => Promise<void>
|
|
47
|
+
|
|
48
|
+
export type ConnectorSession = object
|
|
49
|
+
/**
|
|
50
|
+
* Connectors are the base interface for Storage and Hosting connectors
|
|
51
|
+
*/
|
|
52
|
+
export interface Connector<Session extends ConnectorSession = ConnectorSession> {
|
|
53
|
+
connectorId: ConnectorId
|
|
54
|
+
connectorType: ConnectorType
|
|
55
|
+
displayName: string
|
|
56
|
+
icon: string
|
|
57
|
+
disableLogout?: boolean
|
|
58
|
+
color: string
|
|
59
|
+
background: string
|
|
60
|
+
// Get the URL to start the authentication process with OAuth (not used for basic auth)
|
|
61
|
+
getOAuthUrl(session: Session): Promise<string | null>
|
|
62
|
+
// Get the form to display to the user to authenticate (not used for OAuth)
|
|
63
|
+
getLoginForm(session: Session, redirectTo: string): Promise<string | null>
|
|
64
|
+
// Get the form to display to the user to set the connector settings for a given website
|
|
65
|
+
getSettingsForm(session: Session, redirectTo: string): Promise<string | null>
|
|
66
|
+
// Auth and user management
|
|
67
|
+
isLoggedIn(session: Session): Promise<boolean>
|
|
68
|
+
setToken(session: Session, token: object): Promise<void>
|
|
69
|
+
logout(session: Session): Promise<void>
|
|
70
|
+
getUser(session: Session): Promise<ConnectorUser | null>
|
|
71
|
+
// Get the connector options from login form
|
|
72
|
+
// They are stored in the website meta file for hosting connectors
|
|
73
|
+
// And in the user session for storage connectors
|
|
74
|
+
getOptions(formData: object): ConnectorOptions
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Storage are used to store the website data and assets
|
|
79
|
+
* And possibly rename files and directories, and get the URL of a file
|
|
80
|
+
*
|
|
81
|
+
*/
|
|
82
|
+
export interface StorageConnector<Session extends ConnectorSession = ConnectorSession> extends Connector<Session> {
|
|
83
|
+
// CRUD on websites
|
|
84
|
+
listWebsites(session: Session): Promise<WebsiteMeta[]>
|
|
85
|
+
readWebsite(session: Session, websiteId: WebsiteId): Promise<WebsiteData | Readable>
|
|
86
|
+
createWebsite(session: Session, data: WebsiteMetaFileContent): Promise<WebsiteId>
|
|
87
|
+
updateWebsite(session: Session, websiteId: WebsiteId, data: WebsiteData): Promise<void>
|
|
88
|
+
deleteWebsite(session: Session, websiteId: WebsiteId): Promise<void>
|
|
89
|
+
duplicateWebsite(session: Session, websiteId: WebsiteId): Promise<void>
|
|
90
|
+
// CRUD on assets
|
|
91
|
+
writeAssets(session: Session, websiteId: WebsiteId, files: ConnectorFile[], status?: StatusCallback): Promise<string[] | void>
|
|
92
|
+
readAsset(session: Session, websiteId: WebsiteId, fileName: string): Promise<ConnectorFileContent>
|
|
93
|
+
deleteAssets(session: Session, websiteId: WebsiteId, fileNames: string[]): Promise<void>
|
|
94
|
+
//getFileUrl(session: Session, websiteId: WebsiteId, path: string): Promise<string>
|
|
95
|
+
// Handle website meta file
|
|
96
|
+
getWebsiteMeta(session: Session, websiteId: WebsiteId): Promise<WebsiteMeta>
|
|
97
|
+
setWebsiteMeta(session: Session, websiteId: WebsiteId, data: WebsiteMetaFileContent): Promise<void>
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Hosting connectors are used to publish the website
|
|
102
|
+
*/
|
|
103
|
+
export interface HostingConnector<Session extends ConnectorSession = ConnectorSession> extends Connector<Session> {
|
|
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
|
|
105
|
+
getUrl(session: Session, websiteId: WebsiteId): Promise<string>
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function toConnectorEnum(type: string | ConnectorType): ConnectorType {
|
|
109
|
+
const result = ConnectorType[type.toString().toUpperCase() as keyof typeof ConnectorType]
|
|
110
|
+
if(!result) throw new Error(`Unknown connector type ${type}. It should be one of ${Object.keys(ConnectorType).join(', ')}`)
|
|
111
|
+
return result
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get a connector by id or by type
|
|
116
|
+
*/
|
|
117
|
+
export async function getConnector<T extends Connector>(config: ServerConfig, session: any, type: ConnectorType, connectorId?: ConnectorId): Promise<T | undefined> {
|
|
118
|
+
// Get the connectors for this type
|
|
119
|
+
const connectors = config.getConnectors(type) as T[]
|
|
120
|
+
|
|
121
|
+
// Find the connector by id
|
|
122
|
+
if (connectorId) return connectors.find(s => s.connectorId === connectorId && s.connectorType === type)
|
|
123
|
+
// Find the first logged in connector
|
|
124
|
+
for (const connector of connectors) {
|
|
125
|
+
if (await connector.isLoggedIn(session)) {
|
|
126
|
+
return connector
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Defaults to the first connector
|
|
130
|
+
return connectors[0]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Convert a connector to a ConnectorData object to be sent to the frontend
|
|
135
|
+
*/
|
|
136
|
+
export async function toConnectorData(session: any, connector: Connector): Promise<ConnectorData> {
|
|
137
|
+
return {
|
|
138
|
+
connectorId: connector.connectorId,
|
|
139
|
+
type: connector.connectorType,
|
|
140
|
+
displayName: connector.displayName,
|
|
141
|
+
icon: connector.icon,
|
|
142
|
+
disableLogout: !!connector.disableLogout,
|
|
143
|
+
isLoggedIn: await connector.isLoggedIn(session),
|
|
144
|
+
oauthUrl: await connector.getOAuthUrl(session),
|
|
145
|
+
color: connector.color,
|
|
146
|
+
background: connector.background,
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export async function contentToString(content: ConnectorFileContent): Promise<string> {
|
|
151
|
+
// String
|
|
152
|
+
if (typeof content === 'string') return content
|
|
153
|
+
// Buffer
|
|
154
|
+
if (Buffer.isBuffer(content)) return content.toString('utf8')
|
|
155
|
+
// Stream
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
157
|
+
let result = ''
|
|
158
|
+
content.on('data', (chunk: Buffer) => {
|
|
159
|
+
result += chunk.toString('utf8')
|
|
160
|
+
})
|
|
161
|
+
content.on('error', (err: Error) => {
|
|
162
|
+
reject(err)
|
|
163
|
+
})
|
|
164
|
+
content.on('end', () => {
|
|
165
|
+
resolve(result)
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export async function contentToBuffer(content: ConnectorFileContent): Promise<Buffer> {
|
|
171
|
+
// String
|
|
172
|
+
if (typeof content === 'string') return Buffer.from(content, 'utf8')
|
|
173
|
+
// Buffer
|
|
174
|
+
if (Buffer.isBuffer(content)) return content
|
|
175
|
+
// Stream
|
|
176
|
+
if(content instanceof Readable) {
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
const chunks: Buffer[] = []
|
|
179
|
+
content.on('data', (chunk: Buffer) => {
|
|
180
|
+
chunks.push(chunk)
|
|
181
|
+
})
|
|
182
|
+
content.on('error', (err: Error) => {
|
|
183
|
+
reject(err)
|
|
184
|
+
})
|
|
185
|
+
content.on('end', () => {
|
|
186
|
+
resolve(Buffer.concat(chunks))
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
// Unknown
|
|
191
|
+
throw new Error('Unknown content type')
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export function contentToReadable(content: ConnectorFileContent): Readable {
|
|
195
|
+
// String
|
|
196
|
+
if (typeof content === 'string') return Readable.from([content])
|
|
197
|
+
// Buffer
|
|
198
|
+
if (Buffer.isBuffer(content)) return Readable.from([content])
|
|
199
|
+
// Stream
|
|
200
|
+
if (content instanceof Readable) return content
|
|
201
|
+
// Unknown
|
|
202
|
+
throw new Error('Unknown content type')
|
|
203
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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 { ConnectorId, PublicationData, WebsiteData, WebsiteId } from '../types'
|
|
19
|
+
import { ConnectorFile } from './connectors/connectors'
|
|
20
|
+
|
|
21
|
+
export enum ServerEvent {
|
|
22
|
+
STARTUP_START = 'startup-start',
|
|
23
|
+
STARTUP_END = 'startup-end',
|
|
24
|
+
PUBLISH_START = 'publish-start',
|
|
25
|
+
PUBLISH_END = 'publish-end',
|
|
26
|
+
WEBSITE_STORE_START = 'store-start',
|
|
27
|
+
WEBSITE_STORE_END = 'store-end',
|
|
28
|
+
WEBSITE_ASSET_STORE_START = 'asset-store-start',
|
|
29
|
+
WEBSITE_ASSET_STORE_END = 'asset-store-end',
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type PublishStartEventType = PublicationData
|
|
33
|
+
export type PublishEndEventType = Error | null
|
|
34
|
+
export type WebsiteStoreStartEventType = { websiteId: WebsiteId, websiteData: WebsiteData, connectorId: ConnectorId}
|
|
35
|
+
export type WebsiteStoreEndEventType = Error | null
|
|
36
|
+
export type WebsiteAssetStoreStartEventType = { files: ConnectorFile[], websiteId: WebsiteId, connectorId: ConnectorId}
|
|
37
|
+
export type WebsiteAssetStoreEndEventType = Error | null
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Silex website builder, free/libre no-code tool for makers.
|
|
3
|
+
* Copyright (c) 2023 lexoyo and Silex Labs foundation
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or any later version.
|
|
8
|
+
*
|
|
9
|
+
* This program is distributed in the hope that it will be useful,
|
|
10
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
* GNU Affero General Public License for more details.
|
|
13
|
+
*
|
|
14
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
15
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export * as events from './events'
|
package/src/ts/server/express.ts
CHANGED
|
@@ -1,17 +1,69 @@
|
|
|
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
|
+
|
|
1
18
|
import express, { Application } from 'express'
|
|
19
|
+
import bodyParser from 'body-parser'
|
|
20
|
+
import compression from 'compression'
|
|
21
|
+
import cookieParser from 'cookie-parser'
|
|
22
|
+
import session from 'cookie-session'
|
|
23
|
+
import cors from 'cors'
|
|
2
24
|
|
|
3
25
|
import { ServerConfig } from './config'
|
|
4
|
-
import {
|
|
26
|
+
import { ServerEvent } from './events'
|
|
5
27
|
|
|
6
|
-
export
|
|
7
|
-
//
|
|
28
|
+
export function create(config: ServerConfig): Application {
|
|
29
|
+
// Express app
|
|
8
30
|
const app = express()
|
|
9
|
-
|
|
31
|
+
app.set('config', config)
|
|
32
|
+
|
|
33
|
+
// CORS
|
|
34
|
+
const options = config.expressOptions
|
|
35
|
+
if (options.cors) {
|
|
36
|
+
console.info('> CORS are ENABLED:', options.cors)
|
|
37
|
+
app.use(cors({
|
|
38
|
+
origin: options.cors,
|
|
39
|
+
}))
|
|
40
|
+
}
|
|
41
|
+
// compress gzip when possible
|
|
42
|
+
app.use(compression() as any)
|
|
43
|
+
|
|
44
|
+
// cookie & session
|
|
45
|
+
app.use(bodyParser.json({ limit: options.jsonLimit }))
|
|
46
|
+
app.use(bodyParser.text({ limit: options.textLimit }))
|
|
47
|
+
app.use(bodyParser.urlencoded({ limit: options.urlencodedLimit }))
|
|
48
|
+
console.info('> Session name:', options.sessionName)
|
|
49
|
+
app.use(cookieParser() as any)
|
|
50
|
+
app.use(session({
|
|
51
|
+
name: options.sessionName,
|
|
52
|
+
secret: options.sessionSecret,
|
|
53
|
+
}) as any)
|
|
54
|
+
return app
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function start(app: Application): Promise<Application> {
|
|
58
|
+
const config = app.get('config') as ServerConfig
|
|
59
|
+
|
|
60
|
+
// Plugins hook to create API routes
|
|
61
|
+
config.emit(ServerEvent.STARTUP_START, { app })
|
|
10
62
|
|
|
11
63
|
// Start server
|
|
12
64
|
return new Promise((resolve, reject) => {
|
|
13
65
|
app.listen(config.port, () => {
|
|
14
|
-
config.emit(
|
|
66
|
+
config.emit(ServerEvent.STARTUP_END, { app })
|
|
15
67
|
resolve(app)
|
|
16
68
|
})
|
|
17
69
|
})
|
package/src/ts/server/index.ts
CHANGED
|
@@ -1,39 +1,96 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
+
*/
|
|
3
17
|
|
|
4
|
-
import * as
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
|
|
18
|
+
import * as silexApp from './express'
|
|
19
|
+
import api from './api/api'
|
|
20
|
+
import { ServerConfig } from './config'
|
|
21
|
+
import dotenv from 'dotenv'
|
|
22
|
+
import { join } from 'path'
|
|
23
|
+
import { DEV_MESSAGE } from '../constants'
|
|
24
|
+
|
|
25
|
+
// Expose API to calling app as function silex()
|
|
26
|
+
export * from './expose'
|
|
10
27
|
|
|
11
28
|
// Main app
|
|
12
|
-
async function
|
|
13
|
-
//
|
|
14
|
-
|
|
29
|
+
export default async function silex() {
|
|
30
|
+
// Log Silex version
|
|
31
|
+
console.info(DEV_MESSAGE)
|
|
32
|
+
console.info(`Node version: ${process.version}`)
|
|
33
|
+
console.info(`CWD: ${process.cwd()}`)
|
|
34
|
+
|
|
35
|
+
// Load env vars from .env file if any
|
|
36
|
+
const curDirEnv = dotenv.config()
|
|
37
|
+
if (curDirEnv.error) {
|
|
38
|
+
if(curDirEnv.error['code'] === 'ENOENT') {
|
|
39
|
+
console.info('> No .env file found in current directory')
|
|
40
|
+
} else {
|
|
41
|
+
throw curDirEnv.error
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
console.info('> Env vars loaded from .env file')
|
|
45
|
+
}
|
|
15
46
|
|
|
16
|
-
//
|
|
17
|
-
//
|
|
47
|
+
// Load default env vars
|
|
48
|
+
// This will not override existing env vars
|
|
49
|
+
const DEFAULT_ENV_FILE = join(__dirname, '../../../.env.default')
|
|
50
|
+
const rootDirEnv = dotenv.config({ path: DEFAULT_ENV_FILE })
|
|
51
|
+
if (rootDirEnv.error) {
|
|
52
|
+
if(rootDirEnv.error['code'] === 'ENOENT') {
|
|
53
|
+
throw new Error(`\n\nFailed to load default env vars. File not found ${DEFAULT_ENV_FILE}\n\n`)
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error(`\n\nFailed to load default env vars. Error in ${DEFAULT_ENV_FILE}: ${ rootDirEnv.error.message }\n\n`)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
console.info('> Default env vars loaded')
|
|
59
|
+
|
|
60
|
+
// Get the default config object
|
|
61
|
+
const config = new ServerConfig()
|
|
18
62
|
|
|
19
63
|
// start silex
|
|
20
|
-
const app =
|
|
64
|
+
const app = silexApp.create(config)
|
|
21
65
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
66
|
+
// Serve the client config file
|
|
67
|
+
await config.addRoutes(app)
|
|
68
|
+
|
|
69
|
+
// Load the config files
|
|
70
|
+
await config.loadConfigFiles()
|
|
71
|
+
|
|
72
|
+
// Init the connectors in case no plugin adds them
|
|
73
|
+
await config.initDefaultConnectors()
|
|
74
|
+
|
|
75
|
+
// APIs
|
|
76
|
+
app.use('/api', api(config))
|
|
77
|
+
|
|
78
|
+
// Start the server
|
|
79
|
+
await silexApp.start(app)
|
|
80
|
+
|
|
81
|
+
// All good, server is ready
|
|
82
|
+
console.info(`\nSilex is ready, open http://localhost:${config.port} in your browser\n`)
|
|
25
83
|
if (config.debug) {
|
|
26
84
|
startLiverReload()
|
|
27
85
|
}
|
|
28
86
|
}
|
|
29
|
-
main()
|
|
30
87
|
|
|
31
88
|
// livereload
|
|
32
89
|
async function startLiverReload() {
|
|
33
90
|
// Load modules only when needed (they may not even be installed)
|
|
34
91
|
const { createServer } = await import('livereload')
|
|
35
92
|
const { resolve } = await import('path')
|
|
36
|
-
const dist = resolve(__dirname, '
|
|
93
|
+
const dist = resolve(__dirname, '../../client')
|
|
37
94
|
const server = createServer({
|
|
38
95
|
delay: 0,
|
|
39
96
|
}, () => {
|
|
@@ -41,3 +98,7 @@ async function startLiverReload() {
|
|
|
41
98
|
})
|
|
42
99
|
server.watch(dist)
|
|
43
100
|
}
|
|
101
|
+
|
|
102
|
+
if (require.main === module) {
|
|
103
|
+
silex()
|
|
104
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
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 { JobData, JobStatus } from '../types'
|
|
19
|
+
import { startJob, jobSuccess, jobError, getJob, killJob } from './jobs'
|
|
20
|
+
import { expect, afterEach, it, describe } from '@jest/globals'
|
|
21
|
+
|
|
22
|
+
let job: JobData | undefined
|
|
23
|
+
afterEach(() => {
|
|
24
|
+
// Avoid memory leak
|
|
25
|
+
if(job) killJob(job)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('Job Module', () => {
|
|
29
|
+
it('should start a job', () => {
|
|
30
|
+
const {jobId} = startJob('Test job')
|
|
31
|
+
job = getJob(jobId)
|
|
32
|
+
expect(job).not.toBeNull()
|
|
33
|
+
if (job) {
|
|
34
|
+
expect(job.jobId).toEqual(jobId)
|
|
35
|
+
expect(job.status).toEqual(JobStatus.IN_PROGRESS)
|
|
36
|
+
expect(job.message).toEqual('Test job')
|
|
37
|
+
killJob(job)
|
|
38
|
+
expect(getJob(jobId)).toBeUndefined()
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('should end a job with success', () => {
|
|
43
|
+
const {jobId} = startJob('Test job')
|
|
44
|
+
const result = jobSuccess(jobId, 'Job completed successfully')
|
|
45
|
+
expect(result).toBeTruthy()
|
|
46
|
+
job = getJob(jobId)
|
|
47
|
+
expect(job).not.toBeNull()
|
|
48
|
+
if (job) {
|
|
49
|
+
expect(job.status).toEqual(JobStatus.SUCCESS)
|
|
50
|
+
expect(job.message).toEqual('Job completed successfully')
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('should end a job with error', () => {
|
|
55
|
+
const {jobId} = startJob('Test job')
|
|
56
|
+
const result = jobError(jobId, 'Job ended with error')
|
|
57
|
+
expect(result).toBeTruthy()
|
|
58
|
+
job = getJob(jobId)
|
|
59
|
+
expect(job).not.toBeNull()
|
|
60
|
+
if (job) {
|
|
61
|
+
expect(job.status).toEqual(JobStatus.ERROR)
|
|
62
|
+
expect(job.message).toEqual('Job ended with error')
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('should not find a job after ending', done => {
|
|
67
|
+
const {jobId} = startJob('Test job')
|
|
68
|
+
jobSuccess(jobId, 'Job completed successfully')
|
|
69
|
+
setTimeout(() => {
|
|
70
|
+
job = getJob(jobId)
|
|
71
|
+
expect(job).not.toBeUndefined()
|
|
72
|
+
done()
|
|
73
|
+
}, 1000)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
@@ -0,0 +1,89 @@
|
|
|
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 { JobData, JobStatus, JobId } from '../types'
|
|
19
|
+
|
|
20
|
+
// Delay after which the job is deleted from memory
|
|
21
|
+
const TIME_TO_KEEP_AFTER_STOP = 60*10*1000 // 10 min
|
|
22
|
+
|
|
23
|
+
// Store the jobs in memory
|
|
24
|
+
const jobs = new Array<JobData>()
|
|
25
|
+
const timers = new WeakMap<JobData, NodeJS.Timeout>()
|
|
26
|
+
|
|
27
|
+
// Key which will change on server restart
|
|
28
|
+
const processKey = Math.ceil(Math.random() * 1000000)
|
|
29
|
+
|
|
30
|
+
// Next id for the next job
|
|
31
|
+
let nextJobId = 0
|
|
32
|
+
|
|
33
|
+
// Create a new job
|
|
34
|
+
export function startJob(message = ''): JobData {
|
|
35
|
+
const jobId = `${processKey}_${++nextJobId}`
|
|
36
|
+
const job: JobData = {
|
|
37
|
+
jobId,
|
|
38
|
+
status: JobStatus.IN_PROGRESS,
|
|
39
|
+
message: message
|
|
40
|
+
}
|
|
41
|
+
jobs.push(job)
|
|
42
|
+
return job
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Retriev a job if it exists
|
|
46
|
+
export function getJob(id: JobId): JobData | undefined {
|
|
47
|
+
return jobs.find(job => job.jobId === id)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// End the job with success
|
|
52
|
+
export function jobSuccess(id: JobId, message = ''): boolean {
|
|
53
|
+
return end(id, JobStatus.SUCCESS, message)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// End the job with error
|
|
57
|
+
export function jobError(id: JobId, message = ''): boolean {
|
|
58
|
+
return end(id, JobStatus.ERROR, message)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Remove a job from memory
|
|
62
|
+
// This is also used in unit tests to avoid memory lea
|
|
63
|
+
export function killJob(job: JobData) {
|
|
64
|
+
clearTimeout(timers.get(job))
|
|
65
|
+
timers.delete(job)
|
|
66
|
+
jobs.splice(jobs.findIndex(j => job.jobId === j.jobId), 1)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// End the job
|
|
70
|
+
function end(id: JobId, status: JobStatus, message = ''): boolean {
|
|
71
|
+
const job = getJob(id)
|
|
72
|
+
if(job) {
|
|
73
|
+
job.status = status
|
|
74
|
+
if(message) job.message = message
|
|
75
|
+
timers.set(job, setTimeout(() => killJob(job), TIME_TO_KEEP_AFTER_STOP))
|
|
76
|
+
return true
|
|
77
|
+
}
|
|
78
|
+
return false
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Type definition of the job manager
|
|
82
|
+
export interface JobManager {
|
|
83
|
+
startJob: typeof startJob
|
|
84
|
+
jobSuccess: typeof jobSuccess
|
|
85
|
+
jobError: typeof jobError
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Export the job manager
|
|
89
|
+
export const jobManager: JobManager = { startJob, jobSuccess, jobError }
|