@stacksjs/actions 0.70.87 → 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.
Files changed (159) hide show
  1. package/dist/action.js +78 -2
  2. package/dist/actions.js +2 -2
  3. package/dist/add.js +20 -2
  4. package/dist/ai/request-model-access.js +10 -2
  5. package/dist/auth/client.js +44 -3
  6. package/dist/auth/prune.js +35 -2
  7. package/dist/auth/setup.js +152 -36
  8. package/dist/auth/token.js +10 -2
  9. package/dist/blog-admin.d.ts +55 -0
  10. package/dist/blog-admin.js +156 -0
  11. package/dist/blog.d.ts +11 -0
  12. package/dist/blog.js +306 -56
  13. package/dist/build/cli.js +6 -2
  14. package/dist/build/component-libs.js +7 -2
  15. package/dist/build/core.js +55 -2
  16. package/dist/build/desktop.js +5 -2
  17. package/dist/build/docs.js +5 -2
  18. package/dist/build/frontend-static.js +123 -8
  19. package/dist/build/server.js +6 -2
  20. package/dist/build/stacks.js +8 -2
  21. package/dist/build/views.js +11 -2
  22. package/dist/build.js +64 -2
  23. package/dist/bump.js +162 -7
  24. package/dist/cdn/invalidate-cache.js +0 -1
  25. package/dist/changelog.js +27 -3
  26. package/dist/check/ports.js +16 -2
  27. package/dist/clean.js +4 -2
  28. package/dist/commit.js +12 -2
  29. package/dist/copy-types.js +10 -3
  30. package/dist/database/seed.js +26 -2
  31. package/dist/deploy/create-receipt-rule.js +36 -2
  32. package/dist/deploy/index.js +1318 -44
  33. package/dist/dev/api.js +94 -6
  34. package/dist/dev/components.js +7 -2
  35. package/dist/dev/dashboard-globals.js +89 -3
  36. package/dist/dev/dashboard-utils.js +380 -2
  37. package/dist/dev/dashboard.js +435 -8
  38. package/dist/dev/desktop.js +5 -2
  39. package/dist/dev/docs.js +24 -2
  40. package/dist/dev/index.js +29 -2
  41. package/dist/dev/migrate-watcher.js +74 -2
  42. package/dist/dev/system-tray.js +5 -2
  43. package/dist/dev/views.js +147 -2
  44. package/dist/discover-packages.js +32 -2
  45. package/dist/domains/add.js +61 -2
  46. package/dist/domains/purchase.js +66 -2
  47. package/dist/domains/remove.js +24 -2
  48. package/dist/examples.js +34 -2
  49. package/dist/find-projects.js +16 -2
  50. package/dist/fresh.js +17 -2
  51. package/dist/generate/action-types.js +9 -4
  52. package/dist/generate/component-meta.js +9 -3
  53. package/dist/generate/custom-cli-file.js +20 -3
  54. package/dist/generate/env-files.js +46 -6
  55. package/dist/generate/ide-helpers.js +8 -3
  56. package/dist/generate/index.js +158 -2
  57. package/dist/generate/lib-entries.js +16 -3
  58. package/dist/generate/pantry-file.js +46 -2
  59. package/dist/generate/symlink-core.js +2 -2
  60. package/dist/generate/types.js +3 -2
  61. package/dist/generate/vscode-custom-data.js +9 -3
  62. package/dist/generate/web-types.js +0 -1
  63. package/dist/helpers/component-meta.js +295 -2
  64. package/dist/helpers/index.js +1 -2
  65. package/dist/helpers/lib-entries.js +73 -2
  66. package/dist/helpers/package-json.js +45 -14
  67. package/dist/helpers/utils.js +105 -2
  68. package/dist/helpers/vscode-custom-data.js +30 -2
  69. package/dist/index.d.ts +13 -0
  70. package/dist/index.js +50 -2
  71. package/dist/key-generate.js +24 -2
  72. package/dist/lint/fix.js +4 -3
  73. package/dist/lint/index.js +4 -3
  74. package/dist/lint/lint.js +34 -2
  75. package/dist/make-command.js +64 -14
  76. package/dist/make-job.js +41 -16
  77. package/dist/make-policy.js +74 -26
  78. package/dist/make-resource.js +50 -21
  79. package/dist/make.js +328 -2
  80. package/dist/migrate/database.js +16 -2
  81. package/dist/migrate/fresh.js +31 -2
  82. package/dist/orm/base.js +0 -2
  83. package/dist/orm/test.js +0 -1
  84. package/dist/prepublish.js +16 -2
  85. package/dist/queue/clear.js +42 -2
  86. package/dist/queue/dlq-purge.js +28 -2
  87. package/dist/queue/dlq-retry.js +35 -2
  88. package/dist/queue/dlq.js +55 -5
  89. package/dist/queue/failed.js +69 -5
  90. package/dist/queue/flush.js +49 -3
  91. package/dist/queue/inspect.js +154 -8
  92. package/dist/queue/list.js +69 -5
  93. package/dist/queue/monitor.js +94 -6
  94. package/dist/queue/pause.js +28 -2
  95. package/dist/queue/quarantine.js +42 -3
  96. package/dist/queue/resume.js +27 -2
  97. package/dist/queue/retry.js +41 -2
  98. package/dist/queue/schedule-list.js +33 -5
  99. package/dist/queue/schedule.js +12 -2
  100. package/dist/queue/status.js +68 -5
  101. package/dist/queue/table.js +10 -2
  102. package/dist/queue/unquarantine.js +27 -2
  103. package/dist/queue/work.js +57 -2
  104. package/dist/release.js +21 -3
  105. package/dist/route/list.js +78 -3
  106. package/dist/run-action.js +1 -2
  107. package/dist/saas/setup.js +9 -2
  108. package/dist/scaffold-crud.js +164 -40
  109. package/dist/schedule/run.js +7 -2
  110. package/dist/search/flush.js +10 -2
  111. package/dist/search/import.js +10 -2
  112. package/dist/search/settings-list.js +10 -2
  113. package/dist/search/settings.js +9 -2
  114. package/dist/serve/api.js +35 -2
  115. package/dist/setup/index.js +1 -2
  116. package/dist/setup/ssl.js +271 -2
  117. package/dist/stacks.js +265 -2
  118. package/dist/templates.js +301 -2
  119. package/dist/test/feature.js +11 -2
  120. package/dist/test/index.js +11 -2
  121. package/dist/test/ui.js +4 -2
  122. package/dist/test/unit.js +11 -2
  123. package/dist/typecheck.js +4 -2
  124. package/dist/types.js +16 -2
  125. package/dist/upgrade/binary.js +29 -2
  126. package/dist/upgrade/bun.js +0 -1
  127. package/dist/upgrade/dependencies.js +0 -2
  128. package/dist/upgrade/framework-utils.js +193 -2
  129. package/dist/upgrade/framework.js +310 -7
  130. package/dist/upgrade/index.js +17 -2
  131. package/dist/upgrade/packages.js +99 -12
  132. package/dist/upgrade/shell.js +40 -4
  133. package/dist/upgrade.js +38 -2
  134. package/package.json +16 -16
  135. package/dist/chunk-0c8sd1t6.js +0 -2
  136. package/dist/chunk-0g2nzhx9.js +0 -240
  137. package/dist/chunk-0gadhvn7.js +0 -3
  138. package/dist/chunk-0h27aa4r.js +0 -93
  139. package/dist/chunk-3peh8kqs.js +0 -851
  140. package/dist/chunk-62gdfav8.js +0 -3
  141. package/dist/chunk-6bk53y02.js +0 -3
  142. package/dist/chunk-78c5n3s2.js +0 -3
  143. package/dist/chunk-c74qv38e.js +0 -17
  144. package/dist/chunk-cdk2r2jd.js +0 -1
  145. package/dist/chunk-dbz9dp2h.js +0 -3
  146. package/dist/chunk-e142dheq.js +0 -3
  147. package/dist/chunk-ec4gky40.js +0 -3
  148. package/dist/chunk-h3d81wrg.js +0 -3
  149. package/dist/chunk-m3q0x4h0.js +0 -688
  150. package/dist/chunk-mqgbyhph.js +0 -5
  151. package/dist/chunk-n24m8prb.js +0 -3
  152. package/dist/chunk-n5eqwhck.js +0 -7
  153. package/dist/chunk-nsvnqv8y.js +0 -5
  154. package/dist/chunk-nty6mmx4.js +0 -283
  155. package/dist/chunk-s735m9mg.js +0 -1
  156. package/dist/chunk-tpb8jgsk.js +0 -7
  157. package/dist/chunk-tsbk5vne.js +0 -3
  158. package/dist/chunk-xg9xscqz.js +0 -1
  159. package/dist/chunk-y6e448he.js +0 -7
