@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.
- package/LICENSE.md +21 -0
- package/dist/action.d.ts +104 -17
- package/dist/blog.d.ts +12 -0
- package/dist/build/frontend-static.d.ts +16 -0
- package/dist/chunk-00qp27jy.js +93 -0
- package/dist/{chunk-jd1yzkq5.js → chunk-23thftnv.js} +1 -1
- package/dist/{chunk-jbvvb45k.js → chunk-4qzb8g3z.js} +1 -1
- package/dist/{chunk-s03z9zn3.js → chunk-5dfz9en9.js} +2 -2
- package/dist/{chunk-3beht8ja.js → chunk-5hwp0frq.js} +1 -1
- package/dist/{chunk-cqedfbaf.js → chunk-5pwpk005.js} +2 -2
- package/dist/chunk-604jy79b.js +5 -0
- package/dist/{chunk-yh15ydty.js → chunk-63swek9d.js} +2 -2
- package/dist/chunk-67am4dae.js +688 -0
- package/dist/{chunk-gt77jmb5.js → chunk-8gbewxns.js} +1 -1
- package/dist/chunk-8r76qydb.js +240 -0
- package/dist/{chunk-zbhjh5sz.js → chunk-9x17v4x2.js} +2 -2
- package/dist/chunk-aazd6qpv.js +3 -0
- package/dist/{chunk-n2fd1d0m.js → chunk-ag4fy7cx.js} +1 -1
- package/dist/{chunk-2qchdrf9.js → chunk-badehrwa.js} +1 -1
- package/dist/chunk-dbz9dp2h.js +3 -0
- package/dist/{chunk-v0wnrnaa.js → chunk-e8505qz8.js} +2 -2
- package/dist/chunk-jv7ry09n.js +3 -0
- package/dist/{chunk-w418anbq.js → chunk-jve1p4dz.js} +2 -2
- package/dist/chunk-mcwfmqzb.js +283 -0
- package/dist/chunk-n24m8prb.js +3 -0
- package/dist/{chunk-d5yxdz7e.js → chunk-nm9h5rye.js} +2 -2
- package/dist/{chunk-h0hfqr1p.js → chunk-ny1racy0.js} +2 -2
- package/dist/{chunk-2gh7kgpc.js → chunk-p601xr03.js} +1 -1
- package/dist/{chunk-yvva7qsg.js → chunk-pqnzp7x8.js} +2 -2
- package/dist/chunk-rj1cbghx.js +17 -0
- package/dist/chunk-rzhs51h1.js +3 -0
- package/dist/{chunk-tzx3h4r8.js → chunk-sp5cjdhd.js} +213 -76
- package/dist/chunk-tqax3gbq.js +16 -0
- package/dist/{chunk-c8qt2xst.js → chunk-vsj8ns4p.js} +1 -1
- package/dist/{chunk-zaw01rqz.js → chunk-x8nrbsk1.js} +2 -2
- package/dist/dev/dashboard-utils.d.ts +19 -1
- package/dist/dev/migrate-watcher.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/make.d.ts +19 -0
- package/dist/queue/dlq-purge.d.ts +1 -0
- package/dist/queue/dlq-retry.d.ts +1 -0
- package/dist/queue/dlq.d.ts +1 -0
- package/dist/queue/list.d.ts +1 -0
- package/dist/queue/pause.d.ts +1 -0
- package/dist/queue/quarantine.d.ts +1 -0
- package/dist/queue/resume.d.ts +1 -0
- package/dist/queue/unquarantine.d.ts +1 -0
- package/dist/src/action.js +1 -1
- package/dist/src/actions.js +1 -1
- package/dist/src/add.js +1 -1
- package/dist/src/ai/request-model-access.js +1 -1
- package/dist/src/auth/setup.js +82 -24
- package/dist/src/blog.js +102 -0
- package/dist/src/build/core.js +1 -1
- package/dist/src/build/frontend-static.js +9 -0
- package/dist/src/build/views.js +1 -1
- package/dist/src/build.js +1 -1
- package/dist/src/commit.js +1 -1
- package/dist/src/database/seed.js +1 -1
- package/dist/src/deploy/index.js +38 -45
- package/dist/src/dev/api.js +4 -4
- package/dist/src/dev/dashboard-globals.js +1 -1
- package/dist/src/dev/dashboard-utils.js +1 -1
- package/dist/src/dev/dashboard.js +6 -6
- package/dist/src/dev/docs.js +1 -1
- package/dist/src/dev/index.js +1 -1
- package/dist/src/dev/migrate-watcher.js +2 -0
- package/dist/src/dev/views.js +1 -1
- package/dist/src/discover-packages.js +1 -1
- package/dist/src/examples.js +1 -1
- package/dist/src/generate/component-meta.js +1 -1
- package/dist/src/generate/env-files.js +1 -1
- package/dist/src/generate/ide-helpers.js +1 -1
- package/dist/src/generate/index.js +1 -1
- package/dist/src/generate/lib-entries.js +1 -1
- package/dist/src/generate/vscode-custom-data.js +1 -1
- package/dist/src/helpers/component-meta.js +1 -1
- package/dist/src/helpers/index.js +1 -1
- package/dist/src/helpers/lib-entries.js +1 -1
- package/dist/src/helpers/package-json.js +1 -1
- package/dist/src/helpers/utils.js +1 -1
- package/dist/src/helpers/vscode-custom-data.js +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/key-generate.js +1 -1
- package/dist/src/make-command.js +1 -1
- package/dist/src/make-job.js +1 -1
- package/dist/src/make-policy.js +1 -1
- package/dist/src/make-resource.js +1 -1
- package/dist/src/make.js +1 -1
- package/dist/src/migrate/fresh.js +1 -1
- package/dist/src/orm/base.js +1 -1
- package/dist/src/queue/dlq-purge.js +2 -0
- package/dist/src/queue/dlq-retry.js +2 -0
- package/dist/src/queue/dlq.js +5 -0
- package/dist/src/queue/failed.js +4 -4
- package/dist/src/queue/list.js +5 -0
- package/dist/src/queue/pause.js +2 -0
- package/dist/src/queue/quarantine.js +3 -0
- package/dist/src/queue/resume.js +2 -0
- package/dist/src/queue/unquarantine.js +2 -0
- package/dist/src/release.js +1 -1
- package/dist/src/run-action.js +1 -1
- package/dist/src/scaffold-crud.js +1 -1
- package/dist/src/serve/api.js +1 -1
- package/dist/src/setup/index.js +1 -1
- package/dist/src/setup/ssl.js +1 -1
- package/dist/src/stacks.js +1 -1
- package/dist/src/templates.js +1 -1
- package/dist/src/types.js +1 -1
- package/dist/src/upgrade/dependencies.js +1 -1
- package/dist/src/upgrade/framework-utils.js +1 -1
- package/dist/src/upgrade/framework.js +5 -5
- package/dist/src/upgrade/index.js +1 -1
- package/dist/src/upgrade.js +1 -1
- package/dist/upgrade/framework-utils.d.ts +48 -0
- package/package.json +18 -18
- package/dist/chunk-2kaj93p5.js +0 -3
- package/dist/chunk-3086k7zk.js +0 -184
- package/dist/chunk-4fz2qb8b.js +0 -17
- package/dist/chunk-4p0rjazd.js +0 -101
- package/dist/chunk-77pta9ww.js +0 -93
- package/dist/chunk-d4srk6ma.js +0 -3
- package/dist/chunk-h5rff0v9.js +0 -658
- package/dist/chunk-kr2k0h74.js +0 -16
- package/dist/chunk-kzhgexj4.js +0 -3
- package/dist/chunk-sxp97zys.js +0 -3
- 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
|
|
3
|
+
export{L as pa};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
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
|
|
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[]):
|
|
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
|
+
|
package/dist/src/action.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
2
|
+
import{cb as a}from"../chunk-aazd6qpv.js";import"../chunk-4qzb8g3z.js";export{a as Action};
|
package/dist/src/actions.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
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{
|
|
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-
|
|
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();
|
package/dist/src/auth/setup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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
|
|
80
|
+
`);if(await x.unsafe(`
|
|
81
81
|
CREATE INDEX IF NOT EXISTS idx_oauth_access_tokens_token ON oauth_access_tokens(token)
|
|
82
|
-
`),
|
|
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(
|
|
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
|
|
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
|
|
109
|
+
`);await x.unsafe(`
|
|
110
110
|
CREATE INDEX IF NOT EXISTS idx_oauth_refresh_tokens_token ON oauth_refresh_tokens(token)
|
|
111
|
-
`),
|
|
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(
|
|
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
|
|
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
|
|
133
|
-
CREATE INDEX IF NOT EXISTS
|
|
134
|
-
`),
|
|
135
|
-
|
|
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
|
|
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",
|
|
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 (?, ?, ?, ?, ?, ?, ?, ${
|
|
143
|
-
`,["Personal Access Client",
|
|
144
|
-
\u2713 Personal access client created successfully`)}}catch(
|
|
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
|
-
`);
|
|
206
|
+
`);J.exit(0);
|
package/dist/src/blog.js
ADDED
|
@@ -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)=>({"&":"&","<":"<",">":">",'"':"""})[A])}function B(z){return String(z).replace(/[&<>"']/g,(A)=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[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 & 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};
|
package/dist/src/build/core.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var{$:
|
|
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};
|
package/dist/src/build/views.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{runCommand as
|
|
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{
|
|
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};
|
package/dist/src/commit.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{
|
|
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
|
|
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)}
|