@stacksjs/actions 0.70.88 → 0.70.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action.d.ts +149 -0
- package/dist/action.js +78 -0
- package/dist/actions.d.ts +2 -0
- package/dist/actions.js +2 -0
- package/dist/add.d.ts +6 -0
- package/dist/add.js +20 -0
- package/dist/ai/request-model-access.d.ts +1 -0
- package/dist/ai/request-model-access.js +10 -0
- package/dist/auth/client.d.ts +1 -0
- package/dist/auth/client.js +44 -0
- package/dist/auth/prune.d.ts +1 -0
- package/dist/auth/prune.js +35 -0
- package/dist/auth/setup.d.ts +1 -0
- package/dist/auth/setup.js +322 -0
- package/dist/auth/token.d.ts +1 -0
- package/dist/auth/token.js +10 -0
- package/dist/blog-admin.d.ts +55 -0
- package/dist/blog-admin.js +156 -0
- package/dist/blog.d.ts +30 -0
- package/dist/blog.js +398 -0
- package/dist/build/cli.d.ts +1 -0
- package/dist/build/cli.js +6 -0
- package/dist/build/component-libs.d.ts +1 -0
- package/dist/build/component-libs.js +7 -0
- package/dist/build/core.d.ts +1 -0
- package/dist/build/core.js +55 -0
- package/dist/build/desktop.d.ts +1 -0
- package/dist/build/desktop.js +5 -0
- package/dist/build/docs.d.ts +1 -0
- package/dist/build/docs.js +5 -0
- package/dist/build/frontend-static.d.ts +16 -0
- package/dist/build/frontend-static.js +124 -0
- package/dist/build/server.d.ts +1 -0
- package/dist/build/server.js +6 -0
- package/dist/build/stacks.d.ts +1 -0
- package/dist/build/stacks.js +8 -0
- package/dist/build/views.d.ts +1 -0
- package/dist/build/views.js +11 -0
- package/dist/build.d.ts +9 -0
- package/dist/build.js +64 -0
- package/dist/bump.d.ts +1 -0
- package/dist/bump.js +163 -0
- package/dist/cdn/invalidate-cache.d.ts +1 -0
- package/dist/cdn/invalidate-cache.js +0 -0
- package/dist/changelog.d.ts +9 -0
- package/dist/changelog.js +27 -0
- package/dist/check/ports.d.ts +1 -0
- package/dist/check/ports.js +16 -0
- package/dist/clean.d.ts +1 -0
- package/dist/clean.js +4 -0
- package/dist/commit.d.ts +3 -0
- package/dist/commit.js +12 -0
- package/dist/copy-types.d.ts +1 -0
- package/dist/copy-types.js +10 -0
- package/dist/database/seed.d.ts +1 -0
- package/dist/database/seed.js +26 -0
- package/dist/deploy/create-receipt-rule.d.ts +1 -0
- package/dist/deploy/create-receipt-rule.js +36 -0
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/index.js +1574 -0
- package/dist/dev/api.d.ts +1 -0
- package/dist/dev/api.js +94 -0
- package/dist/dev/components.d.ts +1 -0
- package/dist/dev/components.js +7 -0
- package/dist/dev/dashboard-globals.d.ts +4 -0
- package/dist/dev/dashboard-globals.js +89 -0
- package/dist/dev/dashboard-utils.d.ts +150 -0
- package/dist/dev/dashboard-utils.js +380 -0
- package/dist/dev/dashboard.d.ts +22 -0
- package/dist/dev/dashboard.js +435 -0
- package/dist/dev/desktop.d.ts +1 -0
- package/dist/dev/desktop.js +5 -0
- package/dist/dev/docs.d.ts +1 -0
- package/dist/dev/docs.js +24 -0
- package/dist/dev/index.d.ts +10 -0
- package/dist/dev/index.js +29 -0
- package/dist/dev/migrate-watcher.d.ts +1 -0
- package/dist/dev/migrate-watcher.js +74 -0
- package/dist/dev/system-tray.d.ts +1 -0
- package/dist/dev/system-tray.js +5 -0
- package/dist/dev/views.d.ts +1 -0
- package/dist/dev/views.js +147 -0
- package/dist/discover-packages.d.ts +18 -0
- package/dist/discover-packages.js +32 -0
- package/dist/domains/add.d.ts +1 -0
- package/dist/domains/add.js +61 -0
- package/dist/domains/purchase.d.ts +1 -0
- package/dist/domains/purchase.js +66 -0
- package/dist/domains/remove.d.ts +1 -0
- package/dist/domains/remove.js +24 -0
- package/dist/examples.d.ts +5 -0
- package/dist/examples.js +34 -0
- package/dist/find-projects.d.ts +1 -0
- package/dist/find-projects.js +16 -0
- package/dist/fresh.d.ts +1 -0
- package/dist/fresh.js +17 -0
- package/dist/generate/action-types.d.ts +1 -0
- package/dist/generate/action-types.js +13 -0
- package/dist/generate/component-meta.d.ts +1 -0
- package/dist/generate/component-meta.js +9 -0
- package/dist/generate/custom-cli-file.d.ts +1 -0
- package/dist/generate/custom-cli-file.js +21 -0
- package/dist/generate/env-files.d.ts +1 -0
- package/dist/generate/env-files.js +66 -0
- package/dist/generate/ide-helpers.d.ts +1 -0
- package/dist/generate/ide-helpers.js +8 -0
- package/dist/generate/index.d.ts +36 -0
- package/dist/generate/index.js +158 -0
- package/dist/generate/lib-entries.d.ts +1 -0
- package/dist/generate/lib-entries.js +16 -0
- package/dist/generate/pantry-file.d.ts +1 -0
- package/dist/generate/pantry-file.js +46 -0
- package/dist/generate/symlink-core.d.ts +1 -0
- package/dist/generate/symlink-core.js +2 -0
- package/dist/generate/types.d.ts +1 -0
- package/dist/generate/types.js +3 -0
- package/dist/generate/vscode-custom-data.d.ts +1 -0
- package/dist/generate/vscode-custom-data.js +9 -0
- package/dist/generate/web-types.d.ts +1 -0
- package/dist/generate/web-types.js +0 -0
- package/dist/helpers/component-meta.d.ts +26 -0
- package/dist/helpers/component-meta.js +295 -0
- package/dist/helpers/index.d.ts +4 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/lib-entries.d.ts +12 -0
- package/dist/helpers/lib-entries.js +73 -0
- package/dist/helpers/package-json.d.ts +2 -0
- package/dist/helpers/package-json.js +74 -0
- package/dist/helpers/utils.d.ts +23 -0
- package/dist/helpers/utils.js +105 -0
- package/dist/helpers/vscode-custom-data.d.ts +3 -0
- package/dist/helpers/vscode-custom-data.js +30 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +50 -0
- package/dist/key-generate.d.ts +1 -0
- package/dist/key-generate.js +24 -0
- package/dist/lint/fix.d.ts +1 -0
- package/dist/lint/fix.js +4 -0
- package/dist/lint/index.d.ts +1 -0
- package/dist/lint/index.js +4 -0
- package/dist/lint/lint.d.ts +14 -0
- package/dist/lint/lint.js +34 -0
- package/dist/make-command.d.ts +10 -0
- package/dist/make-command.js +95 -0
- package/dist/make-job.d.ts +5 -0
- package/dist/make-job.js +154 -0
- package/dist/make-policy.d.ts +10 -0
- package/dist/make-policy.js +142 -0
- package/dist/make-resource.d.ts +10 -0
- package/dist/make-resource.js +142 -0
- package/dist/make.d.ts +52 -0
- package/dist/make.js +328 -0
- package/dist/migrate/database.d.ts +1 -0
- package/dist/migrate/database.js +16 -0
- package/dist/migrate/fresh.d.ts +1 -0
- package/dist/migrate/fresh.js +31 -0
- package/dist/orm/base.d.ts +1 -0
- package/dist/orm/base.js +0 -0
- package/dist/orm/test.d.ts +1 -0
- package/dist/orm/test.js +0 -0
- package/dist/prepublish.d.ts +1 -0
- package/dist/prepublish.js +16 -0
- package/dist/queue/clear.d.ts +1 -0
- package/dist/queue/clear.js +42 -0
- package/dist/queue/dlq-purge.d.ts +1 -0
- package/dist/queue/dlq-purge.js +28 -0
- package/dist/queue/dlq-retry.d.ts +1 -0
- package/dist/queue/dlq-retry.js +35 -0
- package/dist/queue/dlq.d.ts +1 -0
- package/dist/queue/dlq.js +55 -0
- package/dist/queue/failed.d.ts +1 -0
- package/dist/queue/failed.js +69 -0
- package/dist/queue/flush.d.ts +1 -0
- package/dist/queue/flush.js +49 -0
- package/dist/queue/inspect.d.ts +1 -0
- package/dist/queue/inspect.js +154 -0
- package/dist/queue/list.d.ts +1 -0
- package/dist/queue/list.js +69 -0
- package/dist/queue/monitor.d.ts +1 -0
- package/dist/queue/monitor.js +95 -0
- package/dist/queue/pause.d.ts +1 -0
- package/dist/queue/pause.js +28 -0
- package/dist/queue/quarantine.d.ts +1 -0
- package/dist/queue/quarantine.js +42 -0
- package/dist/queue/resume.d.ts +1 -0
- package/dist/queue/resume.js +27 -0
- package/dist/queue/retry.d.ts +1 -0
- package/dist/queue/retry.js +41 -0
- package/dist/queue/schedule-list.d.ts +1 -0
- package/dist/queue/schedule-list.js +33 -0
- package/dist/queue/schedule.d.ts +1 -0
- package/dist/queue/schedule.js +12 -0
- package/dist/queue/status.d.ts +1 -0
- package/dist/queue/status.js +68 -0
- package/dist/queue/table.d.ts +1 -0
- package/dist/queue/table.js +10 -0
- package/dist/queue/unquarantine.d.ts +1 -0
- package/dist/queue/unquarantine.js +27 -0
- package/dist/queue/work.d.ts +1 -0
- package/dist/queue/work.js +57 -0
- package/dist/release.d.ts +1 -0
- package/dist/release.js +21 -0
- package/dist/route/list.d.ts +1 -0
- package/dist/route/list.js +78 -0
- package/dist/run-action.d.ts +2 -0
- package/dist/run-action.js +1 -0
- package/dist/saas/setup.d.ts +1 -0
- package/dist/saas/setup.js +9 -0
- package/dist/scaffold-crud.d.ts +25 -0
- package/dist/scaffold-crud.js +211 -0
- package/dist/schedule/run.d.ts +1 -0
- package/dist/schedule/run.js +7 -0
- package/dist/search/flush.d.ts +1 -0
- package/dist/search/flush.js +10 -0
- package/dist/search/import.d.ts +1 -0
- package/dist/search/import.js +10 -0
- package/dist/search/settings-list.d.ts +1 -0
- package/dist/search/settings-list.js +10 -0
- package/dist/search/settings.d.ts +1 -0
- package/dist/search/settings.js +9 -0
- package/dist/serve/api.d.ts +1 -0
- package/dist/serve/api.js +35 -0
- package/dist/setup/index.d.ts +1 -0
- package/dist/setup/index.js +1 -0
- package/dist/setup/ssl.d.ts +38 -0
- package/dist/setup/ssl.js +271 -0
- package/dist/stacks.d.ts +4 -0
- package/dist/stacks.js +265 -0
- package/dist/templates.d.ts +28 -0
- package/dist/templates.js +301 -0
- package/dist/test/feature.d.ts +1 -0
- package/dist/test/feature.js +11 -0
- package/dist/test/index.d.ts +1 -0
- package/dist/test/index.js +11 -0
- package/dist/test/ui.d.ts +1 -0
- package/dist/test/ui.js +4 -0
- package/dist/test/unit.d.ts +1 -0
- package/dist/test/unit.js +11 -0
- package/dist/typecheck.d.ts +1 -0
- package/dist/typecheck.js +4 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +16 -0
- package/dist/upgrade/binary.d.ts +1 -0
- package/dist/upgrade/binary.js +29 -0
- package/dist/upgrade/bun.d.ts +1 -0
- package/dist/upgrade/bun.js +0 -0
- package/dist/upgrade/dependencies.d.ts +1 -0
- package/dist/upgrade/dependencies.js +0 -0
- package/dist/upgrade/framework-utils.d.ts +150 -0
- package/dist/upgrade/framework-utils.js +193 -0
- package/dist/upgrade/framework.d.ts +1 -0
- package/dist/upgrade/framework.js +310 -0
- package/dist/upgrade/index.d.ts +1 -0
- package/dist/upgrade/index.js +17 -0
- package/dist/upgrade/packages.d.ts +14 -0
- package/dist/upgrade/packages.js +99 -0
- package/dist/upgrade/shell.d.ts +1 -0
- package/dist/upgrade/shell.js +41 -0
- package/dist/upgrade.d.ts +7 -0
- package/dist/upgrade.js +38 -0
- package/package.json +16 -16
package/dist/make-job.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { log } from "@stacksjs/logging";
|
|
2
|
+
import * as p from "@stacksjs/path";
|
|
3
|
+
import { writeFile } from "@stacksjs/storage";
|
|
4
|
+
export async function makeJob(options) {
|
|
5
|
+
const jobOptions = options, name = options.name;
|
|
6
|
+
if (!name) {
|
|
7
|
+
log.error("Job name is required");
|
|
8
|
+
return !1;
|
|
9
|
+
}
|
|
10
|
+
const jobName = name.endsWith("Job") ? name : `${name}Job`, content = jobOptions.class ?? !1 ? generateClassBasedJob(jobName, jobOptions) : generateFunctionBasedJob(jobName, jobOptions), filePath = p.userJobsPath(`${jobName}.ts`);
|
|
11
|
+
try {
|
|
12
|
+
await writeFile(filePath, content);
|
|
13
|
+
log.success(`Created job: ${filePath}`);
|
|
14
|
+
return !0;
|
|
15
|
+
} catch (error) {
|
|
16
|
+
log.error(`Failed to create job: ${error.message}`);
|
|
17
|
+
return !1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function generateFunctionBasedJob(name, options) {
|
|
21
|
+
const queue = options.queue ?? "default", tries = options.tries ?? 3, backoff = options.backoff ?? 3;
|
|
22
|
+
return `import { Job } from '@stacksjs/queue'
|
|
23
|
+
|
|
24
|
+
export default new Job({
|
|
25
|
+
/**
|
|
26
|
+
* The job name (optional, defaults to filename)
|
|
27
|
+
*/
|
|
28
|
+
name: '${name}',
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* A description of what this job does (optional)
|
|
32
|
+
*/
|
|
33
|
+
description: '${name} job',
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* The queue this job should be dispatched to
|
|
37
|
+
*/
|
|
38
|
+
queue: '${queue}',
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Number of times to retry if the job fails
|
|
42
|
+
*/
|
|
43
|
+
tries: ${tries},
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Seconds to wait between retry attempts
|
|
47
|
+
*/
|
|
48
|
+
backoff: ${backoff},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Cron expression for scheduled jobs (optional)
|
|
52
|
+
* Examples:
|
|
53
|
+
* - '* * * * *' - Every minute
|
|
54
|
+
* - '0 * * * *' - Every hour
|
|
55
|
+
* - '0 0 * * *' - Every day at midnight
|
|
56
|
+
*/
|
|
57
|
+
// rate: '* * * * *',
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Backoff configuration for advanced retry strategies (optional)
|
|
61
|
+
*/
|
|
62
|
+
// backoffConfig: {
|
|
63
|
+
// strategy: 'exponential', // 'fixed' | 'exponential' | 'linear'
|
|
64
|
+
// initialDelay: 1000,
|
|
65
|
+
// factor: 2,
|
|
66
|
+
// maxDelay: 60000,
|
|
67
|
+
// },
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Handle the job
|
|
71
|
+
* @param payload - The job payload data
|
|
72
|
+
* @returns The result of the job processing
|
|
73
|
+
*/
|
|
74
|
+
async handle(payload: Record<string, unknown>) {
|
|
75
|
+
// Add your job logic here.
|
|
76
|
+
console.log('Processing job with payload:', payload)
|
|
77
|
+
|
|
78
|
+
return { success: true }
|
|
79
|
+
},
|
|
80
|
+
})
|
|
81
|
+
`;
|
|
82
|
+
}
|
|
83
|
+
function generateClassBasedJob(name, options) {
|
|
84
|
+
const queue = options.queue ?? "default", tries = options.tries ?? 3;
|
|
85
|
+
return `import { log } from '@stacksjs/logging'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* ${name}
|
|
89
|
+
*
|
|
90
|
+
* Generated job class.
|
|
91
|
+
*/
|
|
92
|
+
export default class ${name} {
|
|
93
|
+
/**
|
|
94
|
+
* Job configuration
|
|
95
|
+
*/
|
|
96
|
+
public static config = {
|
|
97
|
+
/**
|
|
98
|
+
* The queue this job should be dispatched to
|
|
99
|
+
*/
|
|
100
|
+
queue: '${queue}',
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Cron expression for scheduled jobs (optional)
|
|
104
|
+
* Examples:
|
|
105
|
+
* - '* * * * *' - Every minute
|
|
106
|
+
* - '0 * * * *' - Every hour
|
|
107
|
+
* - '0 0 * * *' - Every day at midnight
|
|
108
|
+
*/
|
|
109
|
+
// schedule: '0 0 * * *',
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Prevent overlapping job executions
|
|
113
|
+
*/
|
|
114
|
+
withoutOverlapping: false,
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Timeout in seconds
|
|
118
|
+
*/
|
|
119
|
+
timeout: 60,
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Number of retry attempts
|
|
123
|
+
*/
|
|
124
|
+
retries: ${tries},
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Delay between retries in seconds
|
|
128
|
+
*/
|
|
129
|
+
retryAfter: [60, 120, 300],
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Execute the job
|
|
134
|
+
* @param payload - The job payload data
|
|
135
|
+
*/
|
|
136
|
+
public static async handle(payload?: Record<string, unknown>): Promise<{ success: boolean }> {
|
|
137
|
+
try {
|
|
138
|
+
log.info('${name}: Starting job execution')
|
|
139
|
+
|
|
140
|
+
// Add your job logic here.
|
|
141
|
+
console.log('Processing with payload:', payload)
|
|
142
|
+
|
|
143
|
+
log.info('${name}: Job completed successfully')
|
|
144
|
+
|
|
145
|
+
return { success: true }
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
log.error('${name}: Job failed:', error)
|
|
149
|
+
throw error
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a new policy file in app/Policies
|
|
3
|
+
*/
|
|
4
|
+
export declare function makePolicy(options: MakePolicyOptions): Promise<boolean>;
|
|
5
|
+
export declare interface MakePolicyOptions {
|
|
6
|
+
name?: string
|
|
7
|
+
model?: string
|
|
8
|
+
register?: boolean
|
|
9
|
+
[key: string]: any
|
|
10
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { log } from "@stacksjs/logging";
|
|
2
|
+
import * as p from "@stacksjs/path";
|
|
3
|
+
import { doesExist, get, writeFile } from "@stacksjs/storage";
|
|
4
|
+
export async function makePolicy(options) {
|
|
5
|
+
const name = options.name;
|
|
6
|
+
if (!name) {
|
|
7
|
+
log.error("Policy name is required");
|
|
8
|
+
return !1;
|
|
9
|
+
}
|
|
10
|
+
const policyName = name.endsWith("Policy") ? name : `${name}Policy`, modelName = options.model || policyName.replace("Policy", ""), content = generatePolicyContent(policyName, modelName), filePath = p.appPath(`Policies/${policyName}.ts`);
|
|
11
|
+
try {
|
|
12
|
+
const policiesDir = p.appPath("Policies");
|
|
13
|
+
if (!doesExist(policiesDir)) {
|
|
14
|
+
const { mkdirSync } = await import("@stacksjs/storage");
|
|
15
|
+
mkdirSync(policiesDir, { recursive: !0 });
|
|
16
|
+
}
|
|
17
|
+
await writeFile(filePath, content);
|
|
18
|
+
log.success(`Created policy: ${filePath}`);
|
|
19
|
+
if (options.register !== !1)
|
|
20
|
+
await registerPolicy(modelName, policyName);
|
|
21
|
+
return !0;
|
|
22
|
+
} catch (error) {
|
|
23
|
+
log.error(`Failed to create policy: ${error.message}`);
|
|
24
|
+
return !1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function generatePolicyContent(policyName, modelName) {
|
|
28
|
+
return `import type _User from '../models/User'
|
|
29
|
+
import { BasePolicy } from '@stacksjs/auth'
|
|
30
|
+
|
|
31
|
+
type UserModel = _User
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* ${policyName}
|
|
35
|
+
*
|
|
36
|
+
* This policy controls authorization for ${modelName} model actions.
|
|
37
|
+
*
|
|
38
|
+
* Usage:
|
|
39
|
+
* 1. Register in app/Gates.ts:
|
|
40
|
+
* policies: { '${modelName}': '${policyName}' }
|
|
41
|
+
*
|
|
42
|
+
* 2. Use in your code:
|
|
43
|
+
* import { Gate } from '@stacksjs/auth'
|
|
44
|
+
* await Gate.authorize('view', user, ${modelName.toLowerCase()})
|
|
45
|
+
*
|
|
46
|
+
* 3. Or use the middleware:
|
|
47
|
+
* route.put('/${modelName.toLowerCase()}s/:${modelName.toLowerCase()}', 'Update${modelName}')
|
|
48
|
+
* .middleware('can:update,${modelName.toLowerCase()}')
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
// TODO: Import or define your ${modelName} type
|
|
52
|
+
interface ${modelName} {
|
|
53
|
+
id: number
|
|
54
|
+
user_id: number
|
|
55
|
+
// Add your model properties here
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export default class ${policyName} extends BasePolicy<${modelName}> {
|
|
59
|
+
/**
|
|
60
|
+
* Run before any other checks.
|
|
61
|
+
* Return true to allow, false to deny, null to continue.
|
|
62
|
+
*/
|
|
63
|
+
before(user: UserModel | null, ability: string): boolean | null {
|
|
64
|
+
// Example: Admins can do anything
|
|
65
|
+
// if (user?.role === 'admin') return true
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Determine if the user can view any ${modelName.toLowerCase()}s.
|
|
71
|
+
*/
|
|
72
|
+
viewAny(user: UserModel | null): boolean {
|
|
73
|
+
return true
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Determine if the user can view the ${modelName.toLowerCase()}.
|
|
78
|
+
*/
|
|
79
|
+
view(user: UserModel | null, model: ${modelName}): boolean {
|
|
80
|
+
return true
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Determine if the user can create ${modelName.toLowerCase()}s.
|
|
85
|
+
*/
|
|
86
|
+
create(user: UserModel | null): boolean {
|
|
87
|
+
return user !== null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Determine if the user can update the ${modelName.toLowerCase()}.
|
|
92
|
+
*/
|
|
93
|
+
update(user: UserModel | null, model: ${modelName}): boolean {
|
|
94
|
+
return user?.id === model.user_id
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Determine if the user can delete the ${modelName.toLowerCase()}.
|
|
99
|
+
*/
|
|
100
|
+
delete(user: UserModel | null, model: ${modelName}): boolean {
|
|
101
|
+
return user?.id === model.user_id
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Determine if the user can restore the ${modelName.toLowerCase()}.
|
|
106
|
+
*/
|
|
107
|
+
restore(user: UserModel | null, model: ${modelName}): boolean {
|
|
108
|
+
return user?.id === model.user_id
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Determine if the user can permanently delete the ${modelName.toLowerCase()}.
|
|
113
|
+
*/
|
|
114
|
+
forceDelete(user: UserModel | null, model: ${modelName}): boolean {
|
|
115
|
+
return user?.id === model.user_id
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
async function registerPolicy(modelName, policyName) {
|
|
121
|
+
const gatesPath = p.appPath("Gates.ts");
|
|
122
|
+
try {
|
|
123
|
+
let content = await get(gatesPath);
|
|
124
|
+
const policiesMatch = content.match(/export const policies[^{]*\{([^}]*)\}/);
|
|
125
|
+
if (policiesMatch) {
|
|
126
|
+
const existingPolicies = policiesMatch[1] ?? "";
|
|
127
|
+
if (existingPolicies.includes(`'${modelName}'`)) {
|
|
128
|
+
log.info(`Policy for '${modelName}' already registered in Gates.ts`);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const newPolicy = ` '${modelName}': '${policyName}',
|
|
132
|
+
`, updatedPolicies = `${existingPolicies.trimEnd()}
|
|
133
|
+
${newPolicy}`;
|
|
134
|
+
content = content.replace(/export const policies[^{]*\{([^}]*)\}/, `export const policies: Record<string, string | { policy: string, model?: string }> = {${updatedPolicies}}`);
|
|
135
|
+
await writeFile(gatesPath, content);
|
|
136
|
+
log.success(`Registered policy '${policyName}' for '${modelName}' in Gates.ts`);
|
|
137
|
+
}
|
|
138
|
+
} catch (error) {
|
|
139
|
+
log.warn(`Could not register policy in Gates.ts: ${error.message}`);
|
|
140
|
+
log.info("You may need to manually add it to app/Gates.ts");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a new API resource file in app/Resources
|
|
3
|
+
*/
|
|
4
|
+
export declare function makeResource(options: MakeResourceOptions): Promise<boolean>;
|
|
5
|
+
export declare interface MakeResourceOptions {
|
|
6
|
+
name?: string
|
|
7
|
+
model?: string
|
|
8
|
+
collection?: boolean
|
|
9
|
+
[key: string]: any
|
|
10
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { log } from "@stacksjs/logging";
|
|
2
|
+
import * as p from "@stacksjs/path";
|
|
3
|
+
import { doesExist, writeFile } from "@stacksjs/storage";
|
|
4
|
+
export async function makeResource(options) {
|
|
5
|
+
const name = options.name;
|
|
6
|
+
if (!name) {
|
|
7
|
+
log.error("Resource name is required");
|
|
8
|
+
return !1;
|
|
9
|
+
}
|
|
10
|
+
const resourceName = name.endsWith("Resource") ? name : `${name}Resource`, modelName = options.model || resourceName.replace("Resource", ""), content = options.collection ? generateCollectionResourceContent(resourceName, modelName) : generateResourceContent(resourceName, modelName), resourcesDir = p.appPath("Resources");
|
|
11
|
+
if (!doesExist(resourcesDir)) {
|
|
12
|
+
const { mkdirSync } = await import("@stacksjs/storage");
|
|
13
|
+
mkdirSync(resourcesDir, { recursive: !0 });
|
|
14
|
+
}
|
|
15
|
+
const filePath = p.appPath(`Resources/${resourceName}.ts`);
|
|
16
|
+
try {
|
|
17
|
+
await writeFile(filePath, content);
|
|
18
|
+
log.success(`Created resource: ${filePath}`);
|
|
19
|
+
return !0;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
log.error(`Failed to create resource: ${error.message}`);
|
|
22
|
+
return !1;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function generateResourceContent(resourceName, modelName) {
|
|
26
|
+
return `import type { Request } from '@stacksjs/router'
|
|
27
|
+
import { JsonResource } from '@stacksjs/api'
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ${resourceName}
|
|
31
|
+
*
|
|
32
|
+
* Transforms ${modelName} model data for API responses.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* // Single resource
|
|
36
|
+
* return new ${resourceName}(${modelName.toLowerCase()}).toResponse()
|
|
37
|
+
*
|
|
38
|
+
* // Collection
|
|
39
|
+
* return ${resourceName}.collection(${modelName.toLowerCase()}s).toResponse()
|
|
40
|
+
*
|
|
41
|
+
* // With additional data
|
|
42
|
+
* return new ${resourceName}(${modelName.toLowerCase()})
|
|
43
|
+
* .withAdditional({ message: 'Success' })
|
|
44
|
+
* .toResponse()
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
// TODO: Import or define your ${modelName} type
|
|
48
|
+
interface ${modelName} {
|
|
49
|
+
id: number
|
|
50
|
+
name: string
|
|
51
|
+
created_at: Date
|
|
52
|
+
updated_at: Date
|
|
53
|
+
// Add your model properties here
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default class ${resourceName} extends JsonResource<${modelName}> {
|
|
57
|
+
/**
|
|
58
|
+
* Transform the resource into an array.
|
|
59
|
+
*/
|
|
60
|
+
toArray(request?: Request): Record<string, any> {
|
|
61
|
+
return {
|
|
62
|
+
id: this.resource.id,
|
|
63
|
+
name: this.resource.name,
|
|
64
|
+
|
|
65
|
+
// Conditional fields
|
|
66
|
+
// secret: this.when(request?.user?.isAdmin, this.resource.secret),
|
|
67
|
+
|
|
68
|
+
// Loaded relationships
|
|
69
|
+
// posts: this.whenLoaded('posts', () =>
|
|
70
|
+
// PostResource.collection(this.resource.posts)
|
|
71
|
+
// ),
|
|
72
|
+
|
|
73
|
+
// Relationship counts
|
|
74
|
+
// posts_count: this.whenCounted('posts'),
|
|
75
|
+
|
|
76
|
+
// Timestamps
|
|
77
|
+
created_at: this.resource.created_at,
|
|
78
|
+
updated_at: this.resource.updated_at,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
function generateCollectionResourceContent(resourceName, modelName) {
|
|
85
|
+
const baseResourceName = resourceName.replace("Collection", "");
|
|
86
|
+
return `import type { Request } from '@stacksjs/router'
|
|
87
|
+
import { JsonResource, ResourceCollection } from '@stacksjs/api'
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* ${resourceName}
|
|
91
|
+
*
|
|
92
|
+
* Collection resource for ${modelName} with custom collection behavior.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* return new ${resourceName}(${modelName.toLowerCase()}s).toResponse()
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
// TODO: Import or define your ${modelName} type
|
|
99
|
+
interface ${modelName} {
|
|
100
|
+
id: number
|
|
101
|
+
name: string
|
|
102
|
+
created_at: Date
|
|
103
|
+
updated_at: Date
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Individual resource for the collection
|
|
108
|
+
*/
|
|
109
|
+
class ${baseResourceName} extends JsonResource<${modelName}> {
|
|
110
|
+
toArray(request?: Request): Record<string, any> {
|
|
111
|
+
return {
|
|
112
|
+
id: this.resource.id,
|
|
113
|
+
name: this.resource.name,
|
|
114
|
+
created_at: this.resource.created_at,
|
|
115
|
+
updated_at: this.resource.updated_at,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Collection resource with custom behavior
|
|
122
|
+
*/
|
|
123
|
+
export default class ${resourceName} extends ResourceCollection<${modelName}, ${baseResourceName}> {
|
|
124
|
+
constructor(resources: ${modelName}[]) {
|
|
125
|
+
super(resources, ${baseResourceName})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Add collection-level data to the response
|
|
130
|
+
*/
|
|
131
|
+
toResponse(request?: Request): Record<string, any> {
|
|
132
|
+
return {
|
|
133
|
+
...super.toResponse(request),
|
|
134
|
+
meta: {
|
|
135
|
+
total: this.count(),
|
|
136
|
+
// Add any collection-level metadata here
|
|
137
|
+
},
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
`;
|
|
142
|
+
}
|
package/dist/make.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { MakeOptions } from '@stacksjs/types';
|
|
2
|
+
/**
|
|
3
|
+
* Toggle dry-run mode. The buddy CLI flips this on before invoking a
|
|
4
|
+
* scaffolder when the user passed `--dry-run`. Stays a module-level
|
|
5
|
+
* flag (rather than threading through every signature) so existing
|
|
6
|
+
* scaffolders can opt in just by switching their write call.
|
|
7
|
+
*/
|
|
8
|
+
export declare function setDryRun(enabled: boolean): void;
|
|
9
|
+
export declare function isDryRunActive(): boolean;
|
|
10
|
+
export declare function invoke(options: MakeOptions): Promise<void>;
|
|
11
|
+
export declare function make(options: MakeOptions): Promise<void>;
|
|
12
|
+
export declare function makeAction(options: MakeOptions): Promise<void>;
|
|
13
|
+
export declare function makeComponent(options: MakeOptions): Promise<void>;
|
|
14
|
+
export declare function createAction(options: MakeOptions): Promise<void>;
|
|
15
|
+
export declare function createComponent(options: MakeOptions): Promise<void>;
|
|
16
|
+
export declare function makeDatabase(options: MakeOptions): void;
|
|
17
|
+
export declare function createDatabase(options: MakeOptions): void;
|
|
18
|
+
export declare function factory(options: MakeOptions): void;
|
|
19
|
+
export declare function createFactory(options: MakeOptions): Promise<void>;
|
|
20
|
+
export declare function makeNotification(options: MakeOptions): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Scaffold a Mailable + companion stx template
|
|
23
|
+
* (stacksjs/stacks#1899, A2 from #1904). Pairs:
|
|
24
|
+
*
|
|
25
|
+
* app/Mail/<PascalName>.ts ← Mailable subclass
|
|
26
|
+
* resources/emails/<kebab-name>.stx ← stx template the Mailable resolves
|
|
27
|
+
*
|
|
28
|
+
* The name flows through both files: PascalCase for the class, kebab-case
|
|
29
|
+
* for the template (matching the convention the framework's bundled
|
|
30
|
+
* emails use — `welcome.stx`, `password-reset.stx`, etc.).
|
|
31
|
+
*
|
|
32
|
+
* Idempotent — refuses to overwrite either file when it already exists
|
|
33
|
+
* unless `options.force` is true. The reason: an accidental
|
|
34
|
+
* `buddy make:mail Welcome` against a project that already has a
|
|
35
|
+
* customized `Welcome` mailable would silently nuke the customization
|
|
36
|
+
* otherwise.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createMail(options: MakeOptions & { force?: boolean }): Promise<boolean>;
|
|
39
|
+
export declare function makeMail(options: MakeOptions & { force?: boolean }): Promise<void>;
|
|
40
|
+
export declare function makePage(options: MakeOptions): Promise<void>;
|
|
41
|
+
export declare function createPage(options: MakeOptions): Promise<void>;
|
|
42
|
+
export declare function makeFunction(options: MakeOptions): Promise<void>;
|
|
43
|
+
export declare function createFunction(options: MakeOptions): Promise<void>;
|
|
44
|
+
export declare function makeLanguage(options: MakeOptions): Promise<void>;
|
|
45
|
+
export declare function createLanguage(options: MakeOptions): Promise<void>;
|
|
46
|
+
export declare function makeStack(options: MakeOptions): Promise<void>;
|
|
47
|
+
export declare function createNotification(options: MakeOptions): Promise<boolean>;
|
|
48
|
+
export declare function createMigration(options: MakeOptions): Promise<void>;
|
|
49
|
+
export declare function makeQueueTable(): Promise<void>;
|
|
50
|
+
export declare function makeCertificate(): Promise<void>;
|
|
51
|
+
export declare function createModel(options: MakeOptions): Promise<void>;
|
|
52
|
+
export declare function createMiddleware(options: MakeOptions): Promise<void>;
|