@stacksjs/defaults 0.74.61 → 0.74.63
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/ai/skills/stacks-dashboard/SKILL.md +2 -2
- package/app/Actions/Auth/MagicLinkConsumeAction.ts +7 -3
- package/app/Actions/Auth/RefreshTokenAction.ts +2 -2
- package/app/Actions/Auth/SocialCallbackAction.ts +7 -3
- package/app/Actions/Auth/VerifyAuthenticationAction.ts +24 -1
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/routes/auth.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-dashboard
|
|
3
|
-
description: Use when building or customizing the Stacks admin dashboard, including dashboard pages, model management views, analytics widgets, commerce dashboards, content management, settings panels, deployment monitoring, job/queue management, or the
|
|
3
|
+
description: Use when building or customizing the Stacks admin dashboard, including dashboard pages, model management views, analytics widgets, commerce dashboards, content management, settings panels, deployment monitoring, job/queue management, or the 401 built-in dashboard components. Covers the dashboard system at storage/framework/defaults/.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -8,7 +8,7 @@ allowed-tools: Read Edit Write Bash Grep Glob
|
|
|
8
8
|
|
|
9
9
|
# Stacks Dashboard
|
|
10
10
|
|
|
11
|
-
The Stacks admin dashboard provides a full-featured admin panel with 100+ route views,
|
|
11
|
+
The Stacks admin dashboard provides a full-featured admin panel with 100+ route views, 401 components, and a multi-section layout.
|
|
12
12
|
|
|
13
13
|
## Key Paths
|
|
14
14
|
- Dashboard components: `storage/framework/defaults/resources/components/Dashboard/`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions'
|
|
2
|
-
import { Auth,
|
|
2
|
+
import { Auth, authCookieForBrowserSession, resolveBrowserSessionPolicy, withMagicLink } from '@stacksjs/auth'
|
|
3
3
|
import { config } from '@stacksjs/config'
|
|
4
4
|
import { response } from '@stacksjs/router'
|
|
5
5
|
import { schema } from '@stacksjs/validation'
|
|
@@ -20,9 +20,13 @@ export default new Action({
|
|
|
20
20
|
if (!config.auth.magicLink?.enabled)
|
|
21
21
|
return response.notFound('Magic-link sign-in is not enabled')
|
|
22
22
|
|
|
23
|
+
const policy = resolveBrowserSessionPolicy(false)
|
|
23
24
|
const consumed = await withMagicLink(String(request.get('token')), async grant => ({
|
|
24
25
|
grant,
|
|
25
|
-
result: await Auth.loginUsingId(grant.userId
|
|
26
|
+
result: await Auth.loginUsingId(grant.userId, {
|
|
27
|
+
expiresInMinutes: policy.expiresInMinutes,
|
|
28
|
+
withRefreshToken: policy.withRefreshToken,
|
|
29
|
+
}),
|
|
26
30
|
}))
|
|
27
31
|
if (!consumed.ok) {
|
|
28
32
|
const messages: Record<string, string> = {
|
|
@@ -51,6 +55,6 @@ export default new Action({
|
|
|
51
55
|
email: result.user?.email,
|
|
52
56
|
name: result.user?.name,
|
|
53
57
|
},
|
|
54
|
-
}, { headers: { 'Set-Cookie':
|
|
58
|
+
}, { headers: { 'Set-Cookie': authCookieForBrowserSession(result.token, result.expiresIn) } })
|
|
55
59
|
},
|
|
56
60
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions'
|
|
2
|
-
import {
|
|
2
|
+
import { authCookieForBrowserSession, refreshToken } from '@stacksjs/auth'
|
|
3
3
|
import { response } from '@stacksjs/router'
|
|
4
4
|
import { schema } from '@stacksjs/validation'
|
|
5
5
|
|
|
@@ -34,7 +34,7 @@ export default new Action({
|
|
|
34
34
|
refresh_token: result.refreshToken,
|
|
35
35
|
token_type: 'Bearer',
|
|
36
36
|
expires_in: result.expiresIn,
|
|
37
|
-
}, { headers: { 'Set-Cookie':
|
|
37
|
+
}, { headers: { 'Set-Cookie': authCookieForBrowserSession(result.plainTextToken, result.expiresIn) } })
|
|
38
38
|
}
|
|
39
39
|
catch (error: any) {
|
|
40
40
|
return response.unauthorized(error.message || 'Invalid or expired refresh token')
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Action } from '@stacksjs/actions'
|
|
2
|
-
import { Auth,
|
|
2
|
+
import { Auth, authCookieForBrowserSession, resolveBrowserSessionPolicy, resolveSocialSignIn, SocialSignInRefusedError } from '@stacksjs/auth'
|
|
3
3
|
import { log } from '@stacksjs/logging'
|
|
4
4
|
import { response } from '@stacksjs/router'
|
|
5
5
|
import { isSocialProviderConfigured, socialHandoffFailureRedirect, socialHandoffRedirect, socialProvider } from '@stacksjs/socials'
|
|
@@ -45,7 +45,11 @@ export default new Action({
|
|
|
45
45
|
|
|
46
46
|
const { userId } = await resolveSocialSignIn(provider, identity)
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const policy = resolveBrowserSessionPolicy(false)
|
|
49
|
+
const session = await Auth.loginUsingId(userId, {
|
|
50
|
+
expiresInMinutes: policy.expiresInMinutes,
|
|
51
|
+
withRefreshToken: policy.withRefreshToken,
|
|
52
|
+
})
|
|
49
53
|
if (!session?.token)
|
|
50
54
|
return socialHandoffFailureRedirect('Sign-in could not be completed. Please try again.')
|
|
51
55
|
|
|
@@ -61,7 +65,7 @@ export default new Action({
|
|
|
61
65
|
})
|
|
62
66
|
|
|
63
67
|
// The cookie signs server-rendered pages in; the fragment pack the SPA.
|
|
64
|
-
redirect.headers.append('Set-Cookie',
|
|
68
|
+
redirect.headers.append('Set-Cookie', authCookieForBrowserSession(session.token, session.expiresIn))
|
|
65
69
|
return redirect
|
|
66
70
|
}
|
|
67
71
|
catch (error) {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { AuthenticationCredential } from '@stacksjs/auth'
|
|
2
2
|
import { Action } from '@stacksjs/actions'
|
|
3
3
|
import {
|
|
4
|
+
Auth,
|
|
5
|
+
authCookieForBrowserSession,
|
|
4
6
|
consumeWebAuthnChallenge,
|
|
5
7
|
getUserPasskey,
|
|
8
|
+
resolveBrowserSessionPolicy,
|
|
6
9
|
updatePasskeyCounter,
|
|
7
10
|
verifyAuthenticationResponse,
|
|
8
11
|
} from '@stacksjs/auth'
|
|
@@ -86,7 +89,27 @@ export default new Action({
|
|
|
86
89
|
}
|
|
87
90
|
}
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
const policy = resolveBrowserSessionPolicy(false)
|
|
93
|
+
const session = await Auth.loginUsingId(user.id as number, {
|
|
94
|
+
expiresInMinutes: policy.expiresInMinutes,
|
|
95
|
+
withRefreshToken: policy.withRefreshToken,
|
|
96
|
+
})
|
|
97
|
+
if (!session)
|
|
98
|
+
return response.serverError('Authentication session could not be created')
|
|
99
|
+
|
|
100
|
+
return response.json({
|
|
101
|
+
...verification,
|
|
102
|
+
access_token: session.token,
|
|
103
|
+
refresh_token: session.refreshToken,
|
|
104
|
+
token_type: 'Bearer',
|
|
105
|
+
expires_in: session.expiresIn,
|
|
106
|
+
token: session.token,
|
|
107
|
+
user: {
|
|
108
|
+
id: session.user?.id,
|
|
109
|
+
email: session.user?.email,
|
|
110
|
+
name: session.user?.name,
|
|
111
|
+
},
|
|
112
|
+
}, { headers: { 'Set-Cookie': authCookieForBrowserSession(session.token, session.expiresIn) } })
|
|
90
113
|
}
|
|
91
114
|
catch (error) {
|
|
92
115
|
console.error('Authentication verification failed:', error)
|
package/ide/vscode/package.json
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.74.
|
|
5
|
+
"version": "0.74.63",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@iconify-json/f7": "^1.2.2",
|
|
57
57
|
"@iconify-json/hugeicons": "^1.2.27",
|
|
58
|
-
"@stacksjs/mobile": "^0.74.
|
|
58
|
+
"@stacksjs/mobile": "^0.74.63",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.113",
|
|
60
60
|
"ts-qr-codes": "^0.1.8"
|
|
61
61
|
}
|
package/routes/auth.ts
CHANGED
|
@@ -53,7 +53,7 @@ route.post('/verify-registration', 'Actions/Auth/VerifyRegistrationAction').midd
|
|
|
53
53
|
// Passkey AUTHENTICATION (logging in) is correctly unauthenticated —
|
|
54
54
|
// the caller doesn't have a session yet, that's the point.
|
|
55
55
|
route.get('/generate-authentication-options', 'Actions/Auth/GenerateAuthenticationAction').rateLimit(10, 'minute')
|
|
56
|
-
route.
|
|
56
|
+
route.post('/verify-authentication', 'Actions/Auth/VerifyAuthenticationAction').rateLimit(10, 'minute')
|
|
57
57
|
|
|
58
58
|
// TOTP 2FA. Setup/enable/disable act on the caller's own authenticated
|
|
59
59
|
// account (auth-gated, same identity rule as passkey enrollment above).
|