@@ -1,35 +1,61 @@
1
- // @bun
2
- import{Lb as O}from"./chunk-h3d81wrg.js";import{log as B}from"@stacksjs/logging";import*as J from"@stacksjs/path";import{doesExist as Q,get as R,writeFile as L}from"@stacksjs/storage";async function X(q){let b=q.name;if(!b)return B.error("Policy name is required"),!1;let z=b.endsWith("Policy")?b:`${b}Policy`,v=q.model||z.replace("Policy",""),I=T(z,v),H=J.appPath(`Policies/${z}.ts`);try{let G=J.appPath("Policies");if(!Q(G)){let{mkdirSync:K}=await import("@stacksjs/storage");K(G,{recursive:!0})}if(await L(H,I),B.success(`Created policy: ${H}`),q.register!==!1)await U(v,z);return!0}catch(G){return B.error(`Failed to create policy: ${G.message}`),!1}}function T(q,b){return`import type _User from '../models/User'
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'
3
29
  import { BasePolicy } from '@stacksjs/auth'
4
30
 
5
31
  type UserModel = _User
6
32
 
7
33
  /**
8
- * ${q}
34
+ * ${policyName}
9
35
  *
10
- * This policy controls authorization for ${b} model actions.
36
+ * This policy controls authorization for ${modelName} model actions.
11
37
  *
12
38
  * Usage:
13
39
  * 1. Register in app/Gates.ts:
14
- * policies: { '${b}': '${q}' }
40
+ * policies: { '${modelName}': '${policyName}' }
15
41
  *
16
42
  * 2. Use in your code:
17
43
  * import { Gate } from '@stacksjs/auth'
18
- * await Gate.authorize('view', user, ${b.toLowerCase()})
44
+ * await Gate.authorize('view', user, ${modelName.toLowerCase()})
19
45
  *
20
46
  * 3. Or use the middleware:
21
- * route.put('/${b.toLowerCase()}s/:${b.toLowerCase()}', 'Update${b}')
22
- * .middleware('can:update,${b.toLowerCase()}')
47
+ * route.put('/${modelName.toLowerCase()}s/:${modelName.toLowerCase()}', 'Update${modelName}')
48
+ * .middleware('can:update,${modelName.toLowerCase()}')
23
49
  */
24
50
 
25
- // TODO: Import or define your ${b} type
26
- interface ${b} {
51
+ // TODO: Import or define your ${modelName} type
52
+ interface ${modelName} {
27
53
  id: number
28
54
  user_id: number
29
55
  // Add your model properties here
30
56
  }
31
57
 
32
- export default class ${q} extends BasePolicy<${b}> {
58
+ export default class ${policyName} extends BasePolicy<${modelName}> {
33
59
  /**
34
60
  * Run before any other checks.
35
61
  * Return true to allow, false to deny, null to continue.
@@ -41,54 +67,76 @@ export default class ${q} extends BasePolicy<${b}> {
41
67
  }
42
68
 
43
69
  /**
44
- * Determine if the user can view any ${b.toLowerCase()}s.
70
+ * Determine if the user can view any ${modelName.toLowerCase()}s.
45
71
  */
46
72
  viewAny(user: UserModel | null): boolean {
47
73
  return true
48
74
  }
49
75
 
50
76
  /**
51
- * Determine if the user can view the ${b.toLowerCase()}.
77
+ * Determine if the user can view the ${modelName.toLowerCase()}.
52
78
  */
53
- view(user: UserModel | null, model: ${b}): boolean {
79
+ view(user: UserModel | null, model: ${modelName}): boolean {
54
80
  return true
55
81
  }
56
82
 
57
83
  /**
58
- * Determine if the user can create ${b.toLowerCase()}s.
84
+ * Determine if the user can create ${modelName.toLowerCase()}s.
59
85
  */
60
86
  create(user: UserModel | null): boolean {
61
87
  return user !== null
62
88
  }
63
89
 
64
90
  /**
65
- * Determine if the user can update the ${b.toLowerCase()}.
91
+ * Determine if the user can update the ${modelName.toLowerCase()}.
66
92
  */
67
- update(user: UserModel | null, model: ${b}): boolean {
93
+ update(user: UserModel | null, model: ${modelName}): boolean {
68
94
  return user?.id === model.user_id
69
95
  }
70
96
 
71
97
  /**
72
- * Determine if the user can delete the ${b.toLowerCase()}.
98
+ * Determine if the user can delete the ${modelName.toLowerCase()}.
73
99
  */
74
- delete(user: UserModel | null, model: ${b}): boolean {
100
+ delete(user: UserModel | null, model: ${modelName}): boolean {
75
101
  return user?.id === model.user_id
76
102
  }
77
103
 
78
104
  /**
79
- * Determine if the user can restore the ${b.toLowerCase()}.
105
+ * Determine if the user can restore the ${modelName.toLowerCase()}.
80
106
  */
81
- restore(user: UserModel | null, model: ${b}): boolean {
107
+ restore(user: UserModel | null, model: ${modelName}): boolean {
82
108
  return user?.id === model.user_id
83
109
  }
84
110
 
85
111
  /**
86
- * Determine if the user can permanently delete the ${b.toLowerCase()}.
112
+ * Determine if the user can permanently delete the ${modelName.toLowerCase()}.
87
113
  */
88
- forceDelete(user: UserModel | null, model: ${b}): boolean {
114
+ forceDelete(user: UserModel | null, model: ${modelName}): boolean {
89
115
  return user?.id === model.user_id
90
116
  }
91
117
  }
92
- `}async function U(q,b){let z=J.appPath("Gates.ts");try{let v=await R(z),I=v.match(/export const policies[^{]*\{([^}]*)\}/);if(I){let H=I[1]??"";if(H.includes(`'${q}'`)){B.info(`Policy for '${q}' already registered in Gates.ts`);return}let G=` '${q}': '${b}',
93
- `,K=`${H.trimEnd()}
94
- ${G}`;v=v.replace(/export const policies[^{]*\{([^}]*)\}/,`export const policies: Record<string, string | { policy: string, model?: string }> = {${K}}`),await L(z,v),B.success(`Registered policy '${b}' for '${q}' in Gates.ts`)}}catch(v){B.warn(`Could not register policy in Gates.ts: ${v.message}`),B.info("You may need to manually add it to app/Gates.ts")}}export{X as makePolicy};
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
+ }
@@ -1,27 +1,51 @@
1
- // @bun
2
- import{Lb as G}from"./chunk-h3d81wrg.js";import{log as x}from"@stacksjs/logging";import*as z from"@stacksjs/path";import{doesExist as H,writeFile as I}from"@stacksjs/storage";async function O(q){let j=q.name;if(!j)return x.error("Resource name is required"),!1;let v=j.endsWith("Resource")?j:`${j}Resource`,A=q.model||v.replace("Resource",""),F=q.collection?K(v,A):J(v,A),B=z.appPath("Resources");if(!H(B)){let{mkdirSync:w}=await import("@stacksjs/storage");w(B,{recursive:!0})}let E=z.appPath(`Resources/${v}.ts`);try{return await I(E,F),x.success(`Created resource: ${E}`),!0}catch(w){return x.error(`Failed to create resource: ${w.message}`),!1}}function J(q,j){return`import type { Request } from '@stacksjs/router'
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'
3
27
  import { JsonResource } from '@stacksjs/api'
4
28
 
5
29
  /**
6
- * ${q}
30
+ * ${resourceName}
7
31
  *
8
- * Transforms ${j} model data for API responses.
32
+ * Transforms ${modelName} model data for API responses.
9
33
  *
10
34
  * @example
11
35
  * // Single resource
12
- * return new ${q}(${j.toLowerCase()}).toResponse()
36
+ * return new ${resourceName}(${modelName.toLowerCase()}).toResponse()
13
37
  *
14
38
  * // Collection
15
- * return ${q}.collection(${j.toLowerCase()}s).toResponse()
39
+ * return ${resourceName}.collection(${modelName.toLowerCase()}s).toResponse()
16
40
  *
17
41
  * // With additional data
18
- * return new ${q}(${j.toLowerCase()})
42
+ * return new ${resourceName}(${modelName.toLowerCase()})
19
43
  * .withAdditional({ message: 'Success' })
20
44
  * .toResponse()
21
45
  */
22
46
 
23
- // TODO: Import or define your ${j} type
24
- interface ${j} {
47
+ // TODO: Import or define your ${modelName} type
48
+ interface ${modelName} {
25
49
  id: number
26
50
  name: string
27
51
  created_at: Date
@@ -29,7 +53,7 @@ interface ${j} {
29
53
  // Add your model properties here
30
54
  }
31
55
 
32
- export default class ${q} extends JsonResource<${j}> {
56
+ export default class ${resourceName} extends JsonResource<${modelName}> {
33
57
  /**
34
58
  * Transform the resource into an array.
35
59
  */
@@ -55,20 +79,24 @@ export default class ${q} extends JsonResource<${j}> {
55
79
  }
56
80
  }
57
81
  }
58
- `}function K(q,j){let v=q.replace("Collection","");return`import type { Request } from '@stacksjs/router'
82
+ `;
83
+ }
84
+ function generateCollectionResourceContent(resourceName, modelName) {
85
+ const baseResourceName = resourceName.replace("Collection", "");
86
+ return `import type { Request } from '@stacksjs/router'
59
87
  import { JsonResource, ResourceCollection } from '@stacksjs/api'
60
88
 
61
89
  /**
62
- * ${q}
90
+ * ${resourceName}
63
91
  *
64
- * Collection resource for ${j} with custom collection behavior.
92
+ * Collection resource for ${modelName} with custom collection behavior.
65
93
  *
66
94
  * @example
67
- * return new ${q}(${j.toLowerCase()}s).toResponse()
95
+ * return new ${resourceName}(${modelName.toLowerCase()}s).toResponse()
68
96
  */
69
97
 
70
- // TODO: Import or define your ${j} type
71
- interface ${j} {
98
+ // TODO: Import or define your ${modelName} type
99
+ interface ${modelName} {
72
100
  id: number
73
101
  name: string
74
102
  created_at: Date
@@ -78,7 +106,7 @@ interface ${j} {
78
106
  /**
79
107
  * Individual resource for the collection
80
108
  */
81
- class ${v} extends JsonResource<${j}> {
109
+ class ${baseResourceName} extends JsonResource<${modelName}> {
82
110
  toArray(request?: Request): Record<string, any> {
83
111
  return {
84
112
  id: this.resource.id,
@@ -92,9 +120,9 @@ class ${v} extends JsonResource<${j}> {
92
120
  /**
93
121
  * Collection resource with custom behavior
94
122
  */
95
- export default class ${q} extends ResourceCollection<${j}, ${v}> {
96
- constructor(resources: ${j}[]) {
97
- super(resources, ${v})
123
+ export default class ${resourceName} extends ResourceCollection<${modelName}, ${baseResourceName}> {
124
+ constructor(resources: ${modelName}[]) {
125
+ super(resources, ${baseResourceName})
98
126
  }
99
127
 
100
128
  /**
@@ -110,4 +138,5 @@ export default class ${q} extends ResourceCollection<${j}, ${v}> {
110
138
  }
111
139
  }
112
140
  }
113
- `}export{O as makeResource};
141
+ `;
142
+ }
package/dist/make.js CHANGED
@@ -1,2 +1,328 @@
1
- // @bun
2
- import{A as k,B as l,C as m,D as n,E as o,F as p,G as q,H as r,I as s,J as t,K as u,L as v,M as w,N as x,O as y,P as z,Q as A,R as B,q as a,r as b,s as c,t as d,u as e,v as f,w as g,x as h,y as i,z as j}from"./chunk-c74qv38e.js";import"./chunk-nty6mmx4.js";import"./chunk-s735m9mg.js";import"./chunk-0gadhvn7.js";import"./chunk-h3d81wrg.js";export{a as setDryRun,v as makeStack,y as makeQueueTable,p as makePage,m as makeNotification,o as makeMail,t as makeLanguage,r as makeFunction,i as makeDatabase,f as makeComponent,z as makeCertificate,e as makeAction,d as make,b as isDryRunActive,c as invoke,k as factory,q as createPage,w as createNotification,A as createModel,x as createMigration,B as createMiddleware,n as createMail,u as createLanguage,s as createFunction,l as createFactory,j as createDatabase,h as createComponent,g as createAction};
1
+ import process from "node:process";
2
+ import { existsSync } from "node:fs";
3
+ import { italic, runCommand } from "@stacksjs/cli";
4
+ import { ExitCode } from "@stacksjs/types";
5
+ import { localUrl } from "@stacksjs/config";
6
+ import { Action } from "@stacksjs/enums";
7
+ import { handleError } from "@stacksjs/error-handling";
8
+ import { log } from "@stacksjs/logging";
9
+ import { frameworkPath, path as p, resolve } from "@stacksjs/path";
10
+ import { createFolder, doesFolderExist, writeTextFile } from "@stacksjs/storage";
11
+ import { kebabCase, pascalCase, template } from "@stacksjs/strings";
12
+ import { runAction } from "./helpers";
13
+ import { CODE_TEMPLATES } from "./templates";
14
+ let isDryRun = !1;
15
+ export function setDryRun(enabled) {
16
+ isDryRun = Boolean(enabled);
17
+ }
18
+ export function isDryRunActive() {
19
+ return isDryRun;
20
+ }
21
+ function generateCode(templateKey, ...args) {
22
+ return template(CODE_TEMPLATES[templateKey], ...args);
23
+ }
24
+ async function writeOrPreview(path, data) {
25
+ if (isDryRun) {
26
+ const lines = data.split(`
27
+ `), preview = lines.slice(0, 60).map((l) => ` ${l}`).join(`
28
+ `), truncated = lines.length > 60 ? `
29
+ ${italic(`\u2026 ${lines.length - 60} more lines elided`)}` : "";
30
+ log.info(`[dry-run] would write ${path} (${lines.length} lines)`);
31
+ process.stdout.write(`${preview}${truncated}
32
+
33
+ `);
34
+ return;
35
+ }
36
+ await writeTextFile({ path, data });
37
+ }
38
+ async function createFileWithTemplate(path, templateKey, ...args) {
39
+ await writeOrPreview(path, generateCode(templateKey, ...args));
40
+ }
41
+ export async function invoke(options) {
42
+ if (options.component)
43
+ await makeComponent(options);
44
+ if (options.database)
45
+ makeDatabase(options);
46
+ if (options.function)
47
+ await makeFunction(options);
48
+ if (options.language)
49
+ await makeLanguage(options);
50
+ if (options.middleware)
51
+ await createMiddleware(options);
52
+ if (options.notification)
53
+ await makeNotification(options);
54
+ if (options.page)
55
+ await makePage(options);
56
+ if (options.stack)
57
+ await makeStack(options);
58
+ }
59
+ export async function make(options) {
60
+ return await invoke(options);
61
+ }
62
+ export async function makeAction(options) {
63
+ try {
64
+ const name = options.name;
65
+ log.info("Creating your action...");
66
+ await createAction(options);
67
+ log.success(`Created ${italic(name)} action`);
68
+ } catch (error) {
69
+ log.error("There was an error creating your action", error);
70
+ process.exit(ExitCode.FatalError);
71
+ }
72
+ }
73
+ export async function makeComponent(options) {
74
+ try {
75
+ const name = options.name;
76
+ log.info("Creating your component...");
77
+ await createComponent(options);
78
+ log.success(`Created ${italic(name)} component`);
79
+ } catch (error) {
80
+ log.error("There was an error creating your component", error);
81
+ process.exit(ExitCode.FatalError);
82
+ }
83
+ }
84
+ export async function createAction(options) {
85
+ const name = options.name, opts = options, wantsValidation = Boolean(opts.withValidation || options["with-validation"]), wantsAuth = Boolean(opts.withAuth || options["with-auth"]), templateKey = wantsValidation && wantsAuth ? "actionWithBoth" : wantsValidation ? "actionWithValidation" : wantsAuth ? "actionWithAuth" : "action";
86
+ await createFileWithTemplate(p.userActionsPath(name), templateKey, name);
87
+ }
88
+ export async function createComponent(options) {
89
+ const name = options.name;
90
+ await createFileWithTemplate(p.userComponentsPath(`${name}.vue`), "component", name);
91
+ }
92
+ export function makeDatabase(options) {
93
+ try {
94
+ const name = options.name;
95
+ log.info(`Creating your ${italic(name)} database...`);
96
+ createDatabase(options);
97
+ log.success(`Created ${italic(name)} database`);
98
+ } catch (error) {
99
+ log.error("There was an error creating your database", error);
100
+ process.exit(ExitCode.FatalError);
101
+ }
102
+ }
103
+ export function createDatabase(options) {
104
+ log.debug("createDatabase options", options);
105
+ }
106
+ export function factory(options) {
107
+ try {
108
+ const name = options.name;
109
+ log.info(`Creating your ${italic(name)} factory...`);
110
+ createDatabase(options);
111
+ log.success(`Created ${italic(name)} factory`);
112
+ } catch (error) {
113
+ log.error("There was an error creating your factory", error);
114
+ process.exit(ExitCode.FatalError);
115
+ }
116
+ }
117
+ export async function createFactory(options) {
118
+ const name = options.name || "MyFactory", factoryName = name.endsWith("Factory") ? name : `${name}Factory`;
119
+ try {
120
+ const { path: p } = await import("@stacksjs/path"), factoryPath = `${p.userDatabasePath("factories")}/${factoryName}.ts`;
121
+ if (await Bun.file(factoryPath).exists()) {
122
+ log.warn(`Factory ${factoryName} already exists at ${factoryPath}`);
123
+ return;
124
+ }
125
+ const modelName = name.replace(/Factory$/, ""), content = `import type { ${modelName}Model } from '@stacksjs/orm'
126
+
127
+ export function ${factoryName}(): Partial<${modelName}Model> {
128
+ return {
129
+ // Define your factory attributes here
130
+ }
131
+ }
132
+
133
+ export default ${factoryName}
134
+ `;
135
+ await writeOrPreview(factoryPath, content);
136
+ log.success(`Created factory: ${factoryPath}`);
137
+ } catch (error) {
138
+ log.error(`Failed to create factory ${factoryName}`, error);
139
+ throw error;
140
+ }
141
+ }
142
+ export async function makeNotification(options) {
143
+ try {
144
+ const name = options.name;
145
+ log.info(`Creating your ${italic(name)} notification...`);
146
+ await createNotification(options);
147
+ log.success(`Created ${italic(name)} notification`);
148
+ } catch (error) {
149
+ log.error("There was an error creating your notification", error);
150
+ process.exit(ExitCode.FatalError);
151
+ }
152
+ }
153
+ export async function createMail(options) {
154
+ const rawName = String(options.name || "").trim();
155
+ if (!rawName) {
156
+ log.error("A mail name is required (e.g. `buddy make:mail OrderShipped`).");
157
+ return !1;
158
+ }
159
+ const className = pascalCase(rawName), kebabName = kebabCase(rawName), mailPath = p.userMailPath(`${className}.ts`), templatePath = p.userEmailsPath(`${kebabName}.stx`);
160
+ if (!options.force) {
161
+ if (existsSync(mailPath)) {
162
+ console.error(`${italic(mailPath)} already exists \u2014 re-run with --force to overwrite.`);
163
+ return !1;
164
+ }
165
+ if (existsSync(templatePath)) {
166
+ console.error(`${italic(templatePath)} already exists \u2014 re-run with --force to overwrite.`);
167
+ return !1;
168
+ }
169
+ }
170
+ if (!doesFolderExist(p.userMailPath()))
171
+ await createFolder(p.userMailPath());
172
+ if (!doesFolderExist(p.userEmailsPath()))
173
+ await createFolder(p.userEmailsPath());
174
+ try {
175
+ await createFileWithTemplate(mailPath, "mail", className, kebabName);
176
+ await createFileWithTemplate(templatePath, "mailTemplate", className, kebabName);
177
+ return !0;
178
+ } catch (error) {
179
+ handleError("Error creating mailable", error);
180
+ return !1;
181
+ }
182
+ }
183
+ export async function makeMail(options) {
184
+ try {
185
+ const name = options.name;
186
+ log.info(`Creating your ${italic(name)} mailable...`);
187
+ if (!await createMail(options))
188
+ process.exit(ExitCode.FatalError);
189
+ log.success(`Created ${italic(pascalCase(name))} mailable + ${italic(kebabCase(name))}.stx template`);
190
+ } catch (error) {
191
+ log.error("There was an error creating your mailable", error);
192
+ process.exit(ExitCode.FatalError);
193
+ }
194
+ }
195
+ export async function makePage(options) {
196
+ try {
197
+ const name = options.name;
198
+ log.info("Creating your page...");
199
+ await createPage(options);
200
+ log.success(`Created ${name} page`);
201
+ } catch (error) {
202
+ log.error("There was an error creating your page", error);
203
+ process.exit(ExitCode.FatalError);
204
+ }
205
+ }
206
+ export async function createPage(options) {
207
+ const name = options.name;
208
+ await createFileWithTemplate(p.userViewsPath(`${name}.vue`), "page", name);
209
+ }
210
+ export async function makeFunction(options) {
211
+ try {
212
+ const name = options.name;
213
+ log.info("Creating your function...");
214
+ await createFunction(options);
215
+ log.success(`Created ${name} function`);
216
+ } catch (error) {
217
+ log.error("There was an error creating your function", error);
218
+ process.exit(ExitCode.FatalError);
219
+ }
220
+ }
221
+ export async function createFunction(options) {
222
+ const name = options.name;
223
+ await createFileWithTemplate(p.userFunctionsPath(`${name}.ts`), "function", name);
224
+ }
225
+ export async function makeLanguage(options) {
226
+ try {
227
+ const name = options.name;
228
+ log.info("Creating your translation file...");
229
+ await createLanguage(options);
230
+ log.success(`Created ${name} translation file`);
231
+ } catch (error) {
232
+ log.error("There was an error creating your language.", error);
233
+ process.exit(ExitCode.FatalError);
234
+ }
235
+ }
236
+ export async function createLanguage(options) {
237
+ const name = options.name;
238
+ await createFileWithTemplate(p.resourcesPath(`lang/${name}.yml`), "language", name);
239
+ }
240
+ export async function makeStack(options) {
241
+ try {
242
+ const name = options.name;
243
+ log.info(`Creating your ${name} stack...`);
244
+ const stackDir = resolve(process.cwd(), name);
245
+ if (doesFolderExist(stackDir)) {
246
+ log.error(`Directory "${name}" already exists`);
247
+ process.exit(ExitCode.FatalError);
248
+ }
249
+ await createFolder(stackDir);
250
+ const dirs = ["app/Actions", "app/Models", "config", "database/migrations", "resources/views", "resources/components", "resources/functions", "routes", "public"];
251
+ for (const dir of dirs)
252
+ await createFolder(resolve(stackDir, dir));
253
+ const shortName = name.replace(/^@[^/]+\//, "").replace(/-stack$/, "");
254
+ await createFileWithTemplate(resolve(stackDir, "package.json"), "stackPackageJson", name, shortName);
255
+ log.success(`Successfully scaffolded your "${name}" stack`);
256
+ log.info("");
257
+ log.info(` cd ${name}`);
258
+ log.info(" # Add your models, actions, views, etc.");
259
+ log.info(" # Then publish: bun publish");
260
+ log.info("");
261
+ log.info(" Users install it with:");
262
+ log.info(` buddy stack:install ${name}`);
263
+ } catch (error) {
264
+ log.error("There was an error creating your stack", error);
265
+ process.exit(ExitCode.FatalError);
266
+ }
267
+ }
268
+ export async function createNotification(options) {
269
+ const name = options.name;
270
+ try {
271
+ let importOption = "EmailOptions";
272
+ if (!doesFolderExist("notifications"))
273
+ await createFolder("./notifications");
274
+ if (options.chat)
275
+ importOption = "ChatOptions";
276
+ if (options.sms)
277
+ importOption = "SMSOptions";
278
+ await createFileWithTemplate(p.userNotificationsPath(`${name}.ts`), "notification", importOption);
279
+ return !0;
280
+ } catch (error) {
281
+ handleError("Error creating notification", error);
282
+ return !1;
283
+ }
284
+ }
285
+ export async function createMigration(options) {
286
+ const optionName = options.name, table = "dummy-name";
287
+ if (!optionName[0])
288
+ throw Error("options.name is required and cannot be empty");
289
+ const name = optionName[0].toUpperCase() + optionName.slice(1), path = frameworkPath(`database/migrations/${name}.ts`);
290
+ try {
291
+ await createFileWithTemplate(path, "migration", table);
292
+ log.success(`Successfully created your migration file at stacks/database/migrations/${name}.ts`);
293
+ } catch (error) {
294
+ log.error(error);
295
+ }
296
+ }
297
+ export async function makeQueueTable() {
298
+ await runAction(Action.QueueTable);
299
+ }
300
+ export async function makeCertificate() {
301
+ const domain = await localUrl();
302
+ log.info("Creating SSL certificate...");
303
+ await runCommand(`tlsx ${domain}`, {
304
+ cwd: p.storagePath("keys")
305
+ });
306
+ log.success("Certificate created");
307
+ log.info("Installing SSL certificate...");
308
+ await runCommand("tlsx -install", {
309
+ cwd: p.storagePath("keys")
310
+ });
311
+ log.success("Certificate installed");
312
+ }
313
+ export async function createModel(options) {
314
+ const optionName = options.name;
315
+ if (!optionName[0])
316
+ throw Error("options.name is required and cannot be empty");
317
+ const name = optionName[0].toUpperCase() + optionName.slice(1), tableName = name.replace(/([A-Z])/g, "_$1").toLowerCase().replace(/^_/, "").replace(/([^s])$/, "$1s"), path = p.userModelsPath(`${name}.ts`);
318
+ try {
319
+ await createFileWithTemplate(path, "model", name, tableName);
320
+ log.success(`Model created: ${italic(`app/Models/${name}.ts`)}`);
321
+ } catch (error) {
322
+ log.error(error);
323
+ }
324
+ }
325
+ export async function createMiddleware(options) {
326
+ const name = options.name;
327
+ await createFileWithTemplate(p.userMiddlewarePath(`${name}.ts`), "middleware", name);
328
+ }
@@ -1,2 +1,16 @@
1
- // @bun
2
- import i from"process";import{generateMigrations as t,runDatabaseMigration as a}from"@stacksjs/database";import{log as e}from"@stacksjs/logging";var r=await t();if(r?.isErr)console.error(r.error),e.error("[stacks] generateMigrations failed",r.error),i.exit(1);var o=await a();if(o.isErr)e.error("runDatabaseMigration failed"),e.error(o.error),i.exit(1);i.exit(0);
1
+ import process from "node:process";
2
+ import { generateMigrations, runDatabaseMigration } from "@stacksjs/database";
3
+ import { log } from "@stacksjs/logging";
4
+ const result = await generateMigrations();
5
+ if (result?.isErr) {
6
+ console.error(result.error);
7
+ log.error("[stacks] generateMigrations failed", result.error);
8
+ process.exit(1);
9
+ }
10
+ const migrateResult = await runDatabaseMigration();
11
+ if (migrateResult.isErr) {
12
+ log.error("runDatabaseMigration failed");
13
+ log.error(migrateResult.error);
14
+ process.exit(1);
15
+ }
16
+ process.exit(0);
@@ -1,2 +1,31 @@
1
- // @bun
2
- import v from"process";import{generateMigrations as G,migrateAuthTables as H,migrateNotificationTables as I,migrateRbacTables as J,resetDatabase as K,runDatabaseMigration as L}from"@stacksjs/database";import{log as q}from"@stacksjs/logging";var w=await K();if(w?.isErr)console.error(w.error),q.error("resetDatabase failed",w.error),v.exit(1);var x=await G();if(x?.isErr)console.error(x.error),q.error("generateMigrations failed",x.error),v.exit(1);var z=await H();if(!z.success)q.error(`Failed to migrate auth tables: ${z.error}`);var B=await I();if(!B.success)q.error(`Failed to migrate notification tables: ${B.error}`);var C=await J();if(!C.success)q.error(`Failed to migrate RBAC tables: ${C.error}`);var E=await L();if(E.isErr)q.error("runDatabaseMigration failed"),q.error(E.error),v.exit(1);v.exit(0);
1
+ import process from "node:process";
2
+ import { generateMigrations, migrateAuthTables, migrateNotificationTables, migrateRbacTables, resetDatabase, runDatabaseMigration } from "@stacksjs/database";
3
+ import { log } from "@stacksjs/logging";
4
+ const resetResult = await resetDatabase();
5
+ if (resetResult?.isErr) {
6
+ console.error(resetResult.error);
7
+ log.error("resetDatabase failed", resetResult.error);
8
+ process.exit(1);
9
+ }
10
+ const genResult = await generateMigrations();
11
+ if (genResult?.isErr) {
12
+ console.error(genResult.error);
13
+ log.error("generateMigrations failed", genResult.error);
14
+ process.exit(1);
15
+ }
16
+ const authResult = await migrateAuthTables();
17
+ if (!authResult.success)
18
+ log.error(`Failed to migrate auth tables: ${authResult.error}`);
19
+ const notifResult = await migrateNotificationTables();
20
+ if (!notifResult.success)
21
+ log.error(`Failed to migrate notification tables: ${notifResult.error}`);
22
+ const rbacResult = await migrateRbacTables();
23
+ if (!rbacResult.success)
24
+ log.error(`Failed to migrate RBAC tables: ${rbacResult.error}`);
25
+ const migrateResult = await runDatabaseMigration();
26
+ if (migrateResult.isErr) {
27
+ log.error("runDatabaseMigration failed");
28
+ log.error(migrateResult.error);
29
+ process.exit(1);
30
+ }
31
+ process.exit(0);