Socket
Socket
Sign inDemoInstall

rokay

Package Overview
Dependencies
297
Maintainers
1
Versions
21
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.10 to 0.0.11-alpha.0

4

_dist/cli/client/lint.js
import { Command } from "commander";
import { lintProject } from "../tslint.js";
import { Log } from "../utils/log.js";
import { getRokayCtx } from "../utils/rokay-ctx.js";
import { getClientTsconfig } from "./tsconfig.js";
import { getRokayCtx } from "../utils/rokay-ctx.js";
import { Log } from "../utils/log.js";
export const clientLint = () => new Command("client:lint")

@@ -7,0 +7,0 @@ .description("Run tslint --fix on the client project")

@@ -5,4 +5,4 @@ import { Command } from "commander";

import ts from "typescript";
import { Log } from "../utils/log.js";
import { getRokayCtx } from "../utils/rokay-ctx.js";
import { Log } from "../utils/log.js";
export const clientTsconfig = () => new Command("client:tsconfig")

@@ -9,0 +9,0 @@ .description("Write out the tsconfig file for the client to src/client for editor integration")

@@ -36,3 +36,2 @@ import { Command } from "commander";

"src/client/tsconfig.json",
"src/server/main.ts",
"src/server/tsconfig.json",

@@ -39,0 +38,0 @@ "src/shared/tsconfig.json",

import { Command } from "commander";
import { mkdir, rename, rm } from "fs/promises";
import { resolve } from "path";
import { getDirname } from "../lib/server/node.js";
import { eject } from "./eject.js";

@@ -22,13 +23,20 @@ import { gitignore } from "./gitignore.js";

import { CURRENT_ROKAY_VERSION } from "./utils/rokay-ctx.js";
const __dirname = getDirname(import.meta);
export const comInit = () => new Command("init")
.description("Create a new rokay repo")
.action(() => init()
.then(() => { process.exit(0); })), init = () => prompt("Enter your project's name (i.e. the directory name): ")
.option("--description <description>", "an optional description for the project")
.option("--display-name <displayName>", "the display name for the project (defaults to capitalized name)")
.option("--name <name>", "the project name/directory used for the project")
.option("--port <port>", "the server port")
.option("--theme <theme>", "the background/theme color (defaults to #00f)")
.action((cliArgs) => init(cliArgs)
.then(() => { process.exit(0); })), init = (cliArgs) => argOr(cliArgs.name, "Enter your project's name (i.e. the directory name): ")
.then(name => {
console.log("name:", name);
if (!name) {
throw new Error("You must enter a project name!");
}
return promptDefault("Enter the display name", capitalize(name))
.then(title => promptDefault("Enter a description", "")
.then(description => prompt("Enter the server port: ")
return argOrDefault(cliArgs.displayName, "Enter the display name", capitalize(name))
.then(title => argOrDefault(cliArgs.description, "Enter a description", "")
.then(description => argOr(cliArgs.port, "Enter the server port: ")
.then(p => {

@@ -41,6 +49,6 @@ const port = parseInt(p, 10);

})
.then(port => promptDefault("Enter the background/theme color", "#00f")
.then(port => argOrDefault(cliArgs.theme, "Enter the background/theme color", "#00f")
.then(theme => initWithArgs({ name, description, port, theme, title })))));
});
const capitalize = (str) => str.replace(/(?:\s[a-z]|^[a-z])/g, c => c.toUpperCase()), initWithArgs = ({ name, description, port, theme, title }) => {
const argOr = (val, promptMsg) => (val ? Promise.resolve(val) : prompt(promptMsg)), argOrDefault = (val, promptMsg, def) => (val ? Promise.resolve(val) : promptDefault(promptMsg, def)), capitalize = (str) => str.replace(/(?:\s[a-z]|^[a-z])/g, c => c.toUpperCase()), initWithArgs = ({ name, description, port, theme, title }) => {
const cwd = process.cwd(), dir = resolve(__dirname, "..", "..", "..", ".staging"), ctx = {

@@ -108,20 +116,9 @@ description,

"npm i",
"@types/bcrypt",
"@types/cookie-session",
"@types/express",
"@types/morgan",
"@types/pg",
"@types/uuid",
"bcrypt",
"busboy",
"cookie-session",
"express",
"helmet",
"morgan",
"okay-site-login",
"pg",
"rokay",
"tslib",
"tslint",
"typescript",
"uuid",
].join(" ")))
.then(() => exec("npm link login rokay"));
].join(" ")));

