@stacksjs/defaults 0.75.32 → 0.75.34
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-auth/SKILL.md +6 -6
- package/app/Actions/Auth/OAuthAuthorizationAction.ts +3 -1
- package/app/Actions/Auth/OAuthConsentAction.ts +5 -1
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/components/NativeNavBar.stx +20 -8
- package/resources/components/NativePullToRefresh.stx +2 -0
- package/resources/components/NativeTabItem.stx +4 -1
|
@@ -295,7 +295,7 @@ interface RbacStore { findRoleByName, createRole, deleteRole, getAllRoles, findP
|
|
|
295
295
|
- `SessionAuth.check(sessionId): boolean`
|
|
296
296
|
- `SessionAuth.refresh(sessionId, ttlMs?): boolean`, rejects non-positive or non-finite TTLs without changing the session
|
|
297
297
|
|
|
298
|
-
Internal:
|
|
298
|
+
Internal: database-backed `sessions` rows with expiry, optional IP/User-Agent fingerprint checks, transactional logout and refresh, and timing-safe password comparison with a dummy bcrypt hash. Sessions survive process restarts and are shared by workers through the configured database.
|
|
299
299
|
|
|
300
300
|
## Email Verification (email-verification.ts)
|
|
301
301
|
|
|
@@ -504,12 +504,12 @@ traits: {
|
|
|
504
504
|
|
|
505
505
|
- Auth depends on `@stacksjs/ts-auth` for TOTP and passkey functions
|
|
506
506
|
- Password hashing defaults to bcrypt with 12 rounds (config/hashing.ts)
|
|
507
|
-
- Rate
|
|
508
|
-
- Session auth
|
|
509
|
-
-
|
|
510
|
-
-
|
|
507
|
+
- Rate limiting uses a process-local memory store by default. Production deployments with multiple workers should configure the atomic Redis store or provide a custom atomic store.
|
|
508
|
+
- Session auth is database-backed through the `sessions` table, so it survives server restarts and is shared across workers.
|
|
509
|
+
- New personal and delegated access tokens are opaque 40-byte hex bearers hashed at rest. Legacy `jwt:encryptedId` bearers remain readable during migration.
|
|
510
|
+
- Token validation hashes the bearer directly. Do not parse or expose token contents, and never log plaintext bearer values.
|
|
511
511
|
- Bearer tokens come from the `Authorization: Bearer <token>` header
|
|
512
|
-
- `Auth.user()` internally calls `getBearerToken()`
|
|
512
|
+
- `Auth.user()` internally calls `getBearerToken()` and resolves the bearer through a hashed token lookup
|
|
513
513
|
- RBAC has an internal cache (`userRoles`, `userPermissions`, `rolePermissions`) — call `Rbac.flushCache()` after direct DB changes
|
|
514
514
|
- `syncRoles()` and `syncPermissions()` are guard-scoped replacements: they preserve assignments belonging to other guards
|
|
515
515
|
- Gate `before` callbacks can short-circuit — return `true` to allow, `null` to continue checking
|
|
@@ -31,7 +31,9 @@ async function renderConsentView(
|
|
|
31
31
|
const { renderTemplate } = await import('@stacksjs/stx')
|
|
32
32
|
|
|
33
33
|
return String(await renderTemplate(template, {
|
|
34
|
-
|
|
34
|
+
// Spread into a literal: an interface has no index signature, so it is
|
|
35
|
+
// not a Record<string, unknown> until it becomes an object literal.
|
|
36
|
+
context: { ...context },
|
|
35
37
|
injectCSS: true,
|
|
36
38
|
templateOnly: true,
|
|
37
39
|
processClientScripts: false,
|
|
@@ -18,8 +18,12 @@ export default new Action({
|
|
|
18
18
|
if (!provider)
|
|
19
19
|
return response.notFound('OAuth provider is not enabled')
|
|
20
20
|
|
|
21
|
+
// Check `user` itself rather than only through `id`, so the workspace
|
|
22
|
+
// resolver below sees a narrowed user instead of `AuthenticatedUser | undefined`.
|
|
21
23
|
const user = await request.user()
|
|
22
|
-
|
|
24
|
+
if (!user)
|
|
25
|
+
return response.unauthorized('Authentication required')
|
|
26
|
+
const id = oauthPositiveId(user.id)
|
|
23
27
|
if (!id)
|
|
24
28
|
return response.unauthorized('Authentication required')
|
|
25
29
|
|
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.75.
|
|
5
|
+
"version": "0.75.34",
|
|
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.75.
|
|
58
|
+
"@stacksjs/mobile": "^0.75.34",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.113",
|
|
60
60
|
"ts-qr-codes": "^0.1.8"
|
|
61
61
|
}
|
|
@@ -79,18 +79,30 @@ function tapBack(event: MouseEvent): void {
|
|
|
79
79
|
align-items: center;
|
|
80
80
|
min-height: 2.75rem;
|
|
81
81
|
padding: 0 0.75rem;
|
|
82
|
-
border-bottom: 1px solid transparent;
|
|
83
|
-
transition: background-color 180ms ease, border-color 180ms ease;
|
|
84
82
|
}
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
/* The frosted material is always there and only fades. Adding or removing
|
|
85
|
+
backdrop-filter rebuilds the page's layers, which took 50-140ms of the
|
|
86
|
+
main thread at the moment the page crossed the threshold, mid-scroll. An
|
|
87
|
+
opacity change is the compositor's alone, as long as it never reaches 0:
|
|
88
|
+
WebKit drops a transparent layer and builds it again on the way back. */
|
|
89
|
+
.native-nav-bar::before {
|
|
90
|
+
content: '';
|
|
91
|
+
position: absolute;
|
|
92
|
+
inset: 0;
|
|
93
|
+
z-index: -1;
|
|
94
|
+
border-bottom: 1px solid var(--native-bar-border, rgb(148 163 184 / 0.25));
|
|
88
95
|
background: var(--native-bar-background, rgb(248 250 252 / 0.86));
|
|
89
96
|
backdrop-filter: blur(20px) saturate(180%);
|
|
90
97
|
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
|
98
|
+
opacity: 0.001;
|
|
99
|
+
pointer-events: none;
|
|
100
|
+
transition: opacity 180ms ease;
|
|
91
101
|
}
|
|
92
102
|
|
|
93
|
-
.
|
|
103
|
+
.native-nav-bar.is-scrolled::before { opacity: 1; }
|
|
104
|
+
|
|
105
|
+
.dark .native-nav-bar::before {
|
|
94
106
|
border-color: var(--native-bar-border-dark, rgb(51 65 85 / 0.6));
|
|
95
107
|
background: var(--native-bar-background-dark, rgb(2 6 23 / 0.86));
|
|
96
108
|
}
|
|
@@ -141,11 +153,11 @@ function tapBack(event: MouseEvent): void {
|
|
|
141
153
|
}
|
|
142
154
|
|
|
143
155
|
@media (prefers-reduced-motion: reduce) {
|
|
144
|
-
.native-nav-bar, .native-nav-title { transition: none; }
|
|
156
|
+
.native-nav-bar::before, .native-nav-title { transition: none; }
|
|
145
157
|
}
|
|
146
158
|
|
|
147
159
|
@media (prefers-reduced-transparency: reduce) {
|
|
148
|
-
.native-nav-bar
|
|
149
|
-
.dark .native-nav-bar
|
|
160
|
+
.native-nav-bar::before { backdrop-filter: none; -webkit-backdrop-filter: none; background: var(--native-bar-solid, rgb(248 250 252)); }
|
|
161
|
+
.dark .native-nav-bar::before { background: var(--native-bar-solid-dark, rgb(2 6 23)); }
|
|
150
162
|
}
|
|
151
163
|
</style>
|
|
@@ -77,6 +77,8 @@ const indicatorStyle = derived(() => {
|
|
|
77
77
|
opacity: 0;
|
|
78
78
|
pointer-events: none;
|
|
79
79
|
transform: translateX(-50%) scale(0.6);
|
|
80
|
+
/* Restyled every frame of a pull: its own layer keeps that off the page's paint. */
|
|
81
|
+
will-change: transform, opacity;
|
|
80
82
|
}
|
|
81
83
|
|
|
82
84
|
.dark .native-ptr-indicator { color: var(--native-accent-dark, rgb(96 165 250)); background: var(--native-ptr-background-dark, rgb(30 41 59)); }
|
|
@@ -19,7 +19,9 @@ const hasBadge = badge !== '' && badge !== 0 && badge !== '0'
|
|
|
19
19
|
|
|
20
20
|
<!-- `draggable="false"`: a slow tap on a busy page reaches the WebView as a
|
|
21
21
|
long press, and a draggable link starts a native drag instead of
|
|
22
|
-
navigating.
|
|
22
|
+
navigating. `data-stx-prefetch="eager"`: every tab's page is fetched once
|
|
23
|
+
the current one is idle, so switching tabs is served from the router's
|
|
24
|
+
cache, as instant as a native tab bar. -->
|
|
23
25
|
<StxLink
|
|
24
26
|
to="{{ href }}"
|
|
25
27
|
aria-label="{{ label }}"
|
|
@@ -27,6 +29,7 @@ const hasBadge = badge !== '' && badge !== 0 && badge !== '0'
|
|
|
27
29
|
activeMatch="{{ match }}"
|
|
28
30
|
class="native-tab-item"
|
|
29
31
|
draggable="false"
|
|
32
|
+
data-stx-prefetch="eager"
|
|
30
33
|
>
|
|
31
34
|
<span class="native-tab-glyph">
|
|
32
35
|
<i aria-hidden="true" class="{{ icon }} native-tab-icon"></i>
|