@stacksjs/actions 0.70.87 → 0.70.90

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/action.js +78 -2
  2. package/dist/actions.js +2 -2
  3. package/dist/add.js +20 -2
  4. package/dist/ai/request-model-access.js +10 -2
  5. package/dist/auth/client.js +44 -3
  6. package/dist/auth/prune.js +35 -2
  7. package/dist/auth/setup.js +152 -36
  8. package/dist/auth/token.js +10 -2
  9. package/dist/blog-admin.d.ts +55 -0
  10. package/dist/blog-admin.js +156 -0
  11. package/dist/blog.d.ts +11 -0
  12. package/dist/blog.js +306 -56
  13. package/dist/build/cli.js +6 -2
  14. package/dist/build/component-libs.js +7 -2
  15. package/dist/build/core.js +55 -2
  16. package/dist/build/desktop.js +5 -2
  17. package/dist/build/docs.js +5 -2
  18. package/dist/build/frontend-static.js +123 -8
  19. package/dist/build/server.js +6 -2
  20. package/dist/build/stacks.js +8 -2
  21. package/dist/build/views.js +11 -2
  22. package/dist/build.js +64 -2
  23. package/dist/bump.js +162 -7
  24. package/dist/cdn/invalidate-cache.js +0 -1
  25. package/dist/changelog.js +27 -3
  26. package/dist/check/ports.js +16 -2
  27. package/dist/clean.js +4 -2
  28. package/dist/commit.js +12 -2
  29. package/dist/copy-types.js +10 -3
  30. package/dist/database/seed.js +26 -2
  31. package/dist/deploy/create-receipt-rule.js +36 -2
  32. package/dist/deploy/index.js +1318 -44
  33. package/dist/dev/api.js +94 -6
  34. package/dist/dev/components.js +7 -2
  35. package/dist/dev/dashboard-globals.js +89 -3
  36. package/dist/dev/dashboard-utils.js +380 -2
  37. package/dist/dev/dashboard.js +435 -8
  38. package/dist/dev/desktop.js +5 -2
  39. package/dist/dev/docs.js +24 -2
  40. package/dist/dev/index.js +29 -2
  41. package/dist/dev/migrate-watcher.js +74 -2
  42. package/dist/dev/system-tray.js +5 -2
  43. package/dist/dev/views.js +147 -2
  44. package/dist/discover-packages.js +32 -2
  45. package/dist/domains/add.js +61 -2
  46. package/dist/domains/purchase.js +66 -2
  47. package/dist/domains/remove.js +24 -2
  48. package/dist/examples.js +34 -2
  49. package/dist/find-projects.js +16 -2
  50. package/dist/fresh.js +17 -2
  51. package/dist/generate/action-types.js +9 -4
  52. package/dist/generate/component-meta.js +9 -3
  53. package/dist/generate/custom-cli-file.js +20 -3
  54. package/dist/generate/env-files.js +46 -6
  55. package/dist/generate/ide-helpers.js +8 -3
  56. package/dist/generate/index.js +158 -2
  57. package/dist/generate/lib-entries.js +16 -3
  58. package/dist/generate/pantry-file.js +46 -2
  59. package/dist/generate/symlink-core.js +2 -2
  60. package/dist/generate/types.js +3 -2
  61. package/dist/generate/vscode-custom-data.js +9 -3
  62. package/dist/generate/web-types.js +0 -1
  63. package/dist/helpers/component-meta.js +295 -2
  64. package/dist/helpers/index.js +1 -2
  65. package/dist/helpers/lib-entries.js +73 -2
  66. package/dist/helpers/package-json.js +45 -14
  67. package/dist/helpers/utils.js +105 -2
  68. package/dist/helpers/vscode-custom-data.js +30 -2
  69. package/dist/index.d.ts +13 -0
  70. package/dist/index.js +50 -2
  71. package/dist/key-generate.js +24 -2
  72. package/dist/lint/fix.js +4 -3
  73. package/dist/lint/index.js +4 -3
  74. package/dist/lint/lint.js +34 -2
  75. package/dist/make-command.js +64 -14
  76. package/dist/make-job.js +41 -16
  77. package/dist/make-policy.js +74 -26
  78. package/dist/make-resource.js +50 -21
  79. package/dist/make.js +328 -2
  80. package/dist/migrate/database.js +16 -2
  81. package/dist/migrate/fresh.js +31 -2
  82. package/dist/orm/base.js +0 -2
  83. package/dist/orm/test.js +0 -1
  84. package/dist/prepublish.js +16 -2
  85. package/dist/queue/clear.js +42 -2
  86. package/dist/queue/dlq-purge.js +28 -2
  87. package/dist/queue/dlq-retry.js +35 -2
  88. package/dist/queue/dlq.js +55 -5
  89. package/dist/queue/failed.js +69 -5
  90. package/dist/queue/flush.js +49 -3
  91. package/dist/queue/inspect.js +154 -8
  92. package/dist/queue/list.js +69 -5
  93. package/dist/queue/monitor.js +94 -6
  94. package/dist/queue/pause.js +28 -2
  95. package/dist/queue/quarantine.js +42 -3
  96. package/dist/queue/resume.js +27 -2
  97. package/dist/queue/retry.js +41 -2
  98. package/dist/queue/schedule-list.js +33 -5
  99. package/dist/queue/schedule.js +12 -2
  100. package/dist/queue/status.js +68 -5
  101. package/dist/queue/table.js +10 -2
  102. package/dist/queue/unquarantine.js +27 -2
  103. package/dist/queue/work.js +57 -2
  104. package/dist/release.js +21 -3
  105. package/dist/route/list.js +78 -3
  106. package/dist/run-action.js +1 -2
  107. package/dist/saas/setup.js +9 -2
  108. package/dist/scaffold-crud.js +164 -40
  109. package/dist/schedule/run.js +7 -2
  110. package/dist/search/flush.js +10 -2
  111. package/dist/search/import.js +10 -2
  112. package/dist/search/settings-list.js +10 -2
  113. package/dist/search/settings.js +9 -2
  114. package/dist/serve/api.js +35 -2
  115. package/dist/setup/index.js +1 -2
  116. package/dist/setup/ssl.js +271 -2
  117. package/dist/stacks.js +265 -2
  118. package/dist/templates.js +301 -2
  119. package/dist/test/feature.js +11 -2
  120. package/dist/test/index.js +11 -2
  121. package/dist/test/ui.js +4 -2
  122. package/dist/test/unit.js +11 -2
  123. package/dist/typecheck.js +4 -2
  124. package/dist/types.js +16 -2
  125. package/dist/upgrade/binary.js +29 -2
  126. package/dist/upgrade/bun.js +0 -1
  127. package/dist/upgrade/dependencies.js +0 -2
  128. package/dist/upgrade/framework-utils.js +193 -2
  129. package/dist/upgrade/framework.js +310 -7
  130. package/dist/upgrade/index.js +17 -2
  131. package/dist/upgrade/packages.js +99 -12
  132. package/dist/upgrade/shell.js +40 -4
  133. package/dist/upgrade.js +38 -2
  134. package/package.json +16 -16
  135. package/dist/chunk-0c8sd1t6.js +0 -2
  136. package/dist/chunk-0g2nzhx9.js +0 -240
  137. package/dist/chunk-0gadhvn7.js +0 -3
  138. package/dist/chunk-0h27aa4r.js +0 -93
  139. package/dist/chunk-3peh8kqs.js +0 -851
  140. package/dist/chunk-62gdfav8.js +0 -3
  141. package/dist/chunk-6bk53y02.js +0 -3
  142. package/dist/chunk-78c5n3s2.js +0 -3
  143. package/dist/chunk-c74qv38e.js +0 -17
  144. package/dist/chunk-cdk2r2jd.js +0 -1
  145. package/dist/chunk-dbz9dp2h.js +0 -3
  146. package/dist/chunk-e142dheq.js +0 -3
  147. package/dist/chunk-ec4gky40.js +0 -3
  148. package/dist/chunk-h3d81wrg.js +0 -3
  149. package/dist/chunk-m3q0x4h0.js +0 -688
  150. package/dist/chunk-mqgbyhph.js +0 -5
  151. package/dist/chunk-n24m8prb.js +0 -3
  152. package/dist/chunk-n5eqwhck.js +0 -7
  153. package/dist/chunk-nsvnqv8y.js +0 -5
  154. package/dist/chunk-nty6mmx4.js +0 -283
  155. package/dist/chunk-s735m9mg.js +0 -1
  156. package/dist/chunk-tpb8jgsk.js +0 -7
  157. package/dist/chunk-tsbk5vne.js +0 -3
  158. package/dist/chunk-xg9xscqz.js +0 -1
  159. package/dist/chunk-y6e448he.js +0 -7
package/dist/action.js CHANGED
@@ -1,2 +1,78 @@
1
- // @bun
2
- import{Hb as a}from"./chunk-6bk53y02.js";import"./chunk-h3d81wrg.js";export{a as Action};
1
+ export class Action {
2
+ name;
3
+ description;
4
+ apiResponse;
5
+ rate;
6
+ tries;
7
+ backoff;
8
+ enabled;
9
+ path;
10
+ method;
11
+ validations;
12
+ requestFile;
13
+ skipCsrf;
14
+ csrf;
15
+ authorize;
16
+ before;
17
+ handle;
18
+ model;
19
+ _dependenciesFactory;
20
+ _resolvedDeps;
21
+ _depsOverrides;
22
+ constructor({
23
+ name,
24
+ description,
25
+ apiResponse,
26
+ validations,
27
+ handle,
28
+ rate,
29
+ tries,
30
+ backoff,
31
+ enabled,
32
+ path,
33
+ method,
34
+ requestFile,
35
+ model,
36
+ skipCsrf,
37
+ csrf,
38
+ authorize,
39
+ before,
40
+ dependencies
41
+ }) {
42
+ this.name = name;
43
+ this.description = description;
44
+ this.apiResponse = apiResponse;
45
+ this.validations = validations;
46
+ this.rate = rate;
47
+ this.tries = tries;
48
+ this.backoff = backoff;
49
+ this.enabled = enabled;
50
+ this.path = path;
51
+ this.method = method;
52
+ this.handle = handle;
53
+ this.requestFile = requestFile;
54
+ this.skipCsrf = skipCsrf;
55
+ this.csrf = csrf;
56
+ this.authorize = authorize;
57
+ this.before = before;
58
+ this._dependenciesFactory = dependencies;
59
+ if (model && typeof model === "object" && "name" in model)
60
+ this.model = model.name;
61
+ else if (typeof model === "string")
62
+ this.model = model;
63
+ }
64
+ get deps() {
65
+ if (!this._resolvedDeps)
66
+ this._resolvedDeps = this._dependenciesFactory?.() ?? {};
67
+ if (this._depsOverrides)
68
+ return { ...this._resolvedDeps, ...this._depsOverrides };
69
+ return this._resolvedDeps;
70
+ }
71
+ overrideDependencies(overrides) {
72
+ this._depsOverrides = { ...this._depsOverrides ?? {}, ...overrides };
73
+ }
74
+ resetDependencies() {
75
+ this._depsOverrides = void 0;
76
+ this._resolvedDeps = void 0;
77
+ }
78
+ }
package/dist/actions.js CHANGED
@@ -1,2 +1,2 @@
1
- // @bun
2
- import{Ib as a,Jb as e,Kb as f}from"./chunk-0gadhvn7.js";import"./chunk-h3d81wrg.js";export{e as runActions,a as runAction,f as hasAction,t as actions};
1
+ export * from "./helpers/utils";
2
+ export * as actions from "./helpers/utils";
package/dist/add.js CHANGED
@@ -1,2 +1,20 @@
1
- // @bun
2
- import"./chunk-h3d81wrg.js";import{installPackage as t}from"@stacksjs/cli";async function o(a){if(a?.table)await n();if(a?.calendar)await s()}async function r(a){return await o(a)}async function n(){await t("@stacksjs/table")}async function s(){await t("@stacksjs/calendar")}async function d(a){for(let i of a)await t(i)}export{o as invoke,d as installPackages,n as addTable,s as addCalendar,r as add};
1
+ import { installPackage } from "@stacksjs/cli";
2
+ export async function invoke(options) {
3
+ if (options?.table)
4
+ await addTable();
5
+ if (options?.calendar)
6
+ await addCalendar();
7
+ }
8
+ export async function add(options) {
9
+ return await invoke(options);
10
+ }
11
+ export async function addTable() {
12
+ await installPackage("@stacksjs/table");
13
+ }
14
+ export async function addCalendar() {
15
+ await installPackage("@stacksjs/calendar");
16
+ }
17
+ export async function installPackages(names) {
18
+ for (const name of names)
19
+ await installPackage(name);
20
+ }
@@ -1,2 +1,10 @@
1
- // @bun
2
- import"../chunk-h3d81wrg.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
+ var {require}=import.meta;import { requestModelAccess } from "@stacksjs/ai";
2
+ async function main() {
3
+ try {
4
+ await requestModelAccess();
5
+ } catch (error) {
6
+ console.error("Error requesting model access:", error);
7
+ }
8
+ }
9
+ if (import.meta.main)
10
+ main();
@@ -1,3 +1,44 @@
1
- // @bun
2
- import L from"process";import{randomBytes as T,scryptSync as _}from"crypto";import{db as $}from"@stacksjs/database";import{HttpError as w}from"@stacksjs/error-handling";import{log as D}from"@stacksjs/logging";var J=L.argv.slice(2),U=(G)=>{let M=J.findIndex((z)=>z.startsWith(`--${G}=`)||z.startsWith(`-${G.charAt(0)}=`));if(M!==-1){let z=J[M];if(!z)return;let O=z.indexOf("=");return O>=0?z.slice(O+1):void 0}let N=J.findIndex((z)=>z===`--${G}`||z===`-${G.charAt(0)}`),K=N!==-1?J[N+1]:void 0;if(K&&!K.startsWith("-"))return K;return},V=(G)=>{return J.includes(`--${G}`)},W=U("name")||"OAuth Client",X=U("redirect")||"http://localhost",C=V("personal"),E=V("password");D.info(`Creating OAuth client: ${W}`);var Y=T(40).toString("hex"),Q=T(16).toString("hex"),H=`${Q}:${_(Y,Q,64).toString("hex")}`,R=await $.insertInto("oauth_clients").values({name:W,secret:H,provider:"local",redirect:X,personal_access_client:C,password_client:E,revoked:!1}).executeTakeFirst(),Z=R?.insertId||Number(R?.numInsertedOrUpdatedRows);if(!Z)throw new w(500,"Failed to create OAuth client");D.success("OAuth client created successfully");D.info("");D.info("Client Details:");D.info(` Client ID: ${Z}`);D.info(" Client Secret: [REDACTED]");L.stdout.write(`Client Secret (save now, shown once): ${Y}
3
- `);D.info(` Redirect URI: ${X}`);D.info("");D.warn("Make sure to save the client secret. You will not be able to retrieve it again.");L.exit(0);
1
+ import process from "node:process";
2
+ import { randomBytes, scryptSync } from "node:crypto";
3
+ import { db } from "@stacksjs/database";
4
+ import { HttpError } from "@stacksjs/error-handling";
5
+ import { log } from "@stacksjs/logging";
6
+ const args = process.argv.slice(2), getArg = (name) => {
7
+ const idx = args.findIndex((a) => a.startsWith(`--${name}=`) || a.startsWith(`-${name.charAt(0)}=`));
8
+ if (idx !== -1) {
9
+ const arg = args[idx];
10
+ if (!arg)
11
+ return;
12
+ const eqIdx = arg.indexOf("=");
13
+ return eqIdx >= 0 ? arg.slice(eqIdx + 1) : void 0;
14
+ }
15
+ const flagIdx = args.findIndex((a) => a === `--${name}` || a === `-${name.charAt(0)}`), value = flagIdx !== -1 ? args[flagIdx + 1] : void 0;
16
+ if (value && !value.startsWith("-"))
17
+ return value;
18
+ return;
19
+ }, hasFlag = (name) => {
20
+ return args.includes(`--${name}`);
21
+ }, name = getArg("name") || "OAuth Client", redirect = getArg("redirect") || "http://localhost", isPersonalAccess = hasFlag("personal"), isPasswordClient = hasFlag("password");
22
+ log.info(`Creating OAuth client: ${name}`);
23
+ const secret = randomBytes(40).toString("hex"), salt = randomBytes(16).toString("hex"), hashedSecret = `${salt}:${scryptSync(secret, salt, 64).toString("hex")}`, result = await db.insertInto("oauth_clients").values({
24
+ name,
25
+ secret: hashedSecret,
26
+ provider: "local",
27
+ redirect,
28
+ personal_access_client: isPersonalAccess,
29
+ password_client: isPasswordClient,
30
+ revoked: !1
31
+ }).executeTakeFirst(), insertId = result?.insertId || Number(result?.numInsertedOrUpdatedRows);
32
+ if (!insertId)
33
+ throw new HttpError(500, "Failed to create OAuth client");
34
+ log.success("OAuth client created successfully");
35
+ log.info("");
36
+ log.info("Client Details:");
37
+ log.info(` Client ID: ${insertId}`);
38
+ log.info(" Client Secret: [REDACTED]");
39
+ process.stdout.write(`Client Secret (save now, shown once): ${secret}
40
+ `);
41
+ log.info(` Redirect URI: ${redirect}`);
42
+ log.info("");
43
+ log.warn("Make sure to save the client secret. You will not be able to retrieve it again.");
44
+ process.exit(0);
@@ -1,2 +1,35 @@
1
- // @bun
2
- import S from"process";import{db as T,sql as V}from"@stacksjs/database";import{log as B}from"@stacksjs/logging";var G=S.argv.slice(2),U=(w)=>{return G.includes(`--${w}`)},W=(w)=>{let L=G.findIndex((z)=>z.startsWith(`--${w}=`)||z.startsWith(`-${w.charAt(0)}=`));if(L!==-1){let z=G[L];if(!z)return;let N=z.indexOf("=");return N>=0?z.slice(N+1):void 0}let M=G.findIndex((z)=>z===`--${w}`||z===`-${w.charAt(0)}`),H=M!==-1?G[M+1]:void 0;if(H&&!H.startsWith("-"))return H;return},X=!U("no-expired"),Y=!U("no-revoked"),Q=Number(W("days"))||7;B.info("Pruning authentication tokens...");var J=0,K=0;if(X)B.info("Removing expired tokens..."),J=await T.deleteFrom("personal_access_tokens").where("expires_at","<",V.raw("NOW()")).execute(),B.success(`Removed ${J} expired token(s)`);if(Y){B.info(`Removing tokens revoked more than ${Q} day(s) ago...`);let w=new Date;w.setDate(w.getDate()-Q),K=await T.deleteFrom("personal_access_tokens").where("revoked_at","is not",null).where("revoked_at","<",w.toISOString()).execute(),B.success(`Removed ${K} revoked token(s)`)}B.success(`Token pruning complete. Total removed: ${J+K}`);S.exit(0);
1
+ import process from "node:process";
2
+ import { db, sql } from "@stacksjs/database";
3
+ import { log } from "@stacksjs/logging";
4
+ const args = process.argv.slice(2), hasFlag = (name) => {
5
+ return args.includes(`--${name}`);
6
+ }, getArg = (name) => {
7
+ const idx = args.findIndex((a) => a.startsWith(`--${name}=`) || a.startsWith(`-${name.charAt(0)}=`));
8
+ if (idx !== -1) {
9
+ const arg = args[idx];
10
+ if (!arg)
11
+ return;
12
+ const eqIdx = arg.indexOf("=");
13
+ return eqIdx >= 0 ? arg.slice(eqIdx + 1) : void 0;
14
+ }
15
+ const flagIdx = args.findIndex((a) => a === `--${name}` || a === `-${name.charAt(0)}`), value = flagIdx !== -1 ? args[flagIdx + 1] : void 0;
16
+ if (value && !value.startsWith("-"))
17
+ return value;
18
+ return;
19
+ }, pruneExpired = !hasFlag("no-expired"), pruneRevoked = !hasFlag("no-revoked"), daysOld = Number(getArg("days")) || 7;
20
+ log.info("Pruning authentication tokens...");
21
+ let expiredCount = 0, revokedCount = 0;
22
+ if (pruneExpired) {
23
+ log.info("Removing expired tokens...");
24
+ expiredCount = await db.deleteFrom("personal_access_tokens").where("expires_at", "<", sql.raw("NOW()")).execute();
25
+ log.success(`Removed ${expiredCount} expired token(s)`);
26
+ }
27
+ if (pruneRevoked) {
28
+ log.info(`Removing tokens revoked more than ${daysOld} day(s) ago...`);
29
+ const cutoffDate = new Date;
30
+ cutoffDate.setDate(cutoffDate.getDate() - daysOld);
31
+ revokedCount = await db.deleteFrom("personal_access_tokens").where("revoked_at", "is not", null).where("revoked_at", "<", cutoffDate.toISOString()).execute();
32
+ log.success(`Removed ${revokedCount} revoked token(s)`);
33
+ }
34
+ log.success(`Token pruning complete. Total removed: ${expiredCount + revokedCount}`);
35
+ process.exit(0);
@@ -1,5 +1,17 @@
1
- // @bun
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(`
1
+ import process from "node:process";
2
+ import { randomBytes } from "node:crypto";
3
+ import { db } from "@stacksjs/database";
4
+ import { log } from "@stacksjs/logging";
5
+ import { makeHash } from "@stacksjs/security";
6
+ import { env } from "@stacksjs/env";
7
+ import { sqlHelpers, usersEmailVerifiedAtSql, usersPasswordChangedAtSql } from "@stacksjs/database";
8
+ const dbDriver = env.DB_CONNECTION || "sqlite", sql = sqlHelpers(dbDriver), { isPostgres, isMysql, now, boolTrue, boolFalse: _boolFalse } = sql;
9
+ log.info("Setting up authentication...");
10
+ log.info(`Database driver: ${dbDriver}`);
11
+ log.info("Ensuring OAuth tables exist...");
12
+ try {
13
+ if (isPostgres)
14
+ await db.unsafe(`
3
15
  CREATE TABLE IF NOT EXISTS oauth_clients (
4
16
  id SERIAL PRIMARY KEY,
5
17
  name VARCHAR(255) NOT NULL,
@@ -12,7 +24,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
12
24
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
13
25
  updated_at TIMESTAMP
14
26
  )
15
- `);else if(I)await x.unsafe(`
27
+ `);
28
+ else if (isMysql)
29
+ await db.unsafe(`
16
30
  CREATE TABLE IF NOT EXISTS oauth_clients (
17
31
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
18
32
  name VARCHAR(255) NOT NULL,
@@ -25,7 +39,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
25
39
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
26
40
  updated_at TIMESTAMP
27
41
  )
28
- `);else await x.unsafe(`
42
+ `);
43
+ else
44
+ await db.unsafe(`
29
45
  CREATE TABLE IF NOT EXISTS oauth_clients (
30
46
  id INTEGER PRIMARY KEY AUTOINCREMENT,
31
47
  name VARCHAR(255) NOT NULL,
@@ -38,7 +54,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
38
54
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
39
55
  updated_at TIMESTAMP
40
56
  )
41
- `);if(G)await x.unsafe(`
57
+ `);
58
+ if (isPostgres)
59
+ await db.unsafe(`
42
60
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
43
61
  id SERIAL PRIMARY KEY,
44
62
  user_id INTEGER NOT NULL,
@@ -51,7 +69,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
51
69
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
52
70
  updated_at TIMESTAMP
53
71
  )
54
- `);else if(I)await x.unsafe(`
72
+ `);
73
+ else if (isMysql)
74
+ await db.unsafe(`
55
75
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
56
76
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
57
77
  user_id INTEGER NOT NULL,
@@ -64,7 +84,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
64
84
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
65
85
  updated_at TIMESTAMP NULL
66
86
  )
67
- `);else await x.unsafe(`
87
+ `);
88
+ else
89
+ await db.unsafe(`
68
90
  CREATE TABLE IF NOT EXISTS oauth_access_tokens (
69
91
  id INTEGER PRIMARY KEY AUTOINCREMENT,
70
92
  user_id INTEGER NOT NULL,
@@ -77,9 +99,12 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
77
99
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
78
100
  updated_at TIMESTAMP
79
101
  )
80
- `);if(await x.unsafe(`
102
+ `);
103
+ await db.unsafe(`
81
104
  CREATE INDEX IF NOT EXISTS idx_oauth_access_tokens_token ON oauth_access_tokens(token)
82
- `),G)await x.unsafe(`
105
+ `);
106
+ if (isPostgres)
107
+ await db.unsafe(`
83
108
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
84
109
  id SERIAL PRIMARY KEY,
85
110
  access_token_id INTEGER NOT NULL,
@@ -88,7 +113,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
88
113
  expires_at TIMESTAMP,
89
114
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
90
115
  )
91
- `);else if(I)await x.unsafe(`
116
+ `);
117
+ else if (isMysql)
118
+ await db.unsafe(`
92
119
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
93
120
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
94
121
  access_token_id INTEGER NOT NULL,
@@ -97,7 +124,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
97
124
  expires_at TIMESTAMP NULL,
98
125
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
99
126
  )
100
- `);else await x.unsafe(`
127
+ `);
128
+ else
129
+ await db.unsafe(`
101
130
  CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
102
131
  id INTEGER PRIMARY KEY AUTOINCREMENT,
103
132
  access_token_id INTEGER NOT NULL,
@@ -106,9 +135,19 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
106
135
  expires_at TIMESTAMP,
107
136
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
108
137
  )
109
- `);await x.unsafe(`
138
+ `);
139
+ await db.unsafe(`
110
140
  CREATE INDEX IF NOT EXISTS idx_oauth_refresh_tokens_token ON oauth_refresh_tokens(token)
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(`
141
+ `);
142
+ log.success("OAuth tables ready");
143
+ } catch (error) {
144
+ log.error("Failed to create OAuth tables", error);
145
+ process.exit(1);
146
+ }
147
+ log.info("Ensuring password_resets table exists...");
148
+ try {
149
+ if (isPostgres)
150
+ await db.unsafe(`
112
151
  CREATE TABLE IF NOT EXISTS password_resets (
113
152
  id SERIAL PRIMARY KEY,
114
153
  email VARCHAR(255) NOT NULL,
@@ -116,7 +155,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
116
155
  expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
117
156
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
118
157
  )
119
- `);else if(I)await x.unsafe(`
158
+ `);
159
+ else if (isMysql)
160
+ await db.unsafe(`
120
161
  CREATE TABLE IF NOT EXISTS password_resets (
121
162
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
122
163
  email VARCHAR(255) NOT NULL,
@@ -124,7 +165,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
124
165
  expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
125
166
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
126
167
  )
127
- `);else await x.unsafe(`
168
+ `);
169
+ else
170
+ await db.unsafe(`
128
171
  CREATE TABLE IF NOT EXISTS password_resets (
129
172
  id INTEGER PRIMARY KEY AUTOINCREMENT,
130
173
  email VARCHAR(255) NOT NULL,
@@ -132,9 +175,22 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
132
175
  expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
133
176
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
134
177
  )
135
- `);try{await x.unsafe("ALTER TABLE password_resets ADD COLUMN expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP")}catch{}await x.unsafe(`
178
+ `);
179
+ try {
180
+ await db.unsafe("ALTER TABLE password_resets ADD COLUMN expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP");
181
+ } catch {}
182
+ await db.unsafe(`
136
183
  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(`
184
+ `);
185
+ log.success("Password resets table ready");
186
+ } catch (error) {
187
+ log.error("Failed to create password_resets table", error);
188
+ process.exit(1);
189
+ }
190
+ log.info("Ensuring email_verifications table exists...");
191
+ try {
192
+ if (isPostgres)
193
+ await db.unsafe(`
138
194
  CREATE TABLE IF NOT EXISTS email_verifications (
139
195
  id SERIAL PRIMARY KEY,
140
196
  user_id INTEGER NOT NULL,
@@ -142,7 +198,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
142
198
  expires_at TIMESTAMP NOT NULL,
143
199
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
144
200
  )
145
- `);else if(I)await x.unsafe(`
201
+ `);
202
+ else if (isMysql)
203
+ await db.unsafe(`
146
204
  CREATE TABLE IF NOT EXISTS email_verifications (
147
205
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
148
206
  user_id INTEGER NOT NULL,
@@ -150,7 +208,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
150
208
  expires_at TIMESTAMP NOT NULL,
151
209
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
152
210
  )
153
- `);else await x.unsafe(`
211
+ `);
212
+ else
213
+ await db.unsafe(`
154
214
  CREATE TABLE IF NOT EXISTS email_verifications (
155
215
  id INTEGER PRIMARY KEY AUTOINCREMENT,
156
216
  user_id INTEGER NOT NULL,
@@ -158,9 +218,25 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
158
218
  expires_at TIMESTAMP NOT NULL,
159
219
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
160
220
  )
161
- `);await x.unsafe(`
221
+ `);
222
+ await db.unsafe(`
162
223
  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(`
224
+ `);
225
+ try {
226
+ await db.unsafe(usersEmailVerifiedAtSql(sql));
227
+ } catch {}
228
+ try {
229
+ await db.unsafe(usersPasswordChangedAtSql(sql));
230
+ } catch {}
231
+ log.success("Email verifications table ready");
232
+ } catch (error) {
233
+ log.error("Failed to create email_verifications table", error);
234
+ process.exit(1);
235
+ }
236
+ log.info("Ensuring webauthn_challenges table exists...");
237
+ try {
238
+ if (isPostgres)
239
+ await db.unsafe(`
164
240
  CREATE TABLE IF NOT EXISTS webauthn_challenges (
165
241
  id SERIAL PRIMARY KEY,
166
242
  user_id INTEGER NOT NULL,
@@ -169,7 +245,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
169
245
  expires_at TIMESTAMP NOT NULL,
170
246
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
171
247
  )
172
- `);else if(I)await x.unsafe(`
248
+ `);
249
+ else if (isMysql)
250
+ await db.unsafe(`
173
251
  CREATE TABLE IF NOT EXISTS webauthn_challenges (
174
252
  id INTEGER AUTO_INCREMENT PRIMARY KEY,
175
253
  user_id INTEGER NOT NULL,
@@ -178,7 +256,9 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
178
256
  expires_at TIMESTAMP NOT NULL,
179
257
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
180
258
  )
181
- `);else await x.unsafe(`
259
+ `);
260
+ else
261
+ await db.unsafe(`
182
262
  CREATE TABLE IF NOT EXISTS webauthn_challenges (
183
263
  id INTEGER PRIMARY KEY AUTOINCREMENT,
184
264
  user_id INTEGER NOT NULL,
@@ -187,20 +267,56 @@ import J from"process";import{randomBytes as U}from"crypto";import{db as x}from"
187
267
  expires_at TIMESTAMP NOT NULL,
188
268
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
189
269
  )
190
- `);await x.unsafe(`
270
+ `);
271
+ await db.unsafe(`
191
272
  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
194
- `))?.length>0)console.log(`
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(`
273
+ `);
274
+ log.success("WebAuthn challenges table ready");
275
+ } catch (error) {
276
+ log.error("Failed to create webauthn_challenges table", error);
277
+ process.exit(1);
278
+ }
279
+ log.info("Creating personal access client...");
280
+ try {
281
+ if ((await db.unsafe(`
282
+ SELECT id FROM oauth_clients WHERE personal_access_client = ${boolTrue} LIMIT 1
283
+ `))?.length > 0)
284
+ console.log(`
285
+ \u2713 Personal access client already exists`);
286
+ else {
287
+ const secret = randomBytes(40).toString("hex"), hashedSecret = await makeHash(secret, { algorithm: "bcrypt" });
288
+ if (isPostgres)
289
+ await db.unsafe(`
196
290
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
197
291
  VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
198
- `,["Personal Access Client",N,"local","http://localhost",!0,!1,!1]);else await x.unsafe(`
292
+ `, ["Personal Access Client", hashedSecret, "local", "http://localhost", !0, !1, !1]);
293
+ else
294
+ await db.unsafe(`
199
295
  INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
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(`
203
- \u2713 Authentication setup complete!`);console.log(`
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(`
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
206
- `);J.exit(0);
296
+ VALUES (?, ?, ?, ?, ?, ?, ?, ${now})
297
+ `, ["Personal Access Client", hashedSecret, "local", "http://localhost", 1, 0, 0]);
298
+ console.log(`
299
+ \u2713 Personal access client created successfully`);
300
+ }
301
+ } catch (error) {
302
+ console.error("Failed to create personal access client:", error);
303
+ process.exit(1);
304
+ }
305
+ console.log(`
306
+ \u2713 Authentication setup complete!`);
307
+ console.log(`
308
+ Features enabled:`);
309
+ console.log(" - Token hashing (SHA-256) for secure storage");
310
+ console.log(" - Refresh tokens for seamless token renewal");
311
+ console.log(" - Scope-based authorization");
312
+ console.log(" - Password reset flow");
313
+ console.log(`
314
+ Next steps:`);
315
+ console.log(" 1. Use createToken(userId, name, scopes) to generate tokens");
316
+ console.log(" 2. Use refreshToken(token) to exchange refresh tokens");
317
+ console.log(' 3. Use the "auth" middleware to protect routes');
318
+ console.log(" 4. Use tokenCan(scope) for authorization checks");
319
+ console.log(" 5. POST /password/forgot to request password reset");
320
+ console.log(` 6. POST /password/reset to reset password with token
321
+ `);
322
+ process.exit(0);
@@ -1,2 +1,10 @@
1
- // @bun
2
- import q from"process";import{createPersonalAccessClient as v}from"@stacksjs/auth";import{log as w}from"@stacksjs/logging";var m=await v();if(m?.isErr)console.error(m.error),w.error("createPersonalAccessClient failed",m.error),q.exit(1);q.exit(0);
1
+ import process from "node:process";
2
+ import { createPersonalAccessClient } from "@stacksjs/auth";
3
+ import { log } from "@stacksjs/logging";
4
+ const result = await createPersonalAccessClient();
5
+ if (result?.isErr) {
6
+ console.error(result.error);
7
+ log.error("createPersonalAccessClient failed", result.error);
8
+ process.exit(1);
9
+ }
10
+ process.exit(0);
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Turn a title into a filename-safe slug.
3
+ *
4
+ * Kept intentionally strict (lowercase a-z, 0-9, single hyphens) because the
5
+ * slug becomes both a filename and a public URL.
6
+ */
7
+ export declare function slugify(input: string): string;
8
+ /**
9
+ * Every post on disk, newest first, drafts included.
10
+ *
11
+ * Unlike the public `listPosts` in `blog.ts` this does not require a `date`, so
12
+ * a half-finished post still shows up in the dashboard instead of vanishing.
13
+ */
14
+ export declare function listBlogPosts(): BlogPost[];
15
+ export declare function getBlogPost(slug: string): BlogPost | null;
16
+ /**
17
+ * Create or update a post file.
18
+ *
19
+ * Pass `originalSlug` to rename: the new file is written first, then the old one
20
+ * is removed, so a failure mid-way leaves the original post intact.
21
+ */
22
+ export declare function saveBlogPost(input: BlogPostInput): BlogPost;
23
+ export declare function deleteBlogPost(slug: string): boolean;
24
+ export declare interface BlogPost {
25
+ slug: string
26
+ title: string
27
+ description: string
28
+ date: string
29
+ author: string
30
+ authorBio: string
31
+ poster: string
32
+ featured: boolean
33
+ draft: boolean
34
+ body: string
35
+ wordCount: number
36
+ readingTime: number
37
+ updatedAt: string
38
+ }
39
+ export declare interface BlogPostInput {
40
+ slug?: string
41
+ originalSlug?: string
42
+ title: string
43
+ description?: string
44
+ date?: string
45
+ author?: string
46
+ authorBio?: string
47
+ poster?: string
48
+ featured?: boolean
49
+ draft?: boolean
50
+ body?: string
51
+ }
52
+ export declare class BlogAdminError extends Error {
53
+ readonly status?: number;
54
+ constructor(message: string, status?: number);
55
+ }