@silexlabs/silex 3.0.0-alpha.39 → 3.0.0-alpha.41
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/.silex.js +38 -8
- package/dist/client/client/config.d.ts +11 -41
- package/dist/client/client/grapesjs/LoginDialog.d.ts +13 -0
- package/dist/client/client/grapesjs/PublicationManager.d.ts +69 -0
- package/dist/client/client/grapesjs/PublicationUi.d.ts +58 -0
- package/dist/client/client/grapesjs/index.d.ts +18 -44
- package/dist/client/client/grapesjs/storage.d.ts +1 -0
- package/dist/client/client/services.d.ts +35 -0
- package/dist/client/constants.d.ts +17 -0
- package/dist/client/css/admin.css +86 -3
- package/dist/client/js/main.js +201 -90
- package/dist/client/js/main.js.LICENSE.txt +6 -0
- package/dist/client/types.d.ts +200 -29
- package/dist/constants.d.ts +21 -0
- package/dist/constants.js +38 -1
- package/dist/constants.js.map +1 -0
- package/dist/events.d.ts +2 -0
- package/dist/events.js +17 -0
- package/dist/events.js.map +1 -0
- package/dist/plugins/AuthPlugin.d.ts +1 -0
- package/dist/plugins/AuthPlugin.js +38 -0
- package/dist/plugins/AuthPlugin.js.map +1 -0
- package/dist/plugins/Cache.d.ts +2 -0
- package/dist/plugins/Cache.js +32 -0
- package/dist/plugins/Cache.js.map +1 -0
- package/dist/plugins/FtpBackend.d.ts +92 -0
- package/dist/plugins/FtpBackend.js +604 -0
- package/dist/plugins/FtpBackend.js.map +1 -0
- package/dist/plugins/HooksPlugin.d.ts +7 -0
- package/dist/plugins/HooksPlugin.js +76 -0
- package/dist/plugins/HooksPlugin.js.map +1 -0
- package/dist/plugins/PublicationPlugin.d.ts +17 -0
- package/dist/plugins/PublicationPlugin.js +170 -0
- package/dist/plugins/PublicationPlugin.js.map +1 -0
- package/dist/plugins/SslPlugin.d.ts +1 -0
- package/dist/plugins/SslPlugin.js +86 -0
- package/dist/plugins/SslPlugin.js.map +1 -0
- package/dist/plugins/StaticPlugin.d.ts +1 -0
- package/dist/plugins/StaticPlugin.js +66 -0
- package/dist/plugins/StaticPlugin.js.map +1 -0
- package/dist/plugins/WebsitePlugin.d.ts +14 -0
- package/dist/plugins/WebsitePlugin.js +302 -0
- package/dist/plugins/WebsitePlugin.js.map +1 -0
- package/dist/server/backends/FsBackend.d.ts +42 -0
- package/dist/server/backends/FsBackend.js +269 -0
- package/dist/server/backends/FsBackend.js.map +1 -0
- package/dist/server/backends/index.d.ts +95 -0
- package/dist/server/backends/index.js +255 -0
- package/dist/server/backends/index.js.map +1 -0
- package/dist/server/cli.js +0 -1
- package/dist/server/config.d.ts +58 -0
- package/dist/server/config.js +128 -24
- package/dist/server/config.js.map +1 -0
- package/dist/server/express.js +31 -3
- package/dist/server/index.js +9 -20
- package/dist/server/jobs.d.ts +6 -0
- package/dist/server/jobs.js +75 -0
- package/dist/server/jobs.js.map +1 -0
- package/dist/server/utils/validation.d.ts +7 -0
- package/dist/server/utils/validation.js +37 -0
- package/dist/server/utils/validation.js.map +1 -0
- package/dist/types.d.ts +270 -0
- package/dist/types.js +35 -28
- package/dist/types.js.map +1 -0
- package/package.json +19 -8
- package/public/silex.js +17 -0
- package/src/css/dialog.scss +9 -2
- package/src/css/grapesjs.scss +79 -0
- package/src/css/project-bar.scss +2 -2
- package/src/example-client-config.js +17 -0
- package/src/html/templates/includes.pug +0 -1
- package/src/ts/client/config.ts +7 -6
- package/src/ts/client/grapesjs/LoginDialog.ts +190 -0
- package/src/ts/client/grapesjs/PublicationManager.ts +333 -0
- package/src/ts/client/grapesjs/PublicationUi.ts +320 -0
- package/src/ts/client/grapesjs/index.ts +88 -85
- package/src/ts/client/grapesjs/storage.ts +110 -0
- package/src/ts/client/index.ts +5 -7
- package/src/ts/client/services.ts +129 -0
- package/src/ts/constants.ts +21 -0
- package/src/ts/plugins/AuthPlugin.ts +38 -0
- package/src/ts/plugins/Cache.ts +28 -0
- package/src/ts/plugins/FtpBackend.ts +689 -0
- package/src/ts/plugins/HooksPlugin.ts +79 -0
- package/src/ts/plugins/PublicationPlugin.ts +170 -0
- package/src/{plugins/SslPlugin.js → ts/plugins/SslPlugin.ts} +24 -6
- package/src/ts/plugins/StaticPlugin.ts +68 -0
- package/src/ts/plugins/WebsitePlugin.ts +318 -0
- package/src/ts/server/backends/FsBackend.ts +266 -0
- package/src/ts/server/backends/index.ts +309 -0
- package/src/ts/server/cli.ts +0 -2
- package/src/ts/server/config.ts +103 -33
- package/src/ts/server/express.ts +37 -3
- package/src/ts/server/index.ts +24 -14
- package/src/ts/server/jobs.test.ts +74 -0
- package/src/ts/server/jobs.ts +77 -0
- package/src/ts/server/utils/validation.ts +33 -0
- package/src/ts/types.ts +167 -59
- package/dist/client/client/grapesjs/publish.d.ts +0 -18
- package/dist/page.js +0 -15
- 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/StaticPlugin.js +0 -48
- package/src/plugins/WebsitePlugin.js +0 -207
- package/src/ts/client/grapesjs/publish.ts +0 -403
- /package/.silex/default/{.silex.data.json → website.json} +0 -0
package/src/ts/types.ts
CHANGED
|
@@ -19,65 +19,9 @@
|
|
|
19
19
|
* @fileoverview define types for Silex client and server
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
//
|
|
23
|
-
export const defaultPublicationSettings: PublicationSettings = {
|
|
24
|
-
path: 'publication',
|
|
25
|
-
url: '',
|
|
26
|
-
autoHomePage: true,
|
|
27
|
-
assets: { path: 'assets', url: '/assets' },
|
|
28
|
-
html: { path: '' },
|
|
29
|
-
css: { path: 'css', url: '/css' },
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const defaultSite: WebsiteData = {
|
|
33
|
-
pages: [{name: 'Main', id: 'main', frames: [{component: {type: 'text', stylable: []}, components: []}]}],
|
|
34
|
-
assets: [],
|
|
35
|
-
styles: [],
|
|
36
|
-
name: 'New website',
|
|
37
|
-
settings: {
|
|
38
|
-
description: '',
|
|
39
|
-
title: '',
|
|
40
|
-
head: '',
|
|
41
|
-
lang: '',
|
|
42
|
-
favicon: '',
|
|
43
|
-
'og:title': '',
|
|
44
|
-
'og:description': '',
|
|
45
|
-
'og:image': '',
|
|
46
|
-
},
|
|
47
|
-
fonts: [],
|
|
48
|
-
symbols: [],
|
|
49
|
-
publication: defaultPublicationSettings,
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface WebsiteSettings {
|
|
53
|
-
description: string,
|
|
54
|
-
title: string,
|
|
55
|
-
lang: string,
|
|
56
|
-
head: string,
|
|
57
|
-
favicon: string,
|
|
58
|
-
'og:title': string,
|
|
59
|
-
'og:description': string,
|
|
60
|
-
'og:image': string,
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export interface WebsiteData {
|
|
64
|
-
pages: Page[],
|
|
65
|
-
assets: Asset[],
|
|
66
|
-
styles: Style[],
|
|
67
|
-
name: string,
|
|
68
|
-
settings: WebsiteSettings,
|
|
69
|
-
fonts: Font[],
|
|
70
|
-
symbols: symbol[],
|
|
71
|
-
publication: PublicationSettings,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface Font {
|
|
75
|
-
name: string,
|
|
76
|
-
value: string,
|
|
77
|
-
variants: string[],
|
|
78
|
-
}
|
|
22
|
+
// Publication API
|
|
79
23
|
export interface PublicationSettings {
|
|
80
|
-
|
|
24
|
+
backend?: BackendData, // Set by the postMessage from the login callback page
|
|
81
25
|
url?: string, // URL to display where the website is published to
|
|
82
26
|
autoHomePage?: boolean, // Name the first page `index` instead of its name
|
|
83
27
|
assets?: {
|
|
@@ -95,13 +39,73 @@ export interface PublicationSettings {
|
|
|
95
39
|
},
|
|
96
40
|
}
|
|
97
41
|
|
|
98
|
-
export interface
|
|
42
|
+
export interface WebsiteFile {
|
|
99
43
|
html: string,
|
|
100
44
|
css: string,
|
|
101
45
|
htmlPath: string,
|
|
102
46
|
cssPath: string,
|
|
103
47
|
}
|
|
104
48
|
|
|
49
|
+
export type ApiResponseError = { message: string }
|
|
50
|
+
export type ApiPublicationPublishRequestBody = WebsiteData
|
|
51
|
+
export type ApiPublicationPublishRequestQuery = { id: WebsiteId }
|
|
52
|
+
export type ApiPublicationPublishResponse = { url: string, job: PublicationJobData }
|
|
53
|
+
export type ApiPublicationStatusRequestQuery = { jobId: JobId }
|
|
54
|
+
export type ApiPublicationStatusResponse = PublicationJobData
|
|
55
|
+
export type ApiWebsiteReadRequestQuery = { id?: WebsiteId, backendId?: BackendId }
|
|
56
|
+
export type ApiWebsiteReadResponse = WebsiteMeta[] | WebsiteData
|
|
57
|
+
export type ApiWebsiteWriteRequestQuery = { id: WebsiteId, backendId?: BackendId }
|
|
58
|
+
export type ApiWebsiteWriteRequestBody = WebsiteData
|
|
59
|
+
export type ApiWebsiteWriteResponse = { message: string }
|
|
60
|
+
export type ApiWebsiteDeleteRequestQuery = { id: WebsiteId, backendId?: BackendId }
|
|
61
|
+
export type ApiWebsiteAssetsReadRequestQuery = { id: WebsiteId, backendId?: BackendId }
|
|
62
|
+
export type ApiWebsiteAssetsReadRequestParams = { path: string }
|
|
63
|
+
export type ApiWebsiteAssetsReadResponse = string
|
|
64
|
+
export type ApiWebsiteAssetsWriteRequestQuery = { id: WebsiteId, backendId?: BackendId }
|
|
65
|
+
export type ApiWebsiteAssetsWriteRequestBody = ClientSideFile[]
|
|
66
|
+
export type ApiWebsiteAssetsWriteResponse = { data: string[] }
|
|
67
|
+
export type ApiBackendListRequestQuery = { type: BackendType }
|
|
68
|
+
export type ApiBackendListResponse = BackendData[]
|
|
69
|
+
export type ApiBackendLoginRequestQuery = { backendId: BackendId, type: BackendType, options?: string, error?: string }
|
|
70
|
+
export type ApiBackendLoggedInPostMessage = { type: string, error: boolean, message: string, backendId: BackendId }
|
|
71
|
+
export type ApiBackendLogoutRequestQuery = { backendId: BackendId, type: BackendType }
|
|
72
|
+
export type ApiBackendLoginStatusRequestQuery = { id?: WebsiteId, backendId?: BackendId, type: BackendType }
|
|
73
|
+
export type ApiBackendLoginStatusResponse = { user: BackendUser, backend: BackendData, websiteMeta?: WebsiteMeta}
|
|
74
|
+
|
|
75
|
+
// **
|
|
76
|
+
// Website API
|
|
77
|
+
export interface WebsiteData {
|
|
78
|
+
pages: Page[],
|
|
79
|
+
assets: Asset[],
|
|
80
|
+
styles: Style[],
|
|
81
|
+
name: string,
|
|
82
|
+
settings: WebsiteSettings,
|
|
83
|
+
fonts: Font[],
|
|
84
|
+
symbols: symbol[],
|
|
85
|
+
publication: PublicationSettings,
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface PublicationData extends WebsiteData {
|
|
89
|
+
files?: WebsiteFile[], // Added by the client for publish
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface WebsiteSettings {
|
|
93
|
+
description: string,
|
|
94
|
+
title: string,
|
|
95
|
+
lang: string,
|
|
96
|
+
head: string,
|
|
97
|
+
favicon: string,
|
|
98
|
+
'og:title': string,
|
|
99
|
+
'og:description': string,
|
|
100
|
+
'og:image': string,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface Font {
|
|
104
|
+
name: string,
|
|
105
|
+
value: string,
|
|
106
|
+
variants: string[],
|
|
107
|
+
}
|
|
108
|
+
|
|
105
109
|
export interface Page {
|
|
106
110
|
name?: string,
|
|
107
111
|
id: string,
|
|
@@ -147,3 +151,107 @@ export type Selector = string | {
|
|
|
147
151
|
type: number,
|
|
148
152
|
}
|
|
149
153
|
|
|
154
|
+
// **
|
|
155
|
+
// Backend API
|
|
156
|
+
/**
|
|
157
|
+
* Type for a backend id
|
|
158
|
+
*/
|
|
159
|
+
export type BackendId = string
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Type for a client side file
|
|
163
|
+
* @see backend/File
|
|
164
|
+
*/
|
|
165
|
+
export interface ClientSideFile {
|
|
166
|
+
path: string,
|
|
167
|
+
content: Buffer | string
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Type for file listing
|
|
172
|
+
*/
|
|
173
|
+
export interface FileMeta {
|
|
174
|
+
name: string
|
|
175
|
+
isDir: boolean
|
|
176
|
+
size: number
|
|
177
|
+
createdAt: Date
|
|
178
|
+
updatedAt: Date
|
|
179
|
+
metadata?: object
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Enum to express if the backend is a storage or a hosting
|
|
184
|
+
*/
|
|
185
|
+
export enum BackendType {
|
|
186
|
+
STORAGE = 'STORAGE',
|
|
187
|
+
HOSTING = 'HOSTING',
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Type for a website id
|
|
192
|
+
*/
|
|
193
|
+
export type WebsiteId = string
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Back end data sent to the front end
|
|
197
|
+
*/
|
|
198
|
+
export interface BackendData {
|
|
199
|
+
backendId: BackendId
|
|
200
|
+
type: BackendType
|
|
201
|
+
displayName: string
|
|
202
|
+
icon: string
|
|
203
|
+
disableLogout: boolean
|
|
204
|
+
isLoggedIn: boolean
|
|
205
|
+
authUrl: string | null
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Back end data sent to the front end
|
|
210
|
+
*/
|
|
211
|
+
export interface BackendUser {
|
|
212
|
+
name: string
|
|
213
|
+
email?: string
|
|
214
|
+
picture?: string
|
|
215
|
+
metadata?: object
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Back end data sent to the front end
|
|
220
|
+
* Meta data can be the root path of the websites, or the bucket name, etc.
|
|
221
|
+
*/
|
|
222
|
+
export interface WebsiteMeta {
|
|
223
|
+
websiteId: WebsiteId
|
|
224
|
+
createdAt: Date
|
|
225
|
+
updatedAt: Date
|
|
226
|
+
metadata?: object
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Enum to express if the job is in progress or finished or errored
|
|
231
|
+
*/
|
|
232
|
+
export enum JobStatus {
|
|
233
|
+
IN_PROGRESS = 'IN_PROGRESS',
|
|
234
|
+
SUCCESS = 'SUCCESS',
|
|
235
|
+
ERROR = 'ERROR',
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Id used to track the progress of a publication
|
|
240
|
+
*/
|
|
241
|
+
export type JobId = string
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Data structure which is sent to the client to display the progress of a job
|
|
245
|
+
*/
|
|
246
|
+
export interface JobData {
|
|
247
|
+
jobId: JobId // The job id
|
|
248
|
+
status: JobStatus // status code
|
|
249
|
+
message: string // status to display
|
|
250
|
+
url?: string // url of the published website
|
|
251
|
+
_timeout?: ReturnType<typeof setTimeout> // Internal use
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export interface PublicationJobData extends JobData {
|
|
255
|
+
logs: string[][]
|
|
256
|
+
errors: string[][]
|
|
257
|
+
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export declare const cmdPublish = "publish-open-dialog";
|
|
2
|
-
export declare const publishPlugin: any;
|
|
3
|
-
export declare function getDialogElements(): {
|
|
4
|
-
dialog: Element;
|
|
5
|
-
primary: Element;
|
|
6
|
-
secondary: Element;
|
|
7
|
-
};
|
|
8
|
-
export declare const STATUS_NONE = "STATUS_NONE";
|
|
9
|
-
export declare const STATUS_PENDING = "STATUS_PENDING";
|
|
10
|
-
export declare const STATUS_ERROR = "STATUS_ERROR";
|
|
11
|
-
export declare const STATUS_SUCCESS = "STATUS_SUCCESS";
|
|
12
|
-
export declare let status: string;
|
|
13
|
-
export declare let open: boolean;
|
|
14
|
-
export declare function closeDialog(editor: any): Promise<void>;
|
|
15
|
-
export declare function toggleDialog(editor: any): Promise<void>;
|
|
16
|
-
export declare function openDialog(editor: any): Promise<void>;
|
|
17
|
-
export declare function startPublication(editor: any): Promise<void>;
|
|
18
|
-
export declare function trackProgress(editor: any, statusUrl: any): Promise<void>;
|
package/dist/page.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getPageLink = exports.getPageSlug = void 0;
|
|
4
|
-
function getPageSlug(pageName = 'index') {
|
|
5
|
-
return pageName
|
|
6
|
-
.toLowerCase()
|
|
7
|
-
.replace(/[^a-z0-9 -]/g, '')
|
|
8
|
-
.replace(/\s+/g, '-')
|
|
9
|
-
.replace(/-+/g, '-');
|
|
10
|
-
}
|
|
11
|
-
exports.getPageSlug = getPageSlug;
|
|
12
|
-
function getPageLink(pageName = 'index') {
|
|
13
|
-
return `./${getPageSlug(pageName)}.html`;
|
|
14
|
-
}
|
|
15
|
-
exports.getPageLink = getPageLink;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const express = require('express')
|
|
2
|
-
const { Directus } = require('@directus/sdk')
|
|
3
|
-
|
|
4
|
-
module.exports = async function(config, opts = {}) {
|
|
5
|
-
config.on('silex:startup:start', ({app}) => {
|
|
6
|
-
const router = express.Router()
|
|
7
|
-
router.post(['/publish', '/website', '/assets'], async function(req, res, next) {
|
|
8
|
-
try {
|
|
9
|
-
const token = req.body.token || opts.directusToken
|
|
10
|
-
const directus = new Directus(opts.directusUrl)
|
|
11
|
-
directus.storage.auth_token = token
|
|
12
|
-
const me = await directus.users.me.read()
|
|
13
|
-
next()
|
|
14
|
-
} catch(err) {
|
|
15
|
-
console.error('Publish failed in auth module. Did you provide a directus token?', err.message)
|
|
16
|
-
res.status(403).json({ message: err.message })
|
|
17
|
-
}
|
|
18
|
-
})
|
|
19
|
-
app.use(router)
|
|
20
|
-
})
|
|
21
|
-
}
|
package/src/plugins/Cache.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
exports.noCache = function (req, res, next) {
|
|
2
|
-
res.header('Cache-Control', 'private,no-cache,no-store,must-revalidate,proxy-revalidate')
|
|
3
|
-
res.header('Expires', '-1')
|
|
4
|
-
res.header('Pragma', 'no-cache')
|
|
5
|
-
next()
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
exports.withCache = function (req, res, next) {
|
|
9
|
-
res.header('Cache-Control', 'public,max-age=86400,immutable') // 24h
|
|
10
|
-
next()
|
|
11
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
const { readFile, writeFile, mkdir, copyFile, readdir, stat, rm } = require('node:fs/promises')
|
|
2
|
-
const { join, dirname, basename } = require('path')
|
|
3
|
-
const { homedir } = require('os')
|
|
4
|
-
|
|
5
|
-
//const { URLRewriter, URLTranslator } = require('cssurl')
|
|
6
|
-
|
|
7
|
-
async function mkdirIfNotExists(path, options = null) {
|
|
8
|
-
try {
|
|
9
|
-
return await mkdir(path, options)
|
|
10
|
-
} catch (err) {
|
|
11
|
-
if (err.code === 'EEXIST') {
|
|
12
|
-
return
|
|
13
|
-
} else {
|
|
14
|
-
throw err
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Paths
|
|
20
|
-
const FS_ROOT = process.env.FS_ROOT || join(homedir(), '.silex')
|
|
21
|
-
const ASSETS_PATH = 'assets'
|
|
22
|
-
const ASSETS_URL = 'assets'
|
|
23
|
-
const DATA_FILE_NAME = '/.silex.data.json'
|
|
24
|
-
const PUBLICATION_PATH = 'publication'
|
|
25
|
-
|
|
26
|
-
function path(id = 'default') {
|
|
27
|
-
return join(FS_ROOT, id)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
exports.assetsDir = async function (id) {
|
|
31
|
-
return join(path(id), ASSETS_PATH)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
exports.assetUrl = async function (id, fileName) {
|
|
35
|
-
return `${ASSETS_URL}/${fileName}`
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Init files for projects and each project
|
|
39
|
-
exports.init = async function (id) {
|
|
40
|
-
await mkdirIfNotExists(FS_ROOT)
|
|
41
|
-
const folder = path(id)
|
|
42
|
-
const uploadDir = join(folder, ASSETS_PATH)
|
|
43
|
-
await mkdirIfNotExists(uploadDir, { recursive: true, })
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
exports.del = async function (id) {
|
|
47
|
-
const folder = path(id)
|
|
48
|
-
console.log('Delete', folder)
|
|
49
|
-
await rm(folder, {recursive: true})
|
|
50
|
-
return {ok: true}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// List projects
|
|
54
|
-
exports.list = async function () {
|
|
55
|
-
try {
|
|
56
|
-
const ids = await readdir(FS_ROOT)
|
|
57
|
-
return Promise.all(ids.map(async id => ({
|
|
58
|
-
id,
|
|
59
|
-
...await exports.readData(id),
|
|
60
|
-
stats: await stat(path(id) + DATA_FILE_NAME),
|
|
61
|
-
})))
|
|
62
|
-
} catch (error) {
|
|
63
|
-
if (error.code === 'ENOENT') {
|
|
64
|
-
console.log(`\nError: Directory ${FS_ROOT} does not exist.\nIf your want to read from a different folder ues the FS_ROOT environment variable or --fs-root command line argument?\n`);
|
|
65
|
-
const betterError = new Error(`The directory ${FS_ROOT} does not exist`)
|
|
66
|
-
betterError.code = 'ENOENT'
|
|
67
|
-
throw betterError
|
|
68
|
-
}
|
|
69
|
-
throw error
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
// Read project data
|
|
73
|
-
exports.readData = async function (id) {
|
|
74
|
-
const filePath = path(id) + DATA_FILE_NAME
|
|
75
|
-
try {
|
|
76
|
-
const data = await readFile(filePath)
|
|
77
|
-
return JSON.parse(data.toString())
|
|
78
|
-
} catch (error) {
|
|
79
|
-
if (error.code === 'ENOENT') {
|
|
80
|
-
console.log(`\nError: File ${filePath} or directory ${FS_ROOT} do not exist.\nIf your want to read from a different folder use the FS_ROOT environment variable or --fs-root command line argument?\n`);
|
|
81
|
-
const betterError = new Error(`The website ${id} does not exist`)
|
|
82
|
-
betterError.code = 'ENOENT'
|
|
83
|
-
throw betterError
|
|
84
|
-
}
|
|
85
|
-
throw error
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// Write project data
|
|
89
|
-
exports.writeData = async function (id, data) {
|
|
90
|
-
return writeFile(path(id) + DATA_FILE_NAME, JSON.stringify(data))
|
|
91
|
-
}
|
|
92
|
-
function required(prop, name) {
|
|
93
|
-
if (!prop) throw new Error(`Error missing required param ${name}`)
|
|
94
|
-
}
|
|
95
|
-
exports.publish = async function (id, files, data) {
|
|
96
|
-
const { assets, settings, publication } = data
|
|
97
|
-
required(assets, 'assets')
|
|
98
|
-
required(files, 'files')
|
|
99
|
-
required(id, 'id')
|
|
100
|
-
const folder = path(id)
|
|
101
|
-
const publicationDir = join(folder, publication?.path || PUBLICATION_PATH)
|
|
102
|
-
|
|
103
|
-
// HTML and CSS
|
|
104
|
-
await Promise.all(files
|
|
105
|
-
.map(async (file) => {
|
|
106
|
-
// // Process the page CSS to have correct relative URLs
|
|
107
|
-
// let css = file.css
|
|
108
|
-
// try {
|
|
109
|
-
// if(settings?.html?.path != settings?.css?.path) {
|
|
110
|
-
// const rewriter = new URLRewriter(function(url) {
|
|
111
|
-
// const translator = new URLTranslator()
|
|
112
|
-
// return translator.translate(url, settings?.html?.path, settings?.css?.path)
|
|
113
|
-
// })
|
|
114
|
-
// css = rewriter.rewrite(css)
|
|
115
|
-
// }
|
|
116
|
-
// } catch (err) {
|
|
117
|
-
// console.error('Error processing CSS', err, file)
|
|
118
|
-
// throw new Error(`Error processing CSS. ${err.message}`)
|
|
119
|
-
// }
|
|
120
|
-
try {
|
|
121
|
-
// Paths
|
|
122
|
-
const htmlPath = join(publicationDir, file.htmlPath)
|
|
123
|
-
const cssPath = join(publicationDir, file.cssPath)
|
|
124
|
-
// Init
|
|
125
|
-
await mkdirIfNotExists(dirname(htmlPath), { recursive: true, })
|
|
126
|
-
await mkdirIfNotExists(dirname(cssPath), { recursive: true, })
|
|
127
|
-
// Write
|
|
128
|
-
await writeFile(htmlPath, file.html)
|
|
129
|
-
await writeFile(cssPath, file.css)
|
|
130
|
-
} catch (err) {
|
|
131
|
-
throw new Error(`Publication error: could not write files ${file.cssPath} and ${file.htmlPath}. ${err.message}`)
|
|
132
|
-
}
|
|
133
|
-
}))
|
|
134
|
-
// Assets
|
|
135
|
-
const assetsFolder = join(publicationDir, publication?.assets?.path || ASSETS_PATH)
|
|
136
|
-
await mkdirIfNotExists(assetsFolder, { recursive: true, })
|
|
137
|
-
|
|
138
|
-
assets.forEach(async asset => {
|
|
139
|
-
required(asset.src, 'asset\'s "src" attribute')
|
|
140
|
-
const src = join(folder, asset.src)
|
|
141
|
-
const dst = join(assetsFolder, basename(asset.src))
|
|
142
|
-
try {
|
|
143
|
-
await copyFile(src, dst)
|
|
144
|
-
} catch (err) {
|
|
145
|
-
throw new Error(`Publication error: could not copy asset file ${src} to ${dst}. ${err.message}`)
|
|
146
|
-
}
|
|
147
|
-
})
|
|
148
|
-
return publication?.url
|
|
149
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const bodyParser = require('body-parser')
|
|
2
|
-
const compression = require('compression')
|
|
3
|
-
const cookieParser = require('cookie-parser')
|
|
4
|
-
const session = require('cookie-session')
|
|
5
|
-
const cors = require('cors')
|
|
6
|
-
|
|
7
|
-
module.exports = async function(config, opts = {}) {
|
|
8
|
-
// Options with defaults
|
|
9
|
-
const options = {
|
|
10
|
-
jsonLimit: process.env.SILEX_EXPRESS_JSON_LIMIT || '1mb',
|
|
11
|
-
textLimit: process.env.SILEX_EXPRESS_TEXT_LIMIT || '10mb',
|
|
12
|
-
sessionName: process.env.SILEX_SESSION_NAME || 'silex-session',
|
|
13
|
-
sessionSecret: process.env.SILEX_SESSION_SECRET || 'replace this session secret in env vars',
|
|
14
|
-
cors: process.env.SILEX_CORS_URL,
|
|
15
|
-
...opts,
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
config.on('silex:startup:start', ({app}) => {
|
|
19
|
-
// CORS
|
|
20
|
-
if (options.cors) {
|
|
21
|
-
console.log('> CORS are ENABLED:', options.cors)
|
|
22
|
-
app.use(cors({
|
|
23
|
-
origin: options.cors,
|
|
24
|
-
}))
|
|
25
|
-
}
|
|
26
|
-
// compress gzip when possible
|
|
27
|
-
app.use(compression())
|
|
28
|
-
|
|
29
|
-
// cookie & session
|
|
30
|
-
app.use(bodyParser.json({limit: options.jsonLimit}))
|
|
31
|
-
app.use(bodyParser.text({limit: options.textLimit}))
|
|
32
|
-
app.use(cookieParser())
|
|
33
|
-
app.use(session({
|
|
34
|
-
name: options.sessionName,
|
|
35
|
-
secret: options.sessionSecret,
|
|
36
|
-
}))
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { Config } from '../config'
|
|
2
|
-
import { EVENT_WRITE_END, EVENT_ASSET_WRITE_END } from './WebsitePlugin'
|
|
3
|
-
import { EVENT_PUBLISH_END } from './PublishPlugin'
|
|
4
|
-
import fetch from 'node-fetch'
|
|
5
|
-
import { projectPath, assetsDir } from '../project'
|
|
6
|
-
|
|
7
|
-
// type HooksOptions = {
|
|
8
|
-
// gitUrl?: string
|
|
9
|
-
// buildUrl?: string
|
|
10
|
-
// }
|
|
11
|
-
|
|
12
|
-
const rootPath = process.env.DATA_FOLDER
|
|
13
|
-
|
|
14
|
-
module.exports = async function(config, opts = {}) {
|
|
15
|
-
// Options with defaults
|
|
16
|
-
const options = {
|
|
17
|
-
gitUrl: process.env.SILEX_HOOK_GIT,
|
|
18
|
-
buildUrl: process.env.SILEX_HOOK_BUILD,
|
|
19
|
-
...opts
|
|
20
|
-
}
|
|
21
|
-
config.on(EVENT_WRITE_END, async ({ res, req, projectId, data }) => {
|
|
22
|
-
if(options.gitUrl) {
|
|
23
|
-
await hook(options.gitUrl, {
|
|
24
|
-
path: projectPath(projectId),
|
|
25
|
-
message: 'Change from Silex',
|
|
26
|
-
})
|
|
27
|
-
}
|
|
28
|
-
})
|
|
29
|
-
config.on(EVENT_ASSET_WRITE_END, async ({ res, req, projectId, uploadDir, form, data }) => {
|
|
30
|
-
if(options.gitUrl) {
|
|
31
|
-
await hook(options.gitUrl, {
|
|
32
|
-
path: projectPath(projectId),
|
|
33
|
-
message: 'Change from Silex',
|
|
34
|
-
})
|
|
35
|
-
}
|
|
36
|
-
})
|
|
37
|
-
config.on(EVENT_PUBLISH_END, async ({ projectId, files, req, res }) => {
|
|
38
|
-
if(options.buildUrl) {
|
|
39
|
-
await hook(options.buildUrl)
|
|
40
|
-
}
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
async function hook(url, params = {}) {
|
|
45
|
-
if(url) {
|
|
46
|
-
const urlObj = new URL(url)
|
|
47
|
-
console.log('Calling hook', {url})
|
|
48
|
-
try {
|
|
49
|
-
Object.keys(params)
|
|
50
|
-
.forEach(key => urlObj.searchParams.append(key, params[key]))
|
|
51
|
-
return fetch(urlObj.toString())
|
|
52
|
-
} catch(error) {
|
|
53
|
-
console.log('Hook call failed', {url, error})
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const express = require('express')
|
|
2
|
-
const { resolve } = require('path')
|
|
3
|
-
|
|
4
|
-
const { noCache } = require('./Cache')
|
|
5
|
-
const { minify } = require('html-minifier')
|
|
6
|
-
|
|
7
|
-
const router = express.Router()
|
|
8
|
-
|
|
9
|
-
// type PublishOptions = {
|
|
10
|
-
// statusUrl?: string
|
|
11
|
-
// }
|
|
12
|
-
|
|
13
|
-
module.exports = async function(config, opts = {}) {
|
|
14
|
-
const options = {
|
|
15
|
-
// Defaults
|
|
16
|
-
statusUrl: process.env.SILEX_PUBLICATION_STATUS_URL,
|
|
17
|
-
backend: 'src/plugins/DefaultBackend.js',
|
|
18
|
-
// Options
|
|
19
|
-
...opts,
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Link to the desired backend
|
|
23
|
-
const backend = resolve(__dirname, '../..', options.backend)
|
|
24
|
-
const { publish } = require(backend)
|
|
25
|
-
|
|
26
|
-
config.on('silex:startup:start', ({app}) => {
|
|
27
|
-
// Start publication
|
|
28
|
-
router.post('/publish', async function(req, res) {
|
|
29
|
-
const { pages, files, id } = req.body.data
|
|
30
|
-
if (!pages || !id) {
|
|
31
|
-
console.error('Error in the request, pages and id params required', {id})
|
|
32
|
-
res.status(400).send({
|
|
33
|
-
message: 'Error in the request, pages and id params required',
|
|
34
|
-
})
|
|
35
|
-
} else {
|
|
36
|
-
// Optim
|
|
37
|
-
files.forEach(file => {
|
|
38
|
-
file.html = minify(file.html, {
|
|
39
|
-
continueOnParseError: true,
|
|
40
|
-
collapseInlineTagWhitespace: true,
|
|
41
|
-
collapseWhitespace: true,
|
|
42
|
-
minifyCSS: true,
|
|
43
|
-
minifyJS: true,
|
|
44
|
-
removeScriptTypeAttributes: true,
|
|
45
|
-
removeStyleLinkTypeAttributes: true,
|
|
46
|
-
}).trim()
|
|
47
|
-
})
|
|
48
|
-
// Publication
|
|
49
|
-
await config.emit('silex:publish:start', { id, files, req})
|
|
50
|
-
let url
|
|
51
|
-
try {
|
|
52
|
-
url = await publish(id, files, req.body.data)
|
|
53
|
-
} catch (err) {
|
|
54
|
-
console.error('Error publishing the website', err)
|
|
55
|
-
res.status(500).json({ message: `Error publishing the website. ${err.message}`})
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
const mutable = { id, files, req, res, url, statusUrl: options.statusUrl }
|
|
59
|
-
await config.emit('silex:publish:end', mutable)
|
|
60
|
-
res.json({
|
|
61
|
-
url: mutable.url,
|
|
62
|
-
statusUrl: mutable.statusUrl,
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
app.use(noCache, router)
|
|
68
|
-
})
|
|
69
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
const express = require('express')
|
|
2
|
-
const nodeModules = require('node_modules-path')
|
|
3
|
-
const serveStatic = require('serve-static')
|
|
4
|
-
const { withCache } = require('./Cache')
|
|
5
|
-
|
|
6
|
-
const Path = require('path')
|
|
7
|
-
|
|
8
|
-
// type StaticOptions = {
|
|
9
|
-
// routes?: {
|
|
10
|
-
// path?: string
|
|
11
|
-
// route?: string
|
|
12
|
-
// module?: string
|
|
13
|
-
// }[]
|
|
14
|
-
// }
|
|
15
|
-
|
|
16
|
-
module.exports = async function(config, opts = {}) {
|
|
17
|
-
// Options with defaults
|
|
18
|
-
const options = {
|
|
19
|
-
rootPath: Path.join(__dirname, '../..'),
|
|
20
|
-
routes: [
|
|
21
|
-
{
|
|
22
|
-
route: '/',
|
|
23
|
-
path: 'public',
|
|
24
|
-
}, {
|
|
25
|
-
route: '/',
|
|
26
|
-
path: 'dist/client',
|
|
27
|
-
},
|
|
28
|
-
]
|
|
29
|
-
// add project route for source maps
|
|
30
|
-
.concat(config.debug ? [{
|
|
31
|
-
route: '/',
|
|
32
|
-
path: './',
|
|
33
|
-
}] : []),
|
|
34
|
-
...opts,
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
config.on('silex:startup:start', ({app}) => {
|
|
38
|
-
const router = express.Router()
|
|
39
|
-
options.routes
|
|
40
|
-
.forEach(folder => {
|
|
41
|
-
// either the module root folder or silex root folder
|
|
42
|
-
const path = Path.join(options.rootPath, folder.path || '')
|
|
43
|
-
if (!folder.route) throw new Error('The config for static module has no `route` attribute: ' + folder)
|
|
44
|
-
router.use(folder.route, serveStatic(path))
|
|
45
|
-
})
|
|
46
|
-
app.use(withCache, router)
|
|
47
|
-
})
|
|
48
|
-
}
|