@stacksjs/actions 0.70.88 → 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 (261) hide show
  1. package/dist/action.d.ts +149 -0
  2. package/dist/action.js +78 -0
  3. package/dist/actions.d.ts +2 -0
  4. package/dist/actions.js +2 -0
  5. package/dist/add.d.ts +6 -0
  6. package/dist/add.js +20 -0
  7. package/dist/ai/request-model-access.d.ts +1 -0
  8. package/dist/ai/request-model-access.js +10 -0
  9. package/dist/auth/client.d.ts +1 -0
  10. package/dist/auth/client.js +44 -0
  11. package/dist/auth/prune.d.ts +1 -0
  12. package/dist/auth/prune.js +35 -0
  13. package/dist/auth/setup.d.ts +1 -0
  14. package/dist/auth/setup.js +322 -0
  15. package/dist/auth/token.d.ts +1 -0
  16. package/dist/auth/token.js +10 -0
  17. package/dist/blog-admin.d.ts +55 -0
  18. package/dist/blog-admin.js +156 -0
  19. package/dist/blog.d.ts +30 -0
  20. package/dist/blog.js +398 -0
  21. package/dist/build/cli.d.ts +1 -0
  22. package/dist/build/cli.js +6 -0
  23. package/dist/build/component-libs.d.ts +1 -0
  24. package/dist/build/component-libs.js +7 -0
  25. package/dist/build/core.d.ts +1 -0
  26. package/dist/build/core.js +55 -0
  27. package/dist/build/desktop.d.ts +1 -0
  28. package/dist/build/desktop.js +5 -0
  29. package/dist/build/docs.d.ts +1 -0
  30. package/dist/build/docs.js +5 -0
  31. package/dist/build/frontend-static.d.ts +16 -0
  32. package/dist/build/frontend-static.js +124 -0
  33. package/dist/build/server.d.ts +1 -0
  34. package/dist/build/server.js +6 -0
  35. package/dist/build/stacks.d.ts +1 -0
  36. package/dist/build/stacks.js +8 -0
  37. package/dist/build/views.d.ts +1 -0
  38. package/dist/build/views.js +11 -0
  39. package/dist/build.d.ts +9 -0
  40. package/dist/build.js +64 -0
  41. package/dist/bump.d.ts +1 -0
  42. package/dist/bump.js +163 -0
  43. package/dist/cdn/invalidate-cache.d.ts +1 -0
  44. package/dist/cdn/invalidate-cache.js +0 -0
  45. package/dist/changelog.d.ts +9 -0
  46. package/dist/changelog.js +27 -0
  47. package/dist/check/ports.d.ts +1 -0
  48. package/dist/check/ports.js +16 -0
  49. package/dist/clean.d.ts +1 -0
  50. package/dist/clean.js +4 -0
  51. package/dist/commit.d.ts +3 -0
  52. package/dist/commit.js +12 -0
  53. package/dist/copy-types.d.ts +1 -0
  54. package/dist/copy-types.js +10 -0
  55. package/dist/database/seed.d.ts +1 -0
  56. package/dist/database/seed.js +26 -0
  57. package/dist/deploy/create-receipt-rule.d.ts +1 -0
  58. package/dist/deploy/create-receipt-rule.js +36 -0
  59. package/dist/deploy/index.d.ts +1 -0
  60. package/dist/deploy/index.js +1574 -0
  61. package/dist/dev/api.d.ts +1 -0
  62. package/dist/dev/api.js +94 -0
  63. package/dist/dev/components.d.ts +1 -0
  64. package/dist/dev/components.js +7 -0
  65. package/dist/dev/dashboard-globals.d.ts +4 -0
  66. package/dist/dev/dashboard-globals.js +89 -0
  67. package/dist/dev/dashboard-utils.d.ts +150 -0
  68. package/dist/dev/dashboard-utils.js +380 -0
  69. package/dist/dev/dashboard.d.ts +22 -0
  70. package/dist/dev/dashboard.js +435 -0
  71. package/dist/dev/desktop.d.ts +1 -0
  72. package/dist/dev/desktop.js +5 -0
  73. package/dist/dev/docs.d.ts +1 -0
  74. package/dist/dev/docs.js +24 -0
  75. package/dist/dev/index.d.ts +10 -0
  76. package/dist/dev/index.js +29 -0
  77. package/dist/dev/migrate-watcher.d.ts +1 -0
  78. package/dist/dev/migrate-watcher.js +74 -0
  79. package/dist/dev/system-tray.d.ts +1 -0
  80. package/dist/dev/system-tray.js +5 -0
  81. package/dist/dev/views.d.ts +1 -0
  82. package/dist/dev/views.js +147 -0
  83. package/dist/discover-packages.d.ts +18 -0
  84. package/dist/discover-packages.js +32 -0
  85. package/dist/domains/add.d.ts +1 -0
  86. package/dist/domains/add.js +61 -0
  87. package/dist/domains/purchase.d.ts +1 -0
  88. package/dist/domains/purchase.js +66 -0
  89. package/dist/domains/remove.d.ts +1 -0
  90. package/dist/domains/remove.js +24 -0
  91. package/dist/examples.d.ts +5 -0
  92. package/dist/examples.js +34 -0
  93. package/dist/find-projects.d.ts +1 -0
  94. package/dist/find-projects.js +16 -0
  95. package/dist/fresh.d.ts +1 -0
  96. package/dist/fresh.js +17 -0
  97. package/dist/generate/action-types.d.ts +1 -0
  98. package/dist/generate/action-types.js +13 -0
  99. package/dist/generate/component-meta.d.ts +1 -0
  100. package/dist/generate/component-meta.js +9 -0
  101. package/dist/generate/custom-cli-file.d.ts +1 -0
  102. package/dist/generate/custom-cli-file.js +21 -0
  103. package/dist/generate/env-files.d.ts +1 -0
  104. package/dist/generate/env-files.js +66 -0
  105. package/dist/generate/ide-helpers.d.ts +1 -0
  106. package/dist/generate/ide-helpers.js +8 -0
  107. package/dist/generate/index.d.ts +36 -0
  108. package/dist/generate/index.js +158 -0
  109. package/dist/generate/lib-entries.d.ts +1 -0
  110. package/dist/generate/lib-entries.js +16 -0
  111. package/dist/generate/pantry-file.d.ts +1 -0
  112. package/dist/generate/pantry-file.js +46 -0
  113. package/dist/generate/symlink-core.d.ts +1 -0
  114. package/dist/generate/symlink-core.js +2 -0
  115. package/dist/generate/types.d.ts +1 -0
  116. package/dist/generate/types.js +3 -0
  117. package/dist/generate/vscode-custom-data.d.ts +1 -0
  118. package/dist/generate/vscode-custom-data.js +9 -0
  119. package/dist/generate/web-types.d.ts +1 -0
  120. package/dist/generate/web-types.js +0 -0
  121. package/dist/helpers/component-meta.d.ts +26 -0
  122. package/dist/helpers/component-meta.js +295 -0
  123. package/dist/helpers/index.d.ts +4 -0
  124. package/dist/helpers/index.js +1 -0
  125. package/dist/helpers/lib-entries.d.ts +12 -0
  126. package/dist/helpers/lib-entries.js +73 -0
  127. package/dist/helpers/package-json.d.ts +2 -0
  128. package/dist/helpers/package-json.js +74 -0
  129. package/dist/helpers/utils.d.ts +23 -0
  130. package/dist/helpers/utils.js +105 -0
  131. package/dist/helpers/vscode-custom-data.d.ts +3 -0
  132. package/dist/helpers/vscode-custom-data.js +30 -0
  133. package/dist/index.d.ts +62 -0
  134. package/dist/index.js +50 -0
  135. package/dist/key-generate.d.ts +1 -0
  136. package/dist/key-generate.js +24 -0
  137. package/dist/lint/fix.d.ts +1 -0
  138. package/dist/lint/fix.js +4 -0
  139. package/dist/lint/index.d.ts +1 -0
  140. package/dist/lint/index.js +4 -0
  141. package/dist/lint/lint.d.ts +14 -0
  142. package/dist/lint/lint.js +34 -0
  143. package/dist/make-command.d.ts +10 -0
  144. package/dist/make-command.js +95 -0
  145. package/dist/make-job.d.ts +5 -0
  146. package/dist/make-job.js +154 -0
  147. package/dist/make-policy.d.ts +10 -0
  148. package/dist/make-policy.js +142 -0
  149. package/dist/make-resource.d.ts +10 -0
  150. package/dist/make-resource.js +142 -0
  151. package/dist/make.d.ts +52 -0
  152. package/dist/make.js +328 -0
  153. package/dist/migrate/database.d.ts +1 -0
  154. package/dist/migrate/database.js +16 -0
  155. package/dist/migrate/fresh.d.ts +1 -0
  156. package/dist/migrate/fresh.js +31 -0
  157. package/dist/orm/base.d.ts +1 -0
  158. package/dist/orm/base.js +0 -0
  159. package/dist/orm/test.d.ts +1 -0
  160. package/dist/orm/test.js +0 -0
  161. package/dist/prepublish.d.ts +1 -0
  162. package/dist/prepublish.js +16 -0
  163. package/dist/queue/clear.d.ts +1 -0
  164. package/dist/queue/clear.js +42 -0
  165. package/dist/queue/dlq-purge.d.ts +1 -0
  166. package/dist/queue/dlq-purge.js +28 -0
  167. package/dist/queue/dlq-retry.d.ts +1 -0
  168. package/dist/queue/dlq-retry.js +35 -0
  169. package/dist/queue/dlq.d.ts +1 -0
  170. package/dist/queue/dlq.js +55 -0
  171. package/dist/queue/failed.d.ts +1 -0
  172. package/dist/queue/failed.js +69 -0
  173. package/dist/queue/flush.d.ts +1 -0
  174. package/dist/queue/flush.js +49 -0
  175. package/dist/queue/inspect.d.ts +1 -0
  176. package/dist/queue/inspect.js +154 -0
  177. package/dist/queue/list.d.ts +1 -0
  178. package/dist/queue/list.js +69 -0
  179. package/dist/queue/monitor.d.ts +1 -0
  180. package/dist/queue/monitor.js +95 -0
  181. package/dist/queue/pause.d.ts +1 -0
  182. package/dist/queue/pause.js +28 -0
  183. package/dist/queue/quarantine.d.ts +1 -0
  184. package/dist/queue/quarantine.js +42 -0
  185. package/dist/queue/resume.d.ts +1 -0
  186. package/dist/queue/resume.js +27 -0
  187. package/dist/queue/retry.d.ts +1 -0
  188. package/dist/queue/retry.js +41 -0
  189. package/dist/queue/schedule-list.d.ts +1 -0
  190. package/dist/queue/schedule-list.js +33 -0
  191. package/dist/queue/schedule.d.ts +1 -0
  192. package/dist/queue/schedule.js +12 -0
  193. package/dist/queue/status.d.ts +1 -0
  194. package/dist/queue/status.js +68 -0
  195. package/dist/queue/table.d.ts +1 -0
  196. package/dist/queue/table.js +10 -0
  197. package/dist/queue/unquarantine.d.ts +1 -0
  198. package/dist/queue/unquarantine.js +27 -0
  199. package/dist/queue/work.d.ts +1 -0
  200. package/dist/queue/work.js +57 -0
  201. package/dist/release.d.ts +1 -0
  202. package/dist/release.js +21 -0
  203. package/dist/route/list.d.ts +1 -0
  204. package/dist/route/list.js +78 -0
  205. package/dist/run-action.d.ts +2 -0
  206. package/dist/run-action.js +1 -0
  207. package/dist/saas/setup.d.ts +1 -0
  208. package/dist/saas/setup.js +9 -0
  209. package/dist/scaffold-crud.d.ts +25 -0
  210. package/dist/scaffold-crud.js +211 -0
  211. package/dist/schedule/run.d.ts +1 -0
  212. package/dist/schedule/run.js +7 -0
  213. package/dist/search/flush.d.ts +1 -0
  214. package/dist/search/flush.js +10 -0
  215. package/dist/search/import.d.ts +1 -0
  216. package/dist/search/import.js +10 -0
  217. package/dist/search/settings-list.d.ts +1 -0
  218. package/dist/search/settings-list.js +10 -0
  219. package/dist/search/settings.d.ts +1 -0
  220. package/dist/search/settings.js +9 -0
  221. package/dist/serve/api.d.ts +1 -0
  222. package/dist/serve/api.js +35 -0
  223. package/dist/setup/index.d.ts +1 -0
  224. package/dist/setup/index.js +1 -0
  225. package/dist/setup/ssl.d.ts +38 -0
  226. package/dist/setup/ssl.js +271 -0
  227. package/dist/stacks.d.ts +4 -0
  228. package/dist/stacks.js +265 -0
  229. package/dist/templates.d.ts +28 -0
  230. package/dist/templates.js +301 -0
  231. package/dist/test/feature.d.ts +1 -0
  232. package/dist/test/feature.js +11 -0
  233. package/dist/test/index.d.ts +1 -0
  234. package/dist/test/index.js +11 -0
  235. package/dist/test/ui.d.ts +1 -0
  236. package/dist/test/ui.js +4 -0
  237. package/dist/test/unit.d.ts +1 -0
  238. package/dist/test/unit.js +11 -0
  239. package/dist/typecheck.d.ts +1 -0
  240. package/dist/typecheck.js +4 -0
  241. package/dist/types.d.ts +3 -0
  242. package/dist/types.js +16 -0
  243. package/dist/upgrade/binary.d.ts +1 -0
  244. package/dist/upgrade/binary.js +29 -0
  245. package/dist/upgrade/bun.d.ts +1 -0
  246. package/dist/upgrade/bun.js +0 -0
  247. package/dist/upgrade/dependencies.d.ts +1 -0
  248. package/dist/upgrade/dependencies.js +0 -0
  249. package/dist/upgrade/framework-utils.d.ts +150 -0
  250. package/dist/upgrade/framework-utils.js +193 -0
  251. package/dist/upgrade/framework.d.ts +1 -0
  252. package/dist/upgrade/framework.js +310 -0
  253. package/dist/upgrade/index.d.ts +1 -0
  254. package/dist/upgrade/index.js +17 -0
  255. package/dist/upgrade/packages.d.ts +14 -0
  256. package/dist/upgrade/packages.js +99 -0
  257. package/dist/upgrade/shell.d.ts +1 -0
  258. package/dist/upgrade/shell.js +41 -0
  259. package/dist/upgrade.d.ts +7 -0
  260. package/dist/upgrade.js +38 -0
  261. package/package.json +16 -16
@@ -0,0 +1,149 @@
1
+ import type { ExtractParams, InferValidations, JobOptions, RequestInstance } from '@stacksjs/types';
2
+ /**
3
+ * Shape of `validations:` on an action. Each entry pairs a
4
+ * ts-validation `Validator<T>` rule with an optional error message.
5
+ *
6
+ * Kept loose at the index-signature level so existing actions with
7
+ * untyped validation objects keep compiling. New code that wants the
8
+ * body-inference benefit (stacksjs/stacks#1851 Phase 2b) declares
9
+ * validations `as const` so {@link InferValidations} can read the
10
+ * concrete rule types.
11
+ *
12
+ * Exported so the router can run validations without redeclaring the
13
+ * type (stacksjs/stacks#1870 R-3 — the previous copy in
14
+ * `stacks-router.ts` would drift out of sync).
15
+ */
16
+ export declare interface ActionValidations {
17
+ [key: string]: {
18
+ rule: { validate: (value: any) => any }
19
+ message?: string | Record<string, string>
20
+ }
21
+ }
22
+ /**
23
+ * Shape of {@link validateActionInput}'s return value. Lives here next
24
+ * to {@link ActionValidations} so the router and actions package share
25
+ * a single declaration (stacksjs/stacks#1870 R-3).
26
+ */
27
+ export declare interface ValidationResult {
28
+ valid: boolean
29
+ errors: Record<string, string[]>
30
+ }
31
+ declare interface ActionOptions<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '',> {
32
+ name?: string
33
+ description?: string
34
+ apiResponse?: boolean
35
+ validations?: TValidations
36
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
37
+ rate?: JobOptions['rate']
38
+ tries?: JobOptions['tries']
39
+ backoff?: JobOptions['backoff']
40
+ enabled?: JobOptions['enabled']
41
+ path?: TPath
42
+ requestFile?: string
43
+ model?: TModel
44
+ skipCsrf?: boolean
45
+ csrf?: boolean
46
+ authorize?: (
47
+ request: InferRequest<TModel, TValidations, TPath>,
48
+ ) => boolean | Response | Promise<boolean | Response>
49
+ before?: (
50
+ request: InferRequest<TModel, TValidations, TPath>,
51
+ ) => void | Response | Promise<void | Response>
52
+ handle: {
53
+ bivarianceHack: (
54
+ request: InferRequest<TModel, TValidations, TPath>,
55
+ ) => ActionResult | Promise<ActionResult>
56
+ }['bivarianceHack']
57
+ dependencies?: () => Record<string, unknown>
58
+ }
59
+ /**
60
+ * Resolve the body shape (`TFields`) for an action's request:
61
+ *
62
+ * 1. If `model:` is a `defineModel()` return, use its row shape —
63
+ * preserves the existing model-aware ergonomics.
64
+ * 2. Else if `validations:` is set as a const, infer the body
65
+ * from each rule's `Validator<T>` output type
66
+ * (stacksjs/stacks#1851 Phase 2b).
67
+ * 3. Else fall back to `Record<string, any>` — bare-typed action
68
+ * with no narrowing.
69
+ */
70
+ declare type ResolveBody<TModel, TValidations> = TModel extends { _isStacksModel: true }
71
+ ? TModel
72
+ : TValidations extends ActionValidations
73
+ ? InferValidations<TValidations>
74
+ : Record<string, any>;
75
+ /**
76
+ * Build the request type passed to the action's `handle()`. Combines
77
+ * the body resolution above with path-extracted params from `TPath`
78
+ * (stacksjs/stacks#1851 Phase 2a).
79
+ */
80
+ declare type InferRequest<TModel, TValidations, TPath extends string> = TPath extends ''
81
+ ? RequestInstance<ResolveBody<TModel, TValidations>>
82
+ : RequestInstance<ResolveBody<TModel, TValidations>, ExtractParams<TPath>>;
83
+ /**
84
+ * Everything an action's `handle()` is allowed to return. The router's
85
+ * `formatResult()` walks each branch:
86
+ *
87
+ * - `Response` → returned as-is (caller built their own)
88
+ * - `null` / `undefined` → `204` for API clients, empty `200` for browser
89
+ * - object / array (incl. records) → `Response.json(...)`
90
+ * - `string` / `number` / `boolean` → JSON-encoded for API clients, `text/plain`
91
+ * for top-level browser navigations
92
+ * - `ReadableStream` → streamed back (stacksjs/stacks#1870 R-4)
93
+ *
94
+ * Previously typed `Promise<any> | any`, which let non-serializable returns
95
+ * (class instances with cycles, undefined-bearing tuples, etc.) sneak through
96
+ * to runtime. Narrowing here surfaces them at the call site instead.
97
+ * See stacksjs/stacks#1870 R-11.
98
+ */
99
+ export type ActionResult = | Response
100
+ | ReadableStream
101
+ | null
102
+ | undefined
103
+ | string
104
+ | number
105
+ | boolean
106
+ | object
107
+ | unknown[];
108
+ export declare class Action<TModel = string, TValidations extends ActionValidations | undefined = undefined, TPath extends string = '',> {
109
+ name?: string;
110
+ description?: string;
111
+ apiResponse?: boolean;
112
+ rate?: ActionOptions['rate'];
113
+ tries?: ActionOptions['tries'];
114
+ backoff?: ActionOptions['backoff'];
115
+ enabled?: ActionOptions['enabled'];
116
+ path?: ActionOptions<TModel, TValidations, TPath>['path'];
117
+ method?: ActionOptions['method'];
118
+ validations?: TValidations;
119
+ requestFile?: string;
120
+ skipCsrf?: boolean;
121
+ csrf?: boolean;
122
+ authorize?: ActionOptions<TModel, TValidations, TPath>['authorize'];
123
+ before?: ActionOptions<TModel, TValidations, TPath>['before'];
124
+ handle: ActionOptions<TModel, TValidations, TPath>['handle'];
125
+ model?: string;
126
+ constructor({
127
+ name,
128
+ description,
129
+ apiResponse,
130
+ validations,
131
+ handle,
132
+ rate,
133
+ tries,
134
+ backoff,
135
+ enabled,
136
+ path,
137
+ method,
138
+ requestFile,
139
+ model,
140
+ skipCsrf,
141
+ csrf,
142
+ authorize,
143
+ before,
144
+ dependencies,
145
+ }: ActionOptions<TModel, TValidations, TPath>);
146
+ get deps(): Record<string, unknown>;
147
+ overrideDependencies(overrides: Record<string, unknown>): void;
148
+ resetDependencies(): void;
149
+ }
package/dist/action.js ADDED
@@ -0,0 +1,78 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ export * from './helpers/utils';
2
+ export * as actions from './helpers/utils';
@@ -0,0 +1,2 @@
1
+ export * from "./helpers/utils";
2
+ export * as actions from "./helpers/utils";
package/dist/add.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { AddOptions } from '@stacksjs/types';
2
+ export declare function invoke(options: AddOptions): Promise<void>;
3
+ export declare function add(options: AddOptions): Promise<void>;
4
+ export declare function addTable(): Promise<void>;
5
+ export declare function addCalendar(): Promise<void>;
6
+ export declare function installPackages(names: string[]): Promise<void>;
package/dist/add.js ADDED
@@ -0,0 +1,20 @@
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
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
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();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,44 @@
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);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,35 @@
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);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,322 @@
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(`
15
+ CREATE TABLE IF NOT EXISTS oauth_clients (
16
+ id SERIAL PRIMARY KEY,
17
+ name VARCHAR(255) NOT NULL,
18
+ secret VARCHAR(100),
19
+ provider VARCHAR(255),
20
+ redirect VARCHAR(2000) NOT NULL,
21
+ personal_access_client BOOLEAN NOT NULL DEFAULT false,
22
+ password_client BOOLEAN NOT NULL DEFAULT false,
23
+ revoked BOOLEAN NOT NULL DEFAULT false,
24
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
25
+ updated_at TIMESTAMP
26
+ )
27
+ `);
28
+ else if (isMysql)
29
+ await db.unsafe(`
30
+ CREATE TABLE IF NOT EXISTS oauth_clients (
31
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
32
+ name VARCHAR(255) NOT NULL,
33
+ secret VARCHAR(100),
34
+ provider VARCHAR(255),
35
+ redirect VARCHAR(2000) NOT NULL,
36
+ personal_access_client BOOLEAN NOT NULL DEFAULT 0,
37
+ password_client BOOLEAN NOT NULL DEFAULT 0,
38
+ revoked BOOLEAN NOT NULL DEFAULT 0,
39
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
40
+ updated_at TIMESTAMP
41
+ )
42
+ `);
43
+ else
44
+ await db.unsafe(`
45
+ CREATE TABLE IF NOT EXISTS oauth_clients (
46
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
47
+ name VARCHAR(255) NOT NULL,
48
+ secret VARCHAR(100),
49
+ provider VARCHAR(255),
50
+ redirect VARCHAR(2000) NOT NULL,
51
+ personal_access_client BOOLEAN NOT NULL DEFAULT 0,
52
+ password_client BOOLEAN NOT NULL DEFAULT 0,
53
+ revoked BOOLEAN NOT NULL DEFAULT 0,
54
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
55
+ updated_at TIMESTAMP
56
+ )
57
+ `);
58
+ if (isPostgres)
59
+ await db.unsafe(`
60
+ CREATE TABLE IF NOT EXISTS oauth_access_tokens (
61
+ id SERIAL PRIMARY KEY,
62
+ user_id INTEGER NOT NULL,
63
+ oauth_client_id INTEGER NOT NULL,
64
+ token TEXT NOT NULL,
65
+ name VARCHAR(255),
66
+ scopes TEXT,
67
+ revoked BOOLEAN NOT NULL DEFAULT false,
68
+ expires_at TIMESTAMP,
69
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
70
+ updated_at TIMESTAMP
71
+ )
72
+ `);
73
+ else if (isMysql)
74
+ await db.unsafe(`
75
+ CREATE TABLE IF NOT EXISTS oauth_access_tokens (
76
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
77
+ user_id INTEGER NOT NULL,
78
+ oauth_client_id INTEGER NOT NULL,
79
+ token TEXT NOT NULL,
80
+ name VARCHAR(255),
81
+ scopes TEXT,
82
+ revoked BOOLEAN NOT NULL DEFAULT 0,
83
+ expires_at TIMESTAMP NULL,
84
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
85
+ updated_at TIMESTAMP NULL
86
+ )
87
+ `);
88
+ else
89
+ await db.unsafe(`
90
+ CREATE TABLE IF NOT EXISTS oauth_access_tokens (
91
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
92
+ user_id INTEGER NOT NULL,
93
+ oauth_client_id INTEGER NOT NULL,
94
+ token TEXT NOT NULL,
95
+ name VARCHAR(255),
96
+ scopes TEXT,
97
+ revoked BOOLEAN NOT NULL DEFAULT 0,
98
+ expires_at TIMESTAMP,
99
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
100
+ updated_at TIMESTAMP
101
+ )
102
+ `);
103
+ await db.unsafe(`
104
+ CREATE INDEX IF NOT EXISTS idx_oauth_access_tokens_token ON oauth_access_tokens(token)
105
+ `);
106
+ if (isPostgres)
107
+ await db.unsafe(`
108
+ CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
109
+ id SERIAL PRIMARY KEY,
110
+ access_token_id INTEGER NOT NULL,
111
+ token TEXT NOT NULL,
112
+ revoked BOOLEAN NOT NULL DEFAULT false,
113
+ expires_at TIMESTAMP,
114
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
115
+ )
116
+ `);
117
+ else if (isMysql)
118
+ await db.unsafe(`
119
+ CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
120
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
121
+ access_token_id INTEGER NOT NULL,
122
+ token TEXT NOT NULL,
123
+ revoked BOOLEAN NOT NULL DEFAULT 0,
124
+ expires_at TIMESTAMP NULL,
125
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
126
+ )
127
+ `);
128
+ else
129
+ await db.unsafe(`
130
+ CREATE TABLE IF NOT EXISTS oauth_refresh_tokens (
131
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
132
+ access_token_id INTEGER NOT NULL,
133
+ token TEXT NOT NULL,
134
+ revoked BOOLEAN NOT NULL DEFAULT 0,
135
+ expires_at TIMESTAMP,
136
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
137
+ )
138
+ `);
139
+ await db.unsafe(`
140
+ CREATE INDEX IF NOT EXISTS idx_oauth_refresh_tokens_token ON oauth_refresh_tokens(token)
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(`
151
+ CREATE TABLE IF NOT EXISTS password_resets (
152
+ id SERIAL PRIMARY KEY,
153
+ email VARCHAR(255) NOT NULL,
154
+ token VARCHAR(255) NOT NULL,
155
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
156
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
157
+ )
158
+ `);
159
+ else if (isMysql)
160
+ await db.unsafe(`
161
+ CREATE TABLE IF NOT EXISTS password_resets (
162
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
163
+ email VARCHAR(255) NOT NULL,
164
+ token VARCHAR(255) NOT NULL,
165
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
166
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
167
+ )
168
+ `);
169
+ else
170
+ await db.unsafe(`
171
+ CREATE TABLE IF NOT EXISTS password_resets (
172
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
173
+ email VARCHAR(255) NOT NULL,
174
+ token VARCHAR(255) NOT NULL,
175
+ expires_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
176
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
177
+ )
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(`
183
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_password_resets_email_unique ON password_resets(email)
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(`
194
+ CREATE TABLE IF NOT EXISTS email_verifications (
195
+ id SERIAL PRIMARY KEY,
196
+ user_id INTEGER NOT NULL,
197
+ token VARCHAR(255) NOT NULL,
198
+ expires_at TIMESTAMP NOT NULL,
199
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
200
+ )
201
+ `);
202
+ else if (isMysql)
203
+ await db.unsafe(`
204
+ CREATE TABLE IF NOT EXISTS email_verifications (
205
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
206
+ user_id INTEGER NOT NULL,
207
+ token VARCHAR(255) NOT NULL,
208
+ expires_at TIMESTAMP NOT NULL,
209
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
210
+ )
211
+ `);
212
+ else
213
+ await db.unsafe(`
214
+ CREATE TABLE IF NOT EXISTS email_verifications (
215
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
216
+ user_id INTEGER NOT NULL,
217
+ token VARCHAR(255) NOT NULL,
218
+ expires_at TIMESTAMP NOT NULL,
219
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
220
+ )
221
+ `);
222
+ await db.unsafe(`
223
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_email_verifications_user_id_unique ON email_verifications(user_id)
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(`
240
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
241
+ id SERIAL PRIMARY KEY,
242
+ user_id INTEGER NOT NULL,
243
+ challenge TEXT NOT NULL,
244
+ purpose VARCHAR(32) NOT NULL,
245
+ expires_at TIMESTAMP NOT NULL,
246
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
247
+ )
248
+ `);
249
+ else if (isMysql)
250
+ await db.unsafe(`
251
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
252
+ id INTEGER AUTO_INCREMENT PRIMARY KEY,
253
+ user_id INTEGER NOT NULL,
254
+ challenge TEXT NOT NULL,
255
+ purpose VARCHAR(32) NOT NULL,
256
+ expires_at TIMESTAMP NOT NULL,
257
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
258
+ )
259
+ `);
260
+ else
261
+ await db.unsafe(`
262
+ CREATE TABLE IF NOT EXISTS webauthn_challenges (
263
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
264
+ user_id INTEGER NOT NULL,
265
+ challenge TEXT NOT NULL,
266
+ purpose VARCHAR(32) NOT NULL,
267
+ expires_at TIMESTAMP NOT NULL,
268
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
269
+ )
270
+ `);
271
+ await db.unsafe(`
272
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_webauthn_challenges_user_purpose ON webauthn_challenges(user_id, purpose)
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(`
290
+ INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
291
+ VALUES ($1, $2, $3, $4, $5, $6, $7, NOW())
292
+ `, ["Personal Access Client", hashedSecret, "local", "http://localhost", !0, !1, !1]);
293
+ else
294
+ await db.unsafe(`
295
+ INSERT INTO oauth_clients (name, secret, provider, redirect, personal_access_client, password_client, revoked, created_at)
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);
@@ -0,0 +1 @@
1
+ export {};