@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.
- package/dist/action.d.ts +149 -0
- package/dist/action.js +78 -0
- package/dist/actions.d.ts +2 -0
- package/dist/actions.js +2 -0
- package/dist/add.d.ts +6 -0
- package/dist/add.js +20 -0
- package/dist/ai/request-model-access.d.ts +1 -0
- package/dist/ai/request-model-access.js +10 -0
- package/dist/auth/client.d.ts +1 -0
- package/dist/auth/client.js +44 -0
- package/dist/auth/prune.d.ts +1 -0
- package/dist/auth/prune.js +35 -0
- package/dist/auth/setup.d.ts +1 -0
- package/dist/auth/setup.js +322 -0
- package/dist/auth/token.d.ts +1 -0
- package/dist/auth/token.js +10 -0
- package/dist/blog-admin.d.ts +55 -0
- package/dist/blog-admin.js +156 -0
- package/dist/blog.d.ts +30 -0
- package/dist/blog.js +398 -0
- package/dist/build/cli.d.ts +1 -0
- package/dist/build/cli.js +6 -0
- package/dist/build/component-libs.d.ts +1 -0
- package/dist/build/component-libs.js +7 -0
- package/dist/build/core.d.ts +1 -0
- package/dist/build/core.js +55 -0
- package/dist/build/desktop.d.ts +1 -0
- package/dist/build/desktop.js +5 -0
- package/dist/build/docs.d.ts +1 -0
- package/dist/build/docs.js +5 -0
- package/dist/build/frontend-static.d.ts +16 -0
- package/dist/build/frontend-static.js +124 -0
- package/dist/build/server.d.ts +1 -0
- package/dist/build/server.js +6 -0
- package/dist/build/stacks.d.ts +1 -0
- package/dist/build/stacks.js +8 -0
- package/dist/build/views.d.ts +1 -0
- package/dist/build/views.js +11 -0
- package/dist/build.d.ts +9 -0
- package/dist/build.js +64 -0
- package/dist/bump.d.ts +1 -0
- package/dist/bump.js +163 -0
- package/dist/cdn/invalidate-cache.d.ts +1 -0
- package/dist/cdn/invalidate-cache.js +0 -0
- package/dist/changelog.d.ts +9 -0
- package/dist/changelog.js +27 -0
- package/dist/check/ports.d.ts +1 -0
- package/dist/check/ports.js +16 -0
- package/dist/clean.d.ts +1 -0
- package/dist/clean.js +4 -0
- package/dist/commit.d.ts +3 -0
- package/dist/commit.js +12 -0
- package/dist/copy-types.d.ts +1 -0
- package/dist/copy-types.js +10 -0
- package/dist/database/seed.d.ts +1 -0
- package/dist/database/seed.js +26 -0
- package/dist/deploy/create-receipt-rule.d.ts +1 -0
- package/dist/deploy/create-receipt-rule.js +36 -0
- package/dist/deploy/index.d.ts +1 -0
- package/dist/deploy/index.js +1574 -0
- package/dist/dev/api.d.ts +1 -0
- package/dist/dev/api.js +94 -0
- package/dist/dev/components.d.ts +1 -0
- package/dist/dev/components.js +7 -0
- package/dist/dev/dashboard-globals.d.ts +4 -0
- package/dist/dev/dashboard-globals.js +89 -0
- package/dist/dev/dashboard-utils.d.ts +150 -0
- package/dist/dev/dashboard-utils.js +380 -0
- package/dist/dev/dashboard.d.ts +22 -0
- package/dist/dev/dashboard.js +435 -0
- package/dist/dev/desktop.d.ts +1 -0
- package/dist/dev/desktop.js +5 -0
- package/dist/dev/docs.d.ts +1 -0
- package/dist/dev/docs.js +24 -0
- package/dist/dev/index.d.ts +10 -0
- package/dist/dev/index.js +29 -0
- package/dist/dev/migrate-watcher.d.ts +1 -0
- package/dist/dev/migrate-watcher.js +74 -0
- package/dist/dev/system-tray.d.ts +1 -0
- package/dist/dev/system-tray.js +5 -0
- package/dist/dev/views.d.ts +1 -0
- package/dist/dev/views.js +147 -0
- package/dist/discover-packages.d.ts +18 -0
- package/dist/discover-packages.js +32 -0
- package/dist/domains/add.d.ts +1 -0
- package/dist/domains/add.js +61 -0
- package/dist/domains/purchase.d.ts +1 -0
- package/dist/domains/purchase.js +66 -0
- package/dist/domains/remove.d.ts +1 -0
- package/dist/domains/remove.js +24 -0
- package/dist/examples.d.ts +5 -0
- package/dist/examples.js +34 -0
- package/dist/find-projects.d.ts +1 -0
- package/dist/find-projects.js +16 -0
- package/dist/fresh.d.ts +1 -0
- package/dist/fresh.js +17 -0
- package/dist/generate/action-types.d.ts +1 -0
- package/dist/generate/action-types.js +13 -0
- package/dist/generate/component-meta.d.ts +1 -0
- package/dist/generate/component-meta.js +9 -0
- package/dist/generate/custom-cli-file.d.ts +1 -0
- package/dist/generate/custom-cli-file.js +21 -0
- package/dist/generate/env-files.d.ts +1 -0
- package/dist/generate/env-files.js +66 -0
- package/dist/generate/ide-helpers.d.ts +1 -0
- package/dist/generate/ide-helpers.js +8 -0
- package/dist/generate/index.d.ts +36 -0
- package/dist/generate/index.js +158 -0
- package/dist/generate/lib-entries.d.ts +1 -0
- package/dist/generate/lib-entries.js +16 -0
- package/dist/generate/pantry-file.d.ts +1 -0
- package/dist/generate/pantry-file.js +46 -0
- package/dist/generate/symlink-core.d.ts +1 -0
- package/dist/generate/symlink-core.js +2 -0
- package/dist/generate/types.d.ts +1 -0
- package/dist/generate/types.js +3 -0
- package/dist/generate/vscode-custom-data.d.ts +1 -0
- package/dist/generate/vscode-custom-data.js +9 -0
- package/dist/generate/web-types.d.ts +1 -0
- package/dist/generate/web-types.js +0 -0
- package/dist/helpers/component-meta.d.ts +26 -0
- package/dist/helpers/component-meta.js +295 -0
- package/dist/helpers/index.d.ts +4 -0
- package/dist/helpers/index.js +1 -0
- package/dist/helpers/lib-entries.d.ts +12 -0
- package/dist/helpers/lib-entries.js +73 -0
- package/dist/helpers/package-json.d.ts +2 -0
- package/dist/helpers/package-json.js +74 -0
- package/dist/helpers/utils.d.ts +23 -0
- package/dist/helpers/utils.js +105 -0
- package/dist/helpers/vscode-custom-data.d.ts +3 -0
- package/dist/helpers/vscode-custom-data.js +30 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +50 -0
- package/dist/key-generate.d.ts +1 -0
- package/dist/key-generate.js +24 -0
- package/dist/lint/fix.d.ts +1 -0
- package/dist/lint/fix.js +4 -0
- package/dist/lint/index.d.ts +1 -0
- package/dist/lint/index.js +4 -0
- package/dist/lint/lint.d.ts +14 -0
- package/dist/lint/lint.js +34 -0
- package/dist/make-command.d.ts +10 -0
- package/dist/make-command.js +95 -0
- package/dist/make-job.d.ts +5 -0
- package/dist/make-job.js +154 -0
- package/dist/make-policy.d.ts +10 -0
- package/dist/make-policy.js +142 -0
- package/dist/make-resource.d.ts +10 -0
- package/dist/make-resource.js +142 -0
- package/dist/make.d.ts +52 -0
- package/dist/make.js +328 -0
- package/dist/migrate/database.d.ts +1 -0
- package/dist/migrate/database.js +16 -0
- package/dist/migrate/fresh.d.ts +1 -0
- package/dist/migrate/fresh.js +31 -0
- package/dist/orm/base.d.ts +1 -0
- package/dist/orm/base.js +0 -0
- package/dist/orm/test.d.ts +1 -0
- package/dist/orm/test.js +0 -0
- package/dist/prepublish.d.ts +1 -0
- package/dist/prepublish.js +16 -0
- package/dist/queue/clear.d.ts +1 -0
- package/dist/queue/clear.js +42 -0
- package/dist/queue/dlq-purge.d.ts +1 -0
- package/dist/queue/dlq-purge.js +28 -0
- package/dist/queue/dlq-retry.d.ts +1 -0
- package/dist/queue/dlq-retry.js +35 -0
- package/dist/queue/dlq.d.ts +1 -0
- package/dist/queue/dlq.js +55 -0
- package/dist/queue/failed.d.ts +1 -0
- package/dist/queue/failed.js +69 -0
- package/dist/queue/flush.d.ts +1 -0
- package/dist/queue/flush.js +49 -0
- package/dist/queue/inspect.d.ts +1 -0
- package/dist/queue/inspect.js +154 -0
- package/dist/queue/list.d.ts +1 -0
- package/dist/queue/list.js +69 -0
- package/dist/queue/monitor.d.ts +1 -0
- package/dist/queue/monitor.js +95 -0
- package/dist/queue/pause.d.ts +1 -0
- package/dist/queue/pause.js +28 -0
- package/dist/queue/quarantine.d.ts +1 -0
- package/dist/queue/quarantine.js +42 -0
- package/dist/queue/resume.d.ts +1 -0
- package/dist/queue/resume.js +27 -0
- package/dist/queue/retry.d.ts +1 -0
- package/dist/queue/retry.js +41 -0
- package/dist/queue/schedule-list.d.ts +1 -0
- package/dist/queue/schedule-list.js +33 -0
- package/dist/queue/schedule.d.ts +1 -0
- package/dist/queue/schedule.js +12 -0
- package/dist/queue/status.d.ts +1 -0
- package/dist/queue/status.js +68 -0
- package/dist/queue/table.d.ts +1 -0
- package/dist/queue/table.js +10 -0
- package/dist/queue/unquarantine.d.ts +1 -0
- package/dist/queue/unquarantine.js +27 -0
- package/dist/queue/work.d.ts +1 -0
- package/dist/queue/work.js +57 -0
- package/dist/release.d.ts +1 -0
- package/dist/release.js +21 -0
- package/dist/route/list.d.ts +1 -0
- package/dist/route/list.js +78 -0
- package/dist/run-action.d.ts +2 -0
- package/dist/run-action.js +1 -0
- package/dist/saas/setup.d.ts +1 -0
- package/dist/saas/setup.js +9 -0
- package/dist/scaffold-crud.d.ts +25 -0
- package/dist/scaffold-crud.js +211 -0
- package/dist/schedule/run.d.ts +1 -0
- package/dist/schedule/run.js +7 -0
- package/dist/search/flush.d.ts +1 -0
- package/dist/search/flush.js +10 -0
- package/dist/search/import.d.ts +1 -0
- package/dist/search/import.js +10 -0
- package/dist/search/settings-list.d.ts +1 -0
- package/dist/search/settings-list.js +10 -0
- package/dist/search/settings.d.ts +1 -0
- package/dist/search/settings.js +9 -0
- package/dist/serve/api.d.ts +1 -0
- package/dist/serve/api.js +35 -0
- package/dist/setup/index.d.ts +1 -0
- package/dist/setup/index.js +1 -0
- package/dist/setup/ssl.d.ts +38 -0
- package/dist/setup/ssl.js +271 -0
- package/dist/stacks.d.ts +4 -0
- package/dist/stacks.js +265 -0
- package/dist/templates.d.ts +28 -0
- package/dist/templates.js +301 -0
- package/dist/test/feature.d.ts +1 -0
- package/dist/test/feature.js +11 -0
- package/dist/test/index.d.ts +1 -0
- package/dist/test/index.js +11 -0
- package/dist/test/ui.d.ts +1 -0
- package/dist/test/ui.js +4 -0
- package/dist/test/unit.d.ts +1 -0
- package/dist/test/unit.js +11 -0
- package/dist/typecheck.d.ts +1 -0
- package/dist/typecheck.js +4 -0
- package/dist/types.d.ts +3 -0
- package/dist/types.js +16 -0
- package/dist/upgrade/binary.d.ts +1 -0
- package/dist/upgrade/binary.js +29 -0
- package/dist/upgrade/bun.d.ts +1 -0
- package/dist/upgrade/bun.js +0 -0
- package/dist/upgrade/dependencies.d.ts +1 -0
- package/dist/upgrade/dependencies.js +0 -0
- package/dist/upgrade/framework-utils.d.ts +150 -0
- package/dist/upgrade/framework-utils.js +193 -0
- package/dist/upgrade/framework.d.ts +1 -0
- package/dist/upgrade/framework.js +310 -0
- package/dist/upgrade/index.d.ts +1 -0
- package/dist/upgrade/index.js +17 -0
- package/dist/upgrade/packages.d.ts +14 -0
- package/dist/upgrade/packages.js +99 -0
- package/dist/upgrade/shell.d.ts +1 -0
- package/dist/upgrade/shell.js +41 -0
- package/dist/upgrade.d.ts +7 -0
- package/dist/upgrade.js +38 -0
- package/package.json +16 -16
package/dist/action.d.ts
ADDED
|
@@ -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
|
+
}
|
package/dist/actions.js
ADDED
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 {};
|