@stacksjs/buddy 0.70.346 → 0.70.348

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.
@@ -1 +1 @@
1
- import{chmodSync,cpSync,existsSync,readdirSync,rmSync}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";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) \u2014 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)){log.error(result.error);process.exit(ExitCode.FatalError)}ensureExecutableScripts(path);applyAppVcsTemplate(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(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");process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"new")}function isFolderCheck(path){if(!isFolder(path))return;if(readdirSync(path).filter((entry)=>entry!==".git").length===0)return;log.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.");process.exit(ExitCode.FatalError)}async function isOnline(){try{return(await fetch("https://github.com",{method:"HEAD",signal:AbortSignal.timeout(3000)})).ok}catch{return!1}}async function download(name,path,_options){log.info("Setting up your stack.");try{const{downloadTemplate}=await import("@stacksjs/gitit");await downloadTemplate("gh:stacksjs/stacks",{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 \u2014 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 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)){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)){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)){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)){log.error(result.error);process.exit(ExitCode.FatalError)}log.success("Framework resolved from npm")}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 \u2014 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";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) \u2014 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)){log.error(result.error);process.exit(ExitCode.FatalError)}ensureExecutableScripts(path);applyAppVcsTemplate(path);applyAppConfigTemplate(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(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");process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"new")}function isFolderCheck(path){if(!isFolder(path))return;if(readdirSync(path).filter((entry)=>entry!==".git").length===0)return;log.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.");process.exit(ExitCode.FatalError)}async function isOnline(){try{return(await fetch("https://github.com",{method:"HEAD",signal:AbortSignal.timeout(3000)})).ok}catch{return!1}}async function download(name,path,_options){log.info("Setting up your stack.");try{const{downloadTemplate}=await import("@stacksjs/gitit");await downloadTemplate("gh:stacksjs/stacks",{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 \u2014 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 slug=path.replace(/\/+$/,"").split("/").pop()||"stacks-app",displayName=slug.split(/[-_\s]+/).filter(Boolean).map((part)=>`${part.charAt(0).toUpperCase()}${part.slice(1)}`).join(" ");log.info("Installing app-safe infrastructure configuration...");try{for(const file of readdirSync(source)){if(!file.endsWith(".ts"))continue;const rendered=readFileSync(resolve(source,file),"utf8").replaceAll("__APP_NAME__",displayName).replaceAll("__APP_SLUG__",slug);writeFileSync(resolve(destination,file),rendered)}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 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)){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)){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)){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)){log.error(result.error);process.exit(ExitCode.FatalError)}log.success("Framework resolved from npm")}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 \u2014 run `./buddy <feature>:install` to add features back.")}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/buddy",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.70.346",
5
+ "version": "0.70.348",
6
6
  "description": "Meet Buddy. The Stacks runtime.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -95,53 +95,53 @@
95
95
  "prepublishOnly": "bun run build"
96
96
  },
97
97
  "dependencies": {
98
- "@stacksjs/actions": "^0.70.346",
99
- "@stacksjs/ai": "^0.70.346",
100
- "@stacksjs/alias": "^0.70.346",
101
- "@stacksjs/arrays": "^0.70.346",
102
- "@stacksjs/auth": "^0.70.346",
103
- "@stacksjs/build": "^0.70.346",
104
- "@stacksjs/cache": "^0.70.346",
105
- "@stacksjs/cli": "^0.70.346",
98
+ "@stacksjs/actions": "^0.70.348",
99
+ "@stacksjs/ai": "^0.70.348",
100
+ "@stacksjs/alias": "^0.70.348",
101
+ "@stacksjs/arrays": "^0.70.348",
102
+ "@stacksjs/auth": "^0.70.348",
103
+ "@stacksjs/build": "^0.70.348",
104
+ "@stacksjs/cache": "^0.70.348",
105
+ "@stacksjs/cli": "^0.70.348",
106
106
  "@stacksjs/clapp": "^0.2.12",
107
- "@stacksjs/cloud": "^0.70.346",
108
- "@stacksjs/collections": "^0.70.346",
109
- "@stacksjs/config": "^0.70.346",
110
- "@stacksjs/database": "^0.70.346",
111
- "@stacksjs/desktop-build": "^0.70.346",
112
- "@stacksjs/dns": "^0.70.346",
113
- "@stacksjs/email": "^0.70.346",
114
- "@stacksjs/enums": "^0.70.346",
115
- "@stacksjs/error-handling": "^0.70.346",
116
- "@stacksjs/events": "^0.70.346",
117
- "@stacksjs/git": "^0.70.346",
107
+ "@stacksjs/cloud": "^0.70.348",
108
+ "@stacksjs/collections": "^0.70.348",
109
+ "@stacksjs/config": "^0.70.348",
110
+ "@stacksjs/database": "^0.70.348",
111
+ "@stacksjs/desktop-build": "^0.70.348",
112
+ "@stacksjs/dns": "^0.70.348",
113
+ "@stacksjs/email": "^0.70.348",
114
+ "@stacksjs/enums": "^0.70.348",
115
+ "@stacksjs/error-handling": "^0.70.348",
116
+ "@stacksjs/events": "^0.70.348",
117
+ "@stacksjs/git": "^0.70.348",
118
118
  "@stacksjs/gitit": "^0.2.5",
119
- "@stacksjs/health": "^0.70.346",
119
+ "@stacksjs/health": "^0.70.348",
120
120
  "@stacksjs/dnsx": "^0.2.3",
121
121
  "@stacksjs/httx": "^0.1.10",
122
- "@stacksjs/image": "^0.70.346",
123
- "@stacksjs/lint": "^0.70.346",
124
- "@stacksjs/logging": "^0.70.346",
125
- "@stacksjs/notifications": "^0.70.346",
126
- "@stacksjs/objects": "^0.70.346",
127
- "@stacksjs/orm": "^0.70.346",
128
- "@stacksjs/path": "^0.70.346",
129
- "@stacksjs/skills": "^0.70.346",
130
- "@stacksjs/payments": "^0.70.346",
131
- "@stacksjs/realtime": "^0.70.346",
132
- "@stacksjs/router": "^0.70.346",
122
+ "@stacksjs/image": "^0.70.348",
123
+ "@stacksjs/lint": "^0.70.348",
124
+ "@stacksjs/logging": "^0.70.348",
125
+ "@stacksjs/notifications": "^0.70.348",
126
+ "@stacksjs/objects": "^0.70.348",
127
+ "@stacksjs/orm": "^0.70.348",
128
+ "@stacksjs/path": "^0.70.348",
129
+ "@stacksjs/skills": "^0.70.348",
130
+ "@stacksjs/payments": "^0.70.348",
131
+ "@stacksjs/realtime": "^0.70.348",
132
+ "@stacksjs/router": "^0.70.348",
133
133
  "@stacksjs/rpx": "^0.11.42",
134
- "@stacksjs/search-engine": "^0.70.346",
135
- "@stacksjs/security": "^0.70.346",
136
- "@stacksjs/server": "^0.70.346",
137
- "@stacksjs/storage": "^0.70.346",
138
- "@stacksjs/strings": "^0.70.346",
139
- "@stacksjs/testing": "^0.70.346",
140
- "@stacksjs/tunnel": "^0.70.346",
141
- "@stacksjs/types": "^0.70.346",
142
- "@stacksjs/ui": "^0.70.346",
143
- "@stacksjs/utils": "^0.70.346",
144
- "@stacksjs/validation": "^0.70.346",
134
+ "@stacksjs/search-engine": "^0.70.348",
135
+ "@stacksjs/security": "^0.70.348",
136
+ "@stacksjs/server": "^0.70.348",
137
+ "@stacksjs/storage": "^0.70.348",
138
+ "@stacksjs/strings": "^0.70.348",
139
+ "@stacksjs/testing": "^0.70.348",
140
+ "@stacksjs/tunnel": "^0.70.348",
141
+ "@stacksjs/types": "^0.70.348",
142
+ "@stacksjs/ui": "^0.70.348",
143
+ "@stacksjs/utils": "^0.70.348",
144
+ "@stacksjs/validation": "^0.70.348",
145
145
  "@stacksjs/ts-cloud": "^0.7.103",
146
146
  "ajv": "^8.20.0",
147
147
  "ajv-formats": "^3.0.1",