FaxStore
Creating an extension is a fairly simple process if the basics of JavaScript are known. Extensions come with access to local variables through the exported function along with global variables and event. Extensions should follow recommendations to ensure that the structure between extensions is similar. For example, if a config file is present for an extension.
Table of Contents
Extensions support two file types:
JavaScript (.js)
Sharf (.sharf) these are encrypted Weblutions files, generally present in sold or locked extensions
If an extension is being sold, it can be submitted to Weblutions for assessment and be encrypted.
There is currently no public Sharf encryption access.
If an extension is requiring a configuration file it's recommended to place them into the configs folder inside the extensions folder (/faxstore/extensions/configs/example-config.json). This helps with consistency between extensions and to create less config file clutter in the main extensions folder.
Rendered pages should be kept in the extensions folder within views (/faxstore/src/views/extensions/file.ejs). Other items or directories in views may be overwritten in updates, the views extension folder is not updated.
Keep extension file names and configuration files unique to avoid conflicting file names with other extensions, whether that's added a seed, version number, or developer name in front of the extension files. For example the below examples use two methods to make the file name unique and have less risk of being the same name from other developers.
cooldev-fileuploader-config.json, or;
20304834-fileuploader-config.json
cooldev-fileuploader.js, or;
20304834-fileuploader.js
└── faxstore/
├── extensions/
│ ├── configs/
│ │ ├── exension1-config.json
│ │ └── extension3-config.json
│ ├── extension1.js
│ ├── extension2.js
│ └── extension3.sharf
└── src/
├── static
├── backend
├── pages
├── views/
│ └── extensions/
│ └── extension1.ejs
├── index.js
├── backend.js
├── updatemanager.js
└── setup.jsAny extension within the FaxStore extensions folder will attempt to execute. If it loads or doesn't load it will be logged at start-up. Therefore, it's not recommended to have a "my extension starting" log to the console as FaxStore does this.
There's some content worth learning or at least being aware of before making an extension, such as the express JS eco-system, and MySQL if there's any plans to perform databasing actions. Some resources to learn are linked below
MySQL Package Documentation
FaxStore uses a pool connection which is a connection globally accessible in FaxStore via connection. Generally, the query() function is used to execute MySQL content.
Discord.js v14 Documentation
Recommended if an extension is using the Discord bot, it's also recommended to view the Discord Integration Documentation as well.
A base extension file without having any actual functionality other than having it setup for the environment should look like the below. This ensures database, express, and other functions can be used by the extension.
testext.js
const config = require('../config.json'); // Original Config For Faxstore
const extConfig = require('./configs/EXTENSION_CONFIG.json'); // Extensions config, these should be created for extensions. Full path; extensions/configs/file.json
/*
module.exports params:
- app: ExpressJS application.
- connection: MySQL connection
- bot: Discord bot
- faxstore: FaxStore event system
*/
module.exports = async function(app, connection, bot, faxstore) {
console.log(`Extension started!`);
app.get(`/myextension`, function(req, res) {
res.send(`Here is a page running!`);
});
}Create the base extension file and name it something unique. In this guide we'll use test-helloworld.js
Seeming this extension doesn't need a config file the above base extension file can be used without the configuration content
The app.get() function creates a GET request on the express application.
The res.send() function sends the content as plain text to the users browser.
module.exports = async function(app, connection, bot, faxstore) {
app.get(`/hello-world`, function(req, res) {
res.send(`Hello world of FaxStore!`);
});
}Save the extension file and upload it to the FaxStore extensions folder
Restart FaxStore and see it load in the console
Next learn how to register an extension. It's always recommended to register FaxStore extensions to have it displayed and populate properly on the FaxStore staff pages
This extension will use the FaxStore Global cache to get the logged in user, otherwise a redirect to the login page will be performed. Data will be returned in JSON form.
Create the base extension file and name it something unique. In this guide we'll use test-fetchuser.js
Seeming this extension doesn't need a config file the above base extension file can be used without the configuration content.
Add the app.get for a "/@me" route
module.exports = async function(app, connection, bot, faxstore) {
app.get(`/@me`, function(req, res) {
});
}Now by using a req.isAuthenticated() function it can be determined if the user is logged in when navigating to @me, this function returns a true or false. Adding this to an if statement would be an easy way to do this.
After, the res.redirect() function from express can be used to redirect the user to the specified page.
module.exports = async function(app, connection, bot, faxstore) {
app.get(`/@me`, function(req, res) {
if(req.isAuthenticated() == false) return res.redirect('/login');
});
}Add the return if the user is authenticated by adding the res.json() function for the user object which that data can be captured from the global cache.
module.exports = async function(app, connection, bot, faxstore) {
app.get(`/@me`, function(req, res) {
if(req.isAuthenticated() == false) return res.redirect('/login');
let user = CACHE.customers.find(f => f.id === req.user.id) || {};
return res.json(user);
});
}This will return the user data if found in the cache, otherwise an empty object ({}) is provided.
It's best to use data that FaxStore directly stores and that is updated. While the req.user object contains most user data, it may not be the most up to date in the database. Hence why the cache is used for this data. It's also better on a security level in the event data is injected by a user into the session data which could occur from a bad actor.
Both of these examples are fairly basic. However, they provide a nice base and starting point. Extensions can get complex pretty easily and have many functions. Reach out to our amazing Discord community for assistance in creating content and extensions.