Socket
Socket
Sign inDemoInstall

remake

Package Overview
Dependencies
Maintainers
2
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

remake - npm Package Compare versions

Comparing version 1.11.3 to 2.0.0

.prettierignore

55

index.js

@@ -1,6 +0,13 @@

const program = require('commander');
const Configstore = require('configstore');
const program = require("commander");
const Configstore = require("configstore");
const { clean, build, deploy, backup, updateFramework, create } = require('./utils/commands');
const { version, name } = require('./package.json');
const {
clean,
build,
deploy,
backup,
updateFramework,
create,
} = require("./utils/commands");
const { version, name } = require("./package.json");

@@ -10,42 +17,32 @@ log = console.log;

remakeCliConfig = new Configstore(name, { user: {} });
remakeServiceHost = 'https://remakeapps.com';
remakeServiceHost = "https://remakeapps.com";
program
.version('v' + version, '-v, --version', 'output the current version')
.name('remake')
.usage('command [--help]')
.version("v" + version, "-v, --version", "output the current version")
.name("remake")
.usage("command [--help]");
program
.command('create <projectDir>')
.description('Create a new Remake project')
.option('-m, --multitenant', 'create a multi tenant Remake app')
.command("create <projectDir>")
.description("Create a new Remake project")
.option("-m, --multitenant", "create a multi tenant Remake app")
.action((projectDir, options) => create(projectDir, options));
program
.command('update-framework')
.description('Update the Remake framework in your project')
.command("update-framework")
.description("Update the Remake framework in your project")
.action(() => updateFramework());
program
.command('deploy')
.description('Deploy your Remake app on the Remake server')
.command("deploy")
.description("Deploy your Remake app on the Remake server")
.action(() => deploy());
program
.command('build')
.description('Build your Remake app')
.action(() => build());
program
.command('clean')
.description('Wipe the local Remake environment including caches and build assets')
.action(() => clean());
program
.command('backup')
.description('Backup the deployed version of your app')
.command("backup")
.description("Backup the deployed version of your app")
.action(() => backup());
module.exports = async () => {
program.parse(process.argv)
}
program.parse(process.argv);
};
{
"name": "remake",
"version": "1.11.3",
"version": "2.0.0",
"description": "Generate a full-stack Remake web app",

@@ -35,2 +35,3 @@ "license": "MIT",

"form-data": "^2.5.1",
"husky": "^4.3.0",
"inquirer": "^7.0.0",

@@ -40,5 +41,14 @@ "nanoid": "^2.0.3",

"ora": "^4.0.2",
"replace": "^1.2.0",
"rimraf": "^3.0.0",
"shelljs": "^0.8.4"
},
"devDependencies": {
"prettier": "2.1.2"
},
"husky": {
"hooks": {
"pre-commit": "prettier --check ."
}
}
}

@@ -1,190 +0,110 @@