@@ -16,2 +16,3 @@ #!/usr/bin/env -S node --experimental-vm-modules

import { packageScripts } from "./package-scripts.js";
import { comPackage } from "./package.js";
import { comRoutes, comRoutesWatch } from "./routes/index.js";

@@ -47,5 +48,4 @@ import { comScaffoldApp } from "./scaffold/app.js";

import { watch } from "./watch.js";
import { comPackage } from "./package.js";
const main = (argv) => {
const program = new Command().version("0.0.7-alpha.0")
const program = new Command()
.description("Rokay CLI")

@@ -52,0 +52,0 @@ .addCommand(comBuild())

@@ -14,3 +14,3 @@ import { Command } from "commander";

scaffold.write(resolve(ctx.dir, "src", "shared", "app"), "ts", `\
import { User } from "login/shared/users/types.gen"
import { User } from "okay-site-login/shared/users/types.gen"
import { Asink } from "rokay/prop/async"

@@ -17,0 +17,0 @@ import { Router } from "rokay/route/router"

@@ -20,3 +20,3 @@ import { Command } from "commander";

scaffold.write(resolve(ctx.dir, "src", "client", ctx.name), "ts", `\
import { getUserAsink } from "login/client/users/service"
import { getUserAsink } from "okay-site-login/client/users/service"
import { apd } from "rokay/browser/core"

@@ -23,0 +23,0 @@ import { code, div, h2 } from "rokay/browser/elt"

@@ -31,4 +31,5 @@ import { Command } from "commander";

},
type: "module",
version: "1.0.0",
}, null, 2) + "\n");
};
import { Command } from "commander";
import { resolve } from "path";
import { capitalize } from "../../lib/data/string.js";
import { routesFromCtx } from "../routes/index.js";

@@ -215,3 +214,3 @@ import { typesFromCtx } from "../types/index.js";

})
`), ctx = getRokayCtx(), name = rawName.toLowerCase(), names = name + "s", Name = capitalize(name), NameAPI = `${Name}API`, NameDao = `${Name}Dao`, NameDaoReadArgs = `${NameDao}ReadArgs`, NameRequest = `${Name}Request`, NameRow = `${Name}Row`, NameService = `${Name}Service`, Names = capitalize(names), NamesRouter = `${Names}Router`, clientDir = resolve(ctx.dir, "src", "client", names), sharedDir = resolve(ctx.dir, "src", "shared", names), serverDir = resolve(ctx.dir, "src", "server", names), scaffold = Scaffolder(ctx, dry, Log("scaffold:resource"));
`), ctx = getRokayCtx(), name = rawName.toLowerCase(), names = name + "s", clientDir = resolve(ctx.dir, "src", "client", names), sharedDir = resolve(ctx.dir, "src", "shared", names), serverDir = resolve(ctx.dir, "src", "server", names), scaffold = Scaffolder(ctx, dry, Log("scaffold:resource")), { Name } = scaffold, NameAPI = `${Name}API`, NameDao = `${Name}Dao`, NameDaoReadArgs = `${NameDao}ReadArgs`, NameRequest = `${Name}Request`, NameRow = `${Name}Row`, NameService = `${Name}Service`, Names = Name + "s", NamesRouter = `${Names}Router`;
return Promise.all([

@@ -218,0 +217,0 @@ scaffold.mkdir(clientDir),

import { Command } from "commander";
import { resolve } from "path";
import { capitalize } from "../../lib/data/string.js";
import { Log } from "../utils/log.js";

@@ -12,10 +11,6 @@ import { getRokayCtx } from "../utils/rokay-ctx.js";

.then(() => { process.exit(0); })), scaffoldServer = (ctx, dry) => {
const Name = capitalize(ctx.name), main = `\
import { ${Name} } from "./${ctx.name}.js"
${Name}({})
`, scaffold = Scaffolder(ctx, dry, Log("scaffold:server"));
const scaffold = Scaffolder(ctx, dry, Log("scaffold:server")), { Name, nameSanitized } = scaffold;
return Promise.all([
scaffold.write(resolve(ctx.dir, "src", "server", "app"), "ts", `\
import { User } from "login/shared/users/types.gen"
import { User } from "okay-site-login/shared/users/types.gen"
import { Asink } from "rokay/prop/async"

@@ -41,16 +36,43 @@ import { ServerRouter } from "rokay/server/router"

scaffold.write(resolve(ctx.dir, "src", "server", "config"), "ts", `\
import { LoginConfig } from "okay-site-login/server/config"
export type ${Name}Config = {
login: LoginConfig
}
`),
scaffold.write(resolve(ctx.dir, "src", "server", "main"), "ts", main),
scaffold.write(resolve(ctx.dir, "src", "server", "db"), "ts", `\
import { DB } from "rokay/server/db/db"
export type ${Name}DB = ReturnType<typeof ${Name}DB>
export const
${Name}DB = (db: DB) => ({
single: db.single,
transact: db.transact,
})
`),
scaffold.write(resolve(ctx.dir, "src", "server", "main"), "ts", `\
import { getLoginConfig } from "okay-site-login/server/config"
import { ${Name} } from "./${ctx.name}.js"
${Name}({
login: getLoginConfig(),
})
`),
scaffold.write(resolve(ctx.dir, "src", "server", ctx.name), "ts", `\
import express from "express"
import { UserService } from "login/server/users/service"
import { userExpress } from "login/server/utils"
import { LoginDB } from "okay-site-login/server/login-db"
import { UserService } from "okay-site-login/server/users/service"
import { UserServer } from "okay-site-login/server/utils"
import { resolve } from "path"
import { Pool } from "pg"
import { migrate } from "rokay/server/db/pg"
import { NotFound } from "rokay/server/errors"
import { renderPage } from "rokay/server/render"
import pg from "pg"
import { DBPG } from "rokay/server/db/db-pg"
import { Eq } from "rokay/server/db/filter"
import { migrate } from "rokay/server/db/migrate"
import { getDirname } from "rokay/server/node"

@@ -60,62 +82,60 @@ import { AppServer } from "./app.js"

import { ${Name}Config } from "./config.js"
import { ${Name}DB } from "./db.js"
import { HTML } from "./html.js"
const { Pool } = pg
export const
${Name} = (_config: ${Name}Config) => {
const
pool = new Pool(),
const __dirname = getDirname(import.meta)
PORT = process.env.PORT || ${ctx.port},
STATIC_DIR = resolve(__dirname, "..", "..", "static"),
TITLE = ${JSON.stringify(ctx.title)},
users = UserService(pool),
export const
${Name} = (config: ${Name}Config) => {
getAndMigrate${Name}DB().then(({ ${nameSanitized}DB: _${nameSanitized}DB, loginDB }) => {
const
users = UserService(config.login, loginDB)
app = userExpress(TITLE, users)
// APIs GO HERE
.get("*", (req, res, next) => {
res.setHeader("Vary", "Content-Type")
if (req.headers.accept && req.headers.accept.includes("text/html")) {
users.current(req, res)
.then(user => {
const app = AppServer(req, user)
res.send(renderPage(HTML(app, Base(app))))
}, next)
} else {
next()
}
UserServer(${JSON.stringify(ctx.title)}, ${ctx.port}, {
staticDir: resolve(__dirname, "..", "..", "static"),
users,
}, [
// APIs go here
], (req, res) =>
users.current(req, res).then(user => {
const app = AppServer(req, user)
return HTML(app, Base(app))
})
)
}, error => {
console.error("Error Running Migrations:", error)
})
}
.use(express.static(STATIC_DIR))
.use((req, _, next) => {
next(NotFound(\`Cannot \${req.method} \${req.originalUrl}\`))
})
const
getAndMigrate${Name}DB = (): Promise<{ ${nameSanitized}DB: ${Name}DB, loginDB: LoginDB }> => {
const
project = "${ctx.name}",
pool = new Pool(),
db = DBPG(pool),
Migrations = db.table<{
created: Date
file: string
project: string
}>("migrations")
.use(((error, req, res, _) => {
const { message, status } = error
if (status == null || status >= 500) {
console.error("Internal Server Error:", error)
}
if (!res.headersSent) {
res.status(status != null ? status : 500).send({ message })
} else {
console.error("Headers sent. Not sending anything. URL:", req.originalUrl)
}
}) as express.ErrorRequestHandler)
migrate(pool, ${JSON.stringify(ctx.name)}, resolve(__dirname, "..", "..", "schema"), [
//{ name: <some string>, cb: <some callback> },
])
.then(() => {
app.listen(PORT, () => {
console.log(\`\${TITLE} Listening on Port \${PORT}...\`)
})
}, error => {
console.error("Error Running Migrations:", error)
})
return migrate(
resolve(__dirname, "..", "..", "schema"),
db.transact,
conn =>
conn.q(Migrations.select(["file"], {
where: Eq("project", project)
}))
.then(rows => rows.map(r => r.file)),
(conn, file) =>
conn.e(Migrations.insert([{ file, project }])),
)
.then(() => ({
${nameSanitized}DB: ${Name}DB(db),
loginDB: LoginDB(db),
}))
}

@@ -122,0 +142,0 @@ `),

@@ -16,6 +16,9 @@ import { Command } from "commander";

margin: 0;
padding: 0 }
padding: 0;
}
body { background-color: ${ctx.theme} }
body {
background-color: ${ctx.theme};
}
`);
};

@@ -1,2 +0,7 @@

export const prompt = (question) => new Promise((res, rej) => {
export const
/**
* asks the user the question exactly as given and resolves to the user's trimmed input from stdin.
* this is locked to only allow asking the user one question at a time.
**/
prompt = (question) => withLock(() => new Promise((res, rej) => {
const onerror = (err) => {

@@ -14,3 +19,41 @@ process.stdin.off("data", onsuccess);

process.stdin.on("error", onerror);
}), promptDefault = (question, def) => prompt(`${question} (${def}): `)
})),
/**
* asks the user the given question with the default in parentheses and a colon and space afterward.
* this resolves to def if a blank response is given.
**/
promptDefault = (question, def) => prompt(`${question} (${def}): `)
.then(res => res ? res : def);
const
/**
* a queue of work to do in terms of prompting the user. This prevents multiple calls to prompt
* from stepping on each other's toes and getting back the same answer.
**/
queue = [];
const
/**
* Adds the given cb to the work queue, ensure that only one cb is asking for user input at a time.
* @returns the value that the promise returned by cb resolves to
**/
withLock = (cb) => new Promise(res => {
queue.push(() => new Promise(innerRes => {
res(cb().finally(() => {
innerRes();
}));
}));
if (queue.length === 1) {
runNext();
}
}),
/**
* recursively runs through the items in the work queue until it is empty
**/
runNext = () => {
const next = queue.shift();
if (next == null) {
return;
}
else {
next().finally(runNext);
}
};
import { existsSync } from "fs";
import { mkdir, readFile, writeFile } from "fs/promises";
import { relative } from "path";
import { capitalize } from "../../lib/data/string.js";
import { promptDefault } from "./prompt.js";
export const Scaffolder = (ctx, dry, log) => ({
mkdir(path) {
log("Ensuring directory %s exists...", relative(ctx.dir, path));
return mkdir(path, { recursive: true });
},
write(pathBase, extension, contents) {
const ext = extension != null ? `.${extension}` : "", path = `${pathBase}${ext}`;
if (!dry) {
const rel = relative(ctx.dir, path);
log("Creating %s...", rel);
return readFile(path, { encoding: "utf-8" })
.then(old => {
if (old === contents) {
log("%s already exists, but the content is the same. Skipping.", rel);
return undefined;
}
log("%s already exists and has been modified.", rel);
return promptDefault("Q to Quit, R to Replace, S to Skip, K to Keep Both", "Q")
.then(raw => {
const key = raw.toUpperCase();
if (key === "K") {
let i = 0;
while (existsSync(`${pathBase}.${++i}${ext}`)) { }
const path = `${pathBase}.${i}${ext}`;
log("Writing to", relative(ctx.dir, path));
return writeFile(path, contents);
export const scaffoldName = (name) => capitalize(name.replace(/[^\w]+(\w)/g, (_, c) => c.toUpperCase())), Scaffolder = (ctx, dry, log) => {
const nameSanitized = ctx.name.replace(/[^\w]+(\w)/g, (_, c) => c.toUpperCase()), Name = capitalize(nameSanitized);
return {
mkdir(path) {
log("Ensuring directory %s exists...", relative(ctx.dir, path));
return mkdir(path, { recursive: true });
},
Name,
nameSanitized,
write(pathBase, extension, contents) {
const ext = extension != null ? `.${extension}` : "", path = `${pathBase}${ext}`;
if (!dry) {
const rel = relative(ctx.dir, path);
log("Creating %s...", rel);
return readFile(path, { encoding: "utf-8" })
.then(old => {
if (old === contents) {
log("%s already exists, but the content is the same. Skipping.", rel);
return undefined;
}
else if (key === "S") {
log("Skipping.");
return;
}
else if (key === "Q") {
log("Quitting.");
throw new Error("I Quit!");
}
else if (key === "R") {
log("Replacing.");
log("%s already exists and has been modified.", rel);
return promptDefault("Q to Quit, R to Replace, S to Skip, K to Keep Both", "Q")
.then(raw => {
const key = raw.toUpperCase();
if (key === "K") {
let i = 0;
while (existsSync(`${pathBase}.${++i}${ext}`)) { }
const path = `${pathBase}.${i}${ext}`;
log("Writing to", relative(ctx.dir, path));
return writeFile(path, contents);
}
else if (key === "S") {
log("Skipping.");
return;
}
else if (key === "Q") {
log("Quitting.");
throw new Error("I Quit!");
}
else if (key === "R") {
log("Replacing.");
return writeFile(path, contents);
}
log("Unknown Input. Bailing.");
throw new Error("Unknown Input");
});
}, error => {
if (error.code === "ENOENT") {
log("Writing %s...", rel);
return writeFile(path, contents);
}
log("Unknown Input. Bailing.");
throw new Error("Unknown Input");
throw error;
});
}, error => {
if (error.code === "ENOENT") {
log("Writing %s...", rel);
return writeFile(path, contents);
}
throw error;
});
}
log(`${relative(ctx.dir, path)}:`);
log(contents);
return Promise.resolve();
}
log(`${relative(ctx.dir, path)}:`);
log(contents);
return Promise.resolve();
}
});
};
};

@@ -45,3 +45,3 @@ import { onDestroy } from "./capture.js";

onDestroy(function () {
listeners[key] = undefined;
ctrlListeners[key] = undefined;
});

@@ -48,0 +48,0 @@ },

import { createPool } from "mysql";
import { whereStr } from "./filter.js";
import { getToStmt } from "./stmt.js";
import { Table } from "./table.js";
import { getToStmt } from "./stmt.js";
import { whereStr } from "./filter.js";
export const DBMysql = (config) => {

@@ -6,0 +6,0 @@ const doTransaction = (conn, cb) => new Promise((res, rej) => {

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

import { whereStr } from "./filter.js";
import { getToStmt, returningStr } from "./stmt.js";
import { Table } from "./table.js";
import { getToStmt, returningStr } from "./stmt.js";
import { whereStr } from "./filter.js";
export const DBPG = (pool) => {

@@ -5,0 +5,0 @@ const doTransaction = (cb) => pool.connect()

{
"name": "rokay",
"version": "0.0.10",
"version": "0.0.11-alpha.0",
"description": "A full-stack framework for making CRUD apps in TypeScript.",

@@ -5,0 +5,0 @@ "scripts": {

SocketSocket SOC 2 Logo

Product

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

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc