@stacksjs/actions 0.70.45 → 0.70.53

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 (127) hide show
  1. package/LICENSE.md +21 -0
  2. package/dist/action.d.ts +104 -17
  3. package/dist/blog.d.ts +12 -0
  4. package/dist/build/frontend-static.d.ts +16 -0
  5. package/dist/chunk-00qp27jy.js +93 -0
  6. package/dist/{chunk-jd1yzkq5.js → chunk-23thftnv.js} +1 -1
  7. package/dist/{chunk-jbvvb45k.js → chunk-4qzb8g3z.js} +1 -1
  8. package/dist/{chunk-s03z9zn3.js → chunk-5dfz9en9.js} +2 -2
  9. package/dist/{chunk-3beht8ja.js → chunk-5hwp0frq.js} +1 -1
  10. package/dist/{chunk-cqedfbaf.js → chunk-5pwpk005.js} +2 -2
  11. package/dist/chunk-604jy79b.js +5 -0
  12. package/dist/{chunk-yh15ydty.js → chunk-63swek9d.js} +2 -2
  13. package/dist/chunk-67am4dae.js +688 -0
  14. package/dist/{chunk-gt77jmb5.js → chunk-8gbewxns.js} +1 -1
  15. package/dist/chunk-8r76qydb.js +240 -0
  16. package/dist/{chunk-zbhjh5sz.js → chunk-9x17v4x2.js} +2 -2
  17. package/dist/chunk-aazd6qpv.js +3 -0
  18. package/dist/{chunk-n2fd1d0m.js → chunk-ag4fy7cx.js} +1 -1
  19. package/dist/{chunk-2qchdrf9.js → chunk-badehrwa.js} +1 -1
  20. package/dist/chunk-dbz9dp2h.js +3 -0
  21. package/dist/{chunk-v0wnrnaa.js → chunk-e8505qz8.js} +2 -2
  22. package/dist/chunk-jv7ry09n.js +3 -0
  23. package/dist/{chunk-w418anbq.js → chunk-jve1p4dz.js} +2 -2
  24. package/dist/chunk-mcwfmqzb.js +283 -0
  25. package/dist/chunk-n24m8prb.js +3 -0
  26. package/dist/{chunk-d5yxdz7e.js → chunk-nm9h5rye.js} +2 -2
  27. package/dist/{chunk-h0hfqr1p.js → chunk-ny1racy0.js} +2 -2
  28. package/dist/{chunk-2gh7kgpc.js → chunk-p601xr03.js} +1 -1
  29. package/dist/{chunk-yvva7qsg.js → chunk-pqnzp7x8.js} +2 -2
  30. package/dist/chunk-rj1cbghx.js +17 -0
  31. package/dist/chunk-rzhs51h1.js +3 -0
  32. package/dist/{chunk-tzx3h4r8.js → chunk-sp5cjdhd.js} +213 -76
  33. package/dist/chunk-tqax3gbq.js +16 -0
  34. package/dist/{chunk-c8qt2xst.js → chunk-vsj8ns4p.js} +1 -1
  35. package/dist/{chunk-zaw01rqz.js → chunk-x8nrbsk1.js} +2 -2
  36. package/dist/dev/dashboard-utils.d.ts +19 -1
  37. package/dist/dev/migrate-watcher.d.ts +1 -0
  38. package/dist/index.d.ts +2 -0
  39. package/dist/make.d.ts +19 -0
  40. package/dist/queue/dlq-purge.d.ts +1 -0
  41. package/dist/queue/dlq-retry.d.ts +1 -0
  42. package/dist/queue/dlq.d.ts +1 -0
  43. package/dist/queue/list.d.ts +1 -0
  44. package/dist/queue/pause.d.ts +1 -0
  45. package/dist/queue/quarantine.d.ts +1 -0
  46. package/dist/queue/resume.d.ts +1 -0
  47. package/dist/queue/unquarantine.d.ts +1 -0
  48. package/dist/src/action.js +1 -1
  49. package/dist/src/actions.js +1 -1
  50. package/dist/src/add.js +1 -1
  51. package/dist/src/ai/request-model-access.js +1 -1
  52. package/dist/src/auth/setup.js +82 -24
  53. package/dist/src/blog.js +102 -0
  54. package/dist/src/build/core.js +1 -1
  55. package/dist/src/build/frontend-static.js +9 -0
  56. package/dist/src/build/views.js +1 -1
  57. package/dist/src/build.js +1 -1
  58. package/dist/src/commit.js +1 -1
  59. package/dist/src/database/seed.js +1 -1
  60. package/dist/src/deploy/index.js +38 -45
  61. package/dist/src/dev/api.js +4 -4
  62. package/dist/src/dev/dashboard-globals.js +1 -1
  63. package/dist/src/dev/dashboard-utils.js +1 -1
  64. package/dist/src/dev/dashboard.js +6 -6
  65. package/dist/src/dev/docs.js +1 -1
  66. package/dist/src/dev/index.js +1 -1
  67. package/dist/src/dev/migrate-watcher.js +2 -0
  68. package/dist/src/dev/views.js +1 -1
  69. package/dist/src/discover-packages.js +1 -1
  70. package/dist/src/examples.js +1 -1
  71. package/dist/src/generate/component-meta.js +1 -1
  72. package/dist/src/generate/env-files.js +1 -1
  73. package/dist/src/generate/ide-helpers.js +1 -1
  74. package/dist/src/generate/index.js +1 -1
  75. package/dist/src/generate/lib-entries.js +1 -1
  76. package/dist/src/generate/vscode-custom-data.js +1 -1
  77. package/dist/src/helpers/component-meta.js +1 -1
  78. package/dist/src/helpers/index.js +1 -1
  79. package/dist/src/helpers/lib-entries.js +1 -1
  80. package/dist/src/helpers/package-json.js +1 -1
  81. package/dist/src/helpers/utils.js +1 -1
  82. package/dist/src/helpers/vscode-custom-data.js +1 -1
  83. package/dist/src/index.js +1 -1
  84. package/dist/src/key-generate.js +1 -1
  85. package/dist/src/make-command.js +1 -1
  86. package/dist/src/make-job.js +1 -1
  87. package/dist/src/make-policy.js +1 -1
  88. package/dist/src/make-resource.js +1 -1
  89. package/dist/src/make.js +1 -1
  90. package/dist/src/migrate/fresh.js +1 -1
  91. package/dist/src/orm/base.js +1 -1
  92. package/dist/src/queue/dlq-purge.js +2 -0
  93. package/dist/src/queue/dlq-retry.js +2 -0
  94. package/dist/src/queue/dlq.js +5 -0
  95. package/dist/src/queue/failed.js +4 -4
  96. package/dist/src/queue/list.js +5 -0
  97. package/dist/src/queue/pause.js +2 -0
  98. package/dist/src/queue/quarantine.js +3 -0
  99. package/dist/src/queue/resume.js +2 -0
  100. package/dist/src/queue/unquarantine.js +2 -0
  101. package/dist/src/release.js +1 -1
  102. package/dist/src/run-action.js +1 -1
  103. package/dist/src/scaffold-crud.js +1 -1
  104. package/dist/src/serve/api.js +1 -1
  105. package/dist/src/setup/index.js +1 -1
  106. package/dist/src/setup/ssl.js +1 -1
  107. package/dist/src/stacks.js +1 -1
  108. package/dist/src/templates.js +1 -1
  109. package/dist/src/types.js +1 -1
  110. package/dist/src/upgrade/dependencies.js +1 -1
  111. package/dist/src/upgrade/framework-utils.js +1 -1
  112. package/dist/src/upgrade/framework.js +5 -5
  113. package/dist/src/upgrade/index.js +1 -1
  114. package/dist/src/upgrade.js +1 -1
  115. package/dist/upgrade/framework-utils.d.ts +48 -0
  116. package/package.json +18 -18
  117. package/dist/chunk-2kaj93p5.js +0 -3
  118. package/dist/chunk-3086k7zk.js +0 -184
  119. package/dist/chunk-4fz2qb8b.js +0 -17
  120. package/dist/chunk-4p0rjazd.js +0 -101
  121. package/dist/chunk-77pta9ww.js +0 -93
  122. package/dist/chunk-d4srk6ma.js +0 -3
  123. package/dist/chunk-h5rff0v9.js +0 -658
  124. package/dist/chunk-kr2k0h74.js +0 -16
  125. package/dist/chunk-kzhgexj4.js +0 -3
  126. package/dist/chunk-sxp97zys.js +0 -3
  127. package/dist/chunk-vek18p55.js +0 -5
@@ -1,3 +1,3 @@
1
1
  // @bun
2
2
  import{projectPath as G,storagePath as J}from"@stacksjs/path";async function L(){let x={generated_at:new Date().toISOString(),packages:{}},E=new Set;try{let z=(await Bun.file(G("package.json")).json())?.stacks?.["dont-discover"];if(Array.isArray(z))for(let A of z)E.add(A)}catch{}let H=G("pantry"),I=["*/package.json","@*/*/package.json"];for(let q of I){let z=new Bun.Glob(q);for await(let A of z.scan({cwd:H,absolute:!0,onlyFiles:!0}))try{let B=await Bun.file(A).json(),C=B?.name;if(!C||!B.stacks||E.has(C))continue;x.packages[C]=B.stacks}catch{}}let F=J("framework/discovered-packages.json");try{let q=await Bun.file(F).json();if(JSON.stringify(q.packages??{})===JSON.stringify(x.packages))return q}catch{}return await Bun.write(F,JSON.stringify(x,null,2)),x}
3
- export{L as ra};
3
+ export{L as pa};
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import{D as x}from"./chunk-4fz2qb8b.js";import{italic as I}from"@stacksjs/cli";import{log as W}from"@stacksjs/logging";import{path as Z}from"@stacksjs/path";import{writeTextFile as L}from"@stacksjs/storage";var P={str:"string",string:"string",varchar:"string",text:"text",longtext:"text",int:"number",integer:"number",number:"number",num:"number",bool:"boolean",boolean:"boolean",date:"date",datetime:"date",json:"json"};function U(G){if(!G)return[];let H=G.split(",").map((q)=>q.trim()).filter(Boolean),J=[];for(let q of H){let[K,O="string"]=q.split(":"),Q=K?.trim();if(!Q)continue;let B=P[O.trim().toLowerCase()]??"string";J.push({name:Q,type:B})}return J}function V(G){if(!G)return G;let H=G.toLowerCase();if(H.endsWith("s")||H.endsWith("x")||H.endsWith("z")||H.endsWith("ch")||H.endsWith("sh"))return`${G}es`;if(H.endsWith("y")&&!/[aeiou]y$/.test(H))return`${G.slice(0,-1)}ies`;return`${G}s`}function v(G){return G.replace(/(^|[-_\s])(\w)/g,(H,J,q)=>String(q).toUpperCase())}function X(G){return G.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[-\s]+/g,"_").toLowerCase()}function Y(G){if(G.length===0)return" title: { type: 'string', fillable: true, validation: { rule: schema.string().required() } },";return G.map((H)=>{let J=H.type,q=J==="number"?"schema.number()":J==="boolean"?"schema.boolean()":J==="date"?"schema.date()":J==="json"?"schema.object({})":"schema.string()",K=J==="number"?"number":J==="boolean"?"boolean":J==="date"?"date":J==="json"?"json":"string";return` ${H.name}: { type: '${K}', fillable: true, validation: { rule: ${q} } },`}).join(`
2
+ import{F as x}from"./chunk-rj1cbghx.js";import{italic as I}from"@stacksjs/cli";import{log as W}from"@stacksjs/logging";import{path as Z}from"@stacksjs/path";import{writeTextFile as L}from"@stacksjs/storage";var P={str:"string",string:"string",varchar:"string",text:"text",longtext:"text",int:"number",integer:"number",number:"number",num:"number",bool:"boolean",boolean:"boolean",date:"date",datetime:"date",json:"json"};function U(G){if(!G)return[];let H=G.split(",").map((q)=>q.trim()).filter(Boolean),J=[];for(let q of H){let[K,O="string"]=q.split(":"),Q=K?.trim();if(!Q)continue;let B=P[O.trim().toLowerCase()]??"string";J.push({name:Q,type:B})}return J}function V(G){if(!G)return G;let H=G.toLowerCase();if(H.endsWith("s")||H.endsWith("x")||H.endsWith("z")||H.endsWith("ch")||H.endsWith("sh"))return`${G}es`;if(H.endsWith("y")&&!/[aeiou]y$/.test(H))return`${G.slice(0,-1)}ies`;return`${G}s`}function v(G){return G.replace(/(^|[-_\s])(\w)/g,(H,J,q)=>String(q).toUpperCase())}function X(G){return G.replace(/([a-z0-9])([A-Z])/g,"$1_$2").replace(/[-\s]+/g,"_").toLowerCase()}function Y(G){if(G.length===0)return" title: { type: 'string', fillable: true, validation: { rule: schema.string().required() } },";return G.map((H)=>{let J=H.type,q=J==="number"?"schema.number()":J==="boolean"?"schema.boolean()":J==="date"?"schema.date()":J==="json"?"schema.object({})":"schema.string()",K=J==="number"?"number":J==="boolean"?"boolean":J==="date"?"date":J==="json"?"json":"string";return` ${H.name}: { type: '${K}', fillable: true, validation: { rule: ${q} } },`}).join(`
3
3
  `)}function _(G){if(G.length===0)return" .addColumn('title', 'varchar(255)', col => col.notNull())";return G.map((H)=>{switch(H.type){case"number":return` .addColumn('${H.name}', 'integer')`;case"boolean":return` .addColumn('${H.name}', 'boolean', col => col.defaultTo(false))`;case"text":return` .addColumn('${H.name}', 'text')`;case"date":return` .addColumn('${H.name}', 'timestamp')`;case"json":return` .addColumn('${H.name}', 'text')`;default:return` .addColumn('${H.name}', 'varchar(255)')`}}).join(`
4
4
  `)}function D(G,H,J){let q=v(G);switch(H){case"Index":return`import { Action } from '@stacksjs/actions'
5
5
  import ${q} from '~/app/Models/${q}'
@@ -85,4 +85,4 @@ ${_(H)}
85
85
  `)}
86
86
 
87
87
  `);return}await L({path:G,data:H})}async function h(G,H){let J=v(G);if(!J)throw Error("scaffold:crud requires a non-empty resource name");let q=U(H.fields);W.info(`Scaffolding CRUD for ${I(J)} (${q.length||"no"} fields)`),await $(Z.userModelsPath(`${J}.ts`),E(J,q));let O=`${Date.now().toString()}-create-${V(X(G))}-table.ts`;await $(Z.userMigrationsPath(O),N(G,q));for(let Q of["Index","Show","Store","Update","Destroy"])await $(Z.userActionsPath(`${J}${Q}Action.ts`),D(G,Q,q));W.success(`CRUD scaffold complete: model + migration + 5 actions for ${J}`),W.info(`Next: register \`route.resource('${V(X(G))}', '${J}')\` in routes/api.ts`)}
88
- export{U as w,h as x};
88
+ export{U as B,h as C};
@@ -1,3 +1,4 @@
1
+ import type { DashboardModelOptions } from '@stacksjs/types';
1
2
  /** Convert PascalCase model name to kebab-case ID */
2
3
  export declare function modelNameToId(name: string): string;
3
4
  /** Get the icon for a model name, falling back to the default */
@@ -7,7 +8,7 @@ export declare function scanModelsDir(dir: string, seenNames: Set<string>, model
7
8
  /** Discover models from both user and default directories */
8
9
  export declare function discoverModels(userModelsPath: string, defaultModelsPath: string): Promise<DiscoveredModel[]>;
9
10
  /** Build the manifest array for discovered models */
10
- export declare function buildManifest(models: DiscoveredModel[]): Array<{ id: string, name: string, icon: string, hasDedicatedPage: boolean, category: ModelCategory }>;
11
+ export declare function buildManifest(models: DiscoveredModel[]): DiscoveredModelManifestRow[];
11
12
  /** Check if a port is available by attempting to listen on it */
12
13
  export declare function isPortAvailable(port: number): Promise<boolean>;
13
14
  /** Find an available port starting from the preferred port */
@@ -85,6 +86,22 @@ export declare interface DiscoveredModel {
85
86
  icon: string
86
87
  id: string
87
88
  category?: ModelCategory
89
+ dashboard?: DashboardModelOptions
90
+ }
91
+ /**
92
+ * Manifest row written to `defaults/views/dashboard/.discovered-models.json`
93
+ * for the web-side sidebar to consume. Includes the per-model `dashboard`
94
+ * config (stacksjs/stacks#1843) so both sidebar builders (the native one
95
+ * here and the HTML one in `defaults/resources/functions/dashboard/sidebar.ts`)
96
+ * see the same data.
97
+ */
98
+ export declare interface DiscoveredModelManifestRow {
99
+ id: string
100
+ name: string
101
+ icon: string
102
+ hasDedicatedPage: boolean
103
+ category: ModelCategory
104
+ dashboard?: DashboardModelOptions
88
105
  }
89
106
  /**
90
107
  * Per-section toggles. Read from the project's `config/dashboard.ts` (when
@@ -105,6 +122,7 @@ export declare interface DashboardSectionToggles {
105
122
  management?: boolean
106
123
  utilities?: boolean
107
124
  library?: boolean
125
+ ci?: boolean
108
126
  data?: {
109
127
  dashboard?: boolean
110
128
  activity?: boolean
@@ -0,0 +1 @@
1
+ export declare function startModelMigrationWatcher(): void;
package/dist/index.d.ts CHANGED
@@ -17,6 +17,7 @@ export {
17
17
  createMiddleware,
18
18
  createMigration,
19
19
  createModel,
20
+ createMail,
20
21
  createNotification,
21
22
  createPage,
22
23
  isDryRunActive,
@@ -26,6 +27,7 @@ export {
26
27
  makeDatabase,
27
28
  makeFunction,
28
29
  makeLanguage,
30
+ makeMail,
29
31
  makeNotification,
30
32
  makePage,
31
33
  makeQueueTable,
package/dist/make.d.ts CHANGED
@@ -18,6 +18,25 @@ export declare function createDatabase(options: MakeOptions): void;
18
18
  export declare function factory(options: MakeOptions): void;
19
19
  export declare function createFactory(options: MakeOptions): Promise<void>;
20
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>;
21
40
  export declare function makePage(options: MakeOptions): Promise<void>;
22
41
  export declare function createPage(options: MakeOptions): Promise<void>;
23
42
  export declare function makeFunction(options: MakeOptions): Promise<void>;
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -0,0 +1 @@
1
+
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{Xa as a}from"../chunk-d4srk6ma.js";import"../chunk-jbvvb45k.js";export{a as Action};
2
+ import{cb as a}from"../chunk-aazd6qpv.js";import"../chunk-4qzb8g3z.js";export{a as Action};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{$a as o,Ya as a,Za as e,_a as f}from"../chunk-sxp97zys.js";import"../chunk-jbvvb45k.js";export{e as runActions,a as runAction,f as hasAction,o as actions};
2
+ import{db as a,eb as e,fb as f,gb as o}from"../chunk-rzhs51h1.js";import"../chunk-4qzb8g3z.js";export{e as runActions,a as runAction,f as hasAction,o as actions};
package/dist/src/add.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{ab as a,bb as b,cb as c,db as d,eb as e}from"../chunk-jd1yzkq5.js";import"../chunk-jbvvb45k.js";export{a as invoke,e as installPackages,c as addTable,d as addCalendar,b as add};
2
+ import{hb as a,ib as b,jb as c,kb as d,lb as e}from"../chunk-23thftnv.js";import"../chunk-4qzb8g3z.js";export{a as invoke,e as installPackages,c as addTable,d as addCalendar,b as add};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import"../../chunk-jbvvb45k.js";import{requestModelAccess as e}from"@stacksjs/ai";async function o(){try{await e()}catch(r){console.error("Error requesting model access:",r)}}if(import.meta.main)o();
2
+ import"../../chunk-4qzb8g3z.js";import{requestModelAccess as e}from"@stacksjs/ai";async function o(){try{await e()}catch(r){console.error("Error requesting model access:",r)}}if(import.meta.main)o();
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"@stacksjs/database";import{log as x}from"@stacksjs/logging";import{env as J}from"@stacksjs/env";import{sqlHelpers as K}from"@stacksjs/database";var G=J.DB_CONNECTION||"sqlite",N=K(G),{isPostgres:A,isMysql:C,now:O,boolTrue:R,boolFalse:_}=N;x.info("Setting up authentication...");x.info(`Database driver: ${G}`);x.info("Ensuring OAuth tables exist...");try{if(A)await f.unsafe(`
2
+ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"@stacksjs/database";import{log as z}from"@stacksjs/logging";import{makeHash as W}from"@stacksjs/security";import{env as X}from"@stacksjs/env";import{sqlHelpers as Y,usersEmailVerifiedAtSql as Z,usersPasswordChangedAtSql as _}from"@stacksjs/database";var O=X.DB_CONNECTION||"sqlite",K=Y(O),{isPostgres:G,isMysql:I,now:$,boolTrue:f,boolFalse:D}=K;z.info("Setting up authentication...");z.info(`Database driver: ${O}`);z.info("Ensuring OAuth tables exist...");try{if(G)await x.unsafe(`
3
3
  CREATE TABLE IF NOT EXISTS oauth_clients (
4
4
  id SERIAL PRIMARY KEY,
5
5
  name VARCHAR(255) NOT NULL,
@@ -12,7 +12,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
12
12
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
13
13
  updated_at TIMESTAMP
14
14
  )
15
- `);else if(C)await f.unsafe(`
15
+ `);else if(I)await x.unsafe(`
16
16
  CREATE TABLE IF NOT EXISTS oauth_clients (
17
17
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
18
18
  name VARCHAR(255) NOT NULL,
@@ -25,7 +25,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
25
25
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
26
26
  updated_at TIMESTAMP
27
27
  )
28
- `);else await f.unsafe(`
28
+ `);else await x.unsafe(`
29
29
  CREATE TABLE IF NOT EXISTS oauth_clients (
30
30
  id INTEGER PRIMARY KEY AUTOINCREMENT,
31
31
  name VARCHAR(255) NOT NULL,
@@ -38,7 +38,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
38
38
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
39
39
  updated_at TIMESTAMP
40
40
  )
41
- `);if(A)await f.unsafe(`
41
+ `);if(G)await x.unsafe(`
42
42
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
43
43
  id SERIAL PRIMARY KEY,
44
44
  user_id INTEGER NOT NULL,
@@ -51,7 +51,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
51
51
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
52
52
  updated_at TIMESTAMP
53
53
  )
54
- `);else if(C)await f.unsafe(`
54
+ `);else if(I)await x.unsafe(`
55
55
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
56
56
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
57
57
  user_id INTEGER NOT NULL,
@@ -64,7 +64,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
64
64
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
65
65
  updated_at TIMESTAMP NULL
66
66
  )
67
- `);else await f.unsafe(`
67
+ `);else await x.unsafe(`
68
68
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
69
69
  id INTEGER PRIMARY KEY AUTOINCREMENT,
70
70
  user_id INTEGER NOT NULL,
@@ -77,9 +77,9 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
77
77
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
78
78
  updated_at TIMESTAMP
79
79
  )
80
- `);if(await f.unsafe(`
80
+ `);if(await x.unsafe(`
81
81
  CREATE INDEX IF NOT EXISTS idx_oauth_access_tokens_token ON oauth_access_tokens(token)
82
- `),A)await f.unsafe(`
82
+ `),G)await x.unsafe(`
83
83
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
84
84
  id SERIAL PRIMARY KEY,
85
85
  access_token_id INTEGER NOT NULL,
@@ -88,7 +88,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
88
88
  expires_at TIMESTAMP,
89
89
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
90
90
  )
91
- `);else if(C)await f.unsafe(`
91
+ `);else if(I)await x.unsafe(`
92
92
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
93
93
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
94
94
  access_token_id INTEGER NOT NULL,
@@ -97,7 +97,7 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
97
97
  expires_at TIMESTAMP NULL,
98
98
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
99
99
  )
100
- `);else await f.unsafe(`
100
+ `);else await x.unsafe(`
101
101
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
102
102
  id INTEGER PRIMARY KEY AUTOINCREMENT,
103
103
  access_token_id INTEGER NOT NULL,
@@ -106,43 +106,101 @@ import E from"process";import{randomBytes as I}from"crypto";import{db as f}from"
106
106
  expires_at TIMESTAMP,
107
107
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
108
108
  )
109
- `);await f.unsafe(`
109
+ `);await x.unsafe(`
110
110
  CREATE INDEX IF NOT EXISTS idx_oauth_refresh_tokens_token ON oauth_refresh_tokens(token)
111
- `),x.success("OAuth tables ready")}catch(z){x.error("Failed to create OAuth tables",z),E.exit(1)}x.info("Ensuring password_resets table exists...");try{if(A)await f.unsafe(`
111
+ `),z.success("OAuth tables ready")}catch(F){z.error("Failed to create OAuth tables",F),J.exit(1)}z.info("Ensuring password_resets table exists...");try{if(G)await x.unsafe(`
112
112
  CREATE TABLE IF NOT EXISTS password_resets (
113
113
  id SERIAL PRIMARY KEY,
114
114
  email VARCHAR(255) NOT NULL,
115
115
  token VARCHAR(255) NOT NULL,
116
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
116
117
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
117
118
  )
118
- `);else if(C)await f.unsafe(`
119
+ `);else if(I)await x.unsafe(`
119
120
  CREATE TABLE IF NOT EXISTS password_resets (
120
121
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
121
122
  email VARCHAR(255) NOT NULL,
122
123
  token VARCHAR(255) NOT NULL,
124
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
123
125
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
124
126
  )
125
- `);else await f.unsafe(`
127
+ `);else await x.unsafe(`
126
128
  CREATE TABLE IF NOT EXISTS password_resets (
127
129
  id INTEGER PRIMARY KEY AUTOINCREMENT,
128
130
  email VARCHAR(255) NOT NULL,
129
131
  token VARCHAR(255) NOT NULL,
132
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
130
133
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
131
134
  )
132
- `);await f.unsafe(`
133
- CREATE INDEX IF NOT EXISTS idx_password_resets_email ON password_resets(email)
134
- `),x.success("Password resets table ready")}catch(z){x.error("Failed to create password_resets table",z),E.exit(1)}x.info("Creating personal access client...");try{if((await f.unsafe(`
135
- SELECT id FROM oauth_clients WHERE personal_access_client = ${R} LIMIT 1
135
+ `);try{await x.unsafe("ALTER TABLE password_resets ADD COLUMN expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP")}catch{}await x.unsafe(`
136
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_password_resets_email_unique ON password_resets(email)
137
+ `),z.success("Password resets table ready")}catch(F){z.error("Failed to create password_resets table",F),J.exit(1)}z.info("Ensuring email_verifications table exists...");try{if(G)await x.unsafe(`
138
+ CREATE TABLE IF NOT EXISTS email_verifications (
139
+ id SERIAL PRIMARY KEY,
140
+ user_id INTEGER NOT NULL,
141
+ token VARCHAR(255) NOT NULL,
142
+ expires_at TIMESTAMP NOT NULL,
143
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
144
+ )
145
+ `);else if(I)await x.unsafe(`
146
+ CREATE TABLE IF NOT EXISTS email_verifications (
147
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
148
+ user_id INTEGER NOT NULL,
149
+ token VARCHAR(255) NOT NULL,
150
+ expires_at TIMESTAMP NOT NULL,
151
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
152
+ )
153
+ `);else await x.unsafe(`
154
+ CREATE TABLE IF NOT EXISTS email_verifications (
155
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
156
+ user_id INTEGER NOT NULL,
157
+ token VARCHAR(255) NOT NULL,
158
+ expires_at TIMESTAMP NOT NULL,
159
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
160
+ )
161
+ `);await x.unsafe(`
162
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_email_verifications_user_id_unique ON email_verifications(user_id)
163
+ `);try{await x.unsafe(Z(K))}catch{}try{await x.unsafe(_(K))}catch{}z.success("Email verifications table ready")}catch(F){z.error("Failed to create email_verifications table",F),J.exit(1)}z.info("Ensuring webauthn_challenges table exists...");try{if(G)await x.unsafe(`
164
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
165
+ id SERIAL PRIMARY KEY,
166
+ user_id INTEGER NOT NULL,
167
+ challenge TEXT NOT NULL,
168
+ purpose VARCHAR(32) NOT NULL,
169
+ expires_at TIMESTAMP NOT NULL,
170
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
171
+ )
172
+ `);else if(I)await x.unsafe(`
173
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
174
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
175
+ user_id INTEGER NOT NULL,
176
+ challenge TEXT NOT NULL,
177
+ purpose VARCHAR(32) NOT NULL,
178
+ expires_at TIMESTAMP NOT NULL,
179
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
180
+ )
181
+ `);else await x.unsafe(`
182
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
183
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
184
+ user_id INTEGER NOT NULL,
185
+ challenge TEXT NOT NULL,
186
+ purpose VARCHAR(32) NOT NULL,
187
+ expires_at TIMESTAMP NOT NULL,
188
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
189
+ )
190
+ `);await x.unsafe(`
191
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_webauthn_challenges_user_purpose ON webauthn_challenges(user_id, purpose)
192
+ `),z.success("WebAuthn challenges table ready")}catch(F){z.error("Failed to create webauthn_challenges table",F),J.exit(1)}z.info("Creating personal access client...");try{if((await x.unsafe(`
193
+ SELECT id FROM oauth_clients WHERE personal_access_client = ${f} LIMIT 1
136
194
  `))?.length>0)console.log(`
137
- \u2713 Personal access client already exists`);else{let F=I(40).toString("hex");if(A)await f.unsafe(`
195
+ \u2713 Personal access client already exists`);else{let R=U(40).toString("hex"),N=await W(R,{algorithm:"bcrypt"});if(G)await x.unsafe(`
138
196
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
139
197
  VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
140
- `,["Personal Access Client",F,"local","http://localhost",!0,!1,!1]);else await f.unsafe(`
198
+ `,["Personal Access Client",N,"local","http://localhost",!0,!1,!1]);else await x.unsafe(`
141
199
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
142
- VALUES (?, ?, ?, ?, ?, ?, ?, ${O})
143
- `,["Personal Access Client",F,"local","http://localhost",1,0,0]);console.log(`
144
- \u2713 Personal access client created successfully`)}}catch(z){console.error("Failed to create personal access client:",z),E.exit(1)}console.log(`
200
+ VALUES (?, ?, ?, ?, ?, ?, ?, ${$})
201
+ `,["Personal Access Client",N,"local","http://localhost",1,0,0]);console.log(`
202
+ \u2713 Personal access client created successfully`)}}catch(F){console.error("Failed to create personal access client:",F),J.exit(1)}console.log(`
145
203
  \u2713 Authentication setup complete!`);console.log(`
146
204
  Features enabled:`);console.log(" - Token hashing (SHA-256) for secure storage");console.log(" - Refresh tokens for seamless token renewal");console.log(" - Scope-based authorization");console.log(" - Password reset flow");console.log(`
147
205
  Next steps:`);console.log(" 1. Use createToken(userId, name, scopes) to generate tokens");console.log(" 2. Use refreshToken(token) to exchange refresh tokens");console.log(' 3. Use the "auth" middleware to protect routes');console.log(" 4. Use tokenCan(scope) for authorization checks");console.log(" 5. POST /password/forgot to request password reset");console.log(` 6. POST /password/reset to reset password with token
148
- `);E.exit(0);
206
+ `);J.exit(0);
@@ -0,0 +1,102 @@
1
+ // @bun
2
+ import"../chunk-4qzb8g3z.js";import{existsSync as x,mkdirSync as X,readdirSync as H,readFileSync as R,writeFileSync as h}from"fs";import{homedir as u}from"os";import{join as Z}from"path";var $=Z(process.cwd(),"content/blog"),F=Z($,".theme.css"),O=null;async function S(){if(!O)O=(async()=>{let z=[Z(u(),"Code/Tools/bunpress/packages/bunpress/dist/src/index.js"),Z(process.cwd(),"pantry/@stacksjs/bunpress/dist/src/index.js"),"@stacksjs/bunpress"];for(let A of z)try{if(A.startsWith("@")||x(A))return await import(A)}catch{}return null})();return O}function V(z){return String(z).replace(/[&<>"]/g,(A)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"})[A])}function B(z){return String(z).replace(/[&<>"']/g,(A)=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&apos;"})[A])}function D(z,A){return`${z.replace(/\/$/,"")}/blog/${A}`}function g(z){let A=new Date(z);return Number.isNaN(A.getTime())?z:A.toUTCString()}function c(z){let A=z||"https://stacksjs.com",Q=q().slice(0,50).map((K)=>{let W=D(A,K.slug);return` <item>
3
+ <title>${B(K.fm.title||K.slug)}</title>
4
+ <link>${B(W)}</link>
5
+ <guid>${B(W)}</guid>
6
+ <pubDate>${B(g(K.fm.date))}</pubDate>
7
+ <description>${B(K.fm.description||"")}</description>
8
+ </item>`}).join(`
9
+ `);return`<?xml version="1.0" encoding="UTF-8"?>
10
+ <rss version="2.0">
11
+ <channel>
12
+ <title>The Stacks Blog</title>
13
+ <link>${B(`${A}/blog`)}</link>
14
+ <description>Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.</description>
15
+ ${Q}
16
+ </channel>
17
+ </rss>`}function f(z){let A=z||"https://stacksjs.com";return`<?xml version="1.0" encoding="UTF-8"?>
18
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
19
+ ${[`${A}/blog`,...q().map((Q)=>D(A,Q.slug))].map((Q)=>` <url><loc>${B(Q)}</loc></url>`).join(`
20
+ `)}
21
+ </urlset>`}function d(z){let A=z.match(/^---\n([\s\S]*?)\n---\n?([\s\S]*)$/);if(!A)return{data:{},body:z};let J={};for(let Q of A[1].split(`
22
+ `)){let K=Q.indexOf(":");if(K===-1)continue;let W=Q.slice(0,K).trim(),G=Q.slice(K+1).trim();if(G.startsWith('"')&&G.endsWith('"')||G.startsWith("'")&&G.endsWith("'"))G=G.slice(1,-1);J[W]=G}return{data:J,body:A[2]}}function E(z){if(!z)return"";let A=new Date(z);if(Number.isNaN(A.getTime()))return z;return`${["January","February","March","April","May","June","July","August","September","October","November","December"][A.getUTCMonth()]} ${A.getUTCDate()}, ${A.getUTCFullYear()}`}function I(){return`<script>
23
+ (function () {
24
+ function ok(theme) {
25
+ return theme === 'light' || theme === 'colored' || theme === 'dark'
26
+ }
27
+
28
+ var queryTheme = ''
29
+ try {
30
+ queryTheme = new URLSearchParams(location.search).get('theme') || ''
31
+ }
32
+ catch {}
33
+
34
+ var savedTheme = ''
35
+ try {
36
+ savedTheme = localStorage.getItem('stacks-blog-theme') || ''
37
+ }
38
+ catch {}
39
+
40
+ var theme = ok(queryTheme) ? queryTheme : (ok(savedTheme) ? savedTheme : 'colored')
41
+ document.documentElement.setAttribute('data-theme', theme)
42
+ window.stxBlogTheme = function (nextTheme) {
43
+ try {
44
+ localStorage.setItem('stacks-blog-theme', nextTheme)
45
+ }
46
+ catch {}
47
+ document.documentElement.setAttribute('data-theme', nextTheme)
48
+ }
49
+ })()
50
+ </script>
51
+ <div class="blog-theme-toggle" role="group" aria-label="Theme">
52
+ <button type="button" data-t="colored" title="Park (default)" aria-label="Park theme" onclick="stxBlogTheme('colored')">\uD83C\uDF32</button>
53
+ <button type="button" data-t="light" title="Light" aria-label="Light theme" onclick="stxBlogTheme('light')">\u2600</button>
54
+ <button type="button" data-t="dark" title="Dark" aria-label="Dark theme" onclick="stxBlogTheme('dark')">\uD83C\uDF19</button>
55
+ </div>`}function P(){return`<div class="blog-landscape" aria-hidden="true">
56
+ <span class="ridge"></span>
57
+ <span class="river"></span>
58
+ <p class="colophon">Built with Stacks \xB7 TypeScript &amp; Bun \xB7 <a href="/blog/feed.xml">RSS</a></p>
59
+ </div>`}function k(z,A){let J=x(F)?R(F,"utf-8"):"",Q=z.defaultConfig.markdown?.css||"";return{...z.defaultConfig,title:A.title||"Stacks Blog",description:A.description||"The official Stacks blog.",docsDir:$,theme:"vitepress",markdown:{...z.defaultConfig.markdown,css:`${Q}
60
+ ${J}`},themeConfig:{siteTitle:"Stacks Blog",nav:[{text:"Blog",link:"/blog"},{text:"Docs",link:"/docs"},{text:"GitHub",link:"https://github.com/stacksjs/stacks"}]}}}function q(){if(!x($))return[];return H($).filter((z)=>z.endsWith(".md")).map((z)=>{let{data:A}=d(R(Z($,z),"utf-8"));return{slug:z.replace(/\.md$/,""),fm:A}}).filter((z)=>!!z.fm.title&&!!z.fm.date).sort((z,A)=>{let J=z.fm.featured==="true"?1:0,Q=A.fm.featured==="true"?1:0;if(J!==Q)return Q-J;return(A.fm.date||"").localeCompare(z.fm.date||"")})}async function n(z){return z.wrapInLayout(I()+`
61
+ <a class="blog-back" href="/blog">\u2190 All posts</a>
62
+ <div class="blog-404">
63
+ <span class="blog-404-art" aria-hidden="true"></span>
64
+ <h1>You've wandered off the trail</h1>
65
+ <p>This post isn't on the map (or it moved camp). Head back to <a href="/blog">the trailhead</a>.</p>
66
+ </div>`+P(),k(z,{title:"Not found"}),"/blog","page")}async function y(z,A,J){let Q=Z($,`${A}.md`);if(!x(Q))return null;let K=R(Q,"utf-8"),{html:W,frontmatter:G}=await z.markdownToHtml(K,$);if(!G.title||!G.date)return null;let Y=V((G.author||"S").charAt(0).toUpperCase()),L=`
67
+ <a class="blog-back" href="/blog">\u2190 All posts</a>
68
+ <div class="blog-post-head">
69
+ <h1>${V(G.title||A)}</h1>
70
+ <p class="blog-post-meta">
71
+ <span class="author">${V(G.author||"The Stacks Team")}</span>
72
+ <span class="dot">\xB7</span>
73
+ <time>${V(E(G.date))}</time>
74
+ </p>
75
+ ${G.poster?`<figure class="blog-post-poster"><img src="${V(G.poster)}" alt="${V(G.title||"")}"></figure>`:""}
76
+ </div>`,w=G.authorBio?`<aside class="blog-author-card">
77
+ <div class="avatar">${Y}</div>
78
+ <div><span class="name">${V(G.author||"The Stacks Team")}</span><p class="bio">${V(G.authorBio)}</p></div>
79
+ </aside>`:"",v=`${J}/blog/${A}`,j=`
80
+ <div class="blog-share">
81
+ <span class="blog-share-label">Share</span>
82
+ <a href="https://twitter.com/intent/tweet?url=${encodeURIComponent(v)}&text=${encodeURIComponent(G.title||"")}" target="_blank" rel="noreferrer">X / Twitter</a>
83
+ <a href="https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(v)}" target="_blank" rel="noreferrer">LinkedIn</a>
84
+ </div>`,_=q().filter((M)=>M.slug!==A).slice(0,3),U=_.length?`<nav class="blog-more">
85
+ <h2>More from the blog</h2>
86
+ <ul>${_.map((M)=>`<li><a href="/blog/${V(M.slug)}">${V(M.fm.title||M.slug)}</a></li>`).join("")}</ul>
87
+ </nav>`:"";return z.wrapInLayout(I()+L+W+w+j+U+P(),k(z,G),`/blog/${A}`,"page")}async function N(z){let Q=`
88
+ <div class="blog-listing-head">
89
+ <span class="sign" aria-hidden="true"></span>
90
+ <h1>The Stacks Blog</h1>
91
+ <p>Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.</p>
92
+ </div>
93
+ <div class="blog-cards">${q().map((K)=>{let W=K.fm.featured==="true",G=K.fm.poster?`<div class="blog-card-media"><img src="${V(K.fm.poster)}" alt="" loading="lazy"></div>`:"";return`<a class="blog-card${W?" is-featured":""}" href="/blog/${V(K.slug)}">
94
+ ${G}
95
+ <div>
96
+ ${W?'<span class="blog-card-flag">Featured</span>':""}
97
+ <h2 class="blog-card-title">${V(K.fm.title||K.slug)}</h2>
98
+ <p class="blog-card-excerpt">${V((K.fm.description||"").slice(0,180))}</p>
99
+ <div class="blog-card-meta">${V(K.fm.author||"The Stacks Team")} \xB7 ${V(E(K.fm.date))}</div>
100
+ </div>
101
+ </a>`}).join(`
102
+ `)||"<p>No posts yet.</p>"}</div>`;return z.wrapInLayout(I()+Q+P(),k(z,{title:"Blog",description:"The official Stacks blog."}),"/blog","page")}function C(z,A){let J={...k(z,{title:"The Stacks Blog"}),sitemap:{enabled:!0,baseUrl:`${A}/blog`}};return typeof z.buildRssFeed==="function"?z.buildRssFeed($,J,{enabled:!0,title:"The Stacks Blog",description:"Notes from building a full-stack TypeScript framework whose only dependencies are TypeScript and Bun.",maxItems:50}):Promise.resolve(c(A))}function T(z,A){let J={...k(z,{title:"Blog"}),sitemap:{enabled:!0,baseUrl:`${A}/blog`}};return typeof z.buildSitemap==="function"?z.buildSitemap($,J):Promise.resolve(f(A))}async function m(z){if(z.method!=="GET"&&z.method!=="HEAD")return null;let A=new URL(z.url),{pathname:J}=A,Q=J==="/blog/feed.xml",K=J==="/blog/sitemap.xml",W=J==="/blog"||J==="/blog/"||/^\/blog\/[^/.]+$/.test(J);if(!Q&&!K&&!W)return null;let G=await S();if(!G)return null;let Y=(v,j=200)=>new Response(v,{status:j,headers:{"Content-Type":"text/html; charset=utf-8"}});if(Q)return new Response(await C(G,A.origin),{headers:{"Content-Type":"application/rss+xml; charset=utf-8"}});if(K)return new Response(await T(G,A.origin),{headers:{"Content-Type":"application/xml; charset=utf-8"}});if(J==="/blog"||J==="/blog/")return Y(await N(G));let L=J.replace(/^\/blog\//,"").replace(/\/$/,""),w=await y(G,L,A.origin);return w?Y(w):Y(await n(G),404)}async function r(z={outDir:"dist/blog"}){let A=z.outDir||"dist/blog",J=(z.baseUrl||"").replace(/\/$/,""),Q=await S();if(!Q)throw Error("[blog] BunPress not found \u2014 cannot build the blog.");X(A,{recursive:!0});let K=(G,Y)=>{let L=Z(A,G);X(Z(L,".."),{recursive:!0}),h(L,Y,"utf-8")};K("index.html",await N(Q));let W=q();for(let G of W){let Y=await y(Q,G.slug,J);if(Y)K(Z(G.slug,"index.html"),Y)}K("feed.xml",await C(Q,J)),K("sitemap.xml",await T(Q,J)),console.log(`[blog] built ${W.length} post(s) + listing, feed.xml, sitemap.xml \u2192 ${A}`)}export{m as renderBlog,r as buildBlog};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var{$:G}=globalThis.Bun;import{existsSync as H,readFileSync as K,statSync as L}from"fs";import M from"process";import{dim as z,italic as A,log as w}from"@stacksjs/cli";import{corePath as N}from"@stacksjs/path";import{glob as Q}from"@stacksjs/storage";import{ExitCode as R}from"@stacksjs/types";w.info("Building core packages");var T=(await Q([N("*")],{onlyFiles:!1})).sort(),I=T.filter((q)=>{if(!H(q)||!L(q).isDirectory())return!1;let D=`${q}/package.json`;if(!H(D))return!1;try{return typeof JSON.parse(K(D,"utf8")).scripts?.build==="string"}catch(J){return w.warn(`Skipping ${A(z(q))}: package.json could not be read`),!1}});if(I.length===0)w.info("No core packages found"),M.exit(R.FatalError);var B=[];for(let q of I){w.info(`\uD83C\uDFD7\uFE0F Building ${A(z(q))}`);try{G.cwd(q),await G`bun run build`,w.success(`${A(z(q))} built`)}catch(D){w.warn(`Failed to build ${A(z(q))}, skipping...`),B.push(q)}console.log("")}if(B.length>0){w.warn(`${B.length} package(s) failed to build:`);for(let q of B)w.warn(` - ${q}`)}
2
+ var{$:J}=globalThis.Bun;import{existsSync as L,readFileSync as Q,statSync as V}from"fs";import{basename as W}from"path";import X from"process";import{dim as w,italic as z,log as v}from"@stacksjs/cli";import{feature as Y}from"@stacksjs/config";import{corePath as Z}from"@stacksjs/path";import{glob as D}from"@stacksjs/storage";import{ExitCode as K}from"@stacksjs/types";v.info("Building core packages");var R={cms:"cms",commerce:"commerce",queue:"queue",realtime:"realtime"},U=(await D([Z("*")],{onlyFiles:!1})).sort(),M=U.filter((q)=>{if(!L(q)||!V(q).isDirectory())return!1;let H=`${q}/package.json`;if(!L(H))return!1;let N=W(q),I=R[N];if(I&&!Y(I))return v.info(`Skipping ${z(w(q))} \u2014 feature '${I}' is disabled`),!1;try{return typeof JSON.parse(Q(H,"utf8")).scripts?.build==="string"}catch(O){return v.warn(`Skipping ${z(w(q))}: package.json could not be read`),!1}});if(M.length===0)v.info("No core packages found"),X.exit(K.FatalError);var B=[];for(let q of M){v.info(`\uD83C\uDFD7\uFE0F Building ${z(w(q))}`);try{J.cwd(q),await J`bun run build`,v.success(`${z(w(q))} built`)}catch(H){v.warn(`Failed to build ${z(w(q))}, skipping...`),B.push(q)}console.log("")}if(B.length>0){v.warn(`${B.length} package(s) failed to build:`);for(let q of B)v.warn(` - ${q}`)}
@@ -0,0 +1,9 @@
1
+ // @bun
2
+ import{pb as V}from"../../chunk-4qzb8g3z.js";import{copyFileSync as j,existsSync as _,mkdirSync as w,readdirSync as D,readFileSync as g,rmSync as P,statSync as S,writeFileSync as N}from"fs";import{join as W}from"path";import F from"process";import{publicPath as C,resourcesPath as M,storagePath as v}from"@stacksjs/path";var y=F.argv.includes("--verbose")||F.argv.includes("-v");function Z(...J){if(y)console.log("\uD83D\uDD0D",...J)}async function b(){try{let{generateSignalsRuntime:J}=await import("@stacksjs/stx/signals");return`<script>
3
+ ${J()}
4
+ </script>`}catch{return console.warn("Could not load STX signals runtime"),""}}function A(J,z){if(!_(z))w(z,{recursive:!0});for(let Q of D(J)){if(Q===".DS_Store")continue;let T=W(J,Q),X=W(z,Q);if(S(T).isDirectory())A(T,X);else j(T,X)}}async function h(J={}){let z=J.outDir??v("framework/frontend-dist");if(_(z))P(z,{recursive:!0});w(z,{recursive:!0}),w(W(z,"assets"),{recursive:!0});let Q=M("views/index.stx");if(_(Q)){let q=g(Q,"utf-8"),f=q.match(/<script server>([\s\S]*?)<\/script>/),$={};if(f){let L=f[1]??"";try{let I=[...L.matchAll(/(?:const|let|var)\s+(\w+)\s*=/g)].map((K)=>K[1]).filter((K)=>Boolean(K));$=Function(`${L}
5
+ return { ${I.join(", ")} }`)()}catch(I){Z(` Server block evaluation failed: ${I}, falling back to regex`);let G=L.matchAll(/const\s+(\w+)\s*=\s*(?:'([^']*)'|"([^"]*)"|([\d.]+))/g);for(let K of G){let U=K[1];if(U)$[U]=K[2]??K[3]??K[4]}}q=q.replace(/<script server>[\s\S]*?<\/script>\s*/,"")}q=q.replace(/\{\{\s*(\w+)\s*\}\}/g,(L,I)=>{let G=$[I];return G!==void 0&&G!==null?String(G):""});let R=/@foreach\s*\((\w+)\s+as\s+(\w+)\)([\s\S]*?)@endforeach/g;if(q=q.replace(R,(L,I,G,K)=>{let U=$[I];if(!Array.isArray(U)||U.length===0)return"";let B="";for(let H of U){let Y=K;Y=Y.replace(new RegExp(`\\{\\{\\s*${G}\\.(\\w+)\\s*\\}\\}`,"g"),(k,E)=>{let O=H[E];return O!==void 0&&O!==null?String(O):""}),Y=Y.replace(new RegExp(`\\{!!\\s*${G}\\.(\\w+)\\s*!!\\}`,"g"),(k,E)=>{let O=H[E];return O!==void 0&&O!==null?String(O):""}),B+=Y}return B}),q=q.replace(/^\s*@extends\([^)]+\)\s*$/gm,"").replace(/^\s*@include\([^)]+\)\s*$/gm,"").replace(/^\s*@section\('title',\s*['"][^'"]*['"]\)\s*$/gm,"").replace(/^\s*@section\('(?:content|footer)'\)\s*$/gm,"").replace(/^\s*@endsection\s*$/gm,""),/data-stx-scope|@model|@show|@text|@class|@style|@bind:|@if=|@for=/.test(q)){let L=await b();if(L){let I=q.match(/<body[^>]*>/);if(I){let G=(q.indexOf(I[0])??0)+I[0].length;q=q.slice(0,G)+`
6
+ `+L+q.slice(G)}else q=L+`
7
+ `+q;Z(" Injected STX signals runtime for client-side reactivity")}}N(W(z,"index.html"),q),Z(" Built index.html from STX template")}else N(W(z,"index.html"),`<!DOCTYPE html>
8
+ <html><head><title>Stacks</title></head>
9
+ <body><h1>Welcome to Stacks</h1></body></html>`);let T=M("assets");if(_(T))A(T,W(z,"assets")),Z(" Copied resources/assets directory");let X=C();if(_(X))A(X,z),Z(" Copied public/ directory");return z}if(import.meta.main){let J=await h();console.log(`\u2713 Built frontend static site \u2192 ${J}`)}export{h as buildFrontendStatic};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{runCommand as r}from"@stacksjs/cli";import{frameworkPath as m}from"@stacksjs/path";await r("bun run build",{cwd:m("views/web")});
2
+ import{runCommand as b}from"@stacksjs/cli";import{frameworkPath as x,projectPath as q}from"@stacksjs/path";var z=q("build.ts");if(await Bun.file(z).exists())await b("bun build.ts",{cwd:q()});else await b("bun run build",{cwd:x("views/web")});
package/dist/src/build.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{Oa as B}from"../chunk-zbhjh5sz.js";import"../chunk-v0wnrnaa.js";import"../chunk-n2fd1d0m.js";import"../chunk-s735m9mg.js";import"../chunk-sxp97zys.js";import"../chunk-jbvvb45k.js";import{NpmScript as z}from"@stacksjs/enums";import{log as x}from"@stacksjs/logging";import{hasComponents as D,hasFunctions as G}from"@stacksjs/storage";import{runNpmScript as A}from"@stacksjs/utils";async function H(q){if(q.components)await I(q);else if(q.webComponents||q.elements)await E(q);else if(q.functions)await O(q);else if(q.docs)await K(q);else if(q.stacks)await M(q);await B()}async function W(q){return await H(q)}async function I(q){await A(z.GenerateEntries,q),await J(q),await E(q)}async function J(q){if(D())x.info("Building your component library..."),await A(z.BuildComponents,q),x.success("Your component library was built successfully");else x.warn("No components found."),x.info("Before you can build components,"),x.info("you need to have created some in the ./components folder.")}async function E(q){if(x.info("Building your component library for production use & npm/CDN distribution..."),D())await A(z.BuildWebComponents,q),x.success("Your Web Component library was built successfully");else x.info("No components found.")}async function K(q){x.info("Building the documentation site..."),await A(z.BuildDocs,q),x.success("Docs built successfully")}async function M(q){x.info("Building the Stacks Framework..."),await A(z.BuildStacks,q),x.success("Stacks built successfully")}async function O(q){if(G())x.info("Building your functions library for production usages..."),x.info("Production usages include: manual npm distribution and/or CDN distribution"),await A(z.BuildFunctions,q),x.success("Functions library built successfully");else x.info("No functions found")}export{E as webComponentLibrary,J as vueComponentLibrary,M as stacks,H as invoke,O as functionsLibrary,K as docs,I as componentLibraries,W as build};
2
+ import{Va as B}from"../chunk-9x17v4x2.js";import"../chunk-e8505qz8.js";import"../chunk-ag4fy7cx.js";import"../chunk-s735m9mg.js";import"../chunk-rzhs51h1.js";import"../chunk-4qzb8g3z.js";import{NpmScript as z}from"@stacksjs/enums";import{log as x}from"@stacksjs/logging";import{hasComponents as D,hasFunctions as G}from"@stacksjs/storage";import{runNpmScript as A}from"@stacksjs/utils";async function H(q){if(q.components)await I(q);else if(q.webComponents||q.elements)await E(q);else if(q.functions)await O(q);else if(q.docs)await K(q);else if(q.stacks)await M(q);await B()}async function W(q){return await H(q)}async function I(q){await A(z.GenerateEntries,q),await J(q),await E(q)}async function J(q){if(D())x.info("Building your component library..."),await A(z.BuildComponents,q),x.success("Your component library was built successfully");else x.warn("No components found."),x.info("Before you can build components,"),x.info("you need to have created some in the ./components folder.")}async function E(q){if(x.info("Building your component library for production use & npm/CDN distribution..."),D())await A(z.BuildWebComponents,q),x.success("Your Web Component library was built successfully");else x.info("No components found.")}async function K(q){x.info("Building the documentation site..."),await A(z.BuildDocs,q),x.success("Docs built successfully")}async function M(q){x.info("Building the Stacks Framework..."),await A(z.BuildStacks,q),x.success("Stacks built successfully")}async function O(q){if(G())x.info("Building your functions library for production usages..."),x.info("Production usages include: manual npm distribution and/or CDN distribution"),await A(z.BuildFunctions,q),x.success("Functions library built successfully");else x.info("No functions found")}export{E as webComponentLibrary,J as vueComponentLibrary,M as stacks,H as invoke,O as functionsLibrary,K as docs,I as componentLibraries,W as build};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import{Fa as a,Ga as b}from"../chunk-2gh7kgpc.js";import"../chunk-jbvvb45k.js";export{a as invoke,b as commit};
2
+ import{Ma as a,Na as b}from"../chunk-p601xr03.js";import"../chunk-4qzb8g3z.js";export{a as invoke,b as commit};
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- import A from"process";import{log as q}from"@stacksjs/cli";import{seed as C}from"@stacksjs/database";var D=Date.now();try{let y=await C({verbose:!0}),B=Date.now()-D;if(y.failed>0){q.warn(""),q.warn(`Seeding completed with ${y.failed} failure(s):`);for(let z of y.results)if(!z.success)q.error(` - ${z.model}: ${z.error}`);q.info(""),q.info("Note: Failed models may have schema mismatches or invalid factory functions."),q.info("Tip: Run `./buddy migrate:fresh` to ensure schema is up to date.")}q.info(""),q.success(`Seeding completed in ${B}ms`),q.info(` Total models: ${y.total}`),q.info(` Successful: ${y.successful}`),q.info(` Failed: ${y.failed}`),A.exit(0)}catch(y){q.error("Seeding failed catastrophically:",y),A.exit(1)}
2
+ import A from"process";import{log as q}from"@stacksjs/cli";import{seed as D}from"@stacksjs/database";var B=A.argv.slice(2),F=B.includes("--allow-protected")||B.includes("--allowProtected"),G=B.includes("--fresh"),H=Date.now();try{let y=await D({verbose:!0,fresh:G,allowProtected:F}),C=Date.now()-H;if(y.failed>0){q.warn(""),q.warn(`Seeding completed with ${y.failed} failure(s):`);for(let z of y.results)if(!z.success)q.error(` - ${z.model}: ${z.error}`);q.info(""),q.info("Note: Failed models may have schema mismatches or invalid factory functions."),q.info("Tip: Run `./buddy migrate:fresh` to ensure schema is up to date.")}q.info(""),q.success(`Seeding completed in ${C}ms`),q.info(` Total models: ${y.total}`),q.info(` Successful: ${y.successful}`),q.info(` Failed: ${y.failed}`),A.exit(0)}catch(y){q.error("Seeding failed catastrophically:",y),A.exit(1)}