@stacksjs/buddy 0.75.4 → 0.75.6
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/commands/create.js +1 -1
- package/dist/scaffold-app.d.ts +24 -0
- package/dist/scaffold-app.js +3 -1
- package/package.json +53 -53
package/dist/commands/create.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{chmodSync,cpSync,existsSync,readFileSync,readdirSync,rmSync,writeFileSync}from"node:fs";import process from"node:process";import{runAction}from"@stacksjs/actions";import{bold,cyan,dim,intro,log,onUnknownSubcommand,runCommand}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{resolve}from"@stacksjs/path";import{isFolder}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";import{uninstallAllFeatures}from"./features";import{ensurePantryDependencies,ensurePantryInstalled}from"./setup";import{resultFailed}from"../result";import{appIdentity,applyAppEnvTemplate,renderTemplate}from"../scaffold-app";import{applyAppSiteTemplate}from"../scaffold-site";import{fetchPublishedVersions}from"../registry";export function create(buddy){const descriptions={name:"The name of the project",command:"Create a new Stacks project",ui:"Are you building a UI?",components:"Are you building UI components?",webComponents:"Automagically built optimized custom elements/web components?",views:"How about views?",functions:"Are you developing functions/composables?",api:"Are you building an API?",database:"Do you need a database?",notifications:"Do you need notifications? e.g. email, SMS, push or chat notifications",cache:"Do you need caching?",email:"Do you need email?",project:"Target a specific project",minimal:"Skip optional feature bundles (cms, commerce, dashboard, marketing, monitoring, realtime, queue) - bare-bones API/SPA starter that can re-add them later via `./buddy <feature>:install`.",withCore:"Keep the framework vendored in `storage/framework/core` as a Bun workspace, for working ON Stacks. Apps that only work WITH Stacks want the default, which resolves every @stacksjs/* package from npm.",verbose:"Enable verbose output"};buddy.command("new [name]",descriptions.command).alias("create [name]").option("-n, --name [name]",descriptions.name,{default:!1}).option("-u, --ui",descriptions.ui,{default:!0}).option("-c, --components",descriptions.components,{default:!0}).option("-w, --web-components",descriptions.webComponents,{default:!0}).option("-p, --views",descriptions.views,{default:!0}).option("-f, --functions",descriptions.functions,{default:!0}).option("-a, --api",descriptions.api,{default:!0}).option("-d, --database",descriptions.database,{default:!0}).option("-ca, --cache",descriptions.cache,{default:!1}).option("-e, --email",descriptions.email,{default:!1}).option("-P, --project [project]",descriptions.project,{default:!1}).option("-m, --minimal",descriptions.minimal,{default:!1}).option("--with-core",descriptions.withCore,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy new <name>` ...",options);const startTime=await intro("buddy new");name=name??options.name;const path=resolve(process.cwd(),name);isFolderCheck(path);await onlineCheck();const result=await download(name,path,options);if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}ensureExecutableScripts(path);applyAppVcsTemplate(path);applyAppConfigTemplate(path);applyAppEnv(path);replaceFrameworkSite(path);removeFrameworkTests(path);await ensureEnv(path,options);if(options.minimal)await stripFeatures(path);await install(path,options);if(!options.withCore)await unvendorCore(path,options);if(options.minimal)await regenerateAutoImports(path,options);if(startTime){const time=performance.now()-startTime;log.success(dim(`[${time.toFixed(2)}ms] Completed`))}log.info(bold("Welcome to the Stacks Framework! \u269B\uFE0F"));log.info(`Get started: ${cyan(`cd ${name}`)} and then ${cyan("./buddy dev")}`);log.info(`Run ${cyan("./buddy doctor")} anytime to check your setup`);log.info("To learn more, visit https://stacksjs.com");await log.flush();process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"new")}function isFolderCheck(path){if(!isFolder(path))return;if(readdirSync(path).filter((entry)=>entry!==".git").length===0)return;console.error(`Path ${path} already exists`);process.exit(ExitCode.FatalError)}async function onlineCheck(){if(await isOnline())return;log.info("It appears you are disconnected from the internet.");log.info("Creating a new project requires a brief internet connection to download the template and install dependencies.");await log.flush();process.exit(ExitCode.FatalError)}async function isOnline(){try{return(await fetch("https://github.com",{method:"HEAD",signal:AbortSignal.timeout(3000)})).ok}catch{return!1}}export async function templateRef(fetchVersions=fetchPublishedVersions){try{const{latest}=await fetchVersions("stacks");return latest?`v${latest}`:null}catch{return null}}export function templateSpec(ref){return ref?`gh:stacksjs/stacks#${ref}`:"gh:stacksjs/stacks"}async function download(name,path,_options){log.info("Setting up your stack.");const ref=await templateRef();try{const{downloadTemplate}=await import("@stacksjs/gitit");try{await downloadTemplate(templateSpec(ref),{dir:name,force:!0})}catch(error){if(!ref)throw error;log.warn(`No ${ref} tag to scaffold from (${error instanceof Error?error.message:String(error)}).`);log.info("Falling back to the default branch. If this app does not typecheck, that gap is why.");await downloadTemplate(templateSpec(null),{dir:name,force:!0})}log.success(`Successfully scaffolded your project at ${cyan(path)}`);return{isErr:!1}}catch(error){return{isErr:!0,error:error instanceof Error?error.message:String(error)}}}function applyAppVcsTemplate(path){const source=resolve(path,"storage/framework/defaults/vcs/github"),destination=resolve(path,".github");if(!existsSync(source)){log.warn("No app CI template found at storage/framework/defaults/vcs/github - leaving .github as downloaded.");return}log.info("Installing app-shaped GitHub workflows...");try{rmSync(destination,{recursive:!0,force:!0});cpSync(source,destination,{recursive:!0});log.success("App CI installed")}catch(error){log.warn(`Could not install the app CI template: ${error instanceof Error?error.message:String(error)}`)}}function applyAppConfigTemplate(path){const source=resolve(path,"storage/framework/defaults/scaffold/config"),destination=resolve(path,"config");if(!existsSync(source)){log.warn("No app config template found at storage/framework/defaults/scaffold/config - leaving config as downloaded.");return}const identity=appIdentity(path);log.info("Installing app-safe infrastructure configuration...");try{for(const file of readdirSync(source)){if(!file.endsWith(".ts"))continue;const template=readFileSync(resolve(source,file),"utf8");writeFileSync(resolve(destination,file),renderTemplate(template,identity))}log.success("App-safe infrastructure configuration installed")}catch(error){log.warn(`Could not install the app config template: ${error instanceof Error?error.message:String(error)}`)}}function applyAppEnv(path){try{const changed=applyAppEnvTemplate(path,appIdentity(path));if(changed.length>0)log.success(`Named the app in .env.example (${changed.join(", ")})`)}catch(error){log.warn(`Could not name the app in .env.example: ${error instanceof Error?error.message:String(error)}`)}}function replaceFrameworkSite(path){log.info("Replacing the stacksjs.com site with a starter page...");try{const removed=applyAppSiteTemplate(path);log.success(`Starter page installed (${removed.length} stacksjs.com path${removed.length===1?"":"s"} removed)`)}catch(error){log.warn(`Could not install the starter page: ${error instanceof Error?error.message:String(error)}`)}}function removeFrameworkTests(path){const tests=resolve(path,"tests");if(!existsSync(tests))return;log.info("Removing the framework's own test suite...");for(const entry of readdirSync(tests)){if(entry==="setup.ts")continue;rmSync(resolve(tests,entry),{recursive:!0,force:!0})}log.success("App starts with a clean test suite")}function ensureExecutableScripts(path){for(const script of["buddy","bootstrap"])try{chmodSync(resolve(path,script),493)}catch{}}async function ensureEnv(path,_options){log.info("Ensuring your environment is ready...");await ensurePantryInstalled();await ensurePantryDependencies(path);log.success("Environment is ready")}async function install(path,options){log.info("Installing & setting up Stacks");log.info("Copying .env.example \u2192 .env");let result=await runCommand("cp .env.example .env",{...options,cwd:path});if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}log.info("Removing template-encrypted env files...");const{rm}=await import("node:fs/promises");for(const stale of[".env.development",".env.staging",".env.production",".env.keys"])await rm(`${path}/${stale}`,{force:!0});log.info("Generating application key...");const keyResult=await runAction(Action.KeyGenerate,{...options,cwd:path});if(resultFailed(keyResult)){await log.error(keyResult.error);process.exit(ExitCode.FatalError)}if(existsSync(resolve(path,".git")))log.info("Existing git repository detected, skipping git init");else{log.info("Initializing git repository...");result=await runCommand("git init",{...options,cwd:path});if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}}log.success("Installed & set-up \uD83D\uDE80")}async function unvendorCore(path,options){log.info("Resolving the framework from npm (pass --with-core to keep it vendored)...");const result=await runCommand("./buddy unpublish:core --all --force",{...options,cwd:path});if(resultFailed(result)){const reason=result.error instanceof Error?result.error.stack??result.error.message:String(result.error??"").trim();log.error("Could not resolve the framework from npm.");log.error(reason.length>0?reason:"The step failed without reporting a reason.");log.error("");log.error(`The project at ${path} is half converted: the vendored framework has been`);log.error("removed and the published packages are not in place yet, so ./buddy cannot");log.error("boot there. Finish it by hand with:");log.error("");await log.error(` cd ${path} && rm -f node_modules/stacks && bun install`);await log.error("");await log.error("Or start over with `--with-core` to keep the framework vendored.");process.exit(ExitCode.FatalError)}log.success("Framework resolved from npm")}async function regenerateAutoImports(path,options){const result=await runCommand("./buddy generate --types",{...options,cwd:path});if(resultFailed(result))log.warn("Could not regenerate the auto-import barrels. Run `./buddy generate --types` in the project before `./buddy dev`.")}async function stripFeatures(path){log.info("Stripping optional feature bundles (--minimal)...");const results=await uninstallAllFeatures({root:path});let strippedAny=!1;for(const{feature,configOutcome,filesRemoved}of results)if(configOutcome==="flipped"||filesRemoved.length>0){strippedAny=!0;const fileSummary=filesRemoved.length>0?` (${filesRemoved.length} path${filesRemoved.length===1?"":"s"})`:"";log.info(` - ${feature}${fileSummary}`)}if(!strippedAny)log.info(" \u2192 no feature scaffolding present; nothing to strip.");else log.success("Minimal skeleton ready - run `./buddy <feature>:install` to add features back.")}
|
|
1
|
+
import{chmodSync,cpSync,existsSync,readFileSync,readdirSync,rmSync,writeFileSync}from"node:fs";import process from"node:process";import{runAction}from"@stacksjs/actions";import{bold,cyan,dim,intro,log,onUnknownSubcommand,runCommand}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{resolve}from"@stacksjs/path";import{isFolder}from"@stacksjs/storage";import{ExitCode}from"@stacksjs/types";import{uninstallAllFeatures}from"./features";import{ensurePantryDependencies,ensurePantryInstalled}from"./setup";import{resultFailed}from"../result";import{appIdentity,applyAppChangelogTemplate,applyAppEnvTemplate,applyAppPackageTemplate,renderTemplate}from"../scaffold-app";import{applyAppSiteTemplate}from"../scaffold-site";import{fetchPublishedVersions}from"../registry";export function create(buddy){const descriptions={name:"The name of the project",command:"Create a new Stacks project",ui:"Are you building a UI?",components:"Are you building UI components?",webComponents:"Automagically built optimized custom elements/web components?",views:"How about views?",functions:"Are you developing functions/composables?",api:"Are you building an API?",database:"Do you need a database?",notifications:"Do you need notifications? e.g. email, SMS, push or chat notifications",cache:"Do you need caching?",email:"Do you need email?",project:"Target a specific project",minimal:"Skip optional feature bundles (cms, commerce, dashboard, marketing, monitoring, realtime, queue) - bare-bones API/SPA starter that can re-add them later via `./buddy <feature>:install`.",withCore:"Keep the framework vendored in `storage/framework/core` as a Bun workspace, for working ON Stacks. Apps that only work WITH Stacks want the default, which resolves every @stacksjs/* package from npm.",verbose:"Enable verbose output"};buddy.command("new [name]",descriptions.command).alias("create [name]").option("-n, --name [name]",descriptions.name,{default:!1}).option("-u, --ui",descriptions.ui,{default:!0}).option("-c, --components",descriptions.components,{default:!0}).option("-w, --web-components",descriptions.webComponents,{default:!0}).option("-p, --views",descriptions.views,{default:!0}).option("-f, --functions",descriptions.functions,{default:!0}).option("-a, --api",descriptions.api,{default:!0}).option("-d, --database",descriptions.database,{default:!0}).option("-ca, --cache",descriptions.cache,{default:!1}).option("-e, --email",descriptions.email,{default:!1}).option("-P, --project [project]",descriptions.project,{default:!1}).option("-m, --minimal",descriptions.minimal,{default:!1}).option("--with-core",descriptions.withCore,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy new <name>` ...",options);const startTime=await intro("buddy new");name=name??options.name;const path=resolve(process.cwd(),name);isFolderCheck(path);await onlineCheck();const result=await download(name,path,options);if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}ensureExecutableScripts(path);applyAppVcsTemplate(path);applyAppConfigTemplate(path);applyAppEnv(path);applyAppPackage(path);replaceFrameworkSite(path);removeFrameworkTests(path);await ensureEnv(path,options);if(options.minimal)await stripFeatures(path);await install(path,options);if(!options.withCore)await unvendorCore(path,options);if(options.minimal)await regenerateAutoImports(path,options);if(startTime){const time=performance.now()-startTime;log.success(dim(`[${time.toFixed(2)}ms] Completed`))}log.info(bold("Welcome to the Stacks Framework! \u269B\uFE0F"));log.info(`Get started: ${cyan(`cd ${name}`)} and then ${cyan("./buddy dev")}`);log.info(`Run ${cyan("./buddy doctor")} anytime to check your setup`);log.info("To learn more, visit https://stacksjs.com");await log.flush();process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"new")}function isFolderCheck(path){if(!isFolder(path))return;if(readdirSync(path).filter((entry)=>entry!==".git").length===0)return;console.error(`Path ${path} already exists`);process.exit(ExitCode.FatalError)}async function onlineCheck(){if(await isOnline())return;log.info("It appears you are disconnected from the internet.");log.info("Creating a new project requires a brief internet connection to download the template and install dependencies.");await log.flush();process.exit(ExitCode.FatalError)}async function isOnline(){try{return(await fetch("https://github.com",{method:"HEAD",signal:AbortSignal.timeout(3000)})).ok}catch{return!1}}export async function templateRef(fetchVersions=fetchPublishedVersions){try{const{latest}=await fetchVersions("stacks");return latest?`v${latest}`:null}catch{return null}}export function templateSpec(ref){return ref?`gh:stacksjs/stacks#${ref}`:"gh:stacksjs/stacks"}async function download(name,path,_options){log.info("Setting up your stack.");const ref=await templateRef();try{const{downloadTemplate}=await import("@stacksjs/gitit");try{await downloadTemplate(templateSpec(ref),{dir:name,force:!0})}catch(error){if(!ref)throw error;log.warn(`No ${ref} tag to scaffold from (${error instanceof Error?error.message:String(error)}).`);log.info("Falling back to the default branch. If this app does not typecheck, that gap is why.");await downloadTemplate(templateSpec(null),{dir:name,force:!0})}log.success(`Successfully scaffolded your project at ${cyan(path)}`);return{isErr:!1}}catch(error){return{isErr:!0,error:error instanceof Error?error.message:String(error)}}}function applyAppVcsTemplate(path){const source=resolve(path,"storage/framework/defaults/vcs/github"),destination=resolve(path,".github");if(!existsSync(source)){log.warn("No app CI template found at storage/framework/defaults/vcs/github - leaving .github as downloaded.");return}log.info("Installing app-shaped GitHub workflows...");try{rmSync(destination,{recursive:!0,force:!0});cpSync(source,destination,{recursive:!0});log.success("App CI installed")}catch(error){log.warn(`Could not install the app CI template: ${error instanceof Error?error.message:String(error)}`)}}function applyAppConfigTemplate(path){const source=resolve(path,"storage/framework/defaults/scaffold/config"),destination=resolve(path,"config");if(!existsSync(source)){log.warn("No app config template found at storage/framework/defaults/scaffold/config - leaving config as downloaded.");return}const identity=appIdentity(path);log.info("Installing app-safe infrastructure configuration...");try{for(const file of readdirSync(source)){if(!file.endsWith(".ts"))continue;const template=readFileSync(resolve(source,file),"utf8");writeFileSync(resolve(destination,file),renderTemplate(template,identity))}log.success("App-safe infrastructure configuration installed")}catch(error){log.warn(`Could not install the app config template: ${error instanceof Error?error.message:String(error)}`)}}function applyAppEnv(path){try{const changed=applyAppEnvTemplate(path,appIdentity(path));if(changed.length>0)log.success(`Named the app in .env.example (${changed.join(", ")})`)}catch(error){log.warn(`Could not name the app in .env.example: ${error instanceof Error?error.message:String(error)}`)}}function applyAppPackage(path){try{const identity=appIdentity(path),changed=applyAppPackageTemplate(path,identity);if(changed.length>0)log.success(`Named the app in package.json (${changed.join(", ")})`);if(applyAppChangelogTemplate(path,identity))log.success("Started the app its own CHANGELOG.md")}catch(error){log.warn(`Could not name the app in package.json: ${error instanceof Error?error.message:String(error)}`)}}function replaceFrameworkSite(path){log.info("Replacing the stacksjs.com site with a starter page...");try{const removed=applyAppSiteTemplate(path);log.success(`Starter page installed (${removed.length} stacksjs.com path${removed.length===1?"":"s"} removed)`)}catch(error){log.warn(`Could not install the starter page: ${error instanceof Error?error.message:String(error)}`)}}function removeFrameworkTests(path){const tests=resolve(path,"tests");if(!existsSync(tests))return;log.info("Removing the framework's own test suite...");for(const entry of readdirSync(tests)){if(entry==="setup.ts")continue;rmSync(resolve(tests,entry),{recursive:!0,force:!0})}log.success("App starts with a clean test suite")}function ensureExecutableScripts(path){for(const script of["buddy","bootstrap"])try{chmodSync(resolve(path,script),493)}catch{}}async function ensureEnv(path,_options){log.info("Ensuring your environment is ready...");await ensurePantryInstalled();await ensurePantryDependencies(path);log.success("Environment is ready")}async function install(path,options){log.info("Installing & setting up Stacks");log.info("Copying .env.example \u2192 .env");let result=await runCommand("cp .env.example .env",{...options,cwd:path});if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}log.info("Removing template-encrypted env files...");const{rm}=await import("node:fs/promises");for(const stale of[".env.development",".env.staging",".env.production",".env.keys"])await rm(`${path}/${stale}`,{force:!0});log.info("Generating application key...");const keyResult=await runAction(Action.KeyGenerate,{...options,cwd:path});if(resultFailed(keyResult)){await log.error(keyResult.error);process.exit(ExitCode.FatalError)}if(existsSync(resolve(path,".git")))log.info("Existing git repository detected, skipping git init");else{log.info("Initializing git repository...");result=await runCommand("git init",{...options,cwd:path});if(resultFailed(result)){await log.error(result.error);process.exit(ExitCode.FatalError)}}log.success("Installed & set-up \uD83D\uDE80")}async function unvendorCore(path,options){log.info("Resolving the framework from npm (pass --with-core to keep it vendored)...");const result=await runCommand("./buddy unpublish:core --all --force",{...options,cwd:path});if(resultFailed(result)){const reason=result.error instanceof Error?result.error.stack??result.error.message:String(result.error??"").trim();log.error("Could not resolve the framework from npm.");log.error(reason.length>0?reason:"The step failed without reporting a reason.");log.error("");log.error(`The project at ${path} is half converted: the vendored framework has been`);log.error("removed and the published packages are not in place yet, so ./buddy cannot");log.error("boot there. Finish it by hand with:");log.error("");await log.error(` cd ${path} && rm -f node_modules/stacks && bun install`);await log.error("");await log.error("Or start over with `--with-core` to keep the framework vendored.");process.exit(ExitCode.FatalError)}log.success("Framework resolved from npm")}async function regenerateAutoImports(path,options){const result=await runCommand("./buddy generate --types",{...options,cwd:path});if(resultFailed(result))log.warn("Could not regenerate the auto-import barrels. Run `./buddy generate --types` in the project before `./buddy dev`.")}async function stripFeatures(path){log.info("Stripping optional feature bundles (--minimal)...");const results=await uninstallAllFeatures({root:path});let strippedAny=!1;for(const{feature,configOutcome,filesRemoved}of results)if(configOutcome==="flipped"||filesRemoved.length>0){strippedAny=!0;const fileSummary=filesRemoved.length>0?` (${filesRemoved.length} path${filesRemoved.length===1?"":"s"})`:"";log.info(` - ${feature}${fileSummary}`)}if(!strippedAny)log.info(" \u2192 no feature scaffolding present; nothing to strip.");else log.success("Minimal skeleton ready - run `./buddy <feature>:install` to add features back.")}
|
package/dist/scaffold-app.d.ts
CHANGED
|
@@ -19,6 +19,30 @@ export declare function appEnvValues(identity: AppIdentity): Record<string, stri
|
|
|
19
19
|
* Returns the keys it changed.
|
|
20
20
|
*/
|
|
21
21
|
export declare function applyAppEnvTemplate(root: string, identity: AppIdentity): string[];
|
|
22
|
+
/**
|
|
23
|
+
* The `package.json` keys that describe the Stacks repository rather than the
|
|
24
|
+
* app, since the download IS that repository. Every app was named `stacks` at
|
|
25
|
+
* the framework's version, credited its maintainer, and pointed `repository`,
|
|
26
|
+
* `bugs`, `homepage` and `funding` at stacksjs/stacks - so tooling that reads
|
|
27
|
+
* them (npm, GitHub's dependency graph, buddy-bot's PR links) described the
|
|
28
|
+
* framework instead. `undefined` removes the key.
|
|
29
|
+
*/
|
|
30
|
+
export declare function appPackageValues(identity: AppIdentity): Record<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* Rewrite `package.json` for the new app, touching only the keys
|
|
33
|
+
* `appPackageValues` names and keeping the rest (scripts, dependencies,
|
|
34
|
+
* engines, git hooks) in their original order. Returns the keys it changed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyAppPackageTemplate(root: string, identity: AppIdentity): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Replace the framework's CHANGELOG.md with an empty one for the app.
|
|
39
|
+
*
|
|
40
|
+
* The download carried "# Stacks Changelog": about a megabyte of the
|
|
41
|
+
* framework's own release history, which every app then committed, and which
|
|
42
|
+
* the app's first `release` appended its own notes onto. Returns whether a
|
|
43
|
+
* changelog was replaced.
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyAppChangelogTemplate(root: string, identity: AppIdentity): boolean;
|
|
22
46
|
/** The names a new app goes by, all derived from the directory `buddy new` created. */
|
|
23
47
|
export declare interface AppIdentity {
|
|
24
48
|
slug: string
|
package/dist/scaffold-app.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import{existsSync,readFileSync,writeFileSync}from"node:fs";import{join}from"node:path";export function appIdentity(path){const slug=path.replace(/\/+$/,"").split("/").pop()||"stacks-app",words=slug.split(/[^a-z0-9]+/i).filter(Boolean),displayName=words.map((word)=>`${word.charAt(0).toUpperCase()}${word.slice(1)}`).join(" ")||"My App",kebab=words.join("-").toLowerCase().replace(/^[^a-z]+/,"")||"app";return{slug,displayName,kebab,snake:kebab.replaceAll("-","_"),bundleId:`com.example.${kebab}`}}export function templatePlaceholders(identity){return{__APP_NAME__:identity.displayName,__APP_SLUG__:identity.slug,__APP_TAG_PREFIX__:identity.kebab,__APP_BUNDLE_ID__:identity.bundleId}}export function renderTemplate(source,identity){let rendered=source;for(const[placeholder,value]of Object.entries(templatePlaceholders(identity)))rendered=rendered.replaceAll(placeholder,value);return rendered}export function appEnvValues(identity){return{APP_NAME:`"${identity.displayName.replaceAll('"',"")}"`,APP_URL:`${identity.kebab}.localhost`,DB_DATABASE:identity.snake,MAIL_FROM_ADDRESS:`"no-reply@${identity.kebab}.localhost"`,QUEUE_PREFIX:`${identity.snake}:queue`,PREDICTHQ_DB_PASSWORD:null}}export function applyAppEnvTemplate(root,identity){const file=join(root,".env.example");if(!existsSync(file))return[];const values=appEnvValues(identity),changed=[],lines=readFileSync(file,"utf8").split(`
|
|
2
2
|
`).flatMap((line)=>{const key=/^([A-Z0-9_]+)=/.exec(line)?.[1];if(!key||!(key in values))return[line];changed.push(key);const value=values[key];return value===null?[]:[`${key}=${value}`]});writeFileSync(file,lines.join(`
|
|
3
|
-
`));return changed}
|
|
3
|
+
`));return changed}export function appPackageValues(identity){return{name:identity.kebab,version:"0.0.0",description:identity.displayName,author:void 0,contributors:void 0,funding:void 0,homepage:void 0,repository:void 0,bugs:void 0}}export function applyAppPackageTemplate(root,identity){const file=join(root,"package.json");if(!existsSync(file))return[];const pkg=JSON.parse(readFileSync(file,"utf8")),changed=[];for(const[key,value]of Object.entries(appPackageValues(identity)))if(value===void 0){if(key in pkg){delete pkg[key];changed.push(key)}}else if(pkg[key]!==value){pkg[key]=value;changed.push(key)}writeFileSync(file,`${JSON.stringify(pkg,null,2)}
|
|
4
|
+
`);return changed}export function applyAppChangelogTemplate(root,identity){const file=join(root,"CHANGELOG.md");if(!existsSync(file))return!1;writeFileSync(file,`# ${identity.displayName} Changelog
|
|
5
|
+
`);return!0}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/buddy",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.6",
|
|
6
6
|
"description": "Meet Buddy. The Stacks runtime.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -95,66 +95,66 @@
|
|
|
95
95
|
"prepublishOnly": "bun run build"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@stacksjs/actions": "^0.75.
|
|
99
|
-
"@stacksjs/ai": "^0.75.
|
|
100
|
-
"@stacksjs/alias": "^0.75.
|
|
101
|
-
"@stacksjs/analytics": "^0.75.
|
|
102
|
-
"@stacksjs/api": "^0.75.
|
|
103
|
-
"@stacksjs/arrays": "^0.75.
|
|
104
|
-
"@stacksjs/auth": "^0.75.
|
|
105
|
-
"@stacksjs/browser-extension": "^0.75.
|
|
106
|
-
"@stacksjs/build": "^0.75.
|
|
107
|
-
"@stacksjs/cache": "^0.75.
|
|
108
|
-
"@stacksjs/chat": "^0.75.
|
|
98
|
+
"@stacksjs/actions": "^0.75.6",
|
|
99
|
+
"@stacksjs/ai": "^0.75.6",
|
|
100
|
+
"@stacksjs/alias": "^0.75.6",
|
|
101
|
+
"@stacksjs/analytics": "^0.75.6",
|
|
102
|
+
"@stacksjs/api": "^0.75.6",
|
|
103
|
+
"@stacksjs/arrays": "^0.75.6",
|
|
104
|
+
"@stacksjs/auth": "^0.75.6",
|
|
105
|
+
"@stacksjs/browser-extension": "^0.75.6",
|
|
106
|
+
"@stacksjs/build": "^0.75.6",
|
|
107
|
+
"@stacksjs/cache": "^0.75.6",
|
|
108
|
+
"@stacksjs/chat": "^0.75.6",
|
|
109
109
|
"@stacksjs/clapp": "^0.2.12",
|
|
110
|
-
"@stacksjs/cli": "^0.75.
|
|
111
|
-
"@stacksjs/cloud": "^0.75.
|
|
112
|
-
"@stacksjs/cms": "^0.75.
|
|
113
|
-
"@stacksjs/collections": "^0.75.
|
|
114
|
-
"@stacksjs/config": "^0.75.
|
|
115
|
-
"@stacksjs/database": "^0.75.
|
|
116
|
-
"@stacksjs/desktop-build": "^0.75.
|
|
117
|
-
"@stacksjs/dns": "^0.75.
|
|
110
|
+
"@stacksjs/cli": "^0.75.6",
|
|
111
|
+
"@stacksjs/cloud": "^0.75.6",
|
|
112
|
+
"@stacksjs/cms": "^0.75.6",
|
|
113
|
+
"@stacksjs/collections": "^0.75.6",
|
|
114
|
+
"@stacksjs/config": "^0.75.6",
|
|
115
|
+
"@stacksjs/database": "^0.75.6",
|
|
116
|
+
"@stacksjs/desktop-build": "^0.75.6",
|
|
117
|
+
"@stacksjs/dns": "^0.75.6",
|
|
118
118
|
"@stacksjs/dnsx": "^0.2.3",
|
|
119
|
-
"@stacksjs/email": "^0.75.
|
|
120
|
-
"@stacksjs/enums": "^0.75.
|
|
121
|
-
"@stacksjs/env": "^0.75.
|
|
122
|
-
"@stacksjs/error-handling": "^0.75.
|
|
123
|
-
"@stacksjs/events": "^0.75.
|
|
124
|
-
"@stacksjs/features": "^0.75.
|
|
125
|
-
"@stacksjs/git": "^0.75.
|
|
119
|
+
"@stacksjs/email": "^0.75.6",
|
|
120
|
+
"@stacksjs/enums": "^0.75.6",
|
|
121
|
+
"@stacksjs/env": "^0.75.6",
|
|
122
|
+
"@stacksjs/error-handling": "^0.75.6",
|
|
123
|
+
"@stacksjs/events": "^0.75.6",
|
|
124
|
+
"@stacksjs/features": "^0.75.6",
|
|
125
|
+
"@stacksjs/git": "^0.75.6",
|
|
126
126
|
"@stacksjs/gitit": "^0.2.5",
|
|
127
|
-
"@stacksjs/health": "^0.75.
|
|
127
|
+
"@stacksjs/health": "^0.75.6",
|
|
128
128
|
"@stacksjs/httx": "^0.1.10",
|
|
129
|
-
"@stacksjs/image": "^0.75.
|
|
130
|
-
"@stacksjs/lint": "^0.75.
|
|
131
|
-
"@stacksjs/logging": "^0.75.
|
|
132
|
-
"@stacksjs/notifications": "^0.75.
|
|
133
|
-
"@stacksjs/objects": "^0.75.
|
|
134
|
-
"@stacksjs/orm": "^0.75.
|
|
135
|
-
"@stacksjs/path": "^0.75.
|
|
136
|
-
"@stacksjs/payments": "^0.75.
|
|
137
|
-
"@stacksjs/realtime": "^0.75.
|
|
138
|
-
"@stacksjs/router": "^0.75.
|
|
129
|
+
"@stacksjs/image": "^0.75.6",
|
|
130
|
+
"@stacksjs/lint": "^0.75.6",
|
|
131
|
+
"@stacksjs/logging": "^0.75.6",
|
|
132
|
+
"@stacksjs/notifications": "^0.75.6",
|
|
133
|
+
"@stacksjs/objects": "^0.75.6",
|
|
134
|
+
"@stacksjs/orm": "^0.75.6",
|
|
135
|
+
"@stacksjs/path": "^0.75.6",
|
|
136
|
+
"@stacksjs/payments": "^0.75.6",
|
|
137
|
+
"@stacksjs/realtime": "^0.75.6",
|
|
138
|
+
"@stacksjs/router": "^0.75.6",
|
|
139
139
|
"@stacksjs/rpx": "^0.11.54",
|
|
140
|
-
"@stacksjs/scheduler": "^0.75.
|
|
141
|
-
"@stacksjs/search-engine": "^0.75.
|
|
142
|
-
"@stacksjs/security": "^0.75.
|
|
143
|
-
"@stacksjs/server": "^0.75.
|
|
144
|
-
"@stacksjs/sites": "^0.75.
|
|
145
|
-
"@stacksjs/skills": "^0.75.
|
|
146
|
-
"@stacksjs/storage": "^0.75.
|
|
147
|
-
"@stacksjs/strings": "^0.75.
|
|
140
|
+
"@stacksjs/scheduler": "^0.75.6",
|
|
141
|
+
"@stacksjs/search-engine": "^0.75.6",
|
|
142
|
+
"@stacksjs/security": "^0.75.6",
|
|
143
|
+
"@stacksjs/server": "^0.75.6",
|
|
144
|
+
"@stacksjs/sites": "^0.75.6",
|
|
145
|
+
"@stacksjs/skills": "^0.75.6",
|
|
146
|
+
"@stacksjs/storage": "^0.75.6",
|
|
147
|
+
"@stacksjs/strings": "^0.75.6",
|
|
148
148
|
"@stacksjs/stx": "^0.2.307",
|
|
149
|
-
"@stacksjs/testing": "^0.75.
|
|
150
|
-
"@stacksjs/tinker": "^0.75.
|
|
149
|
+
"@stacksjs/testing": "^0.75.6",
|
|
150
|
+
"@stacksjs/tinker": "^0.75.6",
|
|
151
151
|
"@stacksjs/tlsx": "^0.13.19",
|
|
152
152
|
"@stacksjs/ts-cloud": "^0.16.11",
|
|
153
|
-
"@stacksjs/tunnel": "^0.75.
|
|
154
|
-
"@stacksjs/types": "^0.75.
|
|
155
|
-
"@stacksjs/ui": "^0.75.
|
|
156
|
-
"@stacksjs/utils": "^0.75.
|
|
157
|
-
"@stacksjs/validation": "^0.75.
|
|
153
|
+
"@stacksjs/tunnel": "^0.75.6",
|
|
154
|
+
"@stacksjs/types": "^0.75.6",
|
|
155
|
+
"@stacksjs/ui": "^0.75.6",
|
|
156
|
+
"@stacksjs/utils": "^0.75.6",
|
|
157
|
+
"@stacksjs/validation": "^0.75.6",
|
|
158
158
|
"ajv": "^8.20.0",
|
|
159
159
|
"ajv-formats": "^3.0.1",
|
|
160
160
|
"bun-plugin-stx": "^0.2.307",
|