@stacksjs/buddy 0.72.102 → 0.73.0

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
- export*from"./about";export*from"./auth";export*from"./build";export*from"./cd";export*from"./changelog";export*from"./clean";export*from"./cloud";export*from"./commit";export*from"./completion";export*from"./config-migrate";export*from"./configure";export*from"./create";export*from"./db";export*from"./deploy";export*from"./deploy-preview";export*from"./dev";export*from"./dns";export*from"./docs";export*from"./doctor";export*from"./domains";export*from"./email";export*from"./env";export*from"./features";export*from"./fresh";export*from"./generate";export*from"./http";export*from"./install";export*from"./key";export*from"./lint";export*from"./list";export*from"./mail";export*from"./make";export*from"./migrate";export*from"./migrate-project";export*from"./outdated";export*from"./phone";export*from"./ports";export*from"./link";export*from"./user";export*from"./prepublish";export*from"./projects";export*from"./publish";export*from"./queue";export*from"./release";export*from"./route";export*from"./saas";export*from"./schedule";export*from"./search";export*from"./seed";export*from"./serve";export*from"./setup";export*from"./sms";export*from"./telemetry";export*from"./test";export*from"./tinker";export*from"./types";export*from"./upgrade";export*from"./version";
1
+ export*from"./about";export*from"./auth";export*from"./build";export*from"./cd";export*from"./changelog";export*from"./clean";export*from"./cloud";export*from"./commit";export*from"./completion";export*from"./config-migrate";export*from"./configure";export*from"./create";export*from"./db";export*from"./deploy";export*from"./deploy-preview";export*from"./dev";export*from"./dns";export*from"./docs";export*from"./doctor";export*from"./domains";export*from"./email";export*from"./env";export*from"./features";export*from"./fresh";export*from"./generate";export*from"./http";export*from"./install";export*from"./key";export*from"./libs";export*from"./lint";export*from"./list";export*from"./mail";export*from"./make";export*from"./migrate";export*from"./migrate-project";export*from"./outdated";export*from"./phone";export*from"./ports";export*from"./link";export*from"./user";export*from"./prepublish";export*from"./projects";export*from"./publish";export*from"./queue";export*from"./release";export*from"./route";export*from"./saas";export*from"./schedule";export*from"./search";export*from"./seed";export*from"./serve";export*from"./setup";export*from"./sms";export*from"./telemetry";export*from"./test";export*from"./tinker";export*from"./types";export*from"./upgrade";export*from"./version";
@@ -0,0 +1,2 @@
1
+ import type { CLI } from '@stacksjs/types';
2
+ export declare function libs(buddy: CLI): void;
@@ -0,0 +1 @@
1
+ import{relative}from"node:path";import process from"node:process";import{runAction}from"@stacksjs/actions";import{bold,dim,log,onUnknownSubcommand}from"@stacksjs/cli";import{Action}from"@stacksjs/enums";import{ExitCode}from"@stacksjs/types";import{resultFailed}from"../result";export function libs(buddy){const descriptions={list:"List the packages this project releases out of resources/functions and resources/components",build:"Build every configured library package",publish:"Publish the built library packages to npm",json:"Print the resolved packages as JSON",dryRun:"Run `npm publish --dry-run` instead of publishing",verbose:"Enable verbose output"};buddy.command("libs",descriptions.list).alias("libs:list").alias("libraries").option("--json",descriptions.json,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy libs").action(async(options)=>{const{resolveLibraryPackages,LibraryConfigError}=await import("@stacksjs/actions"),{library}=await import("@stacksjs/config");try{const packages=await resolveLibraryPackages(library);if(options.json){console.log(JSON.stringify(packages.map((pkg)=>({name:pkg.name,kind:pkg.kind,dir:relative(process.cwd(),pkg.dir),private:pkg.private,runtime:pkg.runtime,sources:pkg.sources.map((source)=>relative(process.cwd(),source))})),null,2));return}if(!packages.length){log.info("No library packages are configured. Add one to `packages` in config/library.ts.");return}for(const pkg of packages){console.log(`${bold(pkg.name)} ${dim(`(${pkg.kind}${pkg.private?", private":""})`)}`);console.log(dim(` \u2192 ${relative(process.cwd(),pkg.dir)}`));for(const source of pkg.sources)console.log(dim(` \xB7 ${relative(process.cwd(),source)}`))}}catch(error){if(error instanceof LibraryConfigError){await log.exit(error.message,1);return}throw error}});buddy.command("libs:build",descriptions.build).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{const result=await runAction(Action.BuildLibs,options);if(resultFailed(result)){log.error("Failed to build the library packages.",result.error);process.exit(ExitCode.FatalError)}});buddy.command("libs:publish",descriptions.publish).option("--dry-run",descriptions.dryRun,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy libs:publish --dry-run").action(async(options)=>{const result=await runAction(Action.LibraryPublish,{...options,verbose:!0});if(resultFailed(result)){log.error("Failed to publish the library packages.",result.error);process.exit(ExitCode.FatalError)}});onUnknownSubcommand(buddy,"libs")}
@@ -1 +1 @@
1
- import process from"node:process";import{createFactory,createMiddleware,createMigration,createModel,createNotification,createPage,invoke,makeAction,makeCertificate,makeCommand,makeComponent,makeDatabase,makeFunction,makeJob,makeLanguage,makeMail,makePage,makePolicy,makeQueueTable,makeResource,makeStack,setDryRun}from"@stacksjs/actions";import{intro,italic,onUnknownSubcommand,outro}from"@stacksjs/cli";import{log}from"@stacksjs/logging";import{ExitCode}from"@stacksjs/types";export function make(buddy){const descriptions={action:"Create a new action",command:"Create a new CLI command",model:"Create a new model",middleware:"Create a new middleware",component:"Create a new component",page:"Create a new page",function:"Create a new function",job:"Create a new job",language:"Create a new language",database:"Create a new database",migration:"Create a new migration",factory:"Create a new factory",notification:"Create a new notification",mail:"Create a new Mailable + companion stx template",policy:"Create a new authorization policy",resource:"Create a new API resource",name:"The name of the action",queue:"Make queue migration",queueTable:"Create the queue jobs table migration",stack:"Create a new stack",certificate:"Create a new SSL Certificate",select:"What are you trying to make?",project:"Target a specific project",verbose:"Enable verbose output"};buddy.command("make [make]","The make command").option("-a, --action [action]",descriptions.action,{default:!1}).option("-c, --component [component]",descriptions.component,{default:!1}).option("-d, --database [database]",descriptions.database,{default:!1}).option("-f, --factory [factory]",descriptions.factory,{default:!1}).option("-fn, --function [function]",descriptions.function,{default:!1}).option("-l, --language [language]",descriptions.language,{default:!1}).option("-m, --model [model]",descriptions.model,{default:!1}).option("-mw, --middleware [middleware]",descriptions.middleware,{default:!1}).option("-p, --page [page]",descriptions.page,{default:!1}).option("-mg, --migration [migration]",descriptions.migration,{default:!1}).option("-n, --notification [notification]",descriptions.notification,{default:!1}).option("-qt, --queue-table",descriptions.queue,{default:!1}).option("-s, --stack [stack]",descriptions.stack,{default:!1}).option("--dry-run","Preview the files that would be generated without writing",{default:!1}).option("--with-validation","Include a validation rules block in the generated stub",{default:!1}).option("--with-auth","Include auth-aware boilerplate in the generated stub",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(make,options)=>{log.debug("Running `buddy make` ...",options);if(!buddy.args[0]){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}setDryRun(Boolean(options.dryRun||options["dry-run"]));if(make){options.name=buddy.args[1]??make;switch(make){case"action":await makeAction(options);break;case"certificate":await makeCertificate();break;case"command":await makeCommand(options);break;case"component":await makeComponent(options);break;case"database":makeDatabase(options);break;case"function":await makeFunction(options);break;case"job":await makeJob(options);break;case"language":await makeLanguage(options);break;case"mail":await makeMail(options);break;case"migration":await createMigration(options);break;case"middleware":await createMiddleware(options);break;case"model":await createModel(options);break;case"page":await createPage(options);break;case"notification":await createNotification(options);break;case"policy":await makePolicy(options);break;case"resource":await makeResource(options);break;case"queue-table":await makeQueueTable();break;case"stack":await makeStack(options);break;case"factory":await createFactory(options);break;default:{console.error(`Unknown make subcommand: ${make}`);console.error("Valid subcommands: action, certificate, command, component, database, factory, function, job, language, mail, middleware, migration, model, notification, page, policy, queue-table, resource, stack");process.exit(ExitCode.InvalidArgument)}}}await invoke(options);process.exit(ExitCode.Success)});buddy.command("make:action [name]",descriptions.action).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--dry-run","Preview the file without writing",{default:!1}).option("--with-validation","Generate a stub that calls validate()",{default:!1}).option("--with-auth","Generate a stub that requires an authenticated user",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.info("Running `buddy make:action` ...");log.debug("Running `buddy make:action` ...",name,options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}setDryRun(Boolean(options.dryRun||options["dry-run"]));await makeAction(options)});buddy.command("make:certificate",descriptions.certificate).alias("make:cert").example("buddy make:certificate").action(async(options)=>{log.debug("Running `buddy make:certificate` ...",options);await makeCertificate()});buddy.command("scaffold:crud [name]","Generate model, migration, and CRUD actions").alias("make:crud").alias("make:scaffold").option("-n, --name [name]","Resource name (PascalCase)",{default:!1}).option("-f, --fields [fields]","Comma-separated field list, e.g. title:string,body:text,published:boolean",{default:""}).option("--dry-run","Preview the generated files without writing",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy scaffold:crud Post --fields=title:string,body:text,published:boolean").action(async(name,options)=>{name=name??options.name;if(!name){console.error("scaffold:crud requires a resource name. Example: buddy scaffold:crud Post --fields=title:string,body:text");process.exit(ExitCode.FatalError)}const{scaffoldCrud}=await import("@stacksjs/actions");setDryRun(Boolean(options.dryRun||options["dry-run"]));try{await scaffoldCrud(name,options)}catch(err){console.error("scaffold:crud failed:",err);process.exit(ExitCode.FatalError)}});buddy.command("make:command [name]",descriptions.command).option("-n, --name [name]",descriptions.name,{default:!1}).option("-s, --signature [signature]","The command signature (CLI name)",{default:!1}).option("-d, --description [description]","The command description",{default:!1}).option("--register","Also add an entry to app/Commands.ts (optional - commands are auto-discovered)",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:command SendEmails").example("buddy make:command SendEmails --signature=send-emails").action(async(name,options)=>{log.debug("Running `buddy make:command` ...",options);const perf=await intro("buddy make:command");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a command name.");console.error("Example: buddy make:command SendEmails");process.exit(ExitCode.FatalError)}if(!await makeCommand(options)){await outro("While running the make:command command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} command.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:component [name]",descriptions.component).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:component` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeComponent(options)});buddy.command("make:database [name]",descriptions.database).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action((name,options)=>{log.debug("Running `buddy make:database` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a database name via the `--name` option, or as the command\u2019s argument.");console.error("Example: `buddy make:database my-cool-database`");console.error("Or: `buddy make:database --name=my-cool-database`");console.error("Read more about the documentation here: https://stacksjs.com/docs/make/database");process.exit(ExitCode.FatalError)}makeDatabase(options)});buddy.command("make:factory [name]",descriptions.factory).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:factory` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await createFactory(options)});buddy.command("make:function [name]",descriptions.function).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:function` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeFunction(options)});buddy.command("make:lang [name]",descriptions.language).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:lang` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeLanguage(options)});buddy.command("make:migration [name]",descriptions.migration).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:migration` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a migration name");process.exit(ExitCode.FatalError)}await createMigration(options)});buddy.command("make:model [name]",descriptions.model).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:model` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a model name");process.exit(ExitCode.FatalError)}await createModel(options)});buddy.command("make:mail [name]",descriptions.mail).option("-n, --name [name]",descriptions.name,{default:!1}).option("-f, --force","Overwrite existing files",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:mail OrderShipped").example("buddy make:mail welcome-back // PascalCases to WelcomeBack, kebab-cases to welcome-back").example("buddy make:mail Welcome --force // overwrite existing files").action(async(name,options)=>{log.debug("Running `buddy make:mail` ...",options);const perf=await intro("buddy make:mail");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name (e.g. `buddy make:mail OrderShipped`).");process.exit(ExitCode.FatalError)}await makeMail(options);await outro(`Created your ${italic(name)} mailable.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:notification [name]",descriptions.notification).option("-n, --name [name]",descriptions.name,{default:!1}).option("-e, --email","Is it an email notification?",{default:!0}).option("-c, --chat","Is it a chat notification?",{default:!1}).option("-s, --sms","Is it a SMS notification?",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:notification` ...",options);const perf=await intro("buddy make:notification");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}if(!await createNotification(options)){await outro("While running the make:notification command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} notification.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:policy [name]",descriptions.policy).option("-n, --name [name]",descriptions.name,{default:!1}).option("-m, --model [model]","The model this policy is for",{default:!1}).option("--no-register","Do not register in Gates.ts",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:policy PostPolicy").example("buddy make:policy CommentPolicy --model=Comment").action(async(name,options)=>{log.debug("Running `buddy make:policy` ...",options);const perf=await intro("buddy make:policy");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a policy name.");console.error("Example: buddy make:policy PostPolicy");process.exit(ExitCode.FatalError)}if(!await makePolicy(options)){await outro("While running the make:policy command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} policy.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:resource [name]",descriptions.resource).option("-n, --name [name]",descriptions.name,{default:!1}).option("-m, --model [model]","The model this resource is for",{default:!1}).option("-c, --collection","Create a collection resource",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:resource UserResource").example("buddy make:resource PostResource --model=Post").example("buddy make:resource PostCollection --collection").action(async(name,options)=>{log.debug("Running `buddy make:resource` ...",options);const perf=await intro("buddy make:resource");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a resource name.");console.error("Example: buddy make:resource UserResource");process.exit(ExitCode.FatalError)}if(!await makeResource(options)){await outro("While running the make:resource command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} resource.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:queue-table",descriptions.queueTable).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy make queue:table` ...",options);await makeQueueTable()});buddy.command("make:stack [name]",descriptions.stack).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:stack` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeStack(options)});buddy.command("make:view [name]",descriptions.page).alias("make:page [name]").option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:view` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makePage(options)});buddy.command("make:job [name]",descriptions.job).option("-n, --name [name]",descriptions.name,{default:!1}).option("-q, --queue [queue]","The queue to dispatch to",{default:"default"}).option("-c, --class","Create a class-based job",{default:!1}).option("-t, --tries [tries]","Number of retry attempts",{default:3}).option("-b, --backoff [backoff]","Backoff delay in seconds",{default:3}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:job` ...",options);const perf=await intro("buddy make:job");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a job name.");console.error("Example: buddy make:job SendWelcomeEmail");process.exit(ExitCode.FatalError)}if(!await makeJob(options)){await outro("While running the make:job command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} job.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"make")}
1
+ import process from"node:process";import{createFactory,createMiddleware,createMigration,createModel,createNotification,createPage,invoke,makeAction,makeCertificate,makeCommand,makeComponent,makeDatabase,makeFunction,makeJob,makeLanguage,makeMail,makePage,makePolicy,makeQueueTable,makeResource,makeStack,setDryRun}from"@stacksjs/actions";import{intro,italic,onUnknownSubcommand,outro}from"@stacksjs/cli";import{log}from"@stacksjs/logging";import{ExitCode}from"@stacksjs/types";export function make(buddy){const descriptions={action:"Create a new action",command:"Create a new CLI command",model:"Create a new model",middleware:"Create a new middleware",component:"Create a new component",page:"Create a new page",function:"Create a new function",job:"Create a new job",language:"Create a new language",database:"Create a new database",migration:"Create a new migration",factory:"Create a new factory",notification:"Create a new notification",mail:"Create a new Mailable + companion stx template",policy:"Create a new authorization policy",resource:"Create a new API resource",name:"The name of the action",queue:"Make queue migration",queueTable:"Create the queue jobs table migration",stack:"Create a new stack",certificate:"Create a new SSL Certificate",select:"What are you trying to make?",project:"Target a specific project",verbose:"Enable verbose output"};buddy.command("make [make]","The make command").option("-a, --action [action]",descriptions.action,{default:!1}).option("-c, --component [component]",descriptions.component,{default:!1}).option("-d, --database [database]",descriptions.database,{default:!1}).option("-f, --factory [factory]",descriptions.factory,{default:!1}).option("-fn, --function [function]",descriptions.function,{default:!1}).option("-l, --language [language]",descriptions.language,{default:!1}).option("-m, --model [model]",descriptions.model,{default:!1}).option("-mw, --middleware [middleware]",descriptions.middleware,{default:!1}).option("-p, --page [page]",descriptions.page,{default:!1}).option("-mg, --migration [migration]",descriptions.migration,{default:!1}).option("-n, --notification [notification]",descriptions.notification,{default:!1}).option("-qt, --queue-table",descriptions.queue,{default:!1}).option("-s, --stack [stack]",descriptions.stack,{default:!1}).option("--dry-run","Preview the files that would be generated without writing",{default:!1}).option("--with-validation","Include a validation rules block in the generated stub",{default:!1}).option("--with-auth","Include auth-aware boilerplate in the generated stub",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(make,options)=>{log.debug("Running `buddy make` ...",options);if(!buddy.args[0]){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}setDryRun(Boolean(options.dryRun||options["dry-run"]));if(make){options.name=buddy.args[1]??make;switch(make){case"action":await makeAction(options);break;case"certificate":await makeCertificate();break;case"command":await makeCommand(options);break;case"component":await makeComponent(options);break;case"database":makeDatabase(options);break;case"function":await makeFunction(options);break;case"job":await makeJob(options);break;case"language":await makeLanguage(options);break;case"mail":await makeMail(options);break;case"migration":await createMigration(options);break;case"middleware":await createMiddleware(options);break;case"model":await createModel(options);break;case"page":await createPage(options);break;case"notification":await createNotification(options);break;case"policy":await makePolicy({name:options.name,model:typeof options.model==="string"?options.model:void 0,register:options.register});break;case"resource":await makeResource({name:options.name,model:typeof options.model==="string"?options.model:void 0});break;case"queue-table":await makeQueueTable();break;case"stack":await makeStack(options);break;case"factory":await createFactory(options);break;default:{console.error(`Unknown make subcommand: ${make}`);console.error("Valid subcommands: action, certificate, command, component, database, factory, function, job, language, mail, middleware, migration, model, notification, page, policy, queue-table, resource, stack");process.exit(ExitCode.InvalidArgument)}}}await invoke(options);process.exit(ExitCode.Success)});buddy.command("make:action [name]",descriptions.action).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--dry-run","Preview the file without writing",{default:!1}).option("--with-validation","Generate a stub that calls validate()",{default:!1}).option("--with-auth","Generate a stub that requires an authenticated user",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.info("Running `buddy make:action` ...");log.debug("Running `buddy make:action` ...",name,options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}setDryRun(Boolean(options.dryRun||options["dry-run"]));await makeAction(options)});buddy.command("make:certificate",descriptions.certificate).alias("make:cert").example("buddy make:certificate").action(async(options)=>{log.debug("Running `buddy make:certificate` ...",options);await makeCertificate()});buddy.command("scaffold:crud [name]","Generate model, migration, and CRUD actions").alias("make:crud").alias("make:scaffold").option("-n, --name [name]","Resource name (PascalCase)",{default:!1}).option("-f, --fields [fields]","Comma-separated field list, e.g. title:string,body:text,published:boolean",{default:""}).option("--dry-run","Preview the generated files without writing",{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy scaffold:crud Post --fields=title:string,body:text,published:boolean").action(async(name,options)=>{name=name??options.name;if(!name){console.error("scaffold:crud requires a resource name. Example: buddy scaffold:crud Post --fields=title:string,body:text");process.exit(ExitCode.FatalError)}const{scaffoldCrud}=await import("@stacksjs/actions");setDryRun(Boolean(options.dryRun||options["dry-run"]));try{await scaffoldCrud(name,options)}catch(err){console.error("scaffold:crud failed:",err);process.exit(ExitCode.FatalError)}});buddy.command("make:command [name]",descriptions.command).option("-n, --name [name]",descriptions.name,{default:!1}).option("-s, --signature [signature]","The command signature (CLI name)",{default:!1}).option("-d, --description [description]","The command description",{default:!1}).option("--register","Also add an entry to app/Commands.ts (optional - commands are auto-discovered)",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:command SendEmails").example("buddy make:command SendEmails --signature=send-emails").action(async(name,options)=>{log.debug("Running `buddy make:command` ...",options);const perf=await intro("buddy make:command");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a command name.");console.error("Example: buddy make:command SendEmails");process.exit(ExitCode.FatalError)}if(!await makeCommand(options)){await outro("While running the make:command command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} command.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:component [name]",descriptions.component).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:component` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeComponent(options)});buddy.command("make:database [name]",descriptions.database).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action((name,options)=>{log.debug("Running `buddy make:database` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a database name via the `--name` option, or as the command\u2019s argument.");console.error("Example: `buddy make:database my-cool-database`");console.error("Or: `buddy make:database --name=my-cool-database`");console.error("Read more about the documentation here: https://stacksjs.com/docs/make/database");process.exit(ExitCode.FatalError)}makeDatabase(options)});buddy.command("make:factory [name]",descriptions.factory).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:factory` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await createFactory(options)});buddy.command("make:function [name]",descriptions.function).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:function` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeFunction(options)});buddy.command("make:lang [name]",descriptions.language).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:lang` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeLanguage(options)});buddy.command("make:migration [name]",descriptions.migration).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:migration` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a migration name");process.exit(ExitCode.FatalError)}await createMigration(options)});buddy.command("make:model [name]",descriptions.model).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:model` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a model name");process.exit(ExitCode.FatalError)}await createModel(options)});buddy.command("make:mail [name]",descriptions.mail).option("-n, --name [name]",descriptions.name,{default:!1}).option("-f, --force","Overwrite existing files",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:mail OrderShipped").example("buddy make:mail welcome-back // PascalCases to WelcomeBack, kebab-cases to welcome-back").example("buddy make:mail Welcome --force // overwrite existing files").action(async(name,options)=>{log.debug("Running `buddy make:mail` ...",options);const perf=await intro("buddy make:mail");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name (e.g. `buddy make:mail OrderShipped`).");process.exit(ExitCode.FatalError)}await makeMail(options);await outro(`Created your ${italic(name)} mailable.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:notification [name]",descriptions.notification).option("-n, --name [name]",descriptions.name,{default:!1}).option("-e, --email","Is it an email notification?",{default:!0}).option("-c, --chat","Is it a chat notification?",{default:!1}).option("-s, --sms","Is it a SMS notification?",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:notification` ...",options);const perf=await intro("buddy make:notification");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}if(!await createNotification(options)){await outro("While running the make:notification command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} notification.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:policy [name]",descriptions.policy).option("-n, --name [name]",descriptions.name,{default:!1}).option("-m, --model [model]","The model this policy is for",{default:!1}).option("--no-register","Do not register in Gates.ts",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:policy PostPolicy").example("buddy make:policy CommentPolicy --model=Comment").action(async(name,options)=>{log.debug("Running `buddy make:policy` ...",options);const perf=await intro("buddy make:policy");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a policy name.");console.error("Example: buddy make:policy PostPolicy");process.exit(ExitCode.FatalError)}if(!await makePolicy(options)){await outro("While running the make:policy command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} policy.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:resource [name]",descriptions.resource).option("-n, --name [name]",descriptions.name,{default:!1}).option("-m, --model [model]","The model this resource is for",{default:!1}).option("-c, --collection","Create a collection resource",{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).example("buddy make:resource UserResource").example("buddy make:resource PostResource --model=Post").example("buddy make:resource PostCollection --collection").action(async(name,options)=>{log.debug("Running `buddy make:resource` ...",options);const perf=await intro("buddy make:resource");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a resource name.");console.error("Example: buddy make:resource UserResource");process.exit(ExitCode.FatalError)}if(!await makeResource(options)){await outro("While running the make:resource command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} resource.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});buddy.command("make:queue-table",descriptions.queueTable).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(options)=>{log.debug("Running `buddy make queue:table` ...",options);await makeQueueTable()});buddy.command("make:stack [name]",descriptions.stack).option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:stack` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makeStack(options)});buddy.command("make:view [name]",descriptions.page).alias("make:page [name]").option("-n, --name [name]",descriptions.name,{default:!1}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:view` ...",options);name=name??options.name;options.name=name;if(!name){console.error("You need to specify a name. Read more about the documentation here.");process.exit(ExitCode.FatalError)}await makePage(options)});buddy.command("make:job [name]",descriptions.job).option("-n, --name [name]",descriptions.name,{default:!1}).option("-q, --queue [queue]","The queue to dispatch to",{default:"default"}).option("-c, --class","Create a class-based job",{default:!1}).option("-t, --tries [tries]","Number of retry attempts",{default:3}).option("-b, --backoff [backoff]","Backoff delay in seconds",{default:3}).option("-p, --project [project]",descriptions.project,{default:!1}).option("--verbose",descriptions.verbose,{default:!1}).action(async(name,options)=>{log.debug("Running `buddy make:job` ...",options);const perf=await intro("buddy make:job");name=name??options.name;options.name=name;if(!name){console.error("You need to specify a job name.");console.error("Example: buddy make:job SendWelcomeEmail");process.exit(ExitCode.FatalError)}if(!await makeJob(options)){await outro("While running the make:job command, there was an issue",{startTime:perf,useSeconds:!0});process.exit(ExitCode.FatalError)}await outro(`Created your ${italic(name)} job.`,{startTime:perf,useSeconds:!0});process.exit(ExitCode.Success)});onUnknownSubcommand(buddy,"make")}
@@ -7,19 +7,19 @@ import{getErrorMessage}from"@stacksjs/utils";import{readFileSync,existsSync}from
7
7
  Account:`);console.log(` Sandbox Status: ${status.sandboxStatus==="IN_SANDBOX"?"\u26A0\uFE0F In Sandbox":"\u2705 Production"}`);console.log(` Spending Limit: $${status.spendingLimit}/month`);console.log(`
8
8
  SNS Topics:`);if(status.topics.length===0)console.log(" No SMS topics configured");else for(const topic of status.topics)console.log(` ${topic.name}`);if(status.sandboxStatus==="IN_SANDBOX"){console.log(`
9
9
  \uD83D\uDCA1 To exit sandbox mode:`);console.log(" Run `buddy sms:setup` to file a support request");console.log(" Or visit AWS Console > End User Messaging > SMS > Request production access")}if(status.phoneNumbers.some((p)=>p.status==="PENDING"))console.log(`
10
- \u23F3 Note: Phone number verification can take 24-72 hours for toll-free numbers`)}catch(error){console.error("Error checking status:",getErrorMessage(error));try{const{PinpointSmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new PinpointSmsVoiceClient(process.env.AWS_REGION||"us-east-1"),activeNumbers=(await withTimeout(smsClient.describePhoneNumbers({}))).PhoneNumbers?.filter((p)=>p.Status==="ACTIVE"||p.Status==="PENDING");if(activeNumbers&&activeNumbers.length>0){console.log(`
10
+ \u23F3 Note: Phone number verification can take 24-72 hours for toll-free numbers`)}catch(error){console.error("Error checking status:",getErrorMessage(error));try{const{SmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new SmsVoiceClient(process.env.AWS_REGION||"us-east-1"),activeNumbers=(await withTimeout(smsClient.describePhoneNumbers({}))).PhoneNumbers?.filter((p)=>p.Status==="ACTIVE"||p.Status==="PENDING");if(activeNumbers&&activeNumbers.length>0){console.log(`
11
11
  \u2705 SMS Service Active (End User Messaging)`);for(const phone of activeNumbers)console.log(` Phone: ${phone.PhoneNumber} (${phone.Status})`)}else{console.log(`
12
12
  \u274C SMS service not deployed.`);console.log(" Run `buddy sms:setup` to initialize")}}catch{console.log(`
13
13
  \u274C Could not connect to AWS. Check credentials.`)}}process.exit(0)});buddy.command("sms:send <phone> [message]",descriptions.send).option("--template <name>","Use a message template").action(async(phone,message,options)=>{const msg=message||"Test message from Stacks";console.log(`
14
14
  \uD83D\uDCF1 Sending SMS to ${phone}...
15
- `);loadAwsCredentials();try{const{SMSClient}=await import("@stacksjs/ts-cloud"),smsClient=new SMSClient({region:process.env.AWS_REGION||"us-east-1"}),smsConfig=await import("@stacksjs/config").then((m)=>m.config?.sms);let originationNumber=smsConfig?.originationNumber;if(!originationNumber){const{PinpointSmsVoiceClient}=await import("@stacksjs/ts-cloud"),pinpointV2=new PinpointSmsVoiceClient(process.env.AWS_REGION||"us-east-1");originationNumber=(await withTimeout(pinpointV2.describePhoneNumbers({}))).PhoneNumbers?.find((p)=>p.Status==="ACTIVE")?.PhoneNumber}let finalMessage=msg;if(options?.template&&smsConfig?.templates){const template=smsConfig.templates.find((t)=>t.name===options.template);if(template){finalMessage=template.body;console.log(`Using template: ${options.template}`)}else console.log(`Template "${options.template}" not found. Using default message.`)}const result=await withTimeout(smsClient.send({to:phone,message:finalMessage,originationNumber}),30000);if(result.messageId){console.log("\u2705 SMS sent successfully!");console.log(` Message ID: ${result.messageId}`);if(originationNumber)console.log(` From: ${originationNumber}`)}else console.log("\u274C SMS send failed")}catch(error){console.error("Error sending SMS:",getErrorMessage(error));if(getErrorMessage(error).includes("not found")||getErrorMessage(error).includes("No phone")){console.log(`
15
+ `);loadAwsCredentials();try{const{SmsClient}=await import("@stacksjs/ts-cloud"),smsClient=new SmsClient({region:process.env.AWS_REGION||"us-east-1"}),smsConfig=await import("@stacksjs/config").then((m)=>m.config?.sms);let originationNumber=smsConfig?.originationNumber;if(!originationNumber){const{SmsVoiceClient}=await import("@stacksjs/ts-cloud"),pinpointV2=new SmsVoiceClient(process.env.AWS_REGION||"us-east-1");originationNumber=(await withTimeout(pinpointV2.describePhoneNumbers({}))).PhoneNumbers?.find((p)=>p.Status==="ACTIVE")?.PhoneNumber}let finalMessage=msg;if(options?.template&&smsConfig?.templates){const template=smsConfig.templates.find((t)=>t.name===options.template);if(template){finalMessage=template.body;console.log(`Using template: ${options.template}`)}else console.log(`Template "${options.template}" not found. Using default message.`)}const result=await withTimeout(smsClient.send({to:phone,body:finalMessage,from:originationNumber}),30000);if(result.messageId){console.log("\u2705 SMS sent successfully!");console.log(` Message ID: ${result.messageId}`);if(originationNumber)console.log(` From: ${originationNumber}`)}else console.log("\u274C SMS send failed")}catch(error){console.error("Error sending SMS:",getErrorMessage(error));if(getErrorMessage(error).includes("not found")||getErrorMessage(error).includes("No phone")){console.log(`
16
16
  \uD83D\uDCA1 No origination phone number available.`);console.log(" Run `buddy sms:setup` to provision a phone number.")}else if(getErrorMessage(error).includes("not authorized"))console.log(`
17
17
  \uD83D\uDCA1 Make sure your AWS account has SMS permissions.`);else if(getErrorMessage(error).includes("sandbox"))console.log("\n\uD83D\uDCA1 Your account is in SMS sandbox. Run `buddy sms:setup` to request production access.");else if(getErrorMessage(error).includes("PENDING")){console.log(`
18
18
  \uD83D\uDCA1 Phone number is still pending verification (24-72 hours for toll-free).`);console.log(" Run `buddy sms:status` to check current status.")}}process.exit(0)});buddy.command("sms:setup",descriptions.setup).option("--dry-run","Show what would be done without making changes").action(async(options)=>{console.log(`
19
19
  \uD83D\uDCF1 SMS Service Setup
20
20
  `);loadAwsCredentials();try{const smsConfig=await import("@stacksjs/config").then((m)=>m.config?.sms);if(!smsConfig?.enabled){console.log("SMS is disabled in config/sms.ts");console.log(`
21
21
  To enable SMS:`);console.log("1. Edit config/sms.ts and set enabled: true");console.log("2. Run `buddy sms:setup` again");process.exit(0);return}if(options.dryRun){console.log("[Dry Run] Would set up SMS infrastructure with config:");console.log(` Provider: ${smsConfig.provider}`);console.log(` Country: ${smsConfig.defaultCountryCode}`);console.log(` Message Type: ${smsConfig.messageType}`);console.log(` Monthly Limit: $${smsConfig.maxSpendPerMonth||1}`);console.log(` Two-Way: ${smsConfig.twoWay?.enabled?"Enabled":"Disabled"}`);console.log(` Inbox: ${smsConfig.inbox?.enabled?"Enabled":"Disabled"}`);process.exit(0);return}console.log(`Setting up SMS infrastructure...
22
- `);const{createSmsInfrastructure}=await import("@stacksjs/ts-cloud"),result=await withTimeout(createSmsInfrastructure({enabled:smsConfig.enabled,provider:smsConfig.provider||"pinpoint",originationNumber:smsConfig.originationNumber,defaultCountryCode:smsConfig.defaultCountryCode||"US",messageType:smsConfig.messageType||"TRANSACTIONAL",maxSpendPerMonth:smsConfig.maxSpendPerMonth,inbox:smsConfig.inbox,twoWay:smsConfig.twoWay,optOut:smsConfig.optOut||{enabled:!0,keywords:["STOP"]}}),120000);if(result.success){console.log(`
22
+ `);const{createSmsInfrastructure}=await import("@stacksjs/ts-cloud"),result=await withTimeout(createSmsInfrastructure({enabled:smsConfig.enabled,provider:"sns",originationNumber:smsConfig.originationNumber,defaultCountryCode:smsConfig.defaultCountryCode||"US",messageType:smsConfig.messageType||"TRANSACTIONAL",maxSpendPerMonth:smsConfig.maxSpendPerMonth,inbox:smsConfig.inbox,twoWay:smsConfig.twoWay,optOut:smsConfig.optOut||{enabled:!0,keywords:["STOP"]}}),120000);if(result.success){console.log(`
23
23
  \u2705 SMS infrastructure setup complete!
24
24
  `);if(result.phoneNumber)console.log(` Phone Number: ${result.phoneNumber} (${result.phoneNumberStatus})`);if(result.twoWayTopicArn)console.log(` Two-Way Topic: ${result.twoWayTopicArn}`);if(result.inboxBucket)console.log(` Inbox: s3://${result.inboxBucket}/${result.inboxPrefix}`);console.log(` Spending Limit: $${result.spendingLimit}/month`);console.log(` Sandbox Status: ${result.sandboxStatus}`);if(result.supportCaseId){console.log(`
25
25
  \uD83D\uDCCB Support Case: ${result.supportCaseId}`);console.log(" A support ticket has been filed for sandbox exit.")}if(result.warnings.length>0){console.log(`
@@ -29,13 +29,13 @@ To enable SMS:`);console.log("1. Edit config/sms.ts and set enabled: true");cons
29
29
  `);for(const error of result.errors)console.log(` - ${error}`)}}catch(error){console.error("Error setting up SMS:",getErrorMessage(error));if(getErrorMessage(error).includes("timeout")){console.log(`
30
30
  \uD83D\uDCA1 Setup timed out. Some operations may have completed.`);console.log(" Run `buddy sms:status` to check current status.")}}process.exit(0)});buddy.command("sms:add-phone <phone>",descriptions["add-phone"]).action(async(phone)=>{console.log(`
31
31
  \uD83D\uDCF1 Adding ${phone} to SMS sandbox...
32
- `);loadAwsCredentials();try{const{PinpointSmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new PinpointSmsVoiceClient(process.env.AWS_REGION||"us-east-1"),result=await withTimeout(smsClient.addSandboxPhone(phone),30000);if(result.status==="VERIFIED"){console.log("\u2705 Phone is already verified!");console.log(` ID: ${result.verifiedDestinationNumberId}`)}else if(result.status==="PENDING"){console.log("\uD83D\uDCE8 Verification code sent to phone!");console.log(` ID: ${result.verifiedDestinationNumberId}`);console.log(`
32
+ `);loadAwsCredentials();try{const{SmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new SmsVoiceClient(process.env.AWS_REGION||"us-east-1"),result=await withTimeout(smsClient.addSandboxPhone(phone),30000);if(result.status==="VERIFIED"){console.log("\u2705 Phone is already verified!");console.log(` ID: ${result.verifiedDestinationNumberId}`)}else if(result.status==="PENDING"){console.log("\uD83D\uDCE8 Verification code sent to phone!");console.log(` ID: ${result.verifiedDestinationNumberId}`);console.log(`
33
33
  \uD83D\uDCA1 Next step:`);console.log(` Run: buddy sms:verify ${result.verifiedDestinationNumberId} <code>`);console.log(" Replace <code> with the 6-digit code you received")}else{console.log("\u2753 Unexpected status:",result.status);console.log(" Message:",result.message)}}catch(error){console.error("Error adding phone:",getErrorMessage(error));if(getErrorMessage(error).includes("already exists")){console.log(`
34
34
  \uD83D\uDCA1 Phone number may already be in the sandbox.`);console.log(" Run `buddy sms:status` to check sandbox numbers.")}}process.exit(0)});buddy.command("sms:verify <id> <code>",descriptions.verify).action(async(id,code)=>{console.log(`
35
35
  \uD83D\uDCF1 Verifying sandbox phone...
36
- `);loadAwsCredentials();try{const{PinpointSmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new PinpointSmsVoiceClient(process.env.AWS_REGION||"us-east-1"),result=await withTimeout(smsClient.verifySandboxPhone(id,code),30000);if(result.success){console.log("\u2705 Phone verified successfully!");console.log(` Phone: ${result.phoneNumber}`);console.log(`
36
+ `);loadAwsCredentials();try{const{SmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new SmsVoiceClient(process.env.AWS_REGION||"us-east-1"),result=await withTimeout(smsClient.verifySandboxPhone(id,code),30000);if(result.success){console.log("\u2705 Phone verified successfully!");console.log(` Phone: ${result.phoneNumber}`);console.log(`
37
37
  \uD83D\uDCA1 You can now send SMS to this phone while in sandbox mode.`);console.log(` Run: buddy sms:send ${result.phoneNumber} "Test message"`)}else{console.log("\u274C Verification failed");console.log(` Error: ${result.message}`);console.log(`
38
38
  \uD83D\uDCA1 Make sure you entered the correct 6-digit code.`);console.log(" Run `buddy sms:add-phone <phone>` to resend the code.")}}catch(error){console.error("Error verifying phone:",getErrorMessage(error))}process.exit(0)});buddy.command("sms:sandbox-list","List sandbox verified phone numbers").action(async()=>{console.log(`
39
39
  \uD83D\uDCF1 Sandbox Verified Numbers
40
- `);loadAwsCredentials();try{const{PinpointSmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new PinpointSmsVoiceClient(process.env.AWS_REGION||"us-east-1"),phones=await withTimeout(smsClient.listSandboxPhones(),30000);if(phones.length===0){console.log("No verified sandbox numbers yet.");console.log(`
40
+ `);loadAwsCredentials();try{const{SmsVoiceClient}=await import("@stacksjs/ts-cloud"),smsClient=new SmsVoiceClient(process.env.AWS_REGION||"us-east-1"),phones=await withTimeout(smsClient.listSandboxPhones(),30000);if(phones.length===0){console.log("No verified sandbox numbers yet.");console.log(`
41
41
  To add a phone:`);console.log(" buddy sms:add-phone +1234567890")}else for(const phone of phones){const statusIcon=phone.status==="VERIFIED"?"\u2705":"\u23F3";console.log(` ${statusIcon} ${phone.phoneNumber} (${phone.status})`);console.log(` ID: ${phone.id}`)}}catch(error){console.error("Error listing sandbox phones:",getErrorMessage(error))}process.exit(0)})}
@@ -1,4 +1,4 @@
1
- import{randomBytes}from"node:crypto";import process from"node:process";import{log}from"@stacksjs/cli";import{ExitCode}from"@stacksjs/types";function generatePassword(){return randomBytes(18).toString("base64url")}async function loadUserModel(){const{existsSync}=await import("node:fs"),{join}=await import("node:path"),candidates=[join(process.cwd(),"app/Models/User.ts"),join(process.cwd(),"storage/framework/defaults/app/Models/User.ts"),join(process.cwd(),"node_modules/@stacksjs/defaults/app/Models/User.ts")];for(const candidate of candidates){if(!existsSync(candidate))continue;const loaded=(await import(candidate)).default;if(loaded?.where)return loaded}const{User}=await import("@stacksjs/orm");if(User?.where)return User;log.error("Could not find a User model. Looked in app/Models, the framework defaults and @stacksjs/orm.");await log.flush();process.exit(ExitCode.FatalError)}export function user(buddy){buddy.command("user:add <email>","Create a user account (optionally an admin)").option("--name <name>","Display name. Defaults to the local part of the email.").option("--password <password>","Password. Generated and printed once if omitted.").option("--role <role>","Role to assign, e.g. admin. Seeds the default roles if the table is empty.").option("--update","If the account already exists, reset its password and ensure the role",{default:!1}).example("buddy user:add chris@example.com --role admin").example("buddy user:add support@example.com --name Support --password s3cret").action(async(email,options)=>{const address=String(email||"").trim().toLowerCase();if(!address.includes("@")){log.error(`\`${email}\` is not an email address.`);await log.flush();process.exit(ExitCode.FatalError)}const password=options.password||generatePassword(),generated=!options.password,name=options.name||address.split("@")[0],User=await loadUserModel();let account=await User.where("email",address).first();if(account&&!options.update){log.error(`${address} already exists. Pass --update to reset its password and role.`);await log.flush();process.exit(ExitCode.FatalError)}if(account){await User.where("email",address).update({password});log.success(`Updated ${address}`)}else{await User.create({email:address,name,password});account=await User.where("email",address).first();log.success(`Created ${address}`)}if(options.role){const{createBqbRbacStore,Rbac,seedDefaultRoles}=await import("@stacksjs/auth");try{Rbac.setStore(createBqbRbacStore());await seedDefaultRoles();await Rbac.assignRole(account,options.role);log.success(`Assigned the ${options.role} role`)}catch(error){log.error(`Could not assign the ${options.role} role: ${error instanceof Error?error.message:String(error)}`);log.info("The account exists; assign the role once the roles tables are migrated.")}}if(generated){process.stdout.write(`
1
+ import{randomBytes}from"node:crypto";import process from"node:process";import{log}from"@stacksjs/cli";import{ExitCode}from"@stacksjs/types";function generatePassword(){return randomBytes(18).toString("base64url")}async function loadUserModel(){const{existsSync}=await import("node:fs"),{join}=await import("node:path"),candidates=[join(process.cwd(),"app/Models/User.ts"),join(process.cwd(),"storage/framework/defaults/app/Models/User.ts"),join(process.cwd(),"node_modules/@stacksjs/defaults/app/Models/User.ts")];for(const candidate of candidates){if(!existsSync(candidate))continue;const loaded=(await import(candidate)).default;if(loaded?.where)return loaded}const{User}=await import("@stacksjs/orm");if(User)return User;log.error("Could not find a User model. Looked in app/Models, the framework defaults and @stacksjs/orm.");await log.flush();process.exit(ExitCode.FatalError)}export function user(buddy){buddy.command("user:add <email>","Create a user account (optionally an admin)").option("--name <name>","Display name. Defaults to the local part of the email.").option("--password <password>","Password. Generated and printed once if omitted.").option("--role <role>","Role to assign, e.g. admin. Seeds the default roles if the table is empty.").option("--update","If the account already exists, reset its password and ensure the role",{default:!1}).example("buddy user:add chris@example.com --role admin").example("buddy user:add support@example.com --name Support --password s3cret").action(async(email,options)=>{const address=String(email||"").trim().toLowerCase();if(!address.includes("@")){log.error(`\`${email}\` is not an email address.`);await log.flush();process.exit(ExitCode.FatalError)}const password=options.password||generatePassword(),generated=!options.password,name=options.name||address.split("@")[0],User=await loadUserModel();let account=await User.where("email",address).first();if(account&&!options.update){log.error(`${address} already exists. Pass --update to reset its password and role.`);await log.flush();process.exit(ExitCode.FatalError)}if(account){await User.where("email",address).update({password});log.success(`Updated ${address}`)}else{await User.create({email:address,name,password});account=await User.where("email",address).first();log.success(`Created ${address}`)}if(options.role){const{createBqbRbacStore,Rbac,seedDefaultRoles}=await import("@stacksjs/auth");try{Rbac.setStore(createBqbRbacStore());await seedDefaultRoles();await Rbac.assignRole(account,options.role);log.success(`Assigned the ${options.role} role`)}catch(error){log.error(`Could not assign the ${options.role} role: ${error instanceof Error?error.message:String(error)}`);log.info("The account exists; assign the role once the roles tables are migrated.")}}if(generated){process.stdout.write(`
2
2
  ${address}
3
3
  ${password}
4
4
 
package/dist/config.d.ts CHANGED
@@ -4,7 +4,7 @@ export declare function loadProjectDnsConfig(fallback: DnsConfig): Promise<DnsCo
4
4
  /**
5
5
  * Validate the buddy config structure
6
6
  */
7
- export declare function validateConfig(config: any): ValidationError[];
7
+ export declare function validateConfig(config: unknown): ValidationError[];
8
8
  /**
9
9
  * Load buddy.config.ts from the project root
10
10
  */
package/dist/config.js CHANGED
@@ -1 +1 @@
1
- import{existsSync}from"node:fs";import{pathToFileURL}from"node:url";import{log}from"@stacksjs/cli";import{path as p}from"@stacksjs/path";export async function loadProjectDnsConfig(fallback){const configPath=p.projectConfigPath("dns.ts");if(!existsSync(configPath))return fallback;const loaded=await import(`${pathToFileURL(configPath).href}?updated=${Date.now()}`);return loaded.default??loaded.dns??fallback}export function validateConfig(config){const errors=[];if(typeof config!=="object"||config===null){errors.push({path:"config",message:"Config must be an object",value:config});return errors}if(config.theme!==void 0){const validThemes=["default","dracula","nord","solarized","monokai"];if(typeof config.theme!=="string"||!validThemes.includes(config.theme))errors.push({path:"theme",message:`Theme must be one of: ${validThemes.join(", ")}`,value:config.theme})}if(config.emoji!==void 0&&typeof config.emoji!=="boolean")errors.push({path:"emoji",message:"Emoji must be a boolean",value:config.emoji});if(config.commands!==void 0)if(!Array.isArray(config.commands))errors.push({path:"commands",message:"Commands must be an array",value:config.commands});else config.commands.forEach((cmd,index)=>{if(typeof cmd!=="function")errors.push({path:`commands[${index}]`,message:"Each command must be a function",value:cmd})});if(config.defaultFlags!==void 0)if(typeof config.defaultFlags!=="object"||config.defaultFlags===null)errors.push({path:"defaultFlags",message:"Default flags must be an object",value:config.defaultFlags});else{const flagKeys=["verbose","quiet","debug"];for(const key of Object.keys(config.defaultFlags))if(!flagKeys.includes(key))errors.push({path:`defaultFlags.${key}`,message:`Unknown flag. Valid flags are: ${flagKeys.join(", ")}`,value:config.defaultFlags[key]});else if(typeof config.defaultFlags[key]!=="boolean")errors.push({path:`defaultFlags.${key}`,message:"Flag value must be a boolean",value:config.defaultFlags[key]})}if(config.aliases!==void 0){if(typeof config.aliases!=="object"||config.aliases===null||Array.isArray(config.aliases))errors.push({path:"aliases",message:"Aliases must be an object mapping alias names to command names",value:config.aliases});else for(const[alias,command]of Object.entries(config.aliases))if(typeof command!=="string")errors.push({path:`aliases.${alias}`,message:"Alias target must be a string",value:command})}if(config.plugins!==void 0)if(!Array.isArray(config.plugins))errors.push({path:"plugins",message:"Plugins must be an array",value:config.plugins});else config.plugins.forEach((plugin,index)=>{if(typeof plugin==="string")return;if(typeof plugin!=="object"||plugin===null){errors.push({path:`plugins[${index}]`,message:"Each plugin must be an object or a string (module path)",value:plugin});return}if(!plugin.name||typeof plugin.name!=="string")errors.push({path:`plugins[${index}].name`,message:"Plugin must have a name property of type string",value:plugin.name});if(!plugin.setup||typeof plugin.setup!=="function")errors.push({path:`plugins[${index}].setup`,message:"Plugin must have a setup function",value:plugin.setup});if(plugin.hooks!==void 0){if(typeof plugin.hooks!=="object"||plugin.hooks===null)errors.push({path:`plugins[${index}].hooks`,message:"Plugin hooks must be an object",value:plugin.hooks})}});const validKeys=["theme","emoji","commands","defaultFlags","aliases","plugins"];for(const key of Object.keys(config))if(!validKeys.includes(key))errors.push({path:key,message:`Unknown configuration key. Valid keys are: ${validKeys.join(", ")}`,value:config[key]});return errors}let cachedConfig=null;export async function loadBuddyConfig(){if(cachedConfig)return cachedConfig;const configPaths=[p.projectPath("buddy.config.ts"),p.projectPath("buddy.config.js"),p.projectPath(".buddy.config.ts"),p.projectPath(".buddy.config.js")];for(const configPath of configPaths)if(existsSync(configPath))try{log.debug(`Loading buddy config from ${configPath}`);const configModule=await import(configPath),config=configModule.default||configModule,validationErrors=validateConfig(config);if(validationErrors.length>0){log.error("Invalid buddy.config.ts:");for(const error of validationErrors)log.error(` - ${error.path}: ${error.message}`);throw Error("Configuration validation failed")}cachedConfig=config;return config}catch(error){log.warn(`Failed to load buddy config from ${configPath}:`,error)}cachedConfig={};return cachedConfig}export async function loadPlugins(cli,config){if(!config.plugins||config.plugins.length===0)return;log.debug(`Loading ${config.plugins.length} plugin(s)`);for(const pluginConfig of config.plugins){let plugin;if(typeof pluginConfig==="string")try{const pluginModule=await import(pluginConfig);plugin=pluginModule.default||pluginModule}catch(error){log.error(`Failed to load plugin from ${pluginConfig}:`,error);continue}else plugin=pluginConfig;try{log.debug(`Initializing plugin: ${plugin.name}${plugin.version?` v${plugin.version}`:""}`);await plugin.setup(cli);if(plugin.hooks){if(plugin.hooks.beforeCommand)cli.on("command:*",async(command)=>{if(plugin.hooks?.beforeCommand)await plugin.hooks.beforeCommand({command})});if(plugin.hooks.afterCommand)cli.on("command:*",async(command)=>{if(plugin.hooks?.afterCommand)await plugin.hooks.afterCommand({command})})}log.debug(`Plugin ${plugin.name} initialized successfully`)}catch(error){log.error(`Failed to initialize plugin ${plugin.name}:`,error)}}}export async function applyBuddyConfig(buddy){const config=await loadBuddyConfig();if(config.emoji!==void 0&&buddy.options.noEmoji===void 0)buddy.useEmoji=config.emoji;if(config.defaultFlags){if(config.defaultFlags.verbose&&!buddy.isVerbose)buddy.isVerbose=!0;if(config.defaultFlags.quiet&&!buddy.isQuiet)buddy.isQuiet=!0;if(config.defaultFlags.debug&&!buddy.isDebug)buddy.isDebug=!0}if(config.commands&&Array.isArray(config.commands)){for(const registerCommand of config.commands)if(typeof registerCommand==="function")registerCommand(buddy)}if(config.aliases)for(const[alias,command]of Object.entries(config.aliases)){const targetCommand=buddy.commands.find((cmd)=>cmd.name===command);if(targetCommand&&!targetCommand.aliasNames.includes(alias))targetCommand.aliasNames.push(alias)}}
1
+ import{existsSync}from"node:fs";import{pathToFileURL}from"node:url";import{log}from"@stacksjs/cli";import{path as p}from"@stacksjs/path";export async function loadProjectDnsConfig(fallback){const configPath=p.projectConfigPath("dns.ts");if(!existsSync(configPath))return fallback;const loaded=await import(`${pathToFileURL(configPath).href}?updated=${Date.now()}`);return loaded.default??loaded.dns??fallback}export function validateConfig(config){const errors=[];if(typeof config!=="object"||config===null){errors.push({path:"config",message:"Config must be an object",value:config});return errors}const candidate=config;if(candidate.theme!==void 0){const validThemes=["default","dracula","nord","solarized","monokai"];if(typeof candidate.theme!=="string"||!validThemes.includes(candidate.theme))errors.push({path:"theme",message:`Theme must be one of: ${validThemes.join(", ")}`,value:candidate.theme})}if(candidate.emoji!==void 0&&typeof candidate.emoji!=="boolean")errors.push({path:"emoji",message:"Emoji must be a boolean",value:candidate.emoji});if(candidate.commands!==void 0)if(!Array.isArray(candidate.commands))errors.push({path:"commands",message:"Commands must be an array",value:candidate.commands});else candidate.commands.forEach((cmd,index)=>{if(typeof cmd!=="function")errors.push({path:`commands[${index}]`,message:"Each command must be a function",value:cmd})});if(candidate.defaultFlags!==void 0)if(typeof candidate.defaultFlags!=="object"||candidate.defaultFlags===null)errors.push({path:"defaultFlags",message:"Default flags must be an object",value:candidate.defaultFlags});else{const defaultFlags=candidate.defaultFlags,flagKeys=["verbose","quiet","debug"];for(const key of Object.keys(defaultFlags))if(!flagKeys.includes(key))errors.push({path:`defaultFlags.${key}`,message:`Unknown flag. Valid flags are: ${flagKeys.join(", ")}`,value:defaultFlags[key]});else if(typeof defaultFlags[key]!=="boolean")errors.push({path:`defaultFlags.${key}`,message:"Flag value must be a boolean",value:defaultFlags[key]})}if(candidate.aliases!==void 0){if(typeof candidate.aliases!=="object"||candidate.aliases===null||Array.isArray(candidate.aliases))errors.push({path:"aliases",message:"Aliases must be an object mapping alias names to command names",value:candidate.aliases});else for(const[alias,command]of Object.entries(candidate.aliases))if(typeof command!=="string")errors.push({path:`aliases.${alias}`,message:"Alias target must be a string",value:command})}if(candidate.plugins!==void 0)if(!Array.isArray(candidate.plugins))errors.push({path:"plugins",message:"Plugins must be an array",value:candidate.plugins});else candidate.plugins.forEach((plugin,index)=>{if(typeof plugin==="string")return;if(typeof plugin!=="object"||plugin===null){errors.push({path:`plugins[${index}]`,message:"Each plugin must be an object or a string (module path)",value:plugin});return}if(!plugin.name||typeof plugin.name!=="string")errors.push({path:`plugins[${index}].name`,message:"Plugin must have a name property of type string",value:plugin.name});if(!plugin.setup||typeof plugin.setup!=="function")errors.push({path:`plugins[${index}].setup`,message:"Plugin must have a setup function",value:plugin.setup});if(plugin.hooks!==void 0){if(typeof plugin.hooks!=="object"||plugin.hooks===null)errors.push({path:`plugins[${index}].hooks`,message:"Plugin hooks must be an object",value:plugin.hooks})}});const validKeys=["theme","emoji","commands","defaultFlags","aliases","plugins"];for(const key of Object.keys(config))if(!validKeys.includes(key))errors.push({path:key,message:`Unknown configuration key. Valid keys are: ${validKeys.join(", ")}`,value:candidate[key]});return errors}let cachedConfig=null;export async function loadBuddyConfig(){if(cachedConfig)return cachedConfig;const configPaths=[p.projectPath("buddy.config.ts"),p.projectPath("buddy.config.js"),p.projectPath(".buddy.config.ts"),p.projectPath(".buddy.config.js")];for(const configPath of configPaths)if(existsSync(configPath))try{log.debug(`Loading buddy config from ${configPath}`);const configModule=await import(configPath),config=configModule.default||configModule,validationErrors=validateConfig(config);if(validationErrors.length>0){log.error("Invalid buddy.config.ts:");for(const error of validationErrors)log.error(` - ${error.path}: ${error.message}`);throw Error("Configuration validation failed")}cachedConfig=config;return config}catch(error){log.warn(`Failed to load buddy config from ${configPath}:`,error)}cachedConfig={};return cachedConfig}export async function loadPlugins(cli,config){if(!config.plugins||config.plugins.length===0)return;log.debug(`Loading ${config.plugins.length} plugin(s)`);for(const pluginConfig of config.plugins){let plugin;if(typeof pluginConfig==="string")try{const pluginModule=await import(pluginConfig);plugin=pluginModule.default||pluginModule}catch(error){log.error(`Failed to load plugin from ${pluginConfig}:`,error);continue}else plugin=pluginConfig;try{log.debug(`Initializing plugin: ${plugin.name}${plugin.version?` v${plugin.version}`:""}`);await plugin.setup(cli);if(plugin.hooks){if(plugin.hooks.beforeCommand)cli.on("command:*",async(command)=>{if(plugin.hooks?.beforeCommand)await plugin.hooks.beforeCommand({command})});if(plugin.hooks.afterCommand)cli.on("command:*",async(command)=>{if(plugin.hooks?.afterCommand)await plugin.hooks.afterCommand({command})})}log.debug(`Plugin ${plugin.name} initialized successfully`)}catch(error){log.error(`Failed to initialize plugin ${plugin.name}:`,error)}}}export async function applyBuddyConfig(buddy){const config=await loadBuddyConfig();if(config.emoji!==void 0&&buddy.options.noEmoji===void 0)buddy.useEmoji=config.emoji;if(config.defaultFlags){if(config.defaultFlags.verbose&&!buddy.isVerbose)buddy.isVerbose=!0;if(config.defaultFlags.quiet&&!buddy.isQuiet)buddy.isQuiet=!0;if(config.defaultFlags.debug&&!buddy.isDebug)buddy.isDebug=!0}if(config.commands&&Array.isArray(config.commands)){for(const registerCommand of config.commands)if(typeof registerCommand==="function")registerCommand(buddy)}if(config.aliases)for(const[alias,command]of Object.entries(config.aliases)){const targetCommand=buddy.commands.find((cmd)=>cmd.name===command);if(targetCommand&&!targetCommand.aliasNames.includes(alias))targetCommand.aliasNames.push(alias)}}
@@ -1 +1 @@
1
- const commandRegistry={about:{path:"./commands/about.js",exportName:"about"},add:{path:"./commands/add.js",exportName:"add"},"ai:context":{path:"./commands/ai-context.js",exportName:"aiContext"},auth:{path:"./commands/auth.js",exportName:"auth"},build:{path:"./commands/build.js",exportName:"build"},cd:{path:"./commands/cd.js",exportName:"cd"},changelog:{path:"./commands/changelog.js",exportName:"changelog"},clean:{path:"./commands/clean.js",exportName:"clean"},cloud:{path:"./commands/cloud.js",exportName:"cloud"},commit:{path:"./commands/commit.js",exportName:"commit"},completion:{path:"./commands/completion.js",exportName:"completion"},"config:migrate":{path:"./commands/config-migrate.js",exportName:"configMigrate"},configure:{path:"./commands/configure.js",exportName:"configure"},create:{path:"./commands/create.js",exportName:"create"},new:{path:"./commands/create.js",exportName:"create"},deploy:{path:"./commands/deploy.js",exportName:"deploy"},"deploy:rollback":{path:"./commands/deploy.js",exportName:"deploy"},dev:{path:"./commands/dev.js",exportName:"dev"},"desktop:apple:doctor":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:csr":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:init":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:package":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:provision":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:publish":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},dns:{path:"./commands/dns.js",exportName:"dns"},"dns:pull":{path:"./commands/dns.js",exportName:"dns"},"dns:diff":{path:"./commands/dns.js",exportName:"dns"},"dns:sync":{path:"./commands/dns.js",exportName:"dns"},doctor:{path:"./commands/doctor.js",exportName:"doctor"},domains:{path:"./commands/domains.js",exportName:"domains"},email:{path:"./commands/email.js",exportName:"email"},env:{path:"./commands/env.js",exportName:"env"},"extension:init":{path:"./commands/extension.js",exportName:"extension"},"extension:build":{path:"./commands/extension.js",exportName:"extension"},"extension:package":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:status":{path:"./commands/extension.js",exportName:"extension"},"extension:firefox:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:init":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:provision":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:app":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:publish":{path:"./commands/extension.js",exportName:"extension"},"dashboard:install":{path:"./commands/features.js",exportName:"features"},"dashboard:uninstall":{path:"./commands/features.js",exportName:"features"},"commerce:install":{path:"./commands/features.js",exportName:"features"},"commerce:uninstall":{path:"./commands/features.js",exportName:"features"},"cms:install":{path:"./commands/features.js",exportName:"features"},"cms:uninstall":{path:"./commands/features.js",exportName:"features"},"marketing:install":{path:"./commands/features.js",exportName:"features"},"marketing:uninstall":{path:"./commands/features.js",exportName:"features"},"monitoring:install":{path:"./commands/features.js",exportName:"features"},"monitoring:uninstall":{path:"./commands/features.js",exportName:"features"},"realtime:install":{path:"./commands/features.js",exportName:"features"},"realtime:uninstall":{path:"./commands/features.js",exportName:"features"},"queue:install":{path:"./commands/features.js",exportName:"features"},"queue:uninstall":{path:"./commands/features.js",exportName:"features"},"db:backup":{path:"./commands/db.js",exportName:"db"},"db:backups":{path:"./commands/db.js",exportName:"db"},"db:restore":{path:"./commands/db.js",exportName:"db"},fresh:{path:"./commands/fresh.js",exportName:"fresh"},generate:{path:"./commands/generate.js",exportName:"generate"},http:{path:"./commands/http.js",exportName:"http"},install:{path:"./commands/install.js",exportName:"install"},key:{path:"./commands/key.js",exportName:"key"},lint:{path:"./commands/lint.js",exportName:"lint"},format:{path:"./commands/lint.js",exportName:"lint"},"format:check":{path:"./commands/lint.js",exportName:"lint"},list:{path:"./commands/list.js",exportName:"list"},mail:{path:"./commands/mail.js",exportName:"mailCommands"},"mail:preview":{path:"./commands/mail.js",exportName:"mailCommands"},maintenance:{path:"./commands/maintenance.js",exportName:"maintenance"},down:{path:"./commands/maintenance.js",exportName:"maintenance"},up:{path:"./commands/maintenance.js",exportName:"maintenance"},status:{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon":{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon:status":{path:"./commands/maintenance.js",exportName:"maintenance"},launch:{path:"./commands/maintenance.js",exportName:"maintenance"},make:{path:"./commands/make.js",exportName:"make"},"scaffold:crud":{path:"./commands/make.js",exportName:"make"},migrate:{path:"./commands/migrate.js",exportName:"migrate"},"migrate:fresh":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:switch":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:dns":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:project":{path:"./commands/migrate-project.js",exportName:"migrateProject"},outdated:{path:"./commands/outdated.js",exportName:"outdated"},package:{path:"./commands/package.js",exportName:"packageCommands"},phone:{path:"./commands/phone.js",exportName:"phone"},ports:{path:"./commands/ports.js",exportName:"ports"},"link:core":{path:"./commands/link.js",exportName:"link"},"user:add":{path:"./commands/user.js",exportName:"user"},"user:list":{path:"./commands/user.js",exportName:"user"},"unlink:core":{path:"./commands/link.js",exportName:"link"},prepublish:{path:"./commands/prepublish.js",exportName:"prepublish"},projects:{path:"./commands/projects.js",exportName:"projects"},publish:{path:"./commands/publish.js",exportName:"publish"},"publish:model":{path:"./commands/publish.js",exportName:"publish"},"publish:controller":{path:"./commands/publish.js",exportName:"publish"},"publish:middleware":{path:"./commands/publish.js",exportName:"publish"},"publish:action":{path:"./commands/publish.js",exportName:"publish"},"publish:core":{path:"./commands/publish.js",exportName:"publish"},"core:status":{path:"./commands/publish.js",exportName:"publish"},queue:{path:"./commands/queue.js",exportName:"queue"},release:{path:"./commands/release.js",exportName:"release"},route:{path:"./commands/route.js",exportName:"route"},saas:{path:"./commands/saas.js",exportName:"saas"},"stripe:setup":{path:"./commands/saas.js",exportName:"saas"},schedule:{path:"./commands/schedule.js",exportName:"schedule"},search:{path:"./commands/search.js",exportName:"search"},"search-engine:update":{path:"./commands/search.js",exportName:"search"},"search-engine:settings":{path:"./commands/search.js",exportName:"search"},seed:{path:"./commands/seed.js",exportName:"seed"},"seed:roles":{path:"./commands/seed.js",exportName:"seed"},"roles:seed":{path:"./commands/seed.js",exportName:"seed"},preview:{path:"./commands/serve.js",exportName:"preview"},serve:{path:"./commands/serve.js",exportName:"serve"},"serve:api":{path:"./commands/serve.js",exportName:"serveApi"},setup:{path:"./commands/setup.js",exportName:"setup"},"setup:ai":{path:"./commands/setup.js",exportName:"setup"},"setup:ssl":{path:"./commands/setup.js",exportName:"setup"},"setup:oh-my-zsh":{path:"./commands/setup.js",exportName:"setup"},"ai:setup":{path:"./commands/setup.js",exportName:"setup"},share:{path:"./commands/share.js",exportName:"share"},"simulator:doctor":{path:"./commands/simulator.js",exportName:"simulator"},"simulator:open":{path:"./commands/simulator.js",exportName:"simulator"},stack:{path:"./commands/stacks.js",exportName:"stacks"},sms:{path:"./commands/sms.js",exportName:"sms"},telemetry:{path:"./commands/telemetry.js",exportName:"telemetryCommand"},test:{path:"./commands/test.js",exportName:"test"},tinker:{path:"./commands/tinker.js",exportName:"tinker"},types:{path:"./commands/types.js",exportName:"types"},undeploy:{path:"./commands/cloud.js",exportName:"cloud"},upgrade:{path:"./commands/upgrade.js",exportName:"upgrade"},version:{path:"./commands/version.js",exportName:"version"},"docs:buddy":{path:"./commands/docs.js",exportName:"docs"},"docs:buddy:check":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts:check":{path:"./commands/docs.js",exportName:"docs"},"docs:links":{path:"./commands/docs.js",exportName:"docs"},"docs:links:check":{path:"./commands/docs.js",exportName:"docs"}},commandGroups={minimal:["version","help"],development:["dev","build","test","lint"],database:["migrate","seed","fresh"],scaffolding:["make","generate"],deployment:["deploy","release","cloud"],info:["about","doctor","list"]},loadedRegistrars=new WeakMap;function loaderKey(loader){return`${loader.path}#${loader.exportName}`}export function markLoaded(buddy,commandName){const loader=commandRegistry[commandName];if(!loader)return;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}set.add(loaderKey(loader))}export async function loadCommand(commandName,buddy){const loader=commandRegistry[commandName];if(!loader)return!1;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}const key=loaderKey(loader);if(set.has(key))return!0;set.add(key);try{const commandFunction=(await import(loader.path))[loader.exportName];if(typeof commandFunction==="function"){commandFunction(buddy);return!0}else return!1}catch{return!1}}export async function loadCommands(commandNames,buddy){const timeout=(ms)=>new Promise((_,reject)=>setTimeout(()=>reject(Error("timeout")),ms)),seen=new Set,unique=[];for(const name of commandNames){const loader=commandRegistry[name],key=loader?`${loader.path}#${loader.exportName}`:`name:${name}`;if(seen.has(key))continue;seen.add(key);unique.push(name)}await Promise.all(unique.map(async(name)=>{try{await Promise.race([loadCommand(name,buddy),timeout(5000)])}catch{}}))}export async function loadCommandGroup(groupName,buddy){const commands=commandGroups[groupName];if(commands)await loadCommands(commands,buddy)}export async function loadAllCommands(buddy){const allCommands=Object.keys(commandRegistry);await loadCommands(allCommands,buddy)}export function getCommandNames(){return Object.keys(commandRegistry)}export function getCommandsToLoad(args){const requestedCommand=args[0],isVersionFlag=requestedCommand==="--version"||requestedCommand==="-v",isHelpFlag=requestedCommand==="--help"||requestedCommand==="-h",isHelpWord=requestedCommand==="help";if(isVersionFlag)return["version"];if(!requestedCommand||isHelpFlag||isHelpWord)return Object.keys(commandRegistry);const baseCommand=requestedCommand.split(":")[0];if(baseCommand==="list")return["list",...Object.keys(commandRegistry).filter((k)=>k!=="list")];if(commandRegistry[requestedCommand])return[requestedCommand];if(commandRegistry[baseCommand])return[baseCommand];return Object.keys(commandRegistry)}
1
+ const commandRegistry={about:{path:"./commands/about.js",exportName:"about"},add:{path:"./commands/add.js",exportName:"add"},"ai:context":{path:"./commands/ai-context.js",exportName:"aiContext"},auth:{path:"./commands/auth.js",exportName:"auth"},build:{path:"./commands/build.js",exportName:"build"},cd:{path:"./commands/cd.js",exportName:"cd"},changelog:{path:"./commands/changelog.js",exportName:"changelog"},clean:{path:"./commands/clean.js",exportName:"clean"},cloud:{path:"./commands/cloud.js",exportName:"cloud"},commit:{path:"./commands/commit.js",exportName:"commit"},completion:{path:"./commands/completion.js",exportName:"completion"},"config:migrate":{path:"./commands/config-migrate.js",exportName:"configMigrate"},configure:{path:"./commands/configure.js",exportName:"configure"},create:{path:"./commands/create.js",exportName:"create"},new:{path:"./commands/create.js",exportName:"create"},deploy:{path:"./commands/deploy.js",exportName:"deploy"},"deploy:rollback":{path:"./commands/deploy.js",exportName:"deploy"},dev:{path:"./commands/dev.js",exportName:"dev"},"desktop:apple:doctor":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:csr":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:init":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:package":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:provision":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},"desktop:apple:publish":{path:"./commands/desktop-apple.js",exportName:"desktopApple"},dns:{path:"./commands/dns.js",exportName:"dns"},"dns:pull":{path:"./commands/dns.js",exportName:"dns"},"dns:diff":{path:"./commands/dns.js",exportName:"dns"},"dns:sync":{path:"./commands/dns.js",exportName:"dns"},doctor:{path:"./commands/doctor.js",exportName:"doctor"},domains:{path:"./commands/domains.js",exportName:"domains"},email:{path:"./commands/email.js",exportName:"email"},env:{path:"./commands/env.js",exportName:"env"},"extension:init":{path:"./commands/extension.js",exportName:"extension"},"extension:build":{path:"./commands/extension.js",exportName:"extension"},"extension:package":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:chrome:status":{path:"./commands/extension.js",exportName:"extension"},"extension:firefox:publish":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:init":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:provision":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:app":{path:"./commands/extension.js",exportName:"extension"},"extension:safari:publish":{path:"./commands/extension.js",exportName:"extension"},"dashboard:install":{path:"./commands/features.js",exportName:"features"},"dashboard:uninstall":{path:"./commands/features.js",exportName:"features"},"commerce:install":{path:"./commands/features.js",exportName:"features"},"commerce:uninstall":{path:"./commands/features.js",exportName:"features"},"cms:install":{path:"./commands/features.js",exportName:"features"},"cms:uninstall":{path:"./commands/features.js",exportName:"features"},"marketing:install":{path:"./commands/features.js",exportName:"features"},"marketing:uninstall":{path:"./commands/features.js",exportName:"features"},"monitoring:install":{path:"./commands/features.js",exportName:"features"},"monitoring:uninstall":{path:"./commands/features.js",exportName:"features"},"realtime:install":{path:"./commands/features.js",exportName:"features"},"realtime:uninstall":{path:"./commands/features.js",exportName:"features"},"queue:install":{path:"./commands/features.js",exportName:"features"},"queue:uninstall":{path:"./commands/features.js",exportName:"features"},"db:backup":{path:"./commands/db.js",exportName:"db"},"db:backups":{path:"./commands/db.js",exportName:"db"},"db:restore":{path:"./commands/db.js",exportName:"db"},fresh:{path:"./commands/fresh.js",exportName:"fresh"},generate:{path:"./commands/generate.js",exportName:"generate"},http:{path:"./commands/http.js",exportName:"http"},install:{path:"./commands/install.js",exportName:"install"},key:{path:"./commands/key.js",exportName:"key"},lint:{path:"./commands/lint.js",exportName:"lint"},format:{path:"./commands/lint.js",exportName:"lint"},"format:check":{path:"./commands/lint.js",exportName:"lint"},libs:{path:"./commands/libs.js",exportName:"libs"},libraries:{path:"./commands/libs.js",exportName:"libs"},list:{path:"./commands/list.js",exportName:"list"},mail:{path:"./commands/mail.js",exportName:"mailCommands"},"mail:preview":{path:"./commands/mail.js",exportName:"mailCommands"},maintenance:{path:"./commands/maintenance.js",exportName:"maintenance"},down:{path:"./commands/maintenance.js",exportName:"maintenance"},up:{path:"./commands/maintenance.js",exportName:"maintenance"},status:{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon":{path:"./commands/maintenance.js",exportName:"maintenance"},"coming-soon:status":{path:"./commands/maintenance.js",exportName:"maintenance"},launch:{path:"./commands/maintenance.js",exportName:"maintenance"},make:{path:"./commands/make.js",exportName:"make"},"scaffold:crud":{path:"./commands/make.js",exportName:"make"},migrate:{path:"./commands/migrate.js",exportName:"migrate"},"migrate:fresh":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:switch":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:dns":{path:"./commands/migrate.js",exportName:"migrate"},"migrate:project":{path:"./commands/migrate-project.js",exportName:"migrateProject"},outdated:{path:"./commands/outdated.js",exportName:"outdated"},package:{path:"./commands/package.js",exportName:"packageCommands"},phone:{path:"./commands/phone.js",exportName:"phone"},ports:{path:"./commands/ports.js",exportName:"ports"},"link:core":{path:"./commands/link.js",exportName:"link"},"user:add":{path:"./commands/user.js",exportName:"user"},"user:list":{path:"./commands/user.js",exportName:"user"},"unlink:core":{path:"./commands/link.js",exportName:"link"},prepublish:{path:"./commands/prepublish.js",exportName:"prepublish"},projects:{path:"./commands/projects.js",exportName:"projects"},publish:{path:"./commands/publish.js",exportName:"publish"},"publish:model":{path:"./commands/publish.js",exportName:"publish"},"publish:controller":{path:"./commands/publish.js",exportName:"publish"},"publish:middleware":{path:"./commands/publish.js",exportName:"publish"},"publish:action":{path:"./commands/publish.js",exportName:"publish"},"publish:core":{path:"./commands/publish.js",exportName:"publish"},"core:status":{path:"./commands/publish.js",exportName:"publish"},queue:{path:"./commands/queue.js",exportName:"queue"},release:{path:"./commands/release.js",exportName:"release"},route:{path:"./commands/route.js",exportName:"route"},saas:{path:"./commands/saas.js",exportName:"saas"},"stripe:setup":{path:"./commands/saas.js",exportName:"saas"},schedule:{path:"./commands/schedule.js",exportName:"schedule"},search:{path:"./commands/search.js",exportName:"search"},"search-engine:update":{path:"./commands/search.js",exportName:"search"},"search-engine:settings":{path:"./commands/search.js",exportName:"search"},seed:{path:"./commands/seed.js",exportName:"seed"},"seed:roles":{path:"./commands/seed.js",exportName:"seed"},"roles:seed":{path:"./commands/seed.js",exportName:"seed"},preview:{path:"./commands/serve.js",exportName:"preview"},serve:{path:"./commands/serve.js",exportName:"serve"},"serve:api":{path:"./commands/serve.js",exportName:"serveApi"},setup:{path:"./commands/setup.js",exportName:"setup"},"setup:ai":{path:"./commands/setup.js",exportName:"setup"},"setup:ssl":{path:"./commands/setup.js",exportName:"setup"},"setup:oh-my-zsh":{path:"./commands/setup.js",exportName:"setup"},"ai:setup":{path:"./commands/setup.js",exportName:"setup"},share:{path:"./commands/share.js",exportName:"share"},"simulator:doctor":{path:"./commands/simulator.js",exportName:"simulator"},"simulator:open":{path:"./commands/simulator.js",exportName:"simulator"},stack:{path:"./commands/stacks.js",exportName:"stacks"},sms:{path:"./commands/sms.js",exportName:"sms"},telemetry:{path:"./commands/telemetry.js",exportName:"telemetryCommand"},test:{path:"./commands/test.js",exportName:"test"},tinker:{path:"./commands/tinker.js",exportName:"tinker"},types:{path:"./commands/types.js",exportName:"types"},undeploy:{path:"./commands/cloud.js",exportName:"cloud"},upgrade:{path:"./commands/upgrade.js",exportName:"upgrade"},version:{path:"./commands/version.js",exportName:"version"},"docs:buddy":{path:"./commands/docs.js",exportName:"docs"},"docs:buddy:check":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts":{path:"./commands/docs.js",exportName:"docs"},"docs:artifacts:check":{path:"./commands/docs.js",exportName:"docs"},"docs:links":{path:"./commands/docs.js",exportName:"docs"},"docs:links:check":{path:"./commands/docs.js",exportName:"docs"}},commandGroups={minimal:["version","help"],development:["dev","build","test","lint"],database:["migrate","seed","fresh"],scaffolding:["make","generate"],deployment:["deploy","release","cloud"],info:["about","doctor","list"]},loadedRegistrars=new WeakMap;function loaderKey(loader){return`${loader.path}#${loader.exportName}`}export function markLoaded(buddy,commandName){const loader=commandRegistry[commandName];if(!loader)return;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}set.add(loaderKey(loader))}export async function loadCommand(commandName,buddy){const loader=commandRegistry[commandName];if(!loader)return!1;let set=loadedRegistrars.get(buddy);if(!set){set=new Set;loadedRegistrars.set(buddy,set)}const key=loaderKey(loader);if(set.has(key))return!0;set.add(key);try{const commandFunction=(await import(loader.path))[loader.exportName];if(typeof commandFunction==="function"){commandFunction(buddy);return!0}else return!1}catch{return!1}}export async function loadCommands(commandNames,buddy){const timeout=(ms)=>new Promise((_,reject)=>setTimeout(()=>reject(Error("timeout")),ms)),seen=new Set,unique=[];for(const name of commandNames){const loader=commandRegistry[name],key=loader?`${loader.path}#${loader.exportName}`:`name:${name}`;if(seen.has(key))continue;seen.add(key);unique.push(name)}await Promise.all(unique.map(async(name)=>{try{await Promise.race([loadCommand(name,buddy),timeout(5000)])}catch{}}))}export async function loadCommandGroup(groupName,buddy){const commands=commandGroups[groupName];if(commands)await loadCommands(commands,buddy)}export async function loadAllCommands(buddy){const allCommands=Object.keys(commandRegistry);await loadCommands(allCommands,buddy)}export function getCommandNames(){return Object.keys(commandRegistry)}export function getCommandsToLoad(args){const requestedCommand=args[0],isVersionFlag=requestedCommand==="--version"||requestedCommand==="-v",isHelpFlag=requestedCommand==="--help"||requestedCommand==="-h",isHelpWord=requestedCommand==="help";if(isVersionFlag)return["version"];if(!requestedCommand||isHelpFlag||isHelpWord)return Object.keys(commandRegistry);const baseCommand=requestedCommand.split(":")[0];if(baseCommand==="list")return["list",...Object.keys(commandRegistry).filter((k)=>k!=="list")];if(commandRegistry[requestedCommand])return[requestedCommand];if(commandRegistry[baseCommand])return[baseCommand];return Object.keys(commandRegistry)}
@@ -1 +1 @@
1
- const STATEFUL_SERVICES={postgres:{holds:"the application database",dumpable:!0},mysql:{holds:"the application database",dumpable:!0},mariadb:{holds:"the application database",dumpable:!0},vitess:{holds:"the application database",dumpable:!1}};function isEnabled(value){if(value===!0)return!0;if(!value||typeof value!=="object")return!1;return value.enabled!==!1}export function findUnbackedManagedServices(tsCloudConfig){const managed=tsCloudConfig?.infrastructure?.compute?.managedServices;if(!managed||typeof managed!=="object")return[];const out=[];for(const[name,{holds,dumpable}]of Object.entries(STATEFUL_SERVICES))if(isEnabled(managed[name]))out.push({name,holds,dumpable});return out}export function unbackedDataMessage(services){const first=services[0];if(!first)return"No unbacked managed data services.";const names=services.map((s)=>s.name).join(", "),subject=services.length===1?`${names} is`:`${names} are`,holds=first.holds.charAt(0).toUpperCase()+first.holds.slice(1),head=`${subject} provisioned on the compute instance. ${holds} shares a disk with the web process`;if(services.every((s)=>s.dumpable))return`${head}, and nothing copies its data off the box. The dumps \`buddy deploy\` takes before each migration land on that same disk: they survive a bad migration, not the loss of the instance. Copy them somewhere else on a schedule, and check a restore works (\`buddy db:restore\`) before you need one.`;const undumpable=services.filter((s)=>!s.dumpable).map((s)=>s.name).join(", ");return`${head}, and nothing backs it up. \`buddy db:backup\` does not dump ${undumpable}: a logical dump taken through a vtgate does not restore a sharded keyspace, so pretending otherwise would be worse than saying nothing. Take a snapshot at the storage layer, and test restoring it (stacksjs/stacks#2313).`}
1
+ const STATEFUL_SERVICES={postgres:{holds:"the application database",dumpable:!0},mysql:{holds:"the application database",dumpable:!0},mariadb:{holds:"the application database",dumpable:!0},vitess:{holds:"the application database",dumpable:!1}};function isEnabled(value){if(value===!0)return!0;if(!value||typeof value!=="object")return!1;return value.enabled!==!1}export function findUnbackedManagedServices(tsCloudConfig){const managed=tsCloudConfig?.infrastructure?.compute?.managedServices;if(!managed||typeof managed!=="object")return[];const out=[];for(const[name,{holds,dumpable}]of Object.entries(STATEFUL_SERVICES))if(isEnabled(managed?.[name]))out.push({name,holds,dumpable});return out}export function unbackedDataMessage(services){const first=services[0];if(!first)return"No unbacked managed data services.";const names=services.map((s)=>s.name).join(", "),subject=services.length===1?`${names} is`:`${names} are`,holds=first.holds.charAt(0).toUpperCase()+first.holds.slice(1),head=`${subject} provisioned on the compute instance. ${holds} shares a disk with the web process`;if(services.every((s)=>s.dumpable))return`${head}, and nothing copies its data off the box. The dumps \`buddy deploy\` takes before each migration land on that same disk: they survive a bad migration, not the loss of the instance. Copy them somewhere else on a schedule, and check a restore works (\`buddy db:restore\`) before you need one.`;const undumpable=services.filter((s)=>!s.dumpable).map((s)=>s.name).join(", ");return`${head}, and nothing backs it up. \`buddy db:backup\` does not dump ${undumpable}: a logical dump taken through a vtgate does not restore a sharded keyspace, so pretending otherwise would be worse than saying nothing. Take a snapshot at the storage layer, and test restoring it (stacksjs/stacks#2313).`}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/buddy",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.102",
5
+ "version": "0.73.0",
6
6
  "description": "Meet Buddy. The Stacks runtime.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -95,63 +95,63 @@
95
95
  "prepublishOnly": "bun run build"
96
96
  },
97
97
  "dependencies": {
98
- "@stacksjs/actions": "^0.72.102",
99
- "@stacksjs/ai": "^0.72.102",
100
- "@stacksjs/alias": "^0.72.102",
101
- "@stacksjs/analytics": "^0.72.102",
102
- "@stacksjs/api": "^0.72.102",
103
- "@stacksjs/arrays": "^0.72.102",
104
- "@stacksjs/auth": "^0.72.102",
105
- "@stacksjs/browser-extension": "^0.72.102",
106
- "@stacksjs/build": "^0.72.102",
107
- "@stacksjs/cache": "^0.72.102",
108
- "@stacksjs/chat": "^0.72.102",
98
+ "@stacksjs/actions": "^0.73.0",
99
+ "@stacksjs/ai": "^0.73.0",
100
+ "@stacksjs/alias": "^0.73.0",
101
+ "@stacksjs/analytics": "^0.73.0",
102
+ "@stacksjs/api": "^0.73.0",
103
+ "@stacksjs/arrays": "^0.73.0",
104
+ "@stacksjs/auth": "^0.73.0",
105
+ "@stacksjs/browser-extension": "^0.73.0",
106
+ "@stacksjs/build": "^0.73.0",
107
+ "@stacksjs/cache": "^0.73.0",
108
+ "@stacksjs/chat": "^0.73.0",
109
109
  "@stacksjs/clapp": "^0.2.12",
110
- "@stacksjs/cli": "^0.72.102",
111
- "@stacksjs/cloud": "^0.72.102",
112
- "@stacksjs/cms": "^0.72.102",
113
- "@stacksjs/collections": "^0.72.102",
114
- "@stacksjs/config": "^0.72.102",
115
- "@stacksjs/database": "^0.72.102",
116
- "@stacksjs/desktop-build": "^0.72.102",
117
- "@stacksjs/dns": "^0.72.102",
110
+ "@stacksjs/cli": "^0.73.0",
111
+ "@stacksjs/cloud": "^0.73.0",
112
+ "@stacksjs/cms": "^0.73.0",
113
+ "@stacksjs/collections": "^0.73.0",
114
+ "@stacksjs/config": "^0.73.0",
115
+ "@stacksjs/database": "^0.73.0",
116
+ "@stacksjs/desktop-build": "^0.73.0",
117
+ "@stacksjs/dns": "^0.73.0",
118
118
  "@stacksjs/dnsx": "^0.2.3",
119
- "@stacksjs/email": "^0.72.102",
120
- "@stacksjs/enums": "^0.72.102",
121
- "@stacksjs/env": "^0.72.102",
122
- "@stacksjs/error-handling": "^0.72.102",
123
- "@stacksjs/events": "^0.72.102",
124
- "@stacksjs/git": "^0.72.102",
119
+ "@stacksjs/email": "^0.73.0",
120
+ "@stacksjs/enums": "^0.73.0",
121
+ "@stacksjs/env": "^0.73.0",
122
+ "@stacksjs/error-handling": "^0.73.0",
123
+ "@stacksjs/events": "^0.73.0",
124
+ "@stacksjs/git": "^0.73.0",
125
125
  "@stacksjs/gitit": "^0.2.5",
126
- "@stacksjs/health": "^0.72.102",
126
+ "@stacksjs/health": "^0.73.0",
127
127
  "@stacksjs/httx": "^0.1.10",
128
- "@stacksjs/image": "^0.72.102",
129
- "@stacksjs/lint": "^0.72.102",
130
- "@stacksjs/logging": "^0.72.102",
131
- "@stacksjs/notifications": "^0.72.102",
132
- "@stacksjs/objects": "^0.72.102",
133
- "@stacksjs/orm": "^0.72.102",
134
- "@stacksjs/path": "^0.72.102",
135
- "@stacksjs/payments": "^0.72.102",
136
- "@stacksjs/realtime": "^0.72.102",
137
- "@stacksjs/router": "^0.72.102",
128
+ "@stacksjs/image": "^0.73.0",
129
+ "@stacksjs/lint": "^0.73.0",
130
+ "@stacksjs/logging": "^0.73.0",
131
+ "@stacksjs/notifications": "^0.73.0",
132
+ "@stacksjs/objects": "^0.73.0",
133
+ "@stacksjs/orm": "^0.73.0",
134
+ "@stacksjs/path": "^0.73.0",
135
+ "@stacksjs/payments": "^0.73.0",
136
+ "@stacksjs/realtime": "^0.73.0",
137
+ "@stacksjs/router": "^0.73.0",
138
138
  "@stacksjs/rpx": "^0.11.42",
139
- "@stacksjs/scheduler": "^0.72.102",
140
- "@stacksjs/search-engine": "^0.72.102",
141
- "@stacksjs/security": "^0.72.102",
142
- "@stacksjs/server": "^0.72.102",
143
- "@stacksjs/sites": "^0.72.102",
144
- "@stacksjs/skills": "^0.72.102",
145
- "@stacksjs/storage": "^0.72.102",
146
- "@stacksjs/strings": "^0.72.102",
147
- "@stacksjs/testing": "^0.72.102",
148
- "@stacksjs/tinker": "^0.72.102",
149
- "@stacksjs/ts-cloud": "^0.12.7",
150
- "@stacksjs/tunnel": "^0.72.102",
151
- "@stacksjs/types": "^0.72.102",
152
- "@stacksjs/ui": "^0.72.102",
153
- "@stacksjs/utils": "^0.72.102",
154
- "@stacksjs/validation": "^0.72.102",
139
+ "@stacksjs/scheduler": "^0.73.0",
140
+ "@stacksjs/search-engine": "^0.73.0",
141
+ "@stacksjs/security": "^0.73.0",
142
+ "@stacksjs/server": "^0.73.0",
143
+ "@stacksjs/sites": "^0.73.0",
144
+ "@stacksjs/skills": "^0.73.0",
145
+ "@stacksjs/storage": "^0.73.0",
146
+ "@stacksjs/strings": "^0.73.0",
147
+ "@stacksjs/testing": "^0.73.0",
148
+ "@stacksjs/tinker": "^0.73.0",
149
+ "@stacksjs/ts-cloud": "^0.12.10",
150
+ "@stacksjs/tunnel": "^0.73.0",
151
+ "@stacksjs/types": "^0.73.0",
152
+ "@stacksjs/ui": "^0.73.0",
153
+ "@stacksjs/utils": "^0.73.0",
154
+ "@stacksjs/validation": "^0.73.0",
155
155
  "ajv": "^8.20.0",
156
156
  "ajv-formats": "^3.0.1",
157
157
  "ts-pantry": "^0.11.35"