<h1>Remake</h1>
<p align="center">
<a href="https://storybook.js.org/">
<img src="https://user-images.githubusercontent.com/364330/98124113-bc603180-1e80-11eb-882e-e2246940c7a4.png" alt="Remake" width="400" />
</a>
</p>
### An easy-to-use web app framework
<p align="center">Build full-stack web apps with only HTML and CSS</p>
* **Create editable pages using only HTML templates**
* **Easy to learn, powerful data attribute syntax**
* **Perfect for rapidly prototyping ideas**
<br/>
<p align="center">
<a href="https://github.com/remake/remake-cli/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/remake/remake-cli" alt="License" />
</a>
<a href="https://discord.gg/FB3gNxw">
<img src="https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat" alt="Discord Channel" />
</a>
<a href="https://github.com/sponsors/remake">
<img src="https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&link=<url>" alt="Sponsor" />
</a>
<a href="https://twitter.com/intent/follow?screen_name=remaketheweb">
<img src="https://badgen.net/twitter/follow/remaketheweb?icon=twitter&label=%40remake" alt="Remake Twitter" />
</a>
</p>
## Get started
Remake is a simple, open source framework. It lets you transform a static website into an interactive, editable web app with a few custom HTML attributes.
1. Install the command line tool
- Simple syntax
- User accounts & persistent data
- Inline editing & file uploads
- No backend coding
```
npm install remake -g
```
<b><a href="https://blog.remaketheweb.com/intro-to-remake-part-1-make-web-apps-with-html/">→ Learn more about Remake</a></b>
2. Create a new project
## Why Remake?
```
remake create <project-dir>
```
> What if every HTML webpage knew how to save, edit, and add new items to itself?
3. Run the development server
![Diagram of how Remake works](https://user-images.githubusercontent.com/364330/98125645-b5d2b980-1e82-11eb-909f-527bf0ff224e.png)
```
cd <project-dir>
npm run dev
```
Remake is ideal for indie hackers who want to build editable web apps quickly. Have you ever created a static website and wished people could just start using it? Remake lets you do that.
4. Start building a web app with Remake!
- **Remake lets you build full-stack apps with front-end code.** Remake comes with user accounts, a persistent database, and everything you need to deploy a working application.
- **Remake lets you build CMS-like features on top of a static template.** Users can login to your site and edit their own copy of it.
- **Remake is so easy to use it feels like prototyping.** But it's designed for building scalable, production web apps.
- **Remake gives you control over your design.** You can use any CSS framework and style your pages however you want.
- **Remake is server rendered.** This makes it ideal for SEO and loading pages quickly. The front-end framework isn't even loaded if a user can't edit the current page.
<b><a href="#">→ Learn what makes Remake different</a></b> (coming later today)
## Example
## Get started
![Todos example app](https://remake-website.s3.amazonaws.com/todos-example.gif)
**1. Install [Node.js (12.16+)](https://nodejs.org/)**
*An example of editing, adding, and removing items with the starter todos project.*
**2. Create a project using the Remake CLI**
## What is Remake?
**Remake is everything you need to create a web app in record time, with very little overhead.**
Remake provides all the tools you need to:
* Instantly add [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) to your page
* Have all your pages' data auto-save after it's been edited
* Store your data in a format that's easy to access and understand
Out of the box, Remake comes with:
* **User accounts:** People can sign up and log in to your app!
* **Flat file database:** No need to install, configure, or host a database
* **Simple data handling:** Accessing and saving nested objects is easy
If you know how to build a website with HTML and CSS — and know the basics of [Handlebars](https://handlebarsjs.com/) templating — you can build a full web app with Remake!
## Quickstart resources
* [A simple todo list app in 12 lines of HTML](https://docs.remaketheweb.com/a-simple-example-app/)
* [30 minute tutorial on how to build a Trello clone](https://tutorials.remaketheweb.com/)
## How does it work?
Remake is based around a simple idea:
**What if every HTML webpage knew how to save, edit, and add new items to itself?**
* Remake uses simple data attributes, starting with `data-o` for attributes that output data and starting with `data-i` for attributes that input data
* Using a simple data attribute (`data-i-editable`), you can make the data on an element editable and have it auto-save to the database
* Using another simple data attribute (`data-i-new`), you can easily render back-end partial templates and add them to the page
## Get to know how the data works
#### Saving Data
HTML is formatted like a tree 🌳 in that it has a root node and every other element on a page branches off of that root node.
So, what if we were able to transform HTML into an **object** that we could save to a database just by looking at its natural tree structure?
We can do this in Remake by tagging elements with data. **Remake will parse and save this data automatically** whenever it changes.
Here's how it works in Remake:
```html
<div data-o-type="object"></div>
```
This element has been tagged as an `Object`, which means Remake will convert it into this:
```javascript
{}
npx remake create my-app
```
Let's go through a few more examples:
**3. Run the project**
##### 1. Key/value pairs
```html
<div data-o-type="object" data-o-key-name="David"></div>
```
This will be converted into an object with a key/value pair inside of it:
```javascript
{name: "David"}
cd my-app
npm run dev
```
The first attribute (`data-o-type`) tells us which data type to expect. It can be set to *only* `object` or `list`.
You now have an app running at `http://localhost:3000`. Your app's code is in the `/app` directory and your database is in the `/_remake-data` directory.
The second attribute (`data-o-key-name`) tells us that this `object` has a key of `name` (the key is always the part that comes after `data-o-key-`). And we look at the attribute's value to get the key's value.
<b><a href="https://docs.remaketheweb.com/introducing-remake/">→ Start learning how to build a web app with Remake</a></b>
##### 2. Nested data
## What can you build?
```html
<div data-o-type="object">
<div data-o-type="object" data-o-key="person" data-o-key-name="David">
</div>
</div>
```
Remake is **great at building page builders,** where each user can edit their own content.
This example is a bit more advanced, as it relies on **nested** elements to create **nested** data:
- **[Todo app](https://docs.remaketheweb.com/a-simple-example-app/)** (Build time: 7 min)
- **[Trello clone](https://tutorials.remaketheweb.com/)** (Build time: 30 min)
- (In progress) **[Resume builder](https://resume-builder-remake.netlify.app/)** (Build time: 30 min)
- (In progress) [**Reading list builder**](https://shelfpage.remakeapps.com/) (Build time: 30 min)
- **Landing page builder** (planned)
- **Directory website builder** (planned)
```javascript
{person: {name: "David"}}
```
<b><a href="https://blog.remaketheweb.com/intro-to-remake-part-2-what-you-can-and-cant-build/">→ Learn what else you can build with Remake</a></b>
In this example, we use the `data-o-key` attribute — with nothing after it — to create an object inside of an object. The value of `data-o-key` tells us which key the nested object will be.
![Trello clone built with Remake](https://user-images.githubusercontent.com/364330/98126081-2f6aa780-1e83-11eb-8367-e582daaf8997.png)
#### 3. Lists/Arrays of objects
<p align="center">An example app built with Remake in 30 minutes</p>
Let's look at the only other data type that Remake supports: `Arrays`. In Remake, we use the term `list`.
## Remake’s Mission
How do we create a list in Remake?
Remake aims to equalize power on the internet. A few companies own the platforms where the rest of us publish posts and websites — but owning a platform is usually beyond our reach. Remake switches this narrative and empowers you to build your own publishing platform.
```html
<div data-o-type="list"></div>
```
<b><a href="https://discord.gg/FB3gNxw">→ Join and contribute to our Discord community</a></b>
This is a pretty simple example and will compile into just a simple, empty array:
## Contributing
```
[]
```
Remake is an open-source, and contributions are always welcome. If you identify with Remake's mission, we'd be delighted to have you on board!
How would we go about adding objects to this array? We'd just nest them of course!
- Report bugs
- Suggest features
- Fix issues
- Improve documentation
- Make and share tutorials
```html
<div data-o-type="list">
<div data-o-type="object" data-o-key-name="David">
<div data-o-type="object" data-o-key-name="John">
<div data-o-type="object" data-o-key-name="Mary">
</div>
```
<b><a href="https://github.com/remake/remake-cli/issues/new?assignees=&labels=&template=feature_request.md&title=My%20first%20issue">→ Start by creating your first issue</a></b>
When Remake looks at this, all it sees is:
## Our Contributors
```javascript
[
{name: "David"},
{name: "John"},
{name: "Mary"}
]
```
## Stay in the loop
Sign up for [the newsletter](https://form.remaketheweb.com/) to get updates as this framework develops
## Find out more
* [Contact the author on Twitter](https://twitter.com/panphora)
* [View the public roadmap](https://trello.com/b/BXvugSjT/remake)
* [View a live production app: RequestCreative](https://requestcreative.com)
## Contributors
* **[Andrew de Jong](https://gitlab.com/android4682)**
- [Andrew de Jong](https://gitlab.com/android4682)
- [Painatalman](https://github.com/Painatalman)

@@ -1,13 +0,18 @@

const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const shell = require('shelljs');
const inquirer = require('inquirer');
const { promisify } = require('es6-promisify');
const rimraf = promisify(require('rimraf'));
const ora = require('ora');
const process = require('process');
const fs = require("fs");
const path = require("path");
const chalk = require("chalk");
const shell = require("shelljs");
const inquirer = require("inquirer");
const { promisify } = require("es6-promisify");
const rimraf = promisify(require("rimraf"));
const ora = require("ora");
const process = require("process");
const replace = require("replace");
const { readDotRemake, writeDotRemake, generateDotRemakeContent } = require('./dot-remake');
const {
readDotRemake,
writeDotRemake,
generateDotRemakeContent,
} = require("./dot-remake");
const {
registerUser,

@@ -20,14 +25,14 @@ checkSubdomain,

getAppsList,
backupApp } = require('./helpers');
const { questions } = require('./inquirer-questions');
const { showSuccessfulCreationMessage } = require('./messages');
backupApp,
} = require("./helpers");
const { questions } = require("./inquirer-questions");
const { showSuccessfulCreationMessage } = require("./messages");
const { exit } = require("process");
let spinner = null;
const create = async (projectDir, options) => {
const cwd = process.cwd();
const newProjectDirPath = path.join(cwd, projectDir);
let rimrafError = null;
const create = async (projectName, options) => {
const projectPath = getProjectPath(projectName);
if (fs.existsSync(newProjectDirPath)) {
if (fs.existsSync(projectPath)) {
log(chalk.bgRed("Error: Cannot write to a directory that already exists."));

@@ -37,51 +42,23 @@ process.exit();

// STEP 1
spinner = ora("Creating new project.").start();
shell.exec(`git clone --depth 1 https://github.com/remake/remake-framework.git ${projectDir}`, { silent: true });
spinner.succeed();
cloneRemakeFramework(projectName);
await removeDotGit(projectName);
cleanPackageJson(projectName);
moveReadme();
await setupTemplate();
installNpmPackages();
createDotRemakeFile(projectName, options);
initializeGitRepo();
process.exit(0);
};
// STEP 2a & 2b
spinner = ora("Tidy up new project directory.").start();
rimrafError = await rimraf(path.join(newProjectDirPath, ".git"));
if (rimrafError) {
spinner.fail(chalk.bgRed("Error: Couldn't remove old .git directory from new project."));
process.exit();
}
spinner.succeed();
// put project README in the right place
shell.mv(path.join(newProjectDirPath, "README-FOR-BUNDLE.md"), path.join(newProjectDirPath, "README.md"));
// STEP 3
spinner = ora("Installing npm dependencies.").start();
shell.cd(newProjectDirPath);
shell.exec("npm install", { silent: true });
spinner.succeed();
// STEP 4
// write project name and env variables to .remake file
spinner = ora("Setting up .remake").start();
const dotRemakeObj = {
...generateDotRemakeContent(options.multitenant)
}
spinner.succeed();
const dotRemakeReady = writeDotRemake(dotRemakeObj);
if (dotRemakeReady) {
showSuccessfulCreationMessage(projectDir);
}
}
const clean = () => {
let dotRemakeObj = readDotRemake();
if (!dotRemakeObj) {
log(chalk.bgRed('You are not in the root directory of a remake project.'));
log(chalk.bgRed("You are not in the root directory of a remake project."));
process.exit();
}
spinner = ora('Cleaning project.').start();
shell.exec('npm run clean', { silent:true });
spinner = ora("Cleaning project.").start();
shell.exec("npm run clean", { silent: true });
spinner.succeed();
}
};

@@ -91,7 +68,7 @@ const build = () => {

if (!dotRemakeObj) {
log(chalk.bgRed('You are not in the root directory of a remake project.'));
log(chalk.bgRed("You are not in the root directory of a remake project."));
process.exit();
}
spinner = ora('Building project.').start();
const result = shell.exec('npm run build', { silent: true });
spinner = ora("Building project.").start();
const result = shell.exec("npm run build", { silent: true });
if (result.code === 0) {

@@ -102,11 +79,8 @@ spinner.succeed();

}
}
};
const deploy = async () => {
clean();
build();
let dotRemakeObj = readDotRemake();
if (!dotRemakeObj) {
log(chalk.bgRed('You are not in the root directory of a remake project.'));
log(chalk.bgRed("You are not in the root directory of a remake project."));
process.exit();

@@ -118,16 +92,24 @@ }

const subdomainAnswer = await inquirer.prompt([questions.INPUT_SUBDOMAIN]);
spinner = ora(`Checking if ${subdomainAnswer.subdomain}.remakeapps.com is available`).start();
spinner = ora(
`Checking if ${subdomainAnswer.subdomain}.remakeapps.com is available`
).start();
// check if name is available
const isSubdomainAvailable = await checkSubdomain(subdomainAnswer.subdomain);
const isSubdomainAvailable = await checkSubdomain(
subdomainAnswer.subdomain
);
if (!isSubdomainAvailable) {
spinner.fail(`${subdomainAnswer.subdomain}.remakeapps.com is not available`);
spinner.fail(
`${subdomainAnswer.subdomain}.remakeapps.com is not available`
);
process.exit();
}
spinner.succeed(`${subdomainAnswer.subdomain}.remakeapps.com is available`);
// prompt yes to confirm
const confirmSubdomainAnswer = await inquirer.prompt([questions.CONFIRM_SUBDOMAIN]);
const confirmSubdomainAnswer = await inquirer.prompt([
questions.CONFIRM_SUBDOMAIN,
]);
if (confirmSubdomainAnswer.deployOk === false) {
log(chalk.bgRed('Stopped deployment.'));
log(chalk.bgRed("Stopped deployment."));
process.exit();

@@ -137,14 +119,18 @@ }

spinner = ora(`Registering ${subdomainAnswer.subdomain}`).start();
const subdomainRegistered = await registerSubdomain(subdomainAnswer.subdomain);
const subdomainRegistered = await registerSubdomain(
subdomainAnswer.subdomain
);
if (!subdomainRegistered.success) {
spinner.fail(subdomainRegistered.message)
spinner.fail(subdomainRegistered.message);
process.exit();
}
spinner.succeed(`${subdomainAnswer.subdomain}.remakeapps.com is belonging to your app.`);
spinner.succeed(
`${subdomainAnswer.subdomain}.remakeapps.com is belonging to your app.`
);
spinner = ora(`Writing .remake file.`).start();
dotRemakeObj.projectName = subdomainAnswer.subdomain
const writtenDotRemake = writeDotRemake(dotRemakeObj)
dotRemakeObj.projectName = subdomainAnswer.subdomain;
const writtenDotRemake = writeDotRemake(dotRemakeObj);
if (!writtenDotRemake) {
spinner.fail('Could not write subdomain to .remake');
spinner.fail("Could not write subdomain to .remake");
process.exit();

@@ -159,3 +145,7 @@ }

removeDeploymentZip(dotRemakeObj.projectName);
log(chalk.greenBright(`The app is accessible at the URL: https://${dotRemakeObj.projectName}.remakeapps.com`))
log(
chalk.greenBright(
`The app is accessible at the URL: https://${dotRemakeObj.projectName}.remakeapps.com`
)
);
process.exit();

@@ -166,3 +156,3 @@ } catch (err) {

}
}
};

@@ -173,4 +163,4 @@ const updateFramework = async () => {

const remakeFrameworkPathInApplicationDirectory = path.join(cwd, "_remake");
log (remakeFrameworkPathInApplicationDirectory);
log(remakeFrameworkPathInApplicationDirectory);
// 1. CHECK IF _remake DIRECTORY EXISTS

@@ -194,11 +184,19 @@ if (!fs.existsSync(remakeFrameworkPathInApplicationDirectory)) {

spinner = ora("Copying latest framework into _remake directory.").start();
shell.exec("git clone --depth 1 https://github.com/remake/remake-framework.git", { silent: true });
shell.exec(
"git clone --depth 1 https://github.com/remake/remake-framework.git",
{ silent: true }
);
// 4. MOVE THE _remake DIRECTORY TO WHERE THE OLD _remake DIRECTORY WAS
shell.mv(path.join(cwd, "remake-framework/_remake"), remakeFrameworkPathInApplicationDirectory);
shell.mv(
path.join(cwd, "remake-framework/_remake"),
remakeFrameworkPathInApplicationDirectory
);
rimrafError = await rimraf(path.join(cwd, "remake-framework"))
rimrafError = await rimraf(path.join(cwd, "remake-framework"));
if (rimrafError) {
spinner.fail("Error cleaning up: Couldn't remove the ./remake-framework directory.");
spinner.fail(
"Error cleaning up: Couldn't remove the ./remake-framework directory."
);
return;

@@ -208,4 +206,4 @@ }

log(chalk.greenBright('Framework successfully updated.'))
}
log(chalk.greenBright("Framework successfully updated."));
};

@@ -216,7 +214,10 @@ const backup = async () => {

if (appsList.length === 0) {
log(chalk.yellow('No apps deployed yet.'));
log(chalk.yellow("No apps deployed yet."));
process.exit();
} else {
const question = questions.APP_BACKUP;
question.choices = appsList.map((app) => ({ name: app.name, value: app.id }));
question.choices = appsList.map((app) => ({
name: app.name,
value: app.id,
}));
const backupAnswer = await inquirer.prompt([question]);

@@ -226,4 +227,88 @@ await backupApp(backupAnswer.appId);

}
};
module.exports = { create, deploy, clean, build, updateFramework, backup };
function createDotRemakeFile(projectName, options) {
spinner = ora("Setting up .remake").start();
const dotRemakeObj = {
...generateDotRemakeContent(options.multitenant),
};
spinner.succeed();
const dotRemakeReady = writeDotRemake(dotRemakeObj);
if (!dotRemakeReady) {
spinner.fail(chalk.bgRed("Error: Couldn't create .remake file"));
exit(1);
}
showSuccessfulCreationMessage(projectName);
}
module.exports = { create, deploy, clean, build, updateFramework, backup }
function getProjectPath(projectName) {
const cwd = process.cwd();
const projectPath = path.join(cwd, projectName);
return projectPath;
}
function installNpmPackages() {
spinner = ora("Installing npm dependencies.").start();
shell.exec("npm install", { silent: true });
spinner.succeed();
}
async function setupTemplate() {
const { starter } = await inquirer.prompt([questions.CHOOSE_STARTER]);
spinner = ora(`Cloning ${starter}`).start();
shell.mkdir("starter-tmp");
shell.exec(`git clone ${starter} starter-tmp`, { silent: true });
shell.rm("starter-tmp/README.md");
shell.rm("starter-tmp/.gitignore");
rimrafError = await rimraf(path.join("starter-tmp", ".git"));
shell.mv("starter-tmp/*", "app");
rimrafError = await rimraf(path.join("starter-tmp"));
spinner.succeed();
}
function moveReadme() {
shell.mv("README-FOR-BUNDLE.md", "README.md");
}
function cleanPackageJson(projectName) {
replace({
regex: `"name": "remake-framework"`,
replacement: `"name": "${projectName}"`,
paths: [`${projectName}/package.json`],
silent: true,
});
shell.cd(projectName);
shell.exec(`npm version 1.0.0`);
shell.cd(process.cwd());
}
function initializeGitRepo() {
shell.exec("git init --quiet");
shell.exec("git add . && git commit -m 'Initial commit' --quiet");
}
async function removeDotGit(projectName) {
spinner = ora("Tidy up new project directory.").start();
const projectPath = getProjectPath(projectName);
const rimrafError = await rimraf(path.join(projectPath, ".git"));
if (rimrafError) {
spinner.fail(
chalk.bgRed("Error: Couldn't remove old .git directory from new project.")
);
process.exit();
}
spinner.succeed();
}
function cloneRemakeFramework(projectName) {
spinner = ora("Creating new project.").start();
shell.exec(
`git clone --branch master https://github.com/remake/remake-framework.git ${projectName}`,
{ silent: true }
);
spinner.succeed();
}
const fs = require("fs");
const path = require('path');
const crypto = require('crypto');
const process = require('process');
const nanoidGenerate = require('nanoid/generate');
const path = require("path");
const crypto = require("crypto");
const process = require("process");
const nanoidGenerate = require("nanoid/generate");
const log = console.log;
function getUniqueId () {
return nanoidGenerate("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", 30);
function getUniqueId() {
return nanoidGenerate(
"1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
30
);
}
function generateDotRemakeContent (multitenant) {
function generateDotRemakeContent(multitenant) {
const dotRemakeContent = {
port: 3000,
sessionSecret: getUniqueId()
}
sessionSecret: getUniqueId(),
};
if (multitenant) {
dotRemakeContent.remakeMultiTenant = true;
dotRemakeContent.jwtSecret = crypto.randomBytes(30).toString('base64');
dotRemakeContent.jwtSecret = crypto.randomBytes(30).toString("base64");
}

@@ -25,7 +28,7 @@ return dotRemakeContent;

function writeDotRemake (content) {
function writeDotRemake(content) {
const cwd = process.cwd();
const dotRemakePath = path.join(cwd, '.remake');
const dotRemakePath = path.join(cwd, ".remake");
try {
fs.writeFileSync(dotRemakePath, JSON.stringify(content, null, 4))
fs.writeFileSync(dotRemakePath, JSON.stringify(content, null, 4));
return true;

@@ -38,5 +41,5 @@ } catch (err) {

function readDotRemake () {
function readDotRemake() {
const cwd = process.cwd();
const dotRemakePath = path.join(cwd, '.remake');
const dotRemakePath = path.join(cwd, ".remake");

@@ -49,7 +52,7 @@ // check if .remake file exists

try {
const dotRemake = fs.readFileSync(dotRemakePath, 'utf8');
const dotRemake = fs.readFileSync(dotRemakePath, "utf8");
const dotRemakeObj = JSON.parse(dotRemake);
return dotRemakeObj;
} catch (err) {
log(err)
log(err);
return false;

@@ -59,2 +62,2 @@ }

module.exports = { generateDotRemakeContent, writeDotRemake, readDotRemake }
module.exports = { generateDotRemakeContent, writeDotRemake, readDotRemake };

@@ -1,13 +0,13 @@

const fs = require('fs');
const path = require('path');
const process = require('process');
const inquirer = require('inquirer');
const axios = require('axios');
const chalk = require('chalk');
const archiver = require('archiver');
const shell = require('shelljs');
const FormData = require('form-data');
const fs = require("fs");
const path = require("path");
const process = require("process");
const inquirer = require("inquirer");
const axios = require("axios");
const chalk = require("chalk");
const archiver = require("archiver");
const shell = require("shelljs");
const FormData = require("form-data");
const { questions } = require('./inquirer-questions');
const ora = require('ora');
const { questions } = require("./inquirer-questions");
const ora = require("ora");

@@ -17,43 +17,47 @@ let spinner = null;

const registerUser = async () => {
const userEmail = remakeCliConfig.get('user.email');
const authToken = remakeCliConfig.get('user.authToken');
const userEmail = remakeCliConfig.get("user.email");
const authToken = remakeCliConfig.get("user.authToken");
if (!userEmail || !authToken) {
log(chalk.yellow(`Not logged in.`));
let loginAnswers = await inquirer.prompt([questions.NEW_USER, questions.INPUT_EMAIL, questions.INPUT_PASSWORD]);
if (loginAnswers.existingUser.startsWith('Yes')) {
let loginAnswers = await inquirer.prompt([
questions.NEW_USER,
questions.INPUT_EMAIL,
questions.INPUT_PASSWORD,
]);
if (loginAnswers.existingUser.startsWith("Yes")) {
try {
spinner = ora('Logging you in.').start();
spinner = ora("Logging you in.").start();
let res = await axios({
method: 'post',
url: `${remakeServiceHost}/service/login`,
method: "post",
url: `${remakeServiceHost}/service/login`,
data: {
email: loginAnswers.email,
password: loginAnswers.password,
}
},
});
remakeCliConfig.set('user.email', loginAnswers.email);
remakeCliConfig.set('user.authToken', res.data.token);
spinner.succeed('You are successfuly logged in.');
remakeCliConfig.set("user.email", loginAnswers.email);
remakeCliConfig.set("user.authToken", res.data.token);
spinner.succeed("You are successfuly logged in.");
} catch (err) {
spinner.fail('Could not log you in. Please try again.');
spinner.fail("Could not log you in. Please try again.");
process.exit();
}
} else {
try{
spinner = ora('Creating your account').start();
try {
spinner = ora("Creating your account").start();
let res = await axios({
method: 'post',
url: `${remakeServiceHost}/service/signup`,
method: "post",
url: `${remakeServiceHost}/service/signup`,
data: {
email: loginAnswers.email,
password: loginAnswers.password,
}
},
});
remakeCliConfig.set('user.email', loginAnswers.email);
remakeCliConfig.set('user.authToken', res.data.token);
spinner.succeed('Created your account and logged you in.');
remakeCliConfig.set("user.email", loginAnswers.email);
remakeCliConfig.set("user.authToken", res.data.token);
spinner.succeed("Created your account and logged you in.");
} catch (err) {
spinner.fail('Could not create your account. Please try again.');
spinner.fail("Could not create your account. Please try again.");
process.exit();

@@ -63,3 +67,3 @@ }

}
}
};

@@ -69,10 +73,10 @@ const checkSubdomain = async (subdomain) => {

const availabilityRes = await axios({
method: 'get',
url: `${remakeServiceHost}/service/subdomain/check`,
method: "get",
url: `${remakeServiceHost}/service/subdomain/check`,
headers: {
'Authorization': `Bearer ${remakeCliConfig.get('user.authToken')}`
Authorization: `Bearer ${remakeCliConfig.get("user.authToken")}`,
},
params: {
subdomain,
}
},
});

@@ -84,3 +88,3 @@ if (availabilityRes.status === 200) return true;

}
}
};

@@ -90,10 +94,10 @@ const registerSubdomain = async (subdomain) => {

const domainRegistered = await axios({
method: 'post',
url: `${remakeServiceHost}/service/subdomain/register`,
method: "post",
url: `${remakeServiceHost}/service/subdomain/register`,
headers: {
'Authorization': `Bearer ${remakeCliConfig.get('user.authToken')}`
Authorization: `Bearer ${remakeCliConfig.get("user.authToken")}`,
},
data: {
subdomain,
}
},
});

@@ -104,12 +108,15 @@ if (domainRegistered.status === 200) return { success: true };

}
}
};
const createDeploymentZip = (projectName) => {
const spinner = ora('Archiving files for upload.').start();
const spinner = ora("Archiving files for upload.").start();
return new Promise((resolve, reject) => {
const cwd = process.cwd();
const output = fs.createWriteStream(path.join(cwd, `deployment-${projectName}.zip`), { encoding: 'base64' });
const archive = archiver('zip', { zlib: { level: 9 } });
const output = fs.createWriteStream(
path.join(cwd, `deployment-${projectName}.zip`),
{ encoding: "base64" }
);
const archive = archiver("zip", { zlib: { level: 9 } });
output.on('warning', (err) => {
output.on("warning", (err) => {
spinner.fail();

@@ -119,3 +126,3 @@ reject(err);

output.on('error', (err) => {
output.on("error", (err) => {
spinner.fail();

@@ -125,60 +132,63 @@ reject(err);

output.on('close', () => {
spinner.succeed('Done archiving: ' + archive.pointer() + ' bytes.');
output.on("close", () => {
spinner.succeed("Done archiving: " + archive.pointer() + " bytes.");
resolve();
})
});
archive.pipe(output);
archive.glob('app/**/*');
archive.glob('_remake/dist/**/*')
// archive.glob('_remake-data/*/*.json');
archive.glob("app/data/bootstrap.json");
archive.glob("app/data/global.json");
archive.glob("app/assets/**/*");
archive.glob("app/layouts/**/*");
archive.glob("app/pages/**/*");
archive.glob("app/partials/**/*");
archive.finalize();
})
}
});
};
const removeDeploymentZip = (projectName) => {
spinner = ora('Cleaning up project directory.').start();
spinner = ora("Cleaning up project directory.").start();
const cwd = process.cwd();
shell.rm(path.join(cwd, `deployment-${projectName}.zip`))
shell.rm(path.join(cwd, `deployment-${projectName}.zip`));
spinner.succeed();
}
};
const pushZipToServer = async (projectName) => {
spinner = ora('Pushing your files to the deployment server.').start();
spinner = ora("Pushing your files to the deployment server.").start();
const cwd = process.cwd();
const zipPath = path.join(cwd, `deployment-${projectName}.zip`);
const formData = new FormData();
formData.append('deployment', fs.readFileSync(zipPath), `${projectName}.zip`);
formData.append('appName', projectName);
formData.append("deployment", fs.readFileSync(zipPath), `${projectName}.zip`);
formData.append("appName", projectName);
try {
const res = await axios({
method: 'POST',
method: "POST",
url: `${remakeServiceHost}/service/deploy`,
headers: {
...formData.getHeaders(),
'Authorization': `Bearer ${remakeCliConfig.get('user.authToken')}`,
Authorization: `Bearer ${remakeCliConfig.get("user.authToken")}`,
},
data: formData.getBuffer()
data: formData.getBuffer(),
});
if (res.status === 200)
spinner.succeed('Files successfully uploaded to server.')
spinner.succeed("Files successfully uploaded to server.");
else {
spinner.fail('Could not upload your files to the server.');
throw new Error('Could not upload your files to the server.')
spinner.fail("Could not upload your files to the server.");
throw new Error("Could not upload your files to the server.");
}
} catch (err) {
spinner.fail('Could not upload your files to the server.');
throw new Error(err)
spinner.fail("Could not upload your files to the server.");
throw new Error(err);
}
}
};
const getAppsList = async () => {
const spinner = ora('Getting your apps list.').start();
const spinner = ora("Getting your apps list.").start();
try {
const appListResponse = await axios({
method: 'get',
url: `${remakeServiceHost}/service/apps`,
method: "get",
url: `${remakeServiceHost}/service/apps`,
headers: {
'Authorization': `Bearer ${remakeCliConfig.get('user.authToken')}`
Authorization: `Bearer ${remakeCliConfig.get("user.authToken")}`,
},

@@ -197,25 +207,33 @@ });

}
}
};
const backupApp = async (appId) => {
const spinner = ora('Generating and downlading zip.').start();
const spinner = ora("Generating and downlading zip.").start();
try {
const backupResponse = await axios({
method: 'get',
method: "get",
url: `${remakeServiceHost}/service/backup`,
responseType: 'stream',
responseType: "stream",
headers: {
'Authorization': `Bearer ${remakeCliConfig.get('user.authToken')}`
Authorization: `Bearer ${remakeCliConfig.get("user.authToken")}`,
},
params: {
appId,
}
})
},
});
if (backupResponse.status === 200) {
const fileName = backupResponse.headers['content-disposition'].split('=')[1].replace(/\"/g, '');
const fileName = backupResponse.headers["content-disposition"]
.split("=")[1]
.replace(/\"/g, "");
const writer = fs.createWriteStream(fileName);
backupResponse.data.pipe(writer);
return new Promise((resolve, reject) => {
writer.on('finish', () => { spinner.succeed(); resolve(); });
writer.on('error', () => { spinner.fail(); reject(); });
writer.on("finish", () => {
spinner.succeed();
resolve();
});
writer.on("error", () => {
spinner.fail();
reject();
});
});

@@ -230,3 +248,3 @@ } else {

}
}
};

@@ -242,2 +260,2 @@ module.exports = {

backupApp,
}
};
const validateSubdomain = (subdomain) => {
const subdomainRegex = /^[a-z]+[a-z0-9\-]*$/
if (!subdomainRegex.test(subdomain))
return 'The project name should start with a lowercase letter and should contain only lowercase letters, numbers and dashes.'
const subdomainRegex = /^[a-z]+[a-z0-9\-]*$/;
if (!subdomainRegex.test(subdomain))
return "The project name should start with a lowercase letter and should contain only lowercase letters, numbers and dashes.";
else return true;
}
};
const validateEmail = (email) => {
// regex source: https://stackoverflow.com/a/46181
const emailRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/
const emailRegex = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/;
if (!emailRegex.test(email)) {
return 'Please provide a valid email address.';
}
else return true;
}
return "Please provide a valid email address.";
} else return true;
};
const validatePass = (pass) => {
// at least one digit and one letter + at least 8 chars long
const passRegex = /^(?=.*\d)(?=.*[a-z])[a-zA-Z0-9]{8,}$/
const passRegex = /^(?=.*\d)(?=.*[a-z])[a-zA-Z0-9]{8,}$/;
if (!passRegex.test(pass))
return 'The password should be at least 8 characters long and it should contain at least one digit and a letter.';
return "The password should be at least 8 characters long and it should contain at least one digit and a letter.";
else return true;
}
};
const questions = {
CHOOSE_STARTER: {
message: `Choose a starter template`,
name: "starter",
type: "list",
choices: [
{
name: "Kanban starter",
value: "https://github.com/remake/kanban-starter",
},
{
name: "Default starter",
value: "https://github.com/remake/default-starter",
},
],
},
NEW_USER: {
message: `Did you log in previously?`,
name: 'existingUser',
type: 'list',
choices: ['Yes, proceed to login', 'No, create new account'],
name: "existingUser",
type: "list",
choices: ["Yes, proceed to login", "No, create new account"],
},
INPUT_EMAIL: {
message: `Email >`,
name: 'email',
type: 'input',
name: "email",
type: "input",
validate: validateEmail,

@@ -40,6 +54,6 @@ },

message: `Password >`,
name: 'password',
type: 'password',
mask: '*',
validate: validatePass
name: "password",
type: "password",
mask: "*",
validate: validatePass,
},

@@ -51,19 +65,19 @@ INPUT_SUBDOMAIN: {

> `,
name: 'subdomain',
type: 'input',
validate: validateSubdomain
name: "subdomain",
type: "input",
validate: validateSubdomain,
},
CONFIRM_SUBDOMAIN: {
name: 'deployOk',
message: 'Subdomain is available. Do you want to proceed?',
type: 'confirm'
name: "deployOk",
message: "Subdomain is available. Do you want to proceed?",
type: "confirm",
},
APP_BACKUP: {
message: 'Which app do you want to back up?',
name: 'appId',
type: 'list',
choices: []
}
}
message: "Which app do you want to back up?",
name: "appId",
type: "list",
choices: [],
},
};
module.exports = { questions };
module.exports = { questions };

@@ -1,4 +0,4 @@

const chalk = require('chalk');
const chalk = require("chalk");
function showSuccessfulCreationMessage (projectDir) {
function showSuccessfulCreationMessage(projectDir) {
log(`

@@ -21,2 +21,2 @@ ${chalk.magenta.bold("Your new Remake project has been created!")}

module.exports = {showSuccessfulCreationMessage};
module.exports = { showSuccessfulCreationMessage };
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc