@stacksjs/defaults 0.75.263 → 0.75.267
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-browse/SKILL.md +3 -0
- package/ai/skills/stacks-browse/scripts/browse.ts +73 -14
- package/ai/skills/stacks-chat/SKILL.md +32 -0
- package/ai/skills/stacks-native/CATALOG.md +8 -8
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -4
- package/resources/components/Dashboard/App/RequestsOverview.stx +75 -58
- package/resources/components/Dashboard/App/SourceInventory.stx +68 -59
- package/resources/components/Dashboard/Auth/AccessTokens.stx +57 -37
- package/resources/components/Dashboard/Billing/BillingTransactionHistory.stx +27 -33
- package/resources/components/Dashboard/Commerce/CommercePaymentsTable.stx +85 -49
- package/resources/components/Dashboard/Commerce/CommerceTaxesTable.stx +63 -66
- package/resources/components/Dashboard/Commerce/CommerceVariantsTable.stx +67 -23
- package/resources/components/Dashboard/Content/BlogDashboard.stx +73 -67
- package/resources/components/Dashboard/Content/FileManagerDashboard.stx +39 -12
- package/resources/components/Dashboard/Data/DataRecords.stx +85 -88
- package/resources/components/Dashboard/Deployments/DeploymentTable.stx +49 -64
- package/resources/components/Dashboard/Infrastructure/DnsDashboard.stx +46 -28
- package/resources/components/Dashboard/Operations/RecoveryPointTable.stx +72 -61
- package/resources/components/Dashboard/Operations/SchedulerTaskTable.stx +74 -70
- package/resources/components/Dashboard/Queue/QueueDashboard.stx +27 -61
- package/resources/components/Dashboard/Releases/ReleaseDashboard.stx +35 -61
- package/resources/components/Dashboard/Teams/TeamPeopleDashboard.stx +127 -143
|
@@ -37,6 +37,8 @@ A candidate is validated with `--version` before use, so a dead wrapper (e.g. a
|
|
|
37
37
|
shim pointing at an uninstalled `.app`) is skipped automatically. If none launch, it tells
|
|
38
38
|
you to `brew install --cask chromium` or set `BROWSE_BROWSER`.
|
|
39
39
|
|
|
40
|
+
Startup waits up to 15 seconds for the running browser's valid DevTools port. An exited process or expired deadline fails launch; page readiness and scenario assertions have separate budgets.
|
|
41
|
+
|
|
40
42
|
## Default Stacks dev URLs
|
|
41
43
|
|
|
42
44
|
- Frontend: `http://localhost:3000`
|
|
@@ -121,6 +123,7 @@ On a failed step, execution stops and the report retains its number and error,
|
|
|
121
123
|
the completed steps, final page state and requested screenshot.
|
|
122
124
|
Use `{"action":"assert","selector":"...","absent":true}` to verify that an element is missing or hidden after an interaction.
|
|
123
125
|
Use `{"action":"assert","selector":"button","text":"Save","focused":true}` to verify keyboard focus and focus restoration.
|
|
126
|
+
For asynchronous results, use `{"action":"assert","selector":"button","text":"Sound on","timeoutMs":2000}`. This observes the actual visible result until it matches or the bounded budget expires. Ordinary assertions remain immediate. Only assertions accept `timeoutMs`, an integer from 0 to 30000; protocol and evaluation failures are not retried.
|
|
124
127
|
|
|
125
128
|
### Crawl (whole-site browser audit)
|
|
126
129
|
```bash
|
|
@@ -174,6 +174,28 @@ class Cdp {
|
|
|
174
174
|
|
|
175
175
|
interface Session { proc: ReturnType<typeof spawn>, port: number, userDataDir: string, browser: string }
|
|
176
176
|
|
|
177
|
+
export async function waitForBrowserPort(proc: { exitCode: number | null }, portFile: string, timeoutMs: number): Promise<number | null> {
|
|
178
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0 || timeoutMs > 30_000)
|
|
179
|
+
throw new TypeError('Browser startup timeout must be an integer between 1 and 30000.')
|
|
180
|
+
const deadline = performance.now() + timeoutMs
|
|
181
|
+
while (performance.now() < deadline && proc.exitCode === null) {
|
|
182
|
+
try {
|
|
183
|
+
const line = readFileSync(portFile, 'utf8').split('\n')[0]?.trim()
|
|
184
|
+
const port = Number(line)
|
|
185
|
+
if (Number.isInteger(port) && port > 0 && port <= 65535) {
|
|
186
|
+
if (performance.now() >= deadline || proc.exitCode !== null) return null
|
|
187
|
+
return port
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
|
|
192
|
+
}
|
|
193
|
+
const remaining = deadline - performance.now()
|
|
194
|
+
if (remaining > 0) await Bun.sleep(Math.min(50, remaining))
|
|
195
|
+
}
|
|
196
|
+
return null
|
|
197
|
+
}
|
|
198
|
+
|
|
177
199
|
async function tryLaunch(browser: string): Promise<Session | null> {
|
|
178
200
|
const userDataDir = join(tmpdir(), `stacks-browse-${process.pid}-${Math.floor(Number(process.hrtime.bigint() % 1000000n))}`)
|
|
179
201
|
mkdirSync(userDataDir, { recursive: true })
|
|
@@ -196,18 +218,19 @@ async function tryLaunch(browser: string): Promise<Session | null> {
|
|
|
196
218
|
|
|
197
219
|
// Chromium writes the chosen port to <user-data-dir>/DevToolsActivePort.
|
|
198
220
|
const portFile = join(userDataDir, 'DevToolsActivePort')
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
221
|
+
let port: number | null = null
|
|
222
|
+
try {
|
|
223
|
+
port = await waitForBrowserPort(proc, portFile, 15_000)
|
|
224
|
+
if (port !== null) return { proc, port, userDataDir, browser }
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
if (port === null) {
|
|
228
|
+
try { proc.kill() }
|
|
229
|
+
catch { /* ignore */ }
|
|
230
|
+
try { rmSync(userDataDir, { recursive: true, force: true }) }
|
|
231
|
+
catch { /* a failed launch must not mask the next browser candidate */ }
|
|
204
232
|
}
|
|
205
|
-
await Bun.sleep(50)
|
|
206
233
|
}
|
|
207
|
-
try { proc.kill() }
|
|
208
|
-
catch { /* ignore */ }
|
|
209
|
-
try { rmSync(userDataDir, { recursive: true, force: true }) }
|
|
210
|
-
catch { /* a failed launch must not mask the next browser candidate */ }
|
|
211
234
|
return null
|
|
212
235
|
}
|
|
213
236
|
|
|
@@ -600,9 +623,12 @@ interface ScenarioStep {
|
|
|
600
623
|
key?: string
|
|
601
624
|
ms?: number
|
|
602
625
|
settle?: number
|
|
626
|
+
timeoutMs?: number
|
|
603
627
|
}
|
|
604
628
|
|
|
605
|
-
|
|
629
|
+
class ScenarioAssertionError extends Error {}
|
|
630
|
+
|
|
631
|
+
export function parseScenarioStep(value: string): ScenarioStep {
|
|
606
632
|
let parsed: unknown
|
|
607
633
|
try {
|
|
608
634
|
parsed = JSON.parse(value)
|
|
@@ -633,11 +659,41 @@ function parseScenarioStep(value: string): ScenarioStep {
|
|
|
633
659
|
throw new TypeError('Scenario action "press" requires a key.')
|
|
634
660
|
if (action === 'wait' && (!Number.isFinite(step.ms) || Number(step.ms) < 0 || Number(step.ms) > 30_000))
|
|
635
661
|
throw new TypeError('Scenario action "wait" requires ms between 0 and 30000.')
|
|
662
|
+
if (step.timeoutMs !== undefined && (action !== 'assert' || !Number.isSafeInteger(step.timeoutMs) || Number(step.timeoutMs) < 0 || Number(step.timeoutMs) > 30_000))
|
|
663
|
+
throw new TypeError('Scenario timeoutMs is supported only by assert actions and must be an integer between 0 and 30000.')
|
|
636
664
|
|
|
637
665
|
return step as unknown as ScenarioStep
|
|
638
666
|
}
|
|
639
667
|
|
|
640
|
-
async function runScenarioStep(cdp: Cdp, step: ScenarioStep): Promise<Record<string, unknown>> {
|
|
668
|
+
export async function runScenarioStep(cdp: Pick<Cdp, 'send'>, step: ScenarioStep): Promise<Record<string, unknown>> {
|
|
669
|
+
if (step.action === 'assert' && step.timeoutMs) {
|
|
670
|
+
const deadline = performance.now() + step.timeoutMs
|
|
671
|
+
let last: ScenarioAssertionError | undefined
|
|
672
|
+
const expired = () => new Error(`${last?.message || `Scenario assert failed (${step.selector || ''})`}; timed out after ${step.timeoutMs}ms`)
|
|
673
|
+
while (true) {
|
|
674
|
+
const budget = deadline - performance.now()
|
|
675
|
+
if (budget <= 0) throw expired()
|
|
676
|
+
let timeout: ReturnType<typeof setTimeout> | undefined
|
|
677
|
+
try {
|
|
678
|
+
const expiry = Promise.withResolvers<never>()
|
|
679
|
+
timeout = setTimeout(() => expiry.reject(expired()), budget)
|
|
680
|
+
const answer = await Promise.race([
|
|
681
|
+
runScenarioStep(cdp, { ...step, timeoutMs: 0 }),
|
|
682
|
+
expiry.promise,
|
|
683
|
+
])
|
|
684
|
+
if (performance.now() > deadline) throw expired()
|
|
685
|
+
return answer
|
|
686
|
+
}
|
|
687
|
+
catch (error) {
|
|
688
|
+
if (!(error instanceof ScenarioAssertionError)) throw error
|
|
689
|
+
last = error
|
|
690
|
+
const remaining = deadline - performance.now()
|
|
691
|
+
if (remaining <= 0) throw error
|
|
692
|
+
await Bun.sleep(Math.min(50, remaining))
|
|
693
|
+
}
|
|
694
|
+
finally { if (timeout !== undefined) clearTimeout(timeout) }
|
|
695
|
+
}
|
|
696
|
+
}
|
|
641
697
|
if (step.action === 'wait') {
|
|
642
698
|
await Bun.sleep(Number(step.ms))
|
|
643
699
|
return { action: step.action, ms: Number(step.ms), ok: true }
|
|
@@ -740,8 +796,11 @@ async function runScenarioStep(cdp: Cdp, step: ScenarioStep): Promise<Record<str
|
|
|
740
796
|
returnByValue: true,
|
|
741
797
|
})
|
|
742
798
|
const value = result.result?.value as Record<string, unknown> | undefined
|
|
743
|
-
if (!value?.ok)
|
|
799
|
+
if (!value?.ok) {
|
|
800
|
+
if (step.action === 'assert' && value)
|
|
801
|
+
throw new ScenarioAssertionError(`Scenario assert failed: ${String(value.error || 'unknown error')} (${step.selector || ''})`)
|
|
744
802
|
throw new Error(`Scenario ${step.action} failed: ${String(value?.error || 'unknown error')} (${step.selector || step.key || ''})`)
|
|
803
|
+
}
|
|
745
804
|
if (step.action === 'click') {
|
|
746
805
|
const point = value.clickPoint as { x: number, y: number }
|
|
747
806
|
await cdp.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: point.x, y: point.y, button: 'left', clickCount: 1 })
|
|
@@ -1196,7 +1255,7 @@ async function main() {
|
|
|
1196
1255
|
}
|
|
1197
1256
|
}
|
|
1198
1257
|
|
|
1199
|
-
main().catch((e) => {
|
|
1258
|
+
if (import.meta.main) main().catch((e) => {
|
|
1200
1259
|
console.error('browse error:', e?.message || e)
|
|
1201
1260
|
process.exit(1)
|
|
1202
1261
|
})
|
|
@@ -508,6 +508,38 @@ History is chronological, with `has_more` and a `before` message-id cursor.
|
|
|
508
508
|
Receipts acknowledge only messages through the id actually displayed.
|
|
509
509
|
`MessagingError.status` provides safe HTTP statuses for application handlers.
|
|
510
510
|
|
|
511
|
+
### Attachments
|
|
512
|
+
|
|
513
|
+
`send(id, body, retryKey, attachments?)` records files the application has
|
|
514
|
+
already stored. The trait keeps a reference, never bytes: `file` is the
|
|
515
|
+
application's own name for the upload (a disk path, a bucket key, an id), and
|
|
516
|
+
`type`, `size`, `width` and `height` are optional. Resolving and authorizing
|
|
517
|
+
the file stays with the application, so a disk, a bucket and a CDN look the
|
|
518
|
+
same from here.
|
|
519
|
+
|
|
520
|
+
```ts
|
|
521
|
+
import type { DirectMessageAttachment } from '@stacksjs/chat'
|
|
522
|
+
|
|
523
|
+
const photo: DirectMessageAttachment = { file: upload.key, type: 'image/jpeg', size: upload.size, width: 1200, height: 900 }
|
|
524
|
+
await messenger.send(thread.id, '', retryKey, [photo])
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
- A photo with no caption is a message: `body` may be empty when there is at
|
|
528
|
+
least one attachment, and only then.
|
|
529
|
+
- `message.attachments` is always an array, `[]` for text. Rows written before
|
|
530
|
+
the column existed read as `[]`.
|
|
531
|
+
- A retry key covers the attachments too. The same key with a different file
|
|
532
|
+
is a different message and returns 409, rather than silently keeping the
|
|
533
|
+
first photo.
|
|
534
|
+
- At most 10 attachments, 4000 characters once serialised. Keys the trait does
|
|
535
|
+
not know are dropped, so the column cannot become a second message body.
|
|
536
|
+
- The column is `chat_messages.attachments`, added by `buddy migrate` to a
|
|
537
|
+
database created before it. A database that has not migrated yet still sends
|
|
538
|
+
text.
|
|
539
|
+
- Notification previews are the application's to word: `onMessageSent`
|
|
540
|
+
receives the message with its attachments, so a photo with no caption can
|
|
541
|
+
read as "Sent a photo" rather than as an empty line.
|
|
542
|
+
|
|
511
543
|
For the UI, STX ships `ChatInbox`, `ChatMessage`, and `ChatUnreadBadge` in
|
|
512
544
|
`@stacksjs/components`. Browser stores import `createChat` from
|
|
513
545
|
`@stacksjs/components/chat` and inject their authenticated HTTP transport.
|
|
@@ -18,10 +18,10 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
18
18
|
| `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 9 |
|
|
19
19
|
| `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 6 |
|
|
20
20
|
| `@stacksjs/audio` | [`stacks-audio`](../stacks-audio/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/audio/src/index.ts) | 2 |
|
|
21
|
-
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) |
|
|
21
|
+
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 120 |
|
|
22
22
|
| `@stacksjs/browser` | [`stacks-browser`](../stacks-browser/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser/src/index.ts) | 8 |
|
|
23
23
|
| `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 7 |
|
|
24
|
-
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) |
|
|
24
|
+
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 164 |
|
|
25
25
|
| `@stacksjs/build` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/build/src/index.ts) | 3 |
|
|
26
26
|
| `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 14 |
|
|
27
27
|
| `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
|
|
@@ -65,7 +65,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
65
65
|
| `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 7 |
|
|
66
66
|
| `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 16 |
|
|
67
67
|
| `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
|
|
68
|
-
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) |
|
|
68
|
+
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 72 |
|
|
69
69
|
| `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
|
|
70
70
|
| `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 13 |
|
|
71
71
|
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 28 |
|
|
@@ -79,7 +79,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
79
79
|
| `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 14 |
|
|
80
80
|
| `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 10 |
|
|
81
81
|
| `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 11 |
|
|
82
|
-
| `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) |
|
|
82
|
+
| `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 26 |
|
|
83
83
|
| `@stacksjs/shell` | [`stacks-shell`](../stacks-shell/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/shell/src/index.ts) | 1 |
|
|
84
84
|
| `@stacksjs/sites` | [`stacks-sites`](../stacks-sites/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sites/src/index.ts) | 3 |
|
|
85
85
|
| `@stacksjs/skills` | [`stacks-skills`](../stacks-skills/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/skills/src/index.ts) | 1 |
|
|
@@ -185,7 +185,7 @@ Declared runtime exports: `DEFAULT_ROLE_PACKS`, `createBqbRbacStore`, `generateT
|
|
|
185
185
|
|
|
186
186
|
Local source modules: [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
|
|
187
187
|
|
|
188
|
-
Evidence directory: [
|
|
188
|
+
Evidence directory: [120 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
189
189
|
|
|
190
190
|
### @stacksjs/browser
|
|
191
191
|
|
|
@@ -215,7 +215,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
|
|
|
215
215
|
|
|
216
216
|
Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
|
|
217
217
|
|
|
218
|
-
Evidence directory: [
|
|
218
|
+
Evidence directory: [164 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
219
219
|
|
|
220
220
|
### @stacksjs/build
|
|
221
221
|
|
|
@@ -633,7 +633,7 @@ Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`
|
|
|
633
633
|
|
|
634
634
|
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/messaging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/messaging.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
635
635
|
|
|
636
|
-
Evidence directory: [
|
|
636
|
+
Evidence directory: [72 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
637
637
|
|
|
638
638
|
### @stacksjs/pagination
|
|
639
639
|
|
|
@@ -763,7 +763,7 @@ Declared runtime exports: `server`.
|
|
|
763
763
|
|
|
764
764
|
Local source modules: [src/config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/config.ts), [src/controllers/base.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/controllers/base.ts), [src/imports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/imports.ts), [src/maintenance.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/maintenance.ts), [src/proxy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/proxy.ts), [src/redirects.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/redirects.ts), [src/rewrites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/rewrites.ts), [src/security-headers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/security-headers.ts), [src/shadowed-defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/shadowed-defaults.ts).
|
|
765
765
|
|
|
766
|
-
Evidence directory: [
|
|
766
|
+
Evidence directory: [26 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
767
767
|
|
|
768
768
|
### @stacksjs/shell
|
|
769
769
|
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.267",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
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.267",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,9 +45,9 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
49
|
-
"@stacksjs/sanitizer": "0.2.
|
|
50
|
-
"@stacksjs/stx": "0.2.
|
|
48
|
+
"@stacksjs/mobile": "0.75.267",
|
|
49
|
+
"@stacksjs/sanitizer": "0.2.664",
|
|
50
|
+
"@stacksjs/stx": "0.2.664",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|
|
52
52
|
"@xterm/xterm": "^6.0.0",
|
|
53
53
|
"ts-qr-codes": "^0.1.8"
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import('../UI/Table')
|
|
2
|
+
|
|
1
3
|
<script client>
|
|
2
4
|
import { dashboardApi } from '../../../../functions/dashboard-api'
|
|
3
5
|
|
|
@@ -67,29 +69,75 @@ const filteredRequests = derived(() => {
|
|
|
67
69
|
})
|
|
68
70
|
})
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function statusClass(status: number): string {
|
|
72
|
+
/**
|
|
73
|
+
* Pill colours by tone rather than by value, so every status code and every
|
|
74
|
+
* method the table has not named still lands on a colour, as the hand-rolled
|
|
75
|
+
* pills did.
|
|
76
|
+
*/
|
|
77
|
+
function statusTone(status: number): string {
|
|
78
78
|
if (status >= 500)
|
|
79
|
-
return '
|
|
79
|
+
return 'server'
|
|
80
80
|
if (status >= 400)
|
|
81
|
-
return '
|
|
81
|
+
return 'client'
|
|
82
82
|
if (status >= 300)
|
|
83
|
-
return '
|
|
84
|
-
return '
|
|
83
|
+
return 'redirect'
|
|
84
|
+
return 'ok'
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
function
|
|
87
|
+
function methodTone(method: string): string {
|
|
88
88
|
if (method === 'GET')
|
|
89
|
-
return '
|
|
89
|
+
return 'read'
|
|
90
90
|
if (method === 'DELETE')
|
|
91
|
-
return '
|
|
92
|
-
return '
|
|
91
|
+
return 'delete'
|
|
92
|
+
return 'write'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const COLUMNS = [
|
|
96
|
+
{
|
|
97
|
+
key: 'methodTone',
|
|
98
|
+
label: 'Method',
|
|
99
|
+
type: 'badge' as const,
|
|
100
|
+
sortable: true,
|
|
101
|
+
badgeLabelKey: 'method',
|
|
102
|
+
badgeClasses: {
|
|
103
|
+
read: 'text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40',
|
|
104
|
+
delete: 'text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-950/40',
|
|
105
|
+
write: 'text-violet-700 dark:text-violet-300 bg-violet-50 dark:bg-violet-950/40',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{ key: 'path', label: 'Path', sortable: true, class: 'max-w-md font-mono text-neutral-800 text-xs truncate dark:text-neutral-200' },
|
|
109
|
+
{
|
|
110
|
+
key: 'statusTone',
|
|
111
|
+
label: 'Status',
|
|
112
|
+
type: 'badge' as const,
|
|
113
|
+
sortable: true,
|
|
114
|
+
badgeLabelKey: 'status',
|
|
115
|
+
badgeClasses: {
|
|
116
|
+
server: 'text-red-700 dark:text-red-300 bg-red-50 dark:bg-red-950/40',
|
|
117
|
+
client: 'text-amber-700 dark:text-amber-300 bg-amber-50 dark:bg-amber-950/40',
|
|
118
|
+
redirect: 'text-blue-700 dark:text-blue-300 bg-blue-50 dark:bg-blue-950/40',
|
|
119
|
+
ok: 'text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-950/40',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{ key: 'durationMs', label: 'Duration (ms)', type: 'number' as const, sortable: true, align: 'right' as const, class: 'font-mono whitespace-nowrap' },
|
|
123
|
+
{ key: 'ipAddress', label: 'Client', sortable: true, emptyText: 'Not recorded' },
|
|
124
|
+
{ key: 'createdAt', label: 'Recorded', type: 'datetime' as const, sortable: true, align: 'right' as const, emptyText: 'Unknown', class: 'whitespace-nowrap' },
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
const ROW_ACTIONS = [
|
|
128
|
+
{ action: 'inspect', label: 'Inspect request', icon: 'i-hugeicons-view' },
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
const requestRows = derived(() => filteredRequests().map(request => ({
|
|
132
|
+
...request,
|
|
133
|
+
methodTone: methodTone(request.method),
|
|
134
|
+
statusTone: statusTone(request.status),
|
|
135
|
+
durationMs: Math.round(request.durationMs * 10) / 10,
|
|
136
|
+
})))
|
|
137
|
+
|
|
138
|
+
function handleRowAction(payload: { action: string, row: RequestRow }): void {
|
|
139
|
+
if (payload.action === 'inspect')
|
|
140
|
+
inspectRequest(payload.row)
|
|
93
141
|
}
|
|
94
142
|
|
|
95
143
|
function inspectRequest(request: RequestRow): void {
|
|
@@ -184,49 +232,18 @@ onMount(() => {
|
|
|
184
232
|
</div>
|
|
185
233
|
</div>
|
|
186
234
|
|
|
187
|
-
<
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
:title="search() || methodFilter() !== 'all' || statusFilter() !== 'all' ? 'No matching requests' : 'No requests recorded'"
|
|
196
|
-
description="Request records appear after the application writes to the Request model."
|
|
235
|
+
<Table
|
|
236
|
+
:columns="COLUMNS"
|
|
237
|
+
:data="requestRows()"
|
|
238
|
+
:loading="loading()"
|
|
239
|
+
:row-actions="ROW_ACTIONS"
|
|
240
|
+
action-label-key="path"
|
|
241
|
+
paginated
|
|
242
|
+
:page-size="25"
|
|
243
|
+
:empty-title="search() || methodFilter() !== 'all' || statusFilter() !== 'all' ? 'No matching requests' : 'No requests recorded'"
|
|
244
|
+
empty-description="Request records appear after the application writes to the Request model."
|
|
245
|
+
@row-action="handleRowAction"
|
|
197
246
|
/>
|
|
198
|
-
|
|
199
|
-
<div :if="!loading() && filteredRequests().length > 0" class="overflow-x-auto">
|
|
200
|
-
<table class="w-full">
|
|
201
|
-
<thead class="bg-neutral-50 dark:bg-neutral-800/50">
|
|
202
|
-
<tr>
|
|
203
|
-
<th class="pl-5 pr-4 py-3 font-semibold text-left text-neutral-500 text-xs tracking-wider uppercase dark:text-neutral-400">Request</th>
|
|
204
|
-
<th class="px-4 py-3 font-semibold text-left text-neutral-500 text-xs tracking-wider uppercase dark:text-neutral-400">Status</th>
|
|
205
|
-
<th class="px-4 py-3 font-semibold text-neutral-500 text-right text-xs tracking-wider uppercase dark:text-neutral-400">Duration</th>
|
|
206
|
-
<th class="px-4 py-3 font-semibold text-left text-neutral-500 text-xs tracking-wider uppercase dark:text-neutral-400">Client</th>
|
|
207
|
-
<th class="px-4 py-3 font-semibold text-neutral-500 text-right text-xs tracking-wider uppercase dark:text-neutral-400">Recorded</th>
|
|
208
|
-
<th class="pr-5 py-3 font-semibold text-neutral-500 text-right text-xs tracking-wider uppercase dark:text-neutral-400">Details</th>
|
|
209
|
-
</tr>
|
|
210
|
-
</thead>
|
|
211
|
-
<tbody class="divide-neutral-100 divide-y dark:divide-neutral-700">
|
|
212
|
-
<tr :for="request in filteredRequests()">
|
|
213
|
-
<td class="pl-5 pr-4 py-3.5">
|
|
214
|
-
<div class="flex gap-2 items-center">
|
|
215
|
-
<span :class="'inline-flex px-2 py-0.5 font-medium text-xs rounded ' + methodClass(request.method)">{{ request.method }}</span>
|
|
216
|
-
<code class="max-w-md text-neutral-800 text-xs truncate dark:text-neutral-200">{{ request.path }}</code>
|
|
217
|
-
</div>
|
|
218
|
-
</td>
|
|
219
|
-
<td class="px-4 py-3.5"><span :class="'inline-flex px-2 py-0.5 font-medium text-xs rounded ' + statusClass(request.status)">{{ request.status }}</span></td>
|
|
220
|
-
<td class="px-4 py-3.5 font-mono text-neutral-600 text-right text-xs whitespace-nowrap dark:text-neutral-300">{{ request.durationMs.toFixed(1) }} ms</td>
|
|
221
|
-
<td class="px-4 py-3.5 text-neutral-500 text-xs dark:text-neutral-400">{{ request.ipAddress || 'Not recorded' }}</td>
|
|
222
|
-
<td class="px-4 py-3.5 text-neutral-500 text-right text-xs whitespace-nowrap dark:text-neutral-400">{{ formatDate(request.createdAt) }}</td>
|
|
223
|
-
<td class="pr-5 py-3.5 text-right">
|
|
224
|
-
<Button variant="ghost" size="sm" @click="inspectRequest(request)">Inspect</Button>
|
|
225
|
-
</td>
|
|
226
|
-
</tr>
|
|
227
|
-
</tbody>
|
|
228
|
-
</table>
|
|
229
|
-
</div>
|
|
230
247
|
</Card>
|
|
231
248
|
|
|
232
249
|
<RequestDetailsDialog :request="selectedRequest()" @close="closeInspector" />
|