create-roxyon-app 0.1.3 → 0.1.5
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/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -252,6 +252,7 @@ window.rxError = function (r) {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
// src/scaffold.ts
|
|
255
|
+
var LMJS_VERSION = "2.5.7";
|
|
255
256
|
function run(cmd, args, cwd) {
|
|
256
257
|
return new Promise((res) => {
|
|
257
258
|
const child = spawn(cmd, args, { cwd, stdio: "inherit", shell: process.platform === "win32" });
|
|
@@ -309,10 +310,14 @@ async function scaffold(input) {
|
|
|
309
310
|
folder: input.folder
|
|
310
311
|
});
|
|
311
312
|
if (input.template.viaLmjs) {
|
|
312
|
-
const code = await run(
|
|
313
|
+
const code = await run(
|
|
314
|
+
"npx",
|
|
315
|
+
["--yes", "-p", `@lmjs/cli@${LMJS_VERSION}`, "lm", "create", input.name],
|
|
316
|
+
dir
|
|
317
|
+
);
|
|
313
318
|
if (code !== 0 || !await exists(join(dir, "src", "index.html"))) {
|
|
314
319
|
throw new Error(
|
|
315
|
-
|
|
320
|
+
`Could not scaffold the LumenJS skeleton (npx @lmjs/cli@${LMJS_VERSION} create failed). Is npm online?`
|
|
316
321
|
);
|
|
317
322
|
}
|
|
318
323
|
await patchPackageJson(dir, input.name, {
|
|
@@ -321,7 +326,7 @@ async function scaffold(input) {
|
|
|
321
326
|
build: "lm build --serverless",
|
|
322
327
|
deploy: "lm build --serverless && roxyon deploy"
|
|
323
328
|
},
|
|
324
|
-
devDependencies: { "@lmjs/cli":
|
|
329
|
+
devDependencies: { "@lmjs/cli": LMJS_VERSION }
|
|
325
330
|
});
|
|
326
331
|
if (input.template.baas) {
|
|
327
332
|
for (const f of baasOverlayFiles()) await writeFileOut(dir, f);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts","../src/agent-files.ts","../src/templates.ts"],"sourcesContent":["import { basename, resolve } from 'node:path';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { scaffold } from './scaffold.js';\nimport { TEMPLATES, type TemplateId } from './templates.js';\n\ninterface Args {\n dir?: string;\n template?: TemplateId;\n host?: string;\n folder?: string;\n install: boolean;\n yes: boolean;\n}\n\nfunction parseArgs(argv: string[]): Args {\n const a: Args = { install: true, yes: false };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!;\n if (arg === '--no-install') a.install = false;\n else if (arg === '-y' || arg === '--yes') a.yes = true;\n else if (arg === '--template' || arg === '-t') a.template = argv[++i] as TemplateId;\n else if (arg === '--host') a.host = argv[++i];\n else if (arg === '--folder') a.folder = argv[++i];\n else if (arg === '--help' || arg === '-h') a.dir = '--help';\n else if (!arg.startsWith('-') && !a.dir) a.dir = arg;\n }\n return a;\n}\n\nconst HELP = `${pc.bold('create-roxyon-app')} — scaffold a Roxyon project\n\n npm create roxyon-app@latest my-app\n npx create-roxyon-app my-app --template lumen-baas\n\nOptions:\n -t, --template <id> ${Object.keys(TEMPLATES).join(' | ')}\n --host <domain> deploy host (a domain on your Roxyon subscription)\n --folder <path> sub-path under the host\n --no-install skip npm install\n -y, --yes accept defaults, no prompts\n`;\n\nasync function ask<T>(fn: () => Promise<T | symbol>): Promise<T> {\n const v = await fn();\n if (p.isCancel(v)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n return v as T;\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n if (args.dir === '--help') {\n process.stdout.write(HELP);\n return;\n }\n\n p.intro(pc.bgYellow(pc.black(' create-roxyon-app ')));\n\n const dirInput =\n args.dir ??\n (args.yes\n ? 'roxyon-app'\n : await ask<string>(() =>\n p.text({ message: 'Project directory', placeholder: 'my-app', defaultValue: 'my-app' }),\n ));\n const dir = resolve(dirInput);\n const name = basename(dir);\n\n const templateId: TemplateId =\n args.template ??\n (args.yes\n ? 'lumen'\n : await ask<TemplateId>(() =>\n p.select({\n message: 'Template',\n initialValue: 'lumen' as TemplateId,\n options: Object.values(TEMPLATES).map((t) => ({ value: t.id, label: t.label })),\n }),\n ));\n const template = TEMPLATES[templateId];\n if (!template) {\n p.cancel(`Unknown template \"${templateId}\". Choose: ${Object.keys(TEMPLATES).join(', ')}`);\n process.exit(1);\n }\n\n const host =\n args.host ??\n (args.yes\n ? ''\n : await ask<string>(() =>\n p.text({\n message:\n 'Deploy host (a domain on your Roxyon subscription — leave blank to set later)',\n placeholder: 'example.com',\n defaultValue: '',\n }),\n ));\n\n const folder =\n args.folder ??\n (args.yes || template.runtime === 'lumen'\n ? ''\n : await ask<string>(() =>\n p.text({ message: 'Folder under the host', placeholder: name, defaultValue: name }),\n ));\n\n const s = p.spinner();\n s.start('Scaffolding');\n try {\n const result = await scaffold({\n dir,\n name,\n template,\n host: host || 'example.com',\n folder,\n install: args.install,\n });\n s.stop('Scaffolded.');\n\n const rel = dir.startsWith(process.cwd()) ? `.${dir.slice(process.cwd().length)}` : dir;\n const steps = [\n `cd ${rel}`,\n ...(result.installed ? [] : ['npm install']),\n template.runtime === 'lumen' ? 'npm run dev' : 'npm run dev',\n ...(host ? [] : [pc.dim('# set \"host\" in roxyon.json (or run `roxyon init`)')]),\n 'roxyon login',\n 'roxyon deploy',\n ];\n p.note(steps.join('\\n'), 'Next');\n p.outro(\n `${pc.green('Ready.')} ${template.baas ? 'Set your BaaS keys in src/roxyon-baas.js. ' : ''}AGENTS.md tells any AI assistant how to build & deploy this.`,\n );\n } catch (err) {\n s.stop('Failed.');\n p.cancel(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n process.stderr.write(`${err instanceof Error ? err.stack : String(err)}\\n`);\n process.exit(1);\n});\n","import { spawn } from 'node:child_process';\nimport { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { type ProjectConfig, buildProjectConfig, saveProjectConfig } from '@roxyon/deploy-core';\nimport { type FileOut, agentFiles } from './agent-files.js';\nimport { type Template, baasOverlayFiles, nodeTemplateFiles } from './templates.js';\n\nexport interface ScaffoldInput {\n dir: string;\n name: string;\n template: Template;\n host: string;\n folder: string;\n install: boolean;\n}\n\nexport interface ScaffoldResult {\n dir: string;\n config: ProjectConfig;\n installed: boolean;\n}\n\nfunction run(cmd: string, args: string[], cwd: string): Promise<number> {\n return new Promise((res) => {\n const child = spawn(cmd, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' });\n child.on('close', (code) => res(code ?? 1));\n child.on('error', () => res(127));\n });\n}\n\nasync function writeFileOut(dir: string, f: FileOut): Promise<void> {\n const path = join(dir, f.path);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, f.content);\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isEmptyish(dir: string): Promise<boolean> {\n try {\n const entries = await readdir(dir);\n return entries.filter((e) => e !== '.git' && e !== '.DS_Store').length === 0;\n } catch {\n return true; // does not exist yet\n }\n}\n\n/** Merge `scripts` and `devDependencies` into a package.json, seeding one if absent. */\nasync function patchPackageJson(\n dir: string,\n name: string,\n patch: { scripts?: Record<string, string>; devDependencies?: Record<string, string> },\n): Promise<void> {\n const path = join(dir, 'package.json');\n let pkg: Record<string, unknown> = {};\n try {\n pkg = JSON.parse(await readFile(path, 'utf8'));\n } catch {\n pkg = { name, version: '0.1.0', private: true };\n }\n pkg.scripts = { ...(pkg.scripts as object), ...patch.scripts };\n if (patch.devDependencies) {\n pkg.devDependencies = { ...(pkg.devDependencies as object), ...patch.devDependencies };\n }\n await writeFile(path, `${JSON.stringify(pkg, null, 2)}\\n`);\n}\n\nexport async function scaffold(input: ScaffoldInput): Promise<ScaffoldResult> {\n const dir = resolve(input.dir);\n if (!(await isEmptyish(dir))) {\n throw new Error(`${dir} is not empty.`);\n }\n await mkdir(dir, { recursive: true });\n\n const config = buildProjectConfig({\n cwd: dir,\n name: input.name,\n runtime: input.template.runtime,\n host: input.host,\n folder: input.folder,\n });\n\n // ---- framework skeleton ----\n if (input.template.viaLmjs) {\n // `lm create <name>` fills the CURRENT directory (the name is only used for\n // [ProjectName] substitution, not as a subdirectory).\n const code = await run('npx', ['--yes', '@lmjs/cli', 'create', input.name], dir);\n if (code !== 0 || !(await exists(join(dir, 'src', 'index.html')))) {\n throw new Error(\n 'Could not scaffold the LumenJS skeleton (npx @lmjs/cli create failed). Is npm online?',\n );\n }\n\n await patchPackageJson(dir, input.name, {\n scripts: {\n dev: 'lm serve',\n build: 'lm build --serverless',\n deploy: 'lm build --serverless && roxyon deploy',\n },\n devDependencies: { '@lmjs/cli': '^1.0.51' },\n });\n\n if (input.template.baas) {\n for (const f of baasOverlayFiles()) await writeFileOut(dir, f);\n // Load the RX SDK + our client before index.js.\n const htmlPath = join(dir, 'src', 'index.html');\n try {\n const html = await readFile(htmlPath, 'utf8');\n if (!html.includes('rxjs')) {\n await writeFile(\n htmlPath,\n html.replace(\n '<script src=\"/js/bea.js\"',\n '<script src=\"https://cdn.roxyon.com/libs/rxjs/1.0.0/rx.js\"></script>\\n ' +\n '<script src=\"/roxyon-baas.js\"></script>\\n <script src=\"/js/bea.js\"',\n ),\n );\n }\n } catch {\n /* template shape changed upstream — the file is still copied, just not linked */\n }\n }\n } else {\n for (const f of nodeTemplateFiles(input.name)) await writeFileOut(dir, f);\n }\n\n // ---- Roxyon overlay (every template) ----\n for (const f of agentFiles(config, { baas: input.template.baas })) {\n await writeFileOut(dir, f);\n }\n await saveProjectConfig(config, dir);\n\n // ---- .gitignore ----\n const gitignore = join(dir, '.gitignore');\n const existing = await readFile(gitignore, 'utf8').catch(() => '');\n if (!existing.includes('node_modules')) {\n await writeFile(gitignore, `${existing}${existing ? '\\n' : ''}node_modules\\ndist\\n.DS_Store\\n`);\n }\n\n // ---- install ----\n let installed = false;\n if (input.install) {\n const code = await run('npm', ['install'], dir);\n installed = code === 0;\n }\n\n return { dir, config, installed };\n}\n","import type { ProjectConfig } from '@roxyon/deploy-core';\n\nexport interface FileOut {\n path: string;\n content: string;\n}\n\n/**\n * The files every scaffolded project gets on top of its framework skeleton, so\n * any AI assistant — and any human — knows how to build and deploy it.\n */\nexport function agentFiles(config: ProjectConfig, opts: { baas: boolean }): FileOut[] {\n const isLumen = config.runtime === 'lumen';\n const dev = isLumen ? 'npm run dev' : `(your app: ${config.start ?? 'npm run start'})`;\n const build = config.build ? config.build : '(no build step)';\n\n const agents = `# AGENTS.md\n\nWorking notes for AI assistants and humans. Also read as \\`CLAUDE.md\\`,\n\\`GEMINI.md\\`, \\`.cursor/rules/roxyon.mdc\\`, \\`.github/copilot-instructions.md\\`.\n\n## This project\n\n- **${config.name}** — a ${config.runtime} project deployed on **Roxyon**.\n- Config: \\`roxyon.json\\` (host \\`${config.host}\\`${config.folder ? `, folder \\`${config.folder}\\`` : ''}).\n- Local dev: \\`${dev}\\`\n- Build: \\`${build}\\`\n\n${\n isLumen\n ? `## LumenJS (V1) — the rules that bite\n\nVanilla JS/HTML/CSS, **no build step** for the framework. \\`.view\\` files under\n\\`src/views/\\` are one per route. Full reference: https://lumenjs.com/llms/lumenjs.md\n\n- State is \\`var\\` (never \\`let\\`/\\`const\\`) in a \\`<script>\\` in the view; reactive\n only when named in \\`bind=\"name\"\\` on an ancestor element.\n- **Never nest a \\`bind\\` inside another \\`bind\\`** — the inner subtree stops\n rendering, interpolations come out empty.\n- \\`bind\\` renders its descendants, not the element's own attributes — put it on\n the parent of whatever interpolates.\n- \\`:for\\` does not resolve the loop variable in nested loops or in an element's\n own plain attributes. Build that markup as a JS string and inject with\n \\`.html()\\`. Backtick the moustache on a \\`:for\\` element's own attribute.\n- A \\`{{ fn() }}\\` moustache runs once and goes stale — compute into a \\`var\\`.\n- Forms: \\`o-sub\\` / \\`b-sub\\` on the \\`<form>\\`. There is no \\`v-model\\`.\n`\n : `## Runtime\n\n${config.runtime} app. \\`PORT\\` and \\`HOST\\` are set by the platform — read them\nfrom the environment, never hard-code or override them. The start command is\n\\`${config.start ?? 'npm run start'}\\` (see \\`roxyon.json\\`).\n`\n}${\n opts.baas\n ? `\n## Roxyon BaaS\n\nConfigured in \\`src/roxyon-baas.js\\`. Reference: https://roxyon.com/llms/baas.md\n\n- **A failed write returns HTTP 200 with an \\`error\\` field** — check for it\n before treating any create/update/delete as successful.\n- The \\`in\\` operator takes a comma-joined string, not an array.\n- Auth: \\`rx.login({Email,Password})\\`, \\`rx.me()\\`, \\`rx.logout()\\`.\n`\n : ''\n}\n## Deploy\n\nDo **not** SFTP files or edit them on the server. Deploy with:\n\n\\`\\`\\`bash\nroxyon deploy # or the roxyon_deploy MCP tool (dry run, then confirm:true)\n\\`\\`\\`\n\n- Env vars live on the platform: \\`roxyon env set KEY=value\\`, then redeploy.\n- Git push-to-deploy: \\`roxyon link <repo-url>\\`.\n- First deploy creates the app automatically.\n`;\n\n const llmsTxt = `# ${config.name}\n\n> A ${config.runtime} project on Roxyon. Deploy with \\`roxyon deploy\\`.\n\n## Docs\n\n- [How to build & deploy](AGENTS.md)\n${isLumen ? '- [LumenJS reference](https://lumenjs.com/llms/lumenjs.md)\\n' : ''}${opts.baas ? '- [Roxyon BaaS reference](https://roxyon.com/llms/baas.md)\\n' : ''}- [Deploying to Roxyon](https://roxyon.com/llms/deploy.md)\n`;\n\n const cursorRule = `---\ndescription: How to build and deploy this Roxyon project\nalwaysApply: true\n---\n\n${agents}`;\n\n return [\n { path: 'AGENTS.md', content: agents },\n { path: 'CLAUDE.md', content: 'See [AGENTS.md](AGENTS.md).\\n' },\n { path: 'GEMINI.md', content: 'See [AGENTS.md](AGENTS.md).\\n' },\n { path: 'llms.txt', content: llmsTxt },\n { path: '.cursor/rules/roxyon.mdc', content: cursorRule },\n { path: '.github/copilot-instructions.md', content: agents },\n {\n path: '.roxyonignore',\n content: ['node_modules', '.git', '.next', '.venv', 'dist/.cache', '.DS_Store', ''].join(\n '\\n',\n ),\n },\n ];\n}\n","import type { FileOut } from './agent-files.js';\n\nexport type TemplateId = 'lumen' | 'lumen-baas' | 'node';\n\nexport interface Template {\n id: TemplateId;\n label: string;\n runtime: 'lumen' | 'node';\n baas: boolean;\n /** LumenJS templates are scaffolded by @lmjs/cli, then overlaid. */\n viaLmjs: boolean;\n}\n\nexport const TEMPLATES: Record<TemplateId, Template> = {\n lumen: { id: 'lumen', label: 'LumenJS SPA', runtime: 'lumen', baas: false, viaLmjs: true },\n 'lumen-baas': {\n id: 'lumen-baas',\n label: 'LumenJS SPA + Roxyon BaaS (auth + data example)',\n runtime: 'lumen',\n baas: true,\n viaLmjs: true,\n },\n node: {\n id: 'node',\n label: 'Node.js app (minimal HTTP server)',\n runtime: 'node',\n baas: false,\n viaLmjs: false,\n },\n};\n\n// ---------------------------------------------------------------------------\n// Node template — bundled inline (no framework, no deps).\n// ---------------------------------------------------------------------------\n\nexport function nodeTemplateFiles(name: string): FileOut[] {\n return [\n {\n path: 'package.json',\n content: `${JSON.stringify(\n {\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n start: 'node src/server.js',\n dev: 'node --watch src/server.js',\n },\n engines: { node: '>=20' },\n },\n null,\n 2,\n )}\\n`,\n },\n {\n path: 'src/server.js',\n content: `import { createServer } from 'node:http';\n\n// The platform sets PORT and HOST. Never hard-code or override them.\nconst port = Number(process.env.PORT) || 3000;\nconst host = process.env.HOST || '0.0.0.0';\n\nconst server = createServer((req, res) => {\n if (req.url === '/health') {\n res.writeHead(200, { 'content-type': 'text/plain' });\n res.end('ok');\n return;\n }\n res.writeHead(200, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ hello: 'from ${name} on Roxyon', url: req.url }));\n});\n\nserver.listen(port, host, () => {\n console.log(\\`listening on http://\\${host}:\\${port}\\`);\n});\n`,\n },\n {\n path: 'README.md',\n content: `# ${name}\n\nA Node.js app on Roxyon.\n\n\\`\\`\\`bash\nnpm install\nnpm run dev # local, http://localhost:3000\nroxyon deploy # to Roxyon (first run creates the app)\n\\`\\`\\`\n\nSee [AGENTS.md](AGENTS.md).\n`,\n },\n ];\n}\n\n// ---------------------------------------------------------------------------\n// LumenJS BaaS overlay — added on top of the @lmjs/cli skeleton.\n// ---------------------------------------------------------------------------\n\nexport function baasOverlayFiles(): FileOut[] {\n return [\n {\n path: 'src/roxyon-baas.js',\n content: `// Roxyon BaaS client. The RX SDK is loaded in index.html from the CDN.\n//\n// A FAILED WRITE RESOLVES with an { error } field (top-level or inside\n// results[]) — it does NOT reject. Always run rxError() on a write response.\nwindow.rx = new RX({\n 'Application-ID': 'YOUR_APPLICATION_ID',\n 'JavaScript-KEY': 'YOUR_JAVASCRIPT_KEY',\n});\n\nwindow.rxError = function (r) {\n if (!r) return 'No response from the server.';\n if (r.error) return r.error;\n var rows = r.results;\n if (Object.prototype.toString.call(rows) === '[object Array]') {\n for (var i = 0; i < rows.length; i++) if (rows[i] && rows[i].error) return rows[i].error;\n }\n return '';\n};\n`,\n },\n {\n path: 'src/views/items.view',\n content: `<div class=\"ph50 pv30\" bind=\"items\">\n <div class=\"fs20 b mb20\">Items ({{items.length}})</div>\n <form o-sub=\"addItem\" class=\"mb20\">\n <input name=\"Title\" placeholder=\"New item\" required class=\"p10\" />\n <button type=\"submit\" class=\"p10\">Add</button>\n </form>\n <div :if=\"msg != ''\" class=\"cr mb10\">{{msg}}</div>\n <div :for=\"items as it\">\n <div class=\"pv5\">{{it.Title}}</div>\n </div>\n</div>\n\n<script>\n // 'var' — not let/const. Reactive because it's named in bind=\"items\".\n var items = [];\n var msg = '';\n\n function loadItems() {\n rx.get('/Items', { fields: 'objectId,Title', order: '-createdAt', limit: 50 }).then(function (r) {\n var err = rxError(r);\n if (err) { msg = err; return; }\n items = r.results || [];\n });\n }\n\n function addItem(f, d) {\n msg = '';\n rx.post('/Items', { Title: d.Title }).then(function (r) {\n var err = rxError(r); // a failed write still lands here\n if (err) { msg = err; return; }\n f.find('[name=\"Title\"]').val('');\n loadItems();\n });\n }\n\n loadItems();\n</script>\n\n<settings> { hasFooter: false, hasHeader: false, hasNav: false } </settings>\n`,\n },\n ];\n}\n"],"mappings":"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","names":["resolve","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts","../src/agent-files.ts","../src/templates.ts"],"sourcesContent":["import { basename, resolve } from 'node:path';\nimport * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { scaffold } from './scaffold.js';\nimport { TEMPLATES, type TemplateId } from './templates.js';\n\ninterface Args {\n dir?: string;\n template?: TemplateId;\n host?: string;\n folder?: string;\n install: boolean;\n yes: boolean;\n}\n\nfunction parseArgs(argv: string[]): Args {\n const a: Args = { install: true, yes: false };\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i]!;\n if (arg === '--no-install') a.install = false;\n else if (arg === '-y' || arg === '--yes') a.yes = true;\n else if (arg === '--template' || arg === '-t') a.template = argv[++i] as TemplateId;\n else if (arg === '--host') a.host = argv[++i];\n else if (arg === '--folder') a.folder = argv[++i];\n else if (arg === '--help' || arg === '-h') a.dir = '--help';\n else if (!arg.startsWith('-') && !a.dir) a.dir = arg;\n }\n return a;\n}\n\nconst HELP = `${pc.bold('create-roxyon-app')} — scaffold a Roxyon project\n\n npm create roxyon-app@latest my-app\n npx create-roxyon-app my-app --template lumen-baas\n\nOptions:\n -t, --template <id> ${Object.keys(TEMPLATES).join(' | ')}\n --host <domain> deploy host (a domain on your Roxyon subscription)\n --folder <path> sub-path under the host\n --no-install skip npm install\n -y, --yes accept defaults, no prompts\n`;\n\nasync function ask<T>(fn: () => Promise<T | symbol>): Promise<T> {\n const v = await fn();\n if (p.isCancel(v)) {\n p.cancel('Cancelled.');\n process.exit(0);\n }\n return v as T;\n}\n\nasync function main(): Promise<void> {\n const args = parseArgs(process.argv.slice(2));\n if (args.dir === '--help') {\n process.stdout.write(HELP);\n return;\n }\n\n p.intro(pc.bgYellow(pc.black(' create-roxyon-app ')));\n\n const dirInput =\n args.dir ??\n (args.yes\n ? 'roxyon-app'\n : await ask<string>(() =>\n p.text({ message: 'Project directory', placeholder: 'my-app', defaultValue: 'my-app' }),\n ));\n const dir = resolve(dirInput);\n const name = basename(dir);\n\n const templateId: TemplateId =\n args.template ??\n (args.yes\n ? 'lumen'\n : await ask<TemplateId>(() =>\n p.select({\n message: 'Template',\n initialValue: 'lumen' as TemplateId,\n options: Object.values(TEMPLATES).map((t) => ({ value: t.id, label: t.label })),\n }),\n ));\n const template = TEMPLATES[templateId];\n if (!template) {\n p.cancel(`Unknown template \"${templateId}\". Choose: ${Object.keys(TEMPLATES).join(', ')}`);\n process.exit(1);\n }\n\n const host =\n args.host ??\n (args.yes\n ? ''\n : await ask<string>(() =>\n p.text({\n message:\n 'Deploy host (a domain on your Roxyon subscription — leave blank to set later)',\n placeholder: 'example.com',\n defaultValue: '',\n }),\n ));\n\n const folder =\n args.folder ??\n (args.yes || template.runtime === 'lumen'\n ? ''\n : await ask<string>(() =>\n p.text({ message: 'Folder under the host', placeholder: name, defaultValue: name }),\n ));\n\n const s = p.spinner();\n s.start('Scaffolding');\n try {\n const result = await scaffold({\n dir,\n name,\n template,\n host: host || 'example.com',\n folder,\n install: args.install,\n });\n s.stop('Scaffolded.');\n\n const rel = dir.startsWith(process.cwd()) ? `.${dir.slice(process.cwd().length)}` : dir;\n const steps = [\n `cd ${rel}`,\n ...(result.installed ? [] : ['npm install']),\n template.runtime === 'lumen' ? 'npm run dev' : 'npm run dev',\n ...(host ? [] : [pc.dim('# set \"host\" in roxyon.json (or run `roxyon init`)')]),\n 'roxyon login',\n 'roxyon deploy',\n ];\n p.note(steps.join('\\n'), 'Next');\n p.outro(\n `${pc.green('Ready.')} ${template.baas ? 'Set your BaaS keys in src/roxyon-baas.js. ' : ''}AGENTS.md tells any AI assistant how to build & deploy this.`,\n );\n } catch (err) {\n s.stop('Failed.');\n p.cancel(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nmain().catch((err) => {\n process.stderr.write(`${err instanceof Error ? err.stack : String(err)}\\n`);\n process.exit(1);\n});\n","import { spawn } from 'node:child_process';\nimport { access, mkdir, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { type ProjectConfig, buildProjectConfig, saveProjectConfig } from '@roxyon/deploy-core';\nimport { type FileOut, agentFiles } from './agent-files.js';\nimport { type Template, baasOverlayFiles, nodeTemplateFiles } from './templates.js';\n\n// Pinned: an older lm.js runtime under a newer CLI builds with only a warning and breaks.\nexport const LMJS_VERSION = '2.5.7';\n\nexport interface ScaffoldInput {\n dir: string;\n name: string;\n template: Template;\n host: string;\n folder: string;\n install: boolean;\n}\n\nexport interface ScaffoldResult {\n dir: string;\n config: ProjectConfig;\n installed: boolean;\n}\n\nfunction run(cmd: string, args: string[], cwd: string): Promise<number> {\n return new Promise((res) => {\n const child = spawn(cmd, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' });\n child.on('close', (code) => res(code ?? 1));\n child.on('error', () => res(127));\n });\n}\n\nasync function writeFileOut(dir: string, f: FileOut): Promise<void> {\n const path = join(dir, f.path);\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, f.content);\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function isEmptyish(dir: string): Promise<boolean> {\n try {\n const entries = await readdir(dir);\n return entries.filter((e) => e !== '.git' && e !== '.DS_Store').length === 0;\n } catch {\n return true; // does not exist yet\n }\n}\n\n/** Merge `scripts` and `devDependencies` into a package.json, seeding one if absent. */\nasync function patchPackageJson(\n dir: string,\n name: string,\n patch: { scripts?: Record<string, string>; devDependencies?: Record<string, string> },\n): Promise<void> {\n const path = join(dir, 'package.json');\n let pkg: Record<string, unknown> = {};\n try {\n pkg = JSON.parse(await readFile(path, 'utf8'));\n } catch {\n pkg = { name, version: '0.1.0', private: true };\n }\n pkg.scripts = { ...(pkg.scripts as object), ...patch.scripts };\n if (patch.devDependencies) {\n pkg.devDependencies = { ...(pkg.devDependencies as object), ...patch.devDependencies };\n }\n await writeFile(path, `${JSON.stringify(pkg, null, 2)}\\n`);\n}\n\nexport async function scaffold(input: ScaffoldInput): Promise<ScaffoldResult> {\n const dir = resolve(input.dir);\n if (!(await isEmptyish(dir))) {\n throw new Error(`${dir} is not empty.`);\n }\n await mkdir(dir, { recursive: true });\n\n const config = buildProjectConfig({\n cwd: dir,\n name: input.name,\n runtime: input.template.runtime,\n host: input.host,\n folder: input.folder,\n });\n\n // ---- framework skeleton ----\n if (input.template.viaLmjs) {\n // `lm create <name>` fills the CURRENT directory (the name is only used for\n // [ProjectName] substitution, not as a subdirectory).\n const code = await run(\n 'npx',\n ['--yes', '-p', `@lmjs/cli@${LMJS_VERSION}`, 'lm', 'create', input.name],\n dir,\n );\n if (code !== 0 || !(await exists(join(dir, 'src', 'index.html')))) {\n throw new Error(\n `Could not scaffold the LumenJS skeleton (npx @lmjs/cli@${LMJS_VERSION} create failed). Is npm online?`,\n );\n }\n\n await patchPackageJson(dir, input.name, {\n scripts: {\n dev: 'lm serve',\n build: 'lm build --serverless',\n deploy: 'lm build --serverless && roxyon deploy',\n },\n devDependencies: { '@lmjs/cli': LMJS_VERSION },\n });\n\n if (input.template.baas) {\n for (const f of baasOverlayFiles()) await writeFileOut(dir, f);\n // Load the RX SDK + our client before index.js.\n const htmlPath = join(dir, 'src', 'index.html');\n try {\n const html = await readFile(htmlPath, 'utf8');\n if (!html.includes('rxjs')) {\n await writeFile(\n htmlPath,\n html.replace(\n '<script src=\"/js/bea.js\"',\n '<script src=\"https://cdn.roxyon.com/libs/rxjs/1.0.0/rx.js\"></script>\\n ' +\n '<script src=\"/roxyon-baas.js\"></script>\\n <script src=\"/js/bea.js\"',\n ),\n );\n }\n } catch {\n /* template shape changed upstream — the file is still copied, just not linked */\n }\n }\n } else {\n for (const f of nodeTemplateFiles(input.name)) await writeFileOut(dir, f);\n }\n\n // ---- Roxyon overlay (every template) ----\n for (const f of agentFiles(config, { baas: input.template.baas })) {\n await writeFileOut(dir, f);\n }\n await saveProjectConfig(config, dir);\n\n // ---- .gitignore ----\n const gitignore = join(dir, '.gitignore');\n const existing = await readFile(gitignore, 'utf8').catch(() => '');\n if (!existing.includes('node_modules')) {\n await writeFile(gitignore, `${existing}${existing ? '\\n' : ''}node_modules\\ndist\\n.DS_Store\\n`);\n }\n\n // ---- install ----\n let installed = false;\n if (input.install) {\n const code = await run('npm', ['install'], dir);\n installed = code === 0;\n }\n\n return { dir, config, installed };\n}\n","import type { ProjectConfig } from '@roxyon/deploy-core';\n\nexport interface FileOut {\n path: string;\n content: string;\n}\n\n/**\n * The files every scaffolded project gets on top of its framework skeleton, so\n * any AI assistant — and any human — knows how to build and deploy it.\n */\nexport function agentFiles(config: ProjectConfig, opts: { baas: boolean }): FileOut[] {\n const isLumen = config.runtime === 'lumen';\n const dev = isLumen ? 'npm run dev' : `(your app: ${config.start ?? 'npm run start'})`;\n const build = config.build ? config.build : '(no build step)';\n\n const agents = `# AGENTS.md\n\nWorking notes for AI assistants and humans. Also read as \\`CLAUDE.md\\`,\n\\`GEMINI.md\\`, \\`.cursor/rules/roxyon.mdc\\`, \\`.github/copilot-instructions.md\\`.\n\n## This project\n\n- **${config.name}** — a ${config.runtime} project deployed on **Roxyon**.\n- Config: \\`roxyon.json\\` (host \\`${config.host}\\`${config.folder ? `, folder \\`${config.folder}\\`` : ''}).\n- Local dev: \\`${dev}\\`\n- Build: \\`${build}\\`\n\n${\n isLumen\n ? `## LumenJS (V1) — the rules that bite\n\nVanilla JS/HTML/CSS, **no build step** for the framework. \\`.view\\` files under\n\\`src/views/\\` are one per route. Full reference: https://lumenjs.com/llms/lumenjs.md\n\n- State is \\`var\\` (never \\`let\\`/\\`const\\`) in a \\`<script>\\` in the view; reactive\n only when named in \\`bind=\"name\"\\` on an ancestor element.\n- **Never nest a \\`bind\\` inside another \\`bind\\`** — the inner subtree stops\n rendering, interpolations come out empty.\n- \\`bind\\` renders its descendants, not the element's own attributes — put it on\n the parent of whatever interpolates.\n- \\`:for\\` does not resolve the loop variable in nested loops or in an element's\n own plain attributes. Build that markup as a JS string and inject with\n \\`.html()\\`. Backtick the moustache on a \\`:for\\` element's own attribute.\n- A \\`{{ fn() }}\\` moustache runs once and goes stale — compute into a \\`var\\`.\n- Forms: \\`o-sub\\` / \\`b-sub\\` on the \\`<form>\\`. There is no \\`v-model\\`.\n`\n : `## Runtime\n\n${config.runtime} app. \\`PORT\\` and \\`HOST\\` are set by the platform — read them\nfrom the environment, never hard-code or override them. The start command is\n\\`${config.start ?? 'npm run start'}\\` (see \\`roxyon.json\\`).\n`\n}${\n opts.baas\n ? `\n## Roxyon BaaS\n\nConfigured in \\`src/roxyon-baas.js\\`. Reference: https://roxyon.com/llms/baas.md\n\n- **A failed write returns HTTP 200 with an \\`error\\` field** — check for it\n before treating any create/update/delete as successful.\n- The \\`in\\` operator takes a comma-joined string, not an array.\n- Auth: \\`rx.login({Email,Password})\\`, \\`rx.me()\\`, \\`rx.logout()\\`.\n`\n : ''\n}\n## Deploy\n\nDo **not** SFTP files or edit them on the server. Deploy with:\n\n\\`\\`\\`bash\nroxyon deploy # or the roxyon_deploy MCP tool (dry run, then confirm:true)\n\\`\\`\\`\n\n- Env vars live on the platform: \\`roxyon env set KEY=value\\`, then redeploy.\n- Git push-to-deploy: \\`roxyon link <repo-url>\\`.\n- First deploy creates the app automatically.\n`;\n\n const llmsTxt = `# ${config.name}\n\n> A ${config.runtime} project on Roxyon. Deploy with \\`roxyon deploy\\`.\n\n## Docs\n\n- [How to build & deploy](AGENTS.md)\n${isLumen ? '- [LumenJS reference](https://lumenjs.com/llms/lumenjs.md)\\n' : ''}${opts.baas ? '- [Roxyon BaaS reference](https://roxyon.com/llms/baas.md)\\n' : ''}- [Deploying to Roxyon](https://roxyon.com/llms/deploy.md)\n`;\n\n const cursorRule = `---\ndescription: How to build and deploy this Roxyon project\nalwaysApply: true\n---\n\n${agents}`;\n\n return [\n { path: 'AGENTS.md', content: agents },\n { path: 'CLAUDE.md', content: 'See [AGENTS.md](AGENTS.md).\\n' },\n { path: 'GEMINI.md', content: 'See [AGENTS.md](AGENTS.md).\\n' },\n { path: 'llms.txt', content: llmsTxt },\n { path: '.cursor/rules/roxyon.mdc', content: cursorRule },\n { path: '.github/copilot-instructions.md', content: agents },\n {\n path: '.roxyonignore',\n content: ['node_modules', '.git', '.next', '.venv', 'dist/.cache', '.DS_Store', ''].join(\n '\\n',\n ),\n },\n ];\n}\n","import type { FileOut } from './agent-files.js';\n\nexport type TemplateId = 'lumen' | 'lumen-baas' | 'node';\n\nexport interface Template {\n id: TemplateId;\n label: string;\n runtime: 'lumen' | 'node';\n baas: boolean;\n /** LumenJS templates are scaffolded by @lmjs/cli, then overlaid. */\n viaLmjs: boolean;\n}\n\nexport const TEMPLATES: Record<TemplateId, Template> = {\n lumen: { id: 'lumen', label: 'LumenJS SPA', runtime: 'lumen', baas: false, viaLmjs: true },\n 'lumen-baas': {\n id: 'lumen-baas',\n label: 'LumenJS SPA + Roxyon BaaS (auth + data example)',\n runtime: 'lumen',\n baas: true,\n viaLmjs: true,\n },\n node: {\n id: 'node',\n label: 'Node.js app (minimal HTTP server)',\n runtime: 'node',\n baas: false,\n viaLmjs: false,\n },\n};\n\n// ---------------------------------------------------------------------------\n// Node template — bundled inline (no framework, no deps).\n// ---------------------------------------------------------------------------\n\nexport function nodeTemplateFiles(name: string): FileOut[] {\n return [\n {\n path: 'package.json',\n content: `${JSON.stringify(\n {\n name,\n version: '0.1.0',\n private: true,\n type: 'module',\n scripts: {\n start: 'node src/server.js',\n dev: 'node --watch src/server.js',\n },\n engines: { node: '>=20' },\n },\n null,\n 2,\n )}\\n`,\n },\n {\n path: 'src/server.js',\n content: `import { createServer } from 'node:http';\n\n// The platform sets PORT and HOST. Never hard-code or override them.\nconst port = Number(process.env.PORT) || 3000;\nconst host = process.env.HOST || '0.0.0.0';\n\nconst server = createServer((req, res) => {\n if (req.url === '/health') {\n res.writeHead(200, { 'content-type': 'text/plain' });\n res.end('ok');\n return;\n }\n res.writeHead(200, { 'content-type': 'application/json' });\n res.end(JSON.stringify({ hello: 'from ${name} on Roxyon', url: req.url }));\n});\n\nserver.listen(port, host, () => {\n console.log(\\`listening on http://\\${host}:\\${port}\\`);\n});\n`,\n },\n {\n path: 'README.md',\n content: `# ${name}\n\nA Node.js app on Roxyon.\n\n\\`\\`\\`bash\nnpm install\nnpm run dev # local, http://localhost:3000\nroxyon deploy # to Roxyon (first run creates the app)\n\\`\\`\\`\n\nSee [AGENTS.md](AGENTS.md).\n`,\n },\n ];\n}\n\n// ---------------------------------------------------------------------------\n// LumenJS BaaS overlay — added on top of the @lmjs/cli skeleton.\n// ---------------------------------------------------------------------------\n\nexport function baasOverlayFiles(): FileOut[] {\n return [\n {\n path: 'src/roxyon-baas.js',\n content: `// Roxyon BaaS client. The RX SDK is loaded in index.html from the CDN.\n//\n// A FAILED WRITE RESOLVES with an { error } field (top-level or inside\n// results[]) — it does NOT reject. Always run rxError() on a write response.\nwindow.rx = new RX({\n 'Application-ID': 'YOUR_APPLICATION_ID',\n 'JavaScript-KEY': 'YOUR_JAVASCRIPT_KEY',\n});\n\nwindow.rxError = function (r) {\n if (!r) return 'No response from the server.';\n if (r.error) return r.error;\n var rows = r.results;\n if (Object.prototype.toString.call(rows) === '[object Array]') {\n for (var i = 0; i < rows.length; i++) if (rows[i] && rows[i].error) return rows[i].error;\n }\n return '';\n};\n`,\n },\n {\n path: 'src/views/items.view',\n content: `<div class=\"ph50 pv30\" bind=\"items\">\n <div class=\"fs20 b mb20\">Items ({{items.length}})</div>\n <form o-sub=\"addItem\" class=\"mb20\">\n <input name=\"Title\" placeholder=\"New item\" required class=\"p10\" />\n <button type=\"submit\" class=\"p10\">Add</button>\n </form>\n <div :if=\"msg != ''\" class=\"cr mb10\">{{msg}}</div>\n <div :for=\"items as it\">\n <div class=\"pv5\">{{it.Title}}</div>\n </div>\n</div>\n\n<script>\n // 'var' — not let/const. Reactive because it's named in bind=\"items\".\n var items = [];\n var msg = '';\n\n function loadItems() {\n rx.get('/Items', { fields: 'objectId,Title', order: '-createdAt', limit: 50 }).then(function (r) {\n var err = rxError(r);\n if (err) { msg = err; return; }\n items = r.results || [];\n });\n }\n\n function addItem(f, d) {\n msg = '';\n rx.post('/Items', { Title: d.Title }).then(function (r) {\n var err = rxError(r); // a failed write still lands here\n if (err) { msg = err; return; }\n f.find('[name=\"Title\"]').val('');\n loadItems();\n });\n }\n\n loadItems();\n</script>\n\n<settings> { hasFooter: false, hasHeader: false, hasNav: false } </settings>\n`,\n },\n ];\n}\n"],"mappings":"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","names":["resolve","resolve"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-roxyon-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Scaffold a Roxyon project — LumenJS SPA or a Node app — wired for `roxyon deploy`, with AGENTS.md / llms.txt / editor rules so any AI assistant gets it right.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@clack/prompts": "^0.7.0",
|
|
32
32
|
"picocolors": "^1.1.1",
|
|
33
|
-
"@roxyon/deploy-core": "0.3.
|
|
33
|
+
"@roxyon/deploy-core": "0.3.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^20.16.11",
|