Skip to content

Commit cee9efd

Browse files
committed
chore: wip
chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip chore: wip
1 parent e1cddd0 commit cee9efd

File tree

19 files changed

+144
-59
lines changed

19 files changed

+144
-59
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ updates
1010
tests/unit/coverage
1111
dist*
1212
!.gitkeep
13+
custom-cli
1314

1415
.fleet
1516
.idea

app/Actions/SendWelcomeEmail.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,18 @@ import { Action } from '@stacksjs/actions'
33
export default new Action({
44
name: 'SendWelcomeEmail',
55
description: 'Send a welcome email to a new user',
6+
// longRunning: false,
7+
68
async handle() {
7-
// Send the email
8-
await sendEmail({
9+
return sendEmail({
910
to: 'some@recipient.com',
1011
subject: 'Welcome to our app!',
1112
text: 'We are excited to have you here.',
1213
})
13-
14-
// Return a message
15-
return `Welcome email sent to ${email}`
1614
},
1715
})
1816

1917
function sendEmail({ to, subject, text }: { to: string, subject: string, text: string }) {
2018
log.info('Sending email', { to, subject, text })
21-
return Promise.resolve()
19+
return `Welcome email sent to ${email}`
2220
}

app/Commands/inspire.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
// triggered via `$your-command inspire`
1+
// triggered via `$your-cli inspire` and `buddy inspire`
22
import process from 'node:process'
3-
import { cli, log } from '@stacksjs/cli'
3+
import { log } from '@stacksjs/cli'
44
import { collect } from '@stacksjs/collections'
5+
import { ExitCode } from '@stacksjs/types'
6+
import type { CLI } from '@stacksjs/types'
57

6-
// for enhanced type safety
8+
// for enhanced type-safety & autocompletion, you may want to define the options interface
79
interface InspireOptions {
810
two: boolean
911
}
1012

13+
// could be queried from any API or a database
1114
const quotes = collect([
1215
'The best way to get started is to quit talking and begin doing.',
1316
'The pessimist sees difficulty in every opportunity. The optimist sees opportunity in every difficulty.',
@@ -26,16 +29,18 @@ const quotes = collect([
2629
'Security is mostly a superstition. Life is either a daring adventure or nothing.',
2730
])
2831

29-
cli()
30-
.command('inspire', 'Inspire yourself with a random quote')
31-
.option('--two, -t', 'Show two quotes', { default: false })
32-
.alias('insp')
33-
.action((options: InspireOptions) => {
34-
if (options.two)
35-
quotes.random(2).forEach(quote => log.info(quote))
36-
else
37-
log.info(quotes.random())
32+
export default function (cli: CLI) {
33+
return cli
34+
.command('inspire', 'Inspire yourself with a random quote')
35+
.option('--two, -t', 'Inspire yourself with two random quotes', { default: false })
36+
.alias('insp')
37+
.action((options: InspireOptions) => {
38+
if (options.two)
39+
quotes.random(2).map((quote, index) => log.info(`${index + 1}. ${quote}`))
40+
else
41+
log.info(quotes.random())
3842

39-
log.success('Have a great day!')
40-
process.exit(ExitCode.Success)
41-
})
43+
log.success('Have a great day!')
44+
process.exit(ExitCode.Success)
45+
})
46+
}

app/Jobs/DummyJob.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { Job } from '@stacksjs/queue'
2+
import { Every } from '@stacksjs/types'
23

34
export default new Job({
45
name: 'Send Welcome Email', // defaults to the file name
56
description: 'A demo cron job that runs every 5th minute', // optional
6-
// `run: 'demo-job'` is another option where `demo-job` refers to ./resources/functions/demo-job.ts
77
tries: 3, // defaults to 3, in case of failures
88
backoff: 3, // defaults to 3-second delays between retries
9-
action: 'SendWelcomeEmail',
10-
// handle: () => { // or `action: () => {`
11-
// log.info('This cron job runs every 5th minute')
12-
// },
9+
schedule: Every.FiveSeconds, // '*/5 * * * *' in cron syntax (overwrites the Scheduler's definition)
10+
handle: () => { // or `action: () => {`
11+
log.info('This cron job will get based ')
12+
},
13+
// action: 'SendWelcomeEmail', // instead of handle, you may target an action
1314
})

app/Schedule.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
// import { schedule as run } from '@stacksjs/scheduler'
2-
// import type { Scheduler } from '@stacksjs/types'
1+
import { run } from '@stacksjs/scheduler'
2+
import type { Scheduler } from '@stacksjs/types'
33

4-
// export default {
5-
// schedule() {
6-
// run.command('bun /home/some/script.js').everySecond()
7-
// run.command('bun /home/some/other/script.ts').everyMinute()
8-
// run.action('./actions/SomeAction.ts').everyFiveMinutes() // could use a better dummy example 😅
9-
// run.job('./jobs/DummyJob.ts').everyTenMinutes()
10-
// run.exec('bun /home/some/script.ts').everyMinute()
11-
// run.call(() => {
12-
// // ...
13-
// }).weekly().mondays().at('13:00').timezone('America/Los_Angeles')
14-
// },
15-
// } satisfies Scheduler
4+
export default function scheduler() {
5+
run().command('bun /home/some/script.js').everySecond()
6+
run.command('bun /home/some/other/script.ts').everyMinute()
7+
run.action('./actions/SomeAction.ts').everyFiveMinutes() // could use a better dummy example 😅
8+
run.job('./jobs/DummyJob.ts').everyTenMinutes()
9+
run.exec('bun /home/some/script.ts').everyMinute()
10+
run.call(() => {
11+
// ...
12+
}).weekly().mondays().at('13:00').timezone('America/Los_Angeles')
13+
}

bun.lockb

6.83 KB
Binary file not shown.

config/cli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type { BinaryConfig } from '@stacksjs/types'
88
* you have any questions, feel free to reach out via Discord or GitHub Discussions.
99
*/
1010
export default {
11-
name: 'Buddy CLI',
12-
command: 'buddy', // enables `buddy <command> <options>`
11+
name: 'My Custom CLI',
12+
command: 'custom-cli', // enables `custom-cli <command> <options>`
1313
description: 'This is an example command to illustrate how to create your own commands. Check out `../app/commands` for more.',
1414
} satisfies BinaryConfig
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
export class Action {
22
name: string
33
description: string
4+
longRunning: boolean
45
handle: () => Promise<string>
56

67
constructor({ name, description, handle }: { name: string, description: string, handle: () => Promise<string> }) {
78
this.name = name
89
this.description = description
10+
this.longRunning = false // TODO: Implement long running actions
911
this.handle = handle
1012
}
1113
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import process from 'node:process'
2+
import { ExitCode } from '@stacksjs/types'
3+
import { writeTextFile } from '@stacksjs/storage'
4+
import { projectPath } from '@stacksjs/path'
5+
import { cli } from '@stacksjs/config'
6+
7+
log.info('Creating Vue Component Library Entry Point...')
8+
9+
if (!cli.command) {
10+
log.error('No command defined in the CLI configuration')
11+
process.exit(ExitCode.FatalError)
12+
}
13+
14+
await writeTextFile({
15+
path: projectPath(cli.command),
16+
data: `#!/usr/bin/env bun
17+
import('./storage/framework/core/buddy/src/custom-cli')
18+
`,
19+
}).catch((err) => {
20+
log.error('There was an error generating your custom CLI file.', err)
21+
process.exit(ExitCode.FatalError)
22+
})
23+
24+
log.success('Generated custom CLI file')

storage/framework/core/buddy/src/cli.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import process from 'node:process'
22
import { handleError } from '@stacksjs/error-handling'
33
import { cli } from '@stacksjs/cli'
44
import { ensureProjectIsInitialized } from '@stacksjs/utils'
5+
import { path as p } from '@stacksjs/path'
6+
import { fs } from '@stacksjs/storage'
57
import * as cmd from './commands'
68

79
// setup global error handlers
@@ -44,6 +46,21 @@ async function main() {
4446
// cmd.prepublish(buddy)
4547
cmd.upgrade(buddy)
4648

49+
// dynamically import and register commands from ./app/Commands/*
50+
const commandsDir = p.appPath('Commands')
51+
const commandFiles = fs.readdirSync(commandsDir).filter(file => file.endsWith('.ts'))
52+
53+
for (const file of commandFiles) {
54+
const commandPath = `${commandsDir}/${file}`
55+
const dynamicImport = await import(commandPath)
56+
57+
// Correctly use the default export function
58+
if (typeof dynamicImport.default === 'function')
59+
dynamicImport.default(buddy)
60+
else
61+
console.error(`Expected a default export function in ${file}, but got:`, dynamicImport.default)
62+
}
63+
4764
buddy.parse()
4865
}
4966

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import process from 'node:process'
2+
import { handleError } from '@stacksjs/error-handling'
3+
import { config } from '@stacksjs/config'
4+
import { cli } from '@stacksjs/cli'
5+
import { path as p } from '@stacksjs/path'
6+
import { fs } from '@stacksjs/storage'
7+
8+
// setup global error handlers
9+
process.on('uncaughtException', handleError)
10+
process.on('unhandledRejection', handleError)
11+
12+
async function main() {
13+
const buddy = cli(config.cli.name)
14+
15+
if (!fs.existsSync(p.projectPath(config.cli.command)))
16+
fs.writeFileSync(p.projectPath(config.cli.command), `import('./storage/framework/core/buddy/src/custom-cli')`)
17+
18+
// dynamically import and register commands from ./app/Commands/*
19+
const commandsDir = p.appPath('Commands')
20+
const commandFiles = fs.readdirSync(commandsDir).filter(file => file.endsWith('.ts'))
21+
22+
for (const file of commandFiles) {
23+
const commandPath = `${commandsDir}/${file}`
24+
const dynamicImport = await import(commandPath)
25+
26+
// Correctly use the default export function
27+
if (typeof dynamicImport.default === 'function')
28+
dynamicImport.default(buddy)
29+
else
30+
console.error(`Expected a default export function in ${file}, but got:`, dynamicImport.default)
31+
}
32+
33+
buddy.parse()
34+
}
35+
36+
await main()

storage/framework/core/cli/src/cli.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export function cli(name?: string | CliOptions, options?: CliOptions) {
2121
name = options.name
2222
}
2323

24-
const cli = cac(name)
24+
const cli = cac(name || 'buddy') // default to extending buddy
2525

2626
cli.help()
2727
cli.version(options?.version || version)

storage/framework/core/config/src/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ export const {
1212
analytics,
1313
api,
1414
app,
15-
binary,
1615
cache,
1716
cloud,
17+
cli,
1818
database,
1919
dns,
2020
docs,

storage/framework/core/config/src/defaults.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ export default {
5959
},
6060
},
6161

62-
binary: {
63-
name: 'buddy',
64-
command: 'buddy',
62+
cli: {
63+
name: 'My Custom CLI',
64+
command: 'my-custom-cli',
6565
description: 'Stacks is a full-stack framework for TypeScript.',
6666
source: p.appPath('commands'),
6767
},

storage/framework/core/config/src/overrides.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { StacksConfig } from '@stacksjs/types'
22
import ai from '../../../../../config/ai'
33
import app from '../../../../../config/app'
44
import cache from '../../../../../config/cache'
5-
import binary from '../../../../../config/cli'
5+
import cli from '../../../../../config/cli'
66
import cloud from '../../../../../config/cloud'
77
import database from '../../../../../config/database'
88
import dns from '../../../../../config/dns'
@@ -25,8 +25,8 @@ import ui from '../../../../../config/ui'
2525
export default {
2626
ai,
2727
app,
28-
binary,
2928
cache,
29+
cli,
3030
cloud,
3131
database,
3232
dns,

storage/framework/core/queue/src/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@ import type { JobOptions } from '@stacksjs/types'
33
export class Job {
44
name: JobOptions['name']
55
description: JobOptions['description']
6-
handle: JobOptions['handle']
6+
action?: JobOptions['action']
7+
handle?: JobOptions['handle']
78
tries: JobOptions['tries']
89
backoff: JobOptions['backoff']
910

10-
constructor({ name, description, handle, tries, backoff }: JobOptions) {
11+
constructor({ name, description, handle, tries, backoff, action }: JobOptions) {
1112
this.name = name
1213
this.description = description
1314
this.handle = handle
15+
this.action = action
1416
this.tries = tries
1517
this.backoff = backoff
1618
}

storage/framework/core/scheduler/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ export interface Scheduler {
231231
}
232232

233233
// function run(callback: Function): Scheduler {
234-
function run(callback: ((now: Date | 'manual' | 'init') => void) | string): Scheduler {
234+
export function run(callback: ((now: Date | 'manual' | 'init') => void) | string): Scheduler {
235235
return {
236236
everySecond: () => {
237237
cron.schedule('* * * * * *', callback)

storage/framework/core/types/src/cron-jobs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@ export interface JobOptions {
77
*/
88
name?: string
99

10-
handle: string | Function
10+
handle?: string | Function
1111
action?: string
1212
description?: string
1313
timezone?: string
1414
tries?: number
1515
backoff?: number | number[]
16+
schedule?: string | Every
1617
enabled?: boolean
1718
}
1819

storage/framework/core/types/src/stacks.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,22 @@ export interface StacksOptions {
5252
app: AppConfig
5353

5454
/**
55-
* **Binary Options**
55+
* **Cache Options**
5656
*
57-
* This configuration defines all of your Binary options. Because Stacks is fully-typed, you
57+
* This configuration defines all of your Cache options. Because Stacks is fully-typed, you
5858
* may hover any of the options below and the definitions will be provided. In case you
5959
* have any questions, feel free to reach out via Discord or GitHub Discussions.
6060
*/
61-
binary: BinaryConfig
61+
cache: CacheConfig
6262

6363
/**
64-
* **Cache Options**
64+
* **CLI / Binary Options**
6565
*
66-
* This configuration defines all of your Cache options. Because Stacks is fully-typed, you
66+
* This configuration defines all of your Binary options. Because Stacks is fully-typed, you
6767
* may hover any of the options below and the definitions will be provided. In case you
6868
* have any questions, feel free to reach out via Discord or GitHub Discussions.
6969
*/
70-
cache: CacheConfig
70+
cli: BinaryConfig
7171

7272
/**
7373
* **Cloud Options**

0 commit comments

Comments
 (0)