This documentation guides developers through the process of configuring Silex to use existing connectors or implementing custom storage and hosting connectors.
Connectors are written in Node.js and can be implemented using either JavaScript or TypeScript. The default connectors used by Silex are FsStorage
and FsHosting
, which operate on the file system.
A connector can implement either storage, hosting, or both.
A storage connector is responsible for storing website data. This includes pages, components, symbols, fonts, settings, and assets. Storage connectors can be anything that can store data, such as databases (SQL, NoSQL), file systems, cloud storage services (e.g., AWS S3, Google Cloud Storage), or any other data storage solution.
A hosting connector is used for hosting files online. These connectors manage the hosting and serving of the website's static files. Examples of hosting connectors can include web servers (Apache, Nginx), cloud hosting services (e.g., AWS EC2, Google Compute Engine), or Content Delivery Networks (CDNs).
Once Silex has been configured with connectors, they will enable the user to login and use them from Silex
Here are the storage connectors in the Dashboard:
Here are the same connectors inside the editor (when the user has been logged out):
Here are the hosting connectors:
This is the FTP login form which is provided by the FTP connector:
To use an existing storage or hosting connector, you need to interact with the Silex ServerConfig
object within your .silex.js
file or in your custom plugin.
Here is an example of the config file used for v3.silex.me and here is the real life code
// .silex.js config file or in a plugin file
const { ConnectorType } = require('@silexlabs/silex/dist/server/types')
const FtpConnector = require('@silexlabs/silex/dist/plugins/server/plugins/server/FtpConnector').default
const GitlabConnector = require('@silexlabs/silex/dist/plugins/server/plugins/server/GitlabConnector').default
const dash = require('@silexlabs/silex-dashboard')
module.exports = async function (config) {
await config.addPlugin(dash)
config.setHostingConnectors([
new FtpConnector(config, {
type: ConnectorType.HOSTING,
}),
])
config.setStorageConnectors([
new FtpConnector(config, {
type: ConnectorType.STORAGE,
}),
new GitlabConnector(config, {
clientId: process.env.GITLAB_CLIENT_ID,
clientSecret: process.env.GITLAB_CLIENT_SECRET,
scope: process.env.GITLAB_SCOPE,
}),
])
}
In the example above, FtpConnector
is both a storage and hosting connector and GitLabConnector
is a storage connector. They are both part of Silex core, provided as plugin you can use without installing them.
You create an instance of each connector, and then use the setStorageConnector
and setHostingConnector
methods on the config object to add them.
Or you could have kept Silex default connectors and added other connectors with addStorageConnector
and addHostingConnector
Here are the methods available on the Silex ServerConfig
object to interact with connectors:
addStorageConnector(storage: StorageConnector | StorageConnector[]): Adds a new storage connector or an array of storage connectors.
setStorageConnectors(storageConnectors: StorageConnector[]): Sets the array of storage connectors that Silex can use.
getStorageConnectors(): StorageConnector[]: Returns the array of storage connectors that Silex is currently using.
addHostingConnector(hosting: HostingConnector | HostingConnector[]): Adds a new hosting connector or an array of hosting connectors.
setHostingConnectors(hostings: HostingConnector[]): Sets the array of hosting connectors that Silex can use.
getHostingConnectors(): HostingConnector[]: Returns the array of hosting connectors that Silex is currently using.
see https://docs.gitlab.com/ee/integration/oauth_provider.html#create-a-user-owned-application
Your redirect url should be : https://[yourdomain]/api/connector/login/callback
If you'd like to create custom storage and hosting connectors, you can follow a similar process as configuring existing connectors.
Here's an example:
// In your .silex.js config file or in your custom plugin
export default function(config) {
class MyStorageConnector {
// Your implementation here
}
class MyHostingConnector {
// Your implementation here
}
config.addStorageConnector(new MyStorageConnector());
config.addHostingConnector(new MyHostingConnector());
return {}; // This will be merged into the config object
}
In the example above, MyStorageConnector
and MyHostingConnector
would need to implement the connector interfaces described in the code
/**
* Connectors are the base interface for Storage and Hosting connectors
*/
export interface Connector<Session extends ConnectorSession = ConnectorSession> {
connectorId: ConnectorId
connectorType: ConnectorType
displayName: string
icon: string
disableLogout?: boolean
color: string
background: string
// Get the URL to start the authentication process with OAuth (not used for basic auth)
getOAuthUrl(session: Session): Promise<string | null>
// Get the form to display to the user to authenticate (not used for OAuth)
getLoginForm(session: Session, redirectTo: string): Promise<string | null>
// Get the form to display to the user to set the connector settings for a given website
getSettingsForm(session: Session, redirectTo: string): Promise<string | null>
// Auth and user management
isLoggedIn(session: Session): Promise<boolean>
setToken(session: Session, token: object): Promise<void>
logout(session: Session): Promise<void>
getUser(session: Session): Promise<ConnectorUser>
// Handle website meta file
getWebsiteMeta(session: Session, websiteId: WebsiteId): Promise<WebsiteMeta>
setWebsiteMeta(session: Session, websiteId: WebsiteId, data: WebsiteMetaFileContent): Promise<void>
// Get the connector options from login form
// They are stored in the website meta file for hosting connectors
// And in the user session for storage connectors
getOptions(formData: object): ConnectorOptions
}
/**
* Storage are used to store the website data and assets
* And possibly rename files and directories, and get the URL of a file
*
*/
export interface StorageConnector<Session extends ConnectorSession = ConnectorSession> extends Connector<Session> {
// CRUD on websites
listWebsites(session: Session): Promise<WebsiteMeta[]>
readWebsite(session: Session, websiteId: WebsiteId): Promise<WebsiteData | Readable>
createWebsite(session: Session, data: WebsiteMetaFileContent): Promise<WebsiteId>
updateWebsite(session: Session, websiteId: WebsiteId, data: WebsiteData): Promise<void>
deleteWebsite(session: Session, websiteId: WebsiteId): Promise<void>
// CRUD on assets
writeAssets(session: Session, websiteId: WebsiteId, files: ConnectorFile[], status?: StatusCallback): Promise<void>
readAsset(session: Session, websiteId: WebsiteId, fileName: string): Promise<ConnectorFileContent>
deleteAssets(session: Session, websiteId: WebsiteId, fileNames: string[]): Promise<void>
//getFileUrl(session: Session, websiteId: WebsiteId, path: string): Promise<string>
}
/**
* Hosting connectors are used to publish the website
*/
export interface HostingConnector<Session extends ConnectorSession = ConnectorSession> extends Connector<Session> {
publish(session: Session, websiteId: WebsiteId, files: ConnectorFile[], jobManager: JobManager): Promise<JobData> // Pass the jobManager as plugins do not neccessarily share the same module instance
getUrl(session: Session, websiteId: WebsiteId): Promise<string>
}