@stacksjs/actions 0.70.88 → 0.70.91

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.
Files changed (261) hide show
  1. package/dist/action.d.ts +149 -0
  2. package/dist/action.js +78 -0
  3. package/dist/actions.d.ts +2 -0
  4. package/dist/actions.js +2 -0
  5. package/dist/add.d.ts +6 -0
  6. package/dist/add.js +20 -0
  7. package/dist/ai/request-model-access.d.ts +1 -0
  8. package/dist/ai/request-model-access.js +10 -0
  9. package/dist/auth/client.d.ts +1 -0
  10. package/dist/auth/client.js +44 -0
  11. package/dist/auth/prune.d.ts +1 -0
  12. package/dist/auth/prune.js +35 -0
  13. package/dist/auth/setup.d.ts +1 -0
  14. package/dist/auth/setup.js +322 -0
  15. package/dist/auth/token.d.ts +1 -0
  16. package/dist/auth/token.js +10 -0
  17. package/dist/blog-admin.d.ts +55 -0
  18. package/dist/blog-admin.js +156 -0
  19. package/dist/blog.d.ts +30 -0
  20. package/dist/blog.js +398 -0
  21. package/dist/build/cli.d.ts +1 -0
  22. package/dist/build/cli.js +6 -0
  23. package/dist/build/component-libs.d.ts +1 -0
  24. package/dist/build/component-libs.js +7 -0
  25. package/dist/build/core.d.ts +1 -0
  26. package/dist/build/core.js +55 -0
  27. package/dist/build/desktop.d.ts +1 -0
  28. package/dist/build/desktop.js +5 -0
  29. package/dist/build/docs.d.ts +1 -0
  30. package/dist/build/docs.js +5 -0
  31. package/dist/build/frontend-static.d.ts +16 -0
  32. package/dist/build/frontend-static.js +124 -0
  33. package/dist/build/server.d.ts +1 -0
  34. package/dist/build/server.js +6 -0
  35. package/dist/build/stacks.d.ts +1 -0
  36. package/dist/build/stacks.js +8 -0
  37. package/dist/build/views.d.ts +1 -0
  38. package/dist/build/views.js +11 -0
  39. package/dist/build.d.ts +9 -0
  40. package/dist/build.js +64 -0
  41. package/dist/bump.d.ts +1 -0
  42. package/dist/bump.js +163 -0
  43. package/dist/cdn/invalidate-cache.d.ts +1 -0
  44. package/dist/cdn/invalidate-cache.js +0 -0
  45. package/dist/changelog.d.ts +9 -0
  46. package/dist/changelog.js +27 -0
  47. package/dist/check/ports.d.ts +1 -0
  48. package/dist/check/ports.js +16 -0
  49. package/dist/clean.d.ts +1 -0
  50. package/dist/clean.js +4 -0
  51. package/dist/commit.d.ts +3 -0
  52. package/dist/commit.js +12 -0
  53. package/dist/copy-types.d.ts +1 -0
  54. package/dist/copy-types.js +10 -0
  55. package/dist/database/seed.d.ts +1 -0
  56. package/dist/database/seed.js +26 -0
  57. package/dist/deploy/create-receipt-rule.d.ts +1 -0
  58. package/dist/deploy/create-receipt-rule.js +36 -0
  59. package/dist/deploy/index.d.ts +1 -0
  60. package/dist/deploy/index.js +1574 -0
  61. package/dist/dev/api.d.ts +1 -0
  62. package/dist/dev/api.js +94 -0
  63. package/dist/dev/components.d.ts +1 -0
  64. package/dist/dev/components.js +7 -0
  65. package/dist/dev/dashboard-globals.d.ts +4 -0
  66. package/dist/dev/dashboard-globals.js +89 -0
  67. package/dist/dev/dashboard-utils.d.ts +150 -0
  68. package/dist/dev/dashboard-utils.js +380 -0
  69. package/dist/dev/dashboard.d.ts +22 -0
  70. package/dist/dev/dashboard.js +435 -0
  71. package/dist/dev/desktop.d.ts +1 -0
  72. package/dist/dev/desktop.js +5 -0
  73. package/dist/dev/docs.d.ts +1 -0
  74. package/dist/dev/docs.js +24 -0
  75. package/dist/dev/index.d.ts +10 -0
  76. package/dist/dev/index.js +29 -0
  77. package/dist/dev/migrate-watcher.d.ts +1 -0
  78. package/dist/dev/migrate-watcher.js +74 -0
  79. package/dist/dev/system-tray.d.ts +1 -0
  80. package/dist/dev/system-tray.js +5 -0
  81. package/dist/dev/views.d.ts +1 -0
  82. package/dist/dev/views.js +147 -0
  83. package/dist/discover-packages.d.ts +18 -0
  84. package/dist/discover-packages.js +32 -0
  85. package/dist/domains/add.d.ts +1 -0
  86. package/dist/domains/add.js +61 -0
  87. package/dist/domains/purchase.d.ts +1 -0
  88. package/dist/domains/purchase.js +66 -0
  89. package/dist/domains/remove.d.ts +1 -0
  90. package/dist/domains/remove.js +24 -0
  91. package/dist/examples.d.ts +5 -0
  92. package/dist/examples.js +34 -0
  93. package/dist/find-projects.d.ts +1 -0
  94. package/dist/find-projects.js +16 -0
  95. package/dist/fresh.d.ts +1 -0
  96. package/dist/fresh.js +17 -0
  97. package/dist/generate/action-types.d.ts +1 -0
  98. package/dist/generate/action-types.js +13 -0
  99. package/dist/generate/component-meta.d.ts +1 -0
  100. package/dist/generate/component-meta.js +9 -0
  101. package/dist/generate/custom-cli-file.d.ts +1 -0
  102. package/dist/generate/custom-cli-file.js +21 -0
  103. package/dist/generate/env-files.d.ts +1 -0
  104. package/dist/generate/env-files.js +66 -0
  105. package/dist/generate/ide-helpers.d.ts +1 -0
  106. package/dist/generate/ide-helpers.js +8 -0
  107. package/dist/generate/index.d.ts +36 -0
  108. package/dist/generate/index.js +158 -0
  109. package/dist/generate/lib-entries.d.ts +1 -0
  110. package/dist/generate/lib-entries.js +16 -0
  111. package/dist/generate/pantry-file.d.ts +1 -0
  112. package/dist/generate/pantry-file.js +46 -0
  113. package/dist/generate/symlink-core.d.ts +1 -0
  114. package/dist/generate/symlink-core.js +2 -0
  115. package/dist/generate/types.d.ts +1 -0
  116. package/dist/generate/types.js +3 -0
  117. package/dist/generate/vscode-custom-data.d.ts +1 -0
  118. package/dist/generate/vscode-custom-data.js +9 -0
  119. package/dist/generate/web-types.d.ts +1 -0
  120. package/dist/generate/web-types.js +0 -0
  121. package/dist/helpers/component-meta.d.ts +26 -0
  122. package/dist/helpers/component-meta.js +295 -0
  123. package/dist/helpers/index.d.ts +4 -0
  124. package/dist/helpers/index.js +1 -0
  125. package/dist/helpers/lib-entries.d.ts +12 -0
  126. package/dist/helpers/lib-entries.js +73 -0
  127. package/dist/helpers/package-json.d.ts +2 -0
  128. package/dist/helpers/package-json.js +74 -0
  129. package/dist/helpers/utils.d.ts +23 -0
  130. package/dist/helpers/utils.js +105 -0
  131. package/dist/helpers/vscode-custom-data.d.ts +3 -0
  132. package/dist/helpers/vscode-custom-data.js +30 -0
  133. package/dist/index.d.ts +62 -0
  134. package/dist/index.js +50 -0
  135. package/dist/key-generate.d.ts +1 -0
  136. package/dist/key-generate.js +24 -0
  137. package/dist/lint/fix.d.ts +1 -0
  138. package/dist/lint/fix.js +4 -0
  139. package/dist/lint/index.d.ts +1 -0
  140. package/dist/lint/index.js +4 -0
  141. package/dist/lint/lint.d.ts +14 -0
  142. package/dist/lint/lint.js +34 -0
  143. package/dist/make-command.d.ts +10 -0
  144. package/dist/make-command.js +95 -0
  145. package/dist/make-job.d.ts +5 -0
  146. package/dist/make-job.js +154 -0
  147. package/dist/make-policy.d.ts +10 -0
  148. package/dist/make-policy.js +142 -0
  149. package/dist/make-resource.d.ts +10 -0
  150. package/dist/make-resource.js +142 -0
  151. package/dist/make.d.ts +52 -0
  152. package/dist/make.js +328 -0
  153. package/dist/migrate/database.d.ts +1 -0
  154. package/dist/migrate/database.js +16 -0
  155. package/dist/migrate/fresh.d.ts +1 -0
  156. package/dist/migrate/fresh.js +31 -0
  157. package/dist/orm/base.d.ts +1 -0
  158. package/dist/orm/base.js +0 -0
  159. package/dist/orm/test.d.ts +1 -0
  160. package/dist/orm/test.js +0 -0
  161. package/dist/prepublish.d.ts +1 -0
  162. package/dist/prepublish.js +16 -0
  163. package/dist/queue/clear.d.ts +1 -0
  164. package/dist/queue/clear.js +42 -0
  165. package/dist/queue/dlq-purge.d.ts +1 -0
  166. package/dist/queue/dlq-purge.js +28 -0
  167. package/dist/queue/dlq-retry.d.ts +1 -0
  168. package/dist/queue/dlq-retry.js +35 -0
  169. package/dist/queue/dlq.d.ts +1 -0
  170. package/dist/queue/dlq.js +55 -0
  171. package/dist/queue/failed.d.ts +1 -0
  172. package/dist/queue/failed.js +69 -0
  173. package/dist/queue/flush.d.ts +1 -0
  174. package/dist/queue/flush.js +49 -0
  175. package/dist/queue/inspect.d.ts +1 -0
  176. package/dist/queue/inspect.js +154 -0
  177. package/dist/queue/list.d.ts +1 -0
  178. package/dist/queue/list.js +69 -0
  179. package/dist/queue/monitor.d.ts +1 -0
  180. package/dist/queue/monitor.js +95 -0
  181. package/dist/queue/pause.d.ts +1 -0
  182. package/dist/queue/pause.js +28 -0
  183. package/dist/queue/quarantine.d.ts +1 -0
  184. package/dist/queue/quarantine.js +42 -0
  185. package/dist/queue/resume.d.ts +1 -0
  186. package/dist/queue/resume.js +27 -0
  187. package/dist/queue/retry.d.ts +1 -0
  188. package/dist/queue/retry.js +41 -0
  189. package/dist/queue/schedule-list.d.ts +1 -0
  190. package/dist/queue/schedule-list.js +33 -0
  191. package/dist/queue/schedule.d.ts +1 -0
  192. package/dist/queue/schedule.js +12 -0
  193. package/dist/queue/status.d.ts +1 -0
  194. package/dist/queue/status.js +68 -0
  195. package/dist/queue/table.d.ts +1 -0
  196. package/dist/queue/table.js +10 -0
  197. package/dist/queue/unquarantine.d.ts +1 -0
  198. package/dist/queue/unquarantine.js +27 -0
  199. package/dist/queue/work.d.ts +1 -0
  200. package/dist/queue/work.js +57 -0
  201. package/dist/release.d.ts +1 -0
  202. package/dist/release.js +21 -0
  203. package/dist/route/list.d.ts +1 -0
  204. package/dist/route/list.js +78 -0
  205. package/dist/run-action.d.ts +2 -0
  206. package/dist/run-action.js +1 -0
  207. package/dist/saas/setup.d.ts +1 -0
  208. package/dist/saas/setup.js +9 -0
  209. package/dist/scaffold-crud.d.ts +25 -0
  210. package/dist/scaffold-crud.js +211 -0
  211. package/dist/schedule/run.d.ts +1 -0
  212. package/dist/schedule/run.js +7 -0
  213. package/dist/search/flush.d.ts +1 -0
  214. package/dist/search/flush.js +10 -0
  215. package/dist/search/import.d.ts +1 -0
  216. package/dist/search/import.js +10 -0
  217. package/dist/search/settings-list.d.ts +1 -0
  218. package/dist/search/settings-list.js +10 -0
  219. package/dist/search/settings.d.ts +1 -0
  220. package/dist/search/settings.js +9 -0
  221. package/dist/serve/api.d.ts +1 -0
  222. package/dist/serve/api.js +35 -0
  223. package/dist/setup/index.d.ts +1 -0
  224. package/dist/setup/index.js +1 -0
  225. package/dist/setup/ssl.d.ts +38 -0
  226. package/dist/setup/ssl.js +271 -0
  227. package/dist/stacks.d.ts +4 -0
  228. package/dist/stacks.js +265 -0
  229. package/dist/templates.d.ts +28 -0
  230. package/dist/templates.js +301 -0
  231. package/dist/test/feature.d.ts +1 -0
  232. package/dist/test/feature.js +11 -0
  233. package/dist/test/index.d.ts +1 -0
  234. package/dist/test/index.js +11 -0
  235. package/dist/test/ui.d.ts +1 -0
  236. package/dist/test/ui.js +4 -0
  237. package/dist/test/unit.d.ts +1 -0
  238. package/dist/test/unit.js +11 -0
  239. package/dist/typecheck.d.ts +1 -0
  240. package/dist/typecheck.js +4 -0
  241. package/dist/types.d.ts +3 -0
  242. package/dist/types.js +16 -0
  243. package/dist/upgrade/binary.d.ts +1 -0
  244. package/dist/upgrade/binary.js +29 -0
  245. package/dist/upgrade/bun.d.ts +1 -0
  246. package/dist/upgrade/bun.js +0 -0
  247. package/dist/upgrade/dependencies.d.ts +1 -0
  248. package/dist/upgrade/dependencies.js +0 -0
  249. package/dist/upgrade/framework-utils.d.ts +150 -0
  250. package/dist/upgrade/framework-utils.js +193 -0
  251. package/dist/upgrade/framework.d.ts +1 -0
  252. package/dist/upgrade/framework.js +310 -0
  253. package/dist/upgrade/index.d.ts +1 -0
  254. package/dist/upgrade/index.js +17 -0
  255. package/dist/upgrade/packages.d.ts +14 -0
  256. package/dist/upgrade/packages.js +99 -0
  257. package/dist/upgrade/shell.d.ts +1 -0
  258. package/dist/upgrade/shell.js +41 -0
  259. package/dist/upgrade.d.ts +7 -0
  260. package/dist/upgrade.js +38 -0
  261. package/package.json +16 -16
@@ -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>;