@stacksjs/defaults 0.70.365 → 0.70.366

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.
@@ -326,12 +326,7 @@ function clearFilters(): void {
326
326
 
327
327
  /* ----------------------------------------------------------------- export */
328
328
 
329
- /**
330
- * CSV of what is on screen: current search, filters and sort, all columns
331
- * that are visible, every page rather than just the current one. Exporting
332
- * the raw prop would hand back something the viewer never asked for.
333
- */
334
- function exportCsv(): void {
329
+ function csvBlob(): Blob {
335
330
  const cols = visibleColumns()
336
331
  const escape = (value: any): string => {
337
332
  const text = value === null || value === undefined ? '' : String(value)
@@ -343,15 +338,21 @@ function exportCsv(): void {
343
338
  ...sorted().map(row => cols.map(column => escape(rawValue(row, column.key))).join(',')),
344
339
  ]
345
340
 
346
- const blob = new Blob([`${lines.join('\n')}`], { type: 'text/csv;charset=utf-8' })
347
- const url = URL.createObjectURL(blob)
348
- const link = document.createElement('a')
349
- link.href = url
350
- link.download = `${exportFilename()}.csv`
351
- document.body.appendChild(link)
352
- link.click()
353
- document.body.removeChild(link)
354
- URL.revokeObjectURL(url)
341
+ return new Blob([`${lines.join('\n')}`], { type: 'text/csv;charset=utf-8' })
342
+ }
343
+
344
+ /**
345
+ * CSV of what is on screen: current search, filters and sort, all columns
346
+ * that are visible, every page rather than just the current one. Exporting
347
+ * the raw prop would hand back something the viewer never asked for.
348
+ * useObjectUrl owns URL revocation while the native download link owns the
349
+ * browser interaction.
350
+ */
351
+ const exportBlob = derived(() => exportable() ? csvBlob() : null)
352
+ const exportUrl = useObjectUrl(exportBlob)
353
+ const exportDownload = derived(() => `${exportFilename()}.csv`)
354
+
355
+ function recordExport(): void {
355
356
  emit('export', sorted().length)
356
357
  }
357
358
 
@@ -420,14 +421,14 @@ function cellClass(column: DashboardTableColumn, index: number): string {
420
421
  />
421
422
  </div>
422
423
 
423
- <button
424
+ <Button
424
425
  :if="hasActiveFilters()"
425
- type="button"
426
+ variant="ghost"
427
+ size="xs"
426
428
  @click="clearFilters()"
427
- class="px-2.5 py-1.5 text-neutral-600 text-xs dark:text-neutral-300 hover:text-neutral-900 dark:hover:text-white"
428
429
  >
429
430
  Clear filters
430
- </button>
431
+ </Button>
431
432
 
432
433
  <slot name="toolbar" />
433
434
  </div>
@@ -463,15 +464,19 @@ function cellClass(column: DashboardTableColumn, index: number): string {
463
464
  </div>
464
465
  </div>
465
466
 
466
- <button
467
+ <Button
467
468
  :if="exportable()"
468
- type="button"
469
- @click="exportCsv()"
470
- class="inline-flex gap-1.5 items-center px-2.5 py-1.5 text-neutral-600 text-xs dark:text-neutral-300 hover:bg-stone-50 dark:hover:bg-neutral-800 border border-stone-300 rounded-lg dark:border-neutral-600"
469
+ tag="a"
470
+ variant="outline"
471
+ size="sm"
472
+ :href="exportUrl.value || ''"
473
+ :download="exportDownload()"
474
+ :disabled="!exportUrl.value"
475
+ @click="recordExport()"
471
476
  >
472
477
  <span aria-hidden="true" class="h-3.5 w-3.5 i-hugeicons-download-04"></span>
473
478
  Export CSV
474
- </button>
479
+ </Button>
475
480
  </div>
476
481
  </div>
477
482
 
@@ -588,7 +593,7 @@ function cellClass(column: DashboardTableColumn, index: number): string {
588
593
  <span aria-hidden="true" class="mb-3 p-3 h-12 w-12 text-neutral-400 bg-neutral-100 dark:bg-neutral-800 rounded-full i-hugeicons-search-remove"></span>
589
594
  <p class="font-medium text-neutral-700 text-sm dark:text-neutral-200">No matches</p>
590
595
  <p class="mt-1 text-neutral-500 text-sm dark:text-neutral-400">No rows match the current search or filters.</p>
591
- <button type="button" @click="clearFilters()" class="mt-3 text-blue-600 text-sm dark:text-blue-400 hover:underline">Clear filters</button>
596
+ <Button variant="ghost" size="sm" class="mt-3" @click="clearFilters()">Clear filters</Button>
592
597
  </div>
593
598
 
594
599
  <div :if="visibleRows().length === 0 && !loading() && !hasActiveFilters()" class="flex flex-col items-center justify-center px-4 py-12">
@@ -1,6 +1,6 @@
1
1
  # Dashboard audit
2
2
 
3
- Last refreshed: 2026-07-31
3
+ Last refreshed: 2026-08-11
4
4
 
5
5
  This is the current verification record for `./buddy dev --dashboard`. It
6
6
  replaces the May 2026 migration inventory, whose per-file counts no longer
@@ -11,23 +11,25 @@ described the componentized dashboard.
11
11
  | Surface | Count |
12
12
  |---|---:|
13
13
  | Dashboard STX view files | 120 |
14
- | Dashboard STX components | 283 |
15
- | Dashboard Actions | 359 |
14
+ | Dashboard STX components | 303 |
15
+ | Dashboard Actions | 368 |
16
16
  | Registered `/api/dashboard/*` routes | 283 |
17
- | Framework model files | 69 |
18
- | Framework models declaring `useApi` | 60 |
19
- | Direct `fetch()` calls in dashboard views, components, functions, and stores | 0 |
17
+ | Framework model files | 75 |
18
+ | Framework models declaring `useApi` | 64 |
19
+ | Direct `fetch()` calls in dashboard views, components, and stores | 0 |
20
20
 
21
- The nine models without `useApi` are internal records or relationship-owned
22
- records: order idempotency keys, order items, errors, jobs, failed jobs, and
23
- payment-provider records. They are not missing generic CRUD surfaces.
21
+ The eleven models without `useApi` are internal, relationship-owned, or
22
+ provider-owned records: driver pings, order idempotency keys, order items,
23
+ errors, jobs, failed jobs, payment methods, payment products, payment
24
+ transactions, social accounts, and subscriptions. They are not missing generic
25
+ CRUD surfaces.
24
26
 
25
27
  ## Verified contracts
26
28
 
27
29
  ### Rendering and navigation
28
30
 
29
- - `./buddy dev --dashboard` starts on port 3002 and renders with STX 0.2.144
30
- and Crosswind 0.2.14.
31
+ - `./buddy dev --dashboard` starts on port 3002 and renders with STX 0.2.176
32
+ and Crosswind 0.2.16.
31
33
  - 108 static route views render with HTTP 200.
32
34
  - Full-page and STX fragment requests render for every static route.
33
35
  - STX prewarms the dependency-aware rendered shell cache with four workers.
@@ -37,12 +39,14 @@ payment-provider records. They are not missing generic CRUD surfaces.
37
39
  a dashboard composable invalidates the associated client bundle.
38
40
  - The componentized catch-all renders the native not-found page with HTTP 404
39
41
  for both full-page and STX fragment requests.
40
- - 130 distinct rendered local links and assets resolve without a 404 or 5xx.
42
+ - A dependency-free browser crawl followed the complete rendered link graph
43
+ across 261 distinct page URLs with no HTTP, console, request, or horizontal
44
+ overflow failure.
41
45
  - Rendered pages contain no unresolved PascalCase component tags.
42
46
  - Rendered pages contain no duplicate emitted IDs or broken
43
47
  `aria-labelledby` references.
44
48
  - The live render and navigation audit covers all 108 static destinations,
45
- all 69 discovered model destinations, and the remaining eight parameterized
49
+ all 75 discovered model destinations, and the remaining eight parameterized
46
50
  route families without a full-page or STX fragment failure.
47
51
  - Headless desktop and narrow-viewport visual checks cover the componentized
48
52
  Terms of Service and Privacy Policy routes linked from registration.
@@ -92,9 +96,9 @@ payment-provider records. They are not missing generic CRUD surfaces.
92
96
 
93
97
  ### Data integrity
94
98
 
95
- - The 128 live GET dashboard API routes return JSON or their documented text
99
+ - The 129 live GET dashboard API routes return JSON or their documented text
96
100
  payload with no hidden HTTP-200 error body.
97
- - A fresh live crawl returned 117 successful responses and 11 intentional
101
+ - A fresh live audit returned 118 successful responses and 11 intentional
98
102
  validation, authentication, or missing-resource responses, with no 5xx,
99
103
  method mismatch, transport failure, or HTML fallback.
100
104
  - Generic model routes reject malformed slugs with HTTP 400 before deriving
@@ -118,6 +122,7 @@ payment-provider records. They are not missing generic CRUD surfaces.
118
122
  bun storage/framework/defaults/ai/skills/stacks-dashboard/scripts/audit.ts
119
123
  # Or target a non-default origin:
120
124
  bun storage/framework/defaults/ai/skills/stacks-dashboard/scripts/audit.ts --base-url http://127.0.0.1:3002
125
+ bun storage/framework/defaults/ai/skills/stacks-browse/scripts/browse.ts crawl http://localhost:3002/ --max 500 --settle 350 --summary
121
126
  bun test tests/unit/dashboard-*.test.ts
122
127
  bun test storage/framework/core/actions/tests/dev-csrf.test.ts
123
128
  bun run typecheck
@@ -128,7 +133,7 @@ bunx --bun pickier .
128
133
  The focused contracts cover buttons, native STX bindings, route and Action
129
134
  method alignment, model reads and writes, commerce mutations, deployment
130
135
  guards, navigation source, sidebar behavior, toasts, and skill documentation.
131
- The 2026-07-31 focused run completed 156 tests with 2,916 assertions and no
136
+ The 2026-08-11 focused run completed 226 tests with 5,424 assertions and no
132
137
  failures, followed by both TypeScript checks and a clean repository lint.
133
138
 
134
139
  ## Remaining verification boundaries