@stacksjs/defaults 0.75.452 → 0.75.458

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.
@@ -190,8 +190,11 @@ Do not assume every caller gets that allowlist when constructing config itself.
190
190
  First-party capturePageviews is separate from script injection and the remote
191
191
  driver gate. recordPageview(req) writes qualifying GET page requests to
192
192
  analytics_events; isPageviewRequest filters assets/API/internal paths and obvious
193
- bots/monitors. classifyAgent/referrerHost are coarse helpers, not unique visitor
194
- identification. Capture failures are swallowed so a statistic cannot break a
193
+ bots/monitors. The site's host is the first `X-Forwarded-Host` hop, else the
194
+ URL's host, and a referrer from that host is stored as null: behind rpx the URL
195
+ carries the upstream address, so comparing against it recorded every internal
196
+ click as a referral from the site itself. classifyAgent/referrerHost are coarse
197
+ helpers, not unique visitor identification. Capture failures are swallowed so a statistic cannot break a
195
198
  page. Apply the table/model migration before relying on the dashboard data.
196
199
 
197
200
  Source: `storage/framework/core/analytics/src/registry.ts`, capture.ts and
@@ -25,14 +25,15 @@ console.log(preview.plan.create, preview.plan.keep, preview.plan.skip)
25
25
 
26
26
  desiredDnsRecords(domain, config) converts native config to provider records.
27
27
  planDnsSync(desired, current, { zone? }) returns create/keep/skip with reasons.
28
- syncDnsConfig(domain, config, { dryRun?, provider? }) reports created/kept/failed,
28
+ syncDnsConfig(domain, config, { dryRun?, provider?, resolver? }) reports created/kept/failed,
29
29
  failures/skipped/applied/provider. It only creates missing declared records;
30
30
  it never deletes or overwrites an existing value. Single-value A/AAAA/CNAME
31
31
  records are kept when present; TXT/MX can add distinct values. Editing config
32
32
  does not imply changing an already-present provider value.
33
33
 
34
34
  dryRun reads public DNS without provider credentials; that is not a complete
35
- zone export. Actual apply selects a ts-cloud DNS provider by domain/nameservers
35
+ zone export. It looks up the apex, `www` and every declared in-zone name, so a
36
+ live `_dmarc` or DKIM record reads as kept. Actual apply selects a ts-cloud DNS provider by domain/nameservers
36
37
  and credentials. A missing provider yields an unapplied plan, not fake success.
37
38
  The native sync interface supports Route53/Porkbun/GoDaddy/Cloudflare through
38
39
  the provider factory; retained request/planner tests are not live provider parity.
@@ -51,7 +52,11 @@ Private/loopback/placeholder addresses and out-of-zone records are skipped;
51
52
  TTL normalization applies the planner's current minimum. Resolve conflicts
52
53
  deliberately rather than interpreting keep as identical desired content.
53
54
 
54
- resolveLiveRecords(domain) reads public DNS. renderDnsConfig(domain, records)
55
+ resolveLiveRecords(domain, names?, resolver?) reads public DNS for the apex,
56
+ `www` and the in-zone `names`. A non-apex name with a CNAME is reported as
57
+ that CNAME alone, never as the addresses it resolves to, so `dns:pull` keeps
58
+ an alias an alias. The optional resolver replaces `node:dns` in tests.
59
+ renderDnsConfig(domain, records)
55
60
  renders source for review; dnsProviderForDomain(domain) resolves the mutable
56
61
  provider. Use buddy dns:* --help for pull/sync command flags and output paths.
57
62
 
@@ -135,6 +135,39 @@ export default {
135
135
  } satisfies MobileConfig
136
136
  ```
137
137
 
138
+ ### Launch screen
139
+
140
+ Every app gets a launch splash without configuring one. `buddy build:ios` and
141
+ `build:android` render the app icon with ts-images' splash preset
142
+ (`generateMobileSplash` in `@stacksjs/image`) on `backgroundColor`, plus a
143
+ Dark Mode set on `backgroundColorDark` when the app gives one. iOS gets
144
+ `LaunchLogo.png` at @1x/@2x/@3x; Android gets Android 12's splash icon and
145
+ the logo older versions centre on the window, per density. The mark is drawn
146
+ at its size in points, never as a full-screen picture, so no screen shape
147
+ crops it, and Craft holds it until the first frame on the same colour. Files
148
+ land in `storage/framework/mobile/splash/<platform>`, rebuilt each build.
149
+
150
+ `ios.splash` and `android.splash` take the same options:
151
+
152
+ ```ts
153
+ splash: {
154
+ logo: 'public/logo.svg', // default appIcon, masked to rounded corners
155
+ logoDark: 'public/logo-dark.svg',
156
+ text: 'My App', font: 'resources/fonts/Barlow-Regular.ttf', uppercase: true,
157
+ accent: '#dd0f15', // the glow; default ios.tintColor, false for none
158
+ size: 96, // optical size in points
159
+ shape: 'none', // 'rounded' | 'circle' to mask a full-bleed square
160
+ },
161
+ ```
162
+
163
+ `ios.splash.image` / `imageDark` is a hand-made launch image, used as it is
164
+ (PNG, PDF or SVG at its own size in points; a PNG may have `@2x`/`@3x`
165
+ beside it). It is iOS-only. `splash: false` leaves only the colour. The
166
+ generated splash needs craft-native 0.0.443 or later; with an older Craft the
167
+ build warns and the launch screen shows only the colour (a hand-made image
168
+ still works). A white logo on a white background is repainted dark so it
169
+ stays visible; give `backgroundColor` to set the colour instead.
170
+
138
171
  For the native renderer, every app-owned route must map to an STX screen in
139
172
  `nativeScreens` on both platforms. The example maps `/m/` to
140
173
  `resources/components/Home.stx`; browser routes should render that same shared
@@ -154,6 +187,24 @@ For the web renderer, choose a primary content source:
154
187
  Only enable capabilities the product uses. Craft turns enabled capabilities
155
188
  into native bridge availability and required iOS privacy descriptions.
156
189
 
190
+ `capabilities.shakeGesture` arms the accelerometer while the app is in front,
191
+ on iOS and Android, and sends the page Craft's `shake` event (with its `force`
192
+ in g) once per deliberate shake. It needs craft-native 0.0.435 or later, and
193
+ the build refuses an older one rather than shipping a gesture that does
194
+ nothing.
195
+
196
+ `capabilities.wallet` lets a native screen add a pass through stx's
197
+ `craft.wallet`: `add({ data })` with a base64 `.pkpass` or `add({ url })` with
198
+ an https URL on iOS, an https Google Wallet save URL on Android. On iOS
199
+ `craft.wallet.has(serialNumber)` cannot find a pass yet: Craft adds no
200
+ pass-type entitlement, and iOS shows an app only the passes its entitlement
201
+ covers. `android.capabilities.healthServices` runs a native screen's
202
+ `craft.health.startWorkout()`, `pauseWorkout()`, `resumeWorkout()` and
203
+ `endWorkout()` through Health Services; it needs `android.minSdk` 30, which
204
+ Craft sets when the app leaves it unset. Native passkeys are not offered yet:
205
+ Craft's iOS host has them, and a native screen has nothing to call them with
206
+ until stx's native runtime does (stacksjs/stx#2151).
207
+
157
208
  The shell's behaviour around the page defaults to a native app's; set only
158
209
  what should differ: `swipeBack` (`'router'`, the stx router's interactive
159
210
  swipe, or `'webview'` for WebKit's history swipe), `keyboardAccessory` (off),
@@ -11,17 +11,17 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
11
11
  | Package | Task guidance | Source entry | Retained tests |
12
12
  |---|---|---|---|
13
13
  | `@stacksjs/action-runner` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/action-runner/src/index.ts) | 1 |
14
- | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 96 |
14
+ | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 101 |
15
15
  | `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 21 |
16
16
  | `@stacksjs/alias` | [`stacks-alias`](../stacks-alias/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/alias/src/index.ts) | 3 |
17
- | `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 6 |
17
+ | `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 7 |
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) | 12 |
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) | 12 |
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) | 3 |
21
21
  | `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 127 |
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) | 9 |
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) | 9 |
24
- | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 180 |
24
+ | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 181 |
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) | 6 |
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) | 24 |
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) | 5 |
@@ -35,13 +35,13 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
35
35
  | `@stacksjs/composables` | [`stacks-composables`](../stacks-composables/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/composables/src/index.ts) | 18 |
36
36
  | `@stacksjs/config` | [`stacks-config`](../stacks-config/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/config/src/index.ts) | 16 |
37
37
  | `@stacksjs/cron` | [`stacks-cron`](../stacks-cron/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cron/src/index.ts) | 6 |
38
- | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 138 |
38
+ | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 139 |
39
39
  | `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 22 |
40
40
  | `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 2 |
41
41
  | `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
42
42
  | `@stacksjs/desktop-build` | [`stacks-desktop`](../stacks-desktop/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts) | 15 |
43
43
  | `@stacksjs/development` | [`stacks-development`](../stacks-development/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/development/package.json) | 1 |
44
- | `@stacksjs/dns` | [`stacks-dns`](../stacks-dns/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/index.ts) | 3 |
44
+ | `@stacksjs/dns` | [`stacks-dns`](../stacks-dns/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/index.ts) | 4 |
45
45
  | `@stacksjs/docs` | [`stacks-docs`](../stacks-docs/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/docs/src/index.ts) | 2 |
46
46
  | `@stacksjs/email` | [`stacks-email`](../stacks-email/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/email/src/index.ts) | 23 |
47
47
  | `@stacksjs/enums` | [`stacks-enums`](../stacks-enums/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/enums/src/index.ts) | 3 |
@@ -57,12 +57,12 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
57
57
  | `@stacksjs/health` | [`stacks-health`](../stacks-health/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/health/src/index.ts) | 2 |
58
58
  | `@stacksjs/http` | [`stacks-http`](../stacks-http/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/http/src/index.ts) | 3 |
59
59
  | `@stacksjs/i18n` | [`stacks-i18n`](../stacks-i18n/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/index.ts) | 5 |
60
- | `@stacksjs/image` | [`stacks-image`](../stacks-image/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/index.ts) | 3 |
60
+ | `@stacksjs/image` | [`stacks-image`](../stacks-image/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/index.ts) | 4 |
61
61
  | `@stacksjs/lint` | [`stacks-lint`](../stacks-lint/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/lint/src/index.ts) | 3 |
62
62
  | `@stacksjs/logging` | [`stacks-logging`](../stacks-logging/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/logging/src/index.ts) | 14 |
63
63
  | `@stacksjs/mobile` | [`stacks-mobile`](../stacks-mobile/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/index.ts) | 23 |
64
64
  | `@stacksjs/model-meta` | [`stacks-models`](../stacks-models/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/model-meta/src/index.ts) | 1 |
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 |
65
+ | `@stacksjs/newsletter` | [`stacks-newsletter`](../stacks-newsletter/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/index.ts) | 9 |
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) | 18 |
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) | 10 |
68
68
  | `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 77 |
@@ -71,12 +71,12 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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) | 39 |
72
72
  | `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 8 |
73
73
  | `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 7 |
74
- | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 52 |
75
- | `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 12 |
74
+ | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 55 |
75
+ | `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 13 |
76
76
  | `@stacksjs/registry` | [`stacks-registry`](../stacks-registry/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/registry/src/index.ts) | 1 |
77
77
  | `@stacksjs/repl` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/repl/src/index.ts) | 2 |
78
78
  | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 99 |
79
- | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 17 |
79
+ | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 19 |
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) | 11 |
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) | 12 |
82
82
  | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 28 |
@@ -119,7 +119,7 @@ Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT
119
119
 
120
120
  Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/build/macos-native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/macos-native.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/publication-preflight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/publication-preflight.ts), [src/release-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/release-evidence.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/stx-source.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stx-source.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
121
121
 
122
- Evidence directory: [96 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
122
+ Evidence directory: [101 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
123
123
 
124
124
  ### @stacksjs/ai
125
125
 
@@ -149,7 +149,7 @@ Declared runtime exports: `classifyAgent`, `isPageviewRequest`, `recordPageview`
149
149
 
150
150
  Local source modules: [src/capture.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/capture.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/drivers/index.ts), [src/registry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/registry.ts).
151
151
 
152
- Evidence directory: [6 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
152
+ Evidence directory: [7 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
153
153
 
154
154
  ### @stacksjs/api
155
155
 
@@ -219,7 +219,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
219
219
 
220
220
  Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
221
221
 
222
- Evidence directory: [180 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.
222
+ Evidence directory: [181 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.
223
223
 
224
224
  ### @stacksjs/build
225
225
 
@@ -357,7 +357,7 @@ Declared runtime exports: `Database`, `EntityQueryBuilder`, `__flushAfterCommitN
357
357
 
358
358
  Local source modules: [src/affected-rows.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/affected-rows.ts), [src/auth-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/auth-tables.ts), [src/custom/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/custom/index.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/database.ts), [src/datetime-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/datetime-columns.ts), [src/ddl-constraints.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ddl-constraints.ts), [src/defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/defaults.ts), [src/dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/dialect.ts), [src/driver-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/driver-config.ts), [src/drivers/dynamodb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/dynamodb.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/drivers/index.ts), [src/ensure-database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ensure-database.ts), [src/erd.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/erd.ts), [src/fk-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/fk-audit.ts), [src/framework-renames.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-renames.ts), [src/framework-route-admission.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/framework-route-admission.ts), [src/hand-written-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/hand-written-migrations.ts), [src/ignored-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/ignored-migrations.ts), [src/index-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index-shape.ts), [src/managed-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/managed-columns.ts), [src/migration-dialect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-dialect.ts), [src/migration-ledger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-ledger.ts), [src/migration-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-names.ts), [src/migration-path.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migration-path.ts), [src/migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/migrations.ts), [src/model-sources.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/model-sources.ts), [src/notification-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/notification-tables.ts), [src/package-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-migrations.ts), [src/package-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/package-models.ts), [src/query-logger.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/query-logger.ts), [src/rbac-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/rbac-tables.ts), [src/relation-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/relation-columns.ts), [src/replicas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/replicas.ts), [src/row-lease.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lease.ts), [src/row-lock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/row-lock.ts), [src/safe-migrations.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/safe-migrations.ts), [src/schema-align.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-align.ts), [src/schema-drift.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/schema-drift.ts), [src/seeder.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/seeder.ts), [src/shadowed-models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/shadowed-models.ts), [src/sql-helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/sql-helpers.ts), [src/trait-tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/trait-tables.ts), [src/transaction-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-context.ts), [src/transaction-options.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/transaction-options.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/types.ts), [src/unique-audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/unique-audit.ts), [src/utc-defaults.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utc-defaults.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/utils.ts), [src/uuid-columns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/uuid-columns.ts), [src/vschema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/vschema.ts).
359
359
 
360
- Evidence directory: [138 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
360
+ Evidence directory: [139 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
361
361
 
362
362
  ### @stacksjs/datetime
363
363
 
@@ -411,7 +411,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
411
411
 
412
412
  Local source modules: [src/drivers/aws.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/drivers/aws.ts), [src/sync.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/sync.ts).
413
413
 
414
- Evidence directory: [3 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
414
+ Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
415
415
 
416
416
  ### @stacksjs/docs
417
417
 
@@ -565,9 +565,9 @@ Guidance: [`stacks-image`](../stacks-image/SKILL.md). Source: [storage/framework
565
565
 
566
566
  Declared runtime exports: `ImageBuilder`, `image`, `imageResponseHeaders`, `negotiateImageVariant`, `resolveImageSource`, `signImageTransform`, `verifyImageTransform`.
567
567
 
568
- Local source modules: [src/app-icons.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/app-icons.ts), [src/app-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/app-store.ts), [src/fonts.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/fonts.ts), [src/generate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/generate.ts), [src/social.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/social.ts), [src/theme.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/theme.ts), [src/upload.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/upload.ts).
568
+ Local source modules: [src/app-icons.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/app-icons.ts), [src/app-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/app-store.ts), [src/fonts.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/fonts.ts), [src/generate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/generate.ts), [src/social.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/social.ts), [src/splash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/splash.ts), [src/theme.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/theme.ts), [src/upload.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/upload.ts).
569
569
 
570
- Evidence directory: [3 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
570
+ Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
571
571
 
572
572
  ### @stacksjs/lint
573
573
 
@@ -611,7 +611,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
611
611
 
612
612
  Local source modules: [src/campaigns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/campaigns.ts), [src/delivery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/delivery.ts), [src/headers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/headers.ts), [src/lists.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/lists.ts), [src/newsletter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/newsletter.ts), [src/subscriptions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/subscriptions.ts), [src/sync.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/sync.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/types.ts), [src/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/src/usage.ts).
613
613
 
614
- Evidence directory: [7 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
614
+ Evidence directory: [9 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/newsletter/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
615
615
 
616
616
  ### @stacksjs/notifications
617
617
 
@@ -637,7 +637,7 @@ Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/
637
637
 
638
638
  Guidance: [`stacks-orm`](../stacks-orm/SKILL.md). Source: [storage/framework/core/orm/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts).
639
639
 
640
- Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
640
+ Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `frameworkModelFeature`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
641
641
 
642
642
  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).
643
643
 
@@ -699,7 +699,7 @@ Declared runtime exports: `Batch`, `DispatchedBatch`, `FailedJobNotifier`, `JOB_
699
699
 
700
700
  Local source modules: [src/action-runner.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/action-runner.ts), [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/action.ts), [src/batch.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/batch.ts), [src/bun-queue.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/bun-queue.ts), [src/circuit-breaker.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/circuit-breaker.ts), [src/dead-letter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/dead-letter.ts), [src/discovery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/discovery.ts), [src/driver.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/driver.ts), [src/drivers/redis.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/drivers/redis.ts), [src/envelope.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/envelope.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/events.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/health.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/idempotency.ts), [src/job-progress.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/job-progress.ts), [src/job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/job.ts), [src/notifications.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/notifications.ts), [src/poison.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/poison.ts), [src/scheduler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/scheduler.ts), [src/testing.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/testing.ts), [src/worker.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/worker.ts).
701
701
 
702
- Evidence directory: [52 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
702
+ Evidence directory: [55 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
703
703
 
704
704
  ### @stacksjs/realtime
705
705
 
@@ -709,7 +709,7 @@ Declared runtime exports: `LegacyBroadcast`, `StacksChannel`, `channel`, `create
709
709
 
710
710
  Local source modules: [src/broadcast.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/broadcast.ts), [src/channel.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/channel.ts), [src/emit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/emit.ts), [src/replay-buffer.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/replay-buffer.ts), [src/server-instance.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/server-instance.ts), [src/stream.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/stream.ts), [src/ws.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/ws.ts).
711
711
 
712
- Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
712
+ Evidence directory: [13 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
713
713
 
714
714
  ### @stacksjs/registry
715
715
 
@@ -745,7 +745,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
745
745
 
746
746
  Local source modules: [src/run.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/run.ts), [src/schedule.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/schedule.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/types.ts).
747
747
 
748
- Evidence directory: [17 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
748
+ Evidence directory: [19 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
749
749
 
750
750
  ### @stacksjs/search-engine
751
751
 
@@ -19,6 +19,13 @@ subscriber updates. Preserve one-click unsubscribe headers and suppression.
19
19
  List/campaign helpers own their schema and state transitions; direct column
20
20
  writes can bypass transition guards or schedule/idempotency behavior.
21
21
 
22
+ An address is one person whatever its case: subscribe() stores it trimmed and
23
+ lowercased (normalizeEmail), and subscribe(), unsubscribeAll() and
24
+ syncListSubscribers() find rows case-insensitively, so rows stored with capitals
25
+ before that still match. A sync skips an address whose row on the list is
26
+ unsubscribed under any spelling. subscriberIdsForEmail(email) and
27
+ listStatusForEmail(email, listId) are the lookups they share.
28
+
22
29
  Campaign delivery snapshots, dispatch keys and state conflict errors protect
23
30
  retries and concurrent queue requests. Scheduled work uses the package's actual
24
31
  transition and readiness checks. DeliveryVariant allocation and
@@ -234,7 +234,7 @@ import { replaySince, setReplayBuffer } from '@stacksjs/realtime'
234
234
  setReplayBuffer({ channels: ['orders.*'], maxPerChannel: 100, ttlMs: 5 * 60_000 })
235
235
  ```
236
236
 
237
- Every broadcast on a matching channel, from any API, is recorded and reaches clients as `{ event, channel, data, seq }`. Patterns match with or without the `private-`/`presence-` prefix (`orders.*` covers `private-orders.1`); `replaySince()` takes the full name. The client keeps the last `seq` per channel and sends it back after reconnecting (through a route of the app's), which answers with `replaySince('private-orders.1', seq)`. The buffer and its numbering are per process.
237
+ Every broadcast on a matching channel, from any API, is recorded and reaches clients as `{ event, channel, data, seq }`. Patterns match with or without the `private-`/`presence-` prefix (`orders.*` covers `private-orders.1`); `replaySince()` takes the full name. The client keeps the last `seq` per channel and sends it back after reconnecting (through a route of the app's), which answers with `replaySince('private-orders.1', seq)`. The buffer and its numbering are per process. A channel's `seq` rises by one per message and keeps rising across a restart (each channel starts from the clock, never below a number already issued), so messages sent after a restart are still newer than the `seq` a reconnecting client holds. Do not assume it starts at 1. When the first replayed `seq` is not the client's `seq + 1`, messages were lost: evicted, expired, or sent before a restart.
238
238
 
239
239
  ---
240
240
 
@@ -143,6 +143,17 @@ lock, and a DB-unavailable fallback warns rather than promising cluster
143
143
  coordination. Use the same task name on all participating hosts. Names are
144
144
  sanitized and hashed for lock paths.
145
145
 
146
+ The advisory lock is released when a run ends, so on its own it only stops
147
+ two runs at once. `onOneServer()` therefore also claims the slot: each tick
148
+ inserts `(task, slot)` into a `scheduler_claims` table with a unique key, and
149
+ only the server whose row went in first runs it (`scheduler-claims.ts`,
150
+ stacksjs/stacks#3152). The slot is the cron time the tick woke for; for
151
+ `everySecond()` it is the wall-clock second, and interval timers are not
152
+ aligned across servers, so ticks that straddle a boundary both run. The table
153
+ is created on first use with CREATE TABLE IF NOT EXISTS, and claims older than
154
+ a day are pruned. `Schedule.runNow()` and `buddy schedule:run-one` have no
155
+ slot and always run. SQLite and the DB-unavailable fallback claim nothing.
156
+
146
157
  ### Background Execution
147
158
 
148
159
  When `runInBackground()` is called, each run starts `buddy schedule:run-one <name> --in-process` as a detached child in the project directory. That process registers the app's schedule the way `schedule:run` does and runs the one task there, taking any `withoutOverlapping()` / `onOneServer()` lock itself. The child is `unref()`'d so it does not keep the parent alive, and a non-zero exit is logged under the task's name. The task needs a name (`schedule.job/action/command` have one; a callback needs `.withName()`), or registration fails.
@@ -362,7 +373,7 @@ export default {
362
373
  - A task's default timezone is the app's (`config.app.timezone`, which `config/app.ts` ships as `'America/Los_Angeles'`), not a fixed zone; UTC when the app sets none
363
374
  - `everySecond()` uses `setInterval`, not cron -- it sets `intervalMs = 1000` and bypasses the cron parser entirely
364
375
  - The `Queue` class in `schedule.ts` is just an empty subclass of `Schedule` (`export class Queue extends Schedule {}`) -- it adds no functionality
365
- - `withoutOverlapping()` provides local file locking. `onOneServer()` adds PostgreSQL/MySQL advisory coordination where available
376
+ - `withoutOverlapping()` provides local file locking. `onOneServer()` adds a PostgreSQL/MySQL advisory lock and a per-slot claim in `scheduler_claims`, created on first use
366
377
  - SQLite/Turso and DB-unavailable fallback cannot provide cluster-wide scheduler coordination; read scheduler-lock.ts and its warning
367
378
  - `runInBackground()` runs the task by name in a `buddy schedule:run-one <name> --in-process` child, so the task must be registered under that name by the app's scheduler file, and an unnamed callback is refused
368
379
  - There are TWO scheduler systems: `@stacksjs/scheduler` (fluent API in `schedule.ts`) and the queue-level scheduler in `@stacksjs/queue` (`queue/src/scheduler.ts`). The former runs tasks in-process; the latter dispatches to the queue
@@ -383,8 +394,13 @@ six-field forms: all-wildcard intervals in seconds dividing 60, or leading zero
383
394
  seconds with a five-field schedule. Unsupported specific-second forms throw.
384
395
  `dailyAt(time)`, `weekdays()` and `onQueue(name)` are native methods.
385
396
  `sendOutputTo(path)` and `appendOutputTo(path)` capture supported command
386
- output. `runMissed({ since, max? })` performs bounded catch-up; read its
387
- window/overlap behavior before using it for non-idempotent tasks.
397
+ output. `runMissed({ since, max? })` performs bounded catch-up: each missed
398
+ slot runs in this process, awaited, through the live guards. A paused task
399
+ runs none, only slots inside `between()` run, and a slot is skipped while the
400
+ task holds its `withoutOverlapping()` or `onOneServer()` lock. An
401
+ `onOneServer()` task also claims each slot it replays, so two servers that
402
+ boot together run each missed slot once.
403
+
388
404
 
389
405
  `schedule.notification(recipient, payload, channels?, options?)` schedules
390
406
  native notify fan-out and fails the task if any channel result failed.
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'bun:test'
2
2
  import { activityStatus } from './DashboardActivityAction'
3
- import { formatDashboardStat } from './DashboardStatsAction'
3
+ import { collectDashboardStats, formatDashboardStat } from './DashboardStatsAction'
4
4
 
5
5
  describe('legacy dashboard API projections', () => {
6
6
  it('formats persisted totals without inventing trends', () => {
@@ -24,6 +24,25 @@ describe('legacy dashboard API projections', () => {
24
24
  ).value).toBe('Unavailable')
25
25
  })
26
26
 
27
+ it('settles a count that throws before returning a promise as that card\'s failure', async () => {
28
+ // A query on a model whose feature is off throws on first touch, which is
29
+ // what took /api/dashboard/stats down with commerce off.
30
+ const { shown, results } = await collectDashboardStats([
31
+ { title: 'Users', icon: 'users', iconBg: 'primary', count: async () => 3 },
32
+ { title: 'Orders', icon: 'orders', iconBg: 'success', count: () => { throw new Error('commerce is off') } },
33
+ ])
34
+ expect(shown.map(card => card.title)).toEqual(['Users', 'Orders'])
35
+ expect(results.map(result => result.status)).toEqual(['fulfilled', 'rejected'])
36
+ })
37
+
38
+ it('leaves out a card whose model is not available', async () => {
39
+ const { shown } = await collectDashboardStats([
40
+ { title: 'Users', icon: 'users', iconBg: 'primary', count: async () => 3 },
41
+ { title: 'Customers', icon: 'customers', iconBg: 'warning', count: async () => 1, available: () => false },
42
+ ])
43
+ expect(shown.map(card => card.title)).toEqual(['Users'])
44
+ })
45
+
27
46
  it('derives activity severity from persisted event types', () => {
28
47
  expect(activityStatus('order.completed')).toBe('success')
29
48
  expect(activityStatus('login.failed')).toBe('warning')
@@ -7,6 +7,29 @@ interface DashboardStatDefinition {
7
7
  icon: string
8
8
  iconBg: string
9
9
  count: () => Promise<number>
10
+ /** False when the model's feature is off, so the card is left out. */
11
+ available?: () => boolean
12
+ }
13
+
14
+ /** A model whose feature is off answers `getDefinition` with nothing. */
15
+ function loaded(model: unknown): boolean {
16
+ return Boolean((model as { getDefinition?: () => unknown } | undefined)?.getDefinition?.())
17
+ }
18
+
19
+ /**
20
+ * Settle every available card's count, each on its own.
21
+ *
22
+ * A count runs inside a promise, so one that throws before it returns one -
23
+ * a query on a model whose feature is off throws the moment it is touched -
24
+ * becomes that card's failure, not the request's. It used to be called
25
+ * straight from a map, so with commerce off (the default since #2488) the
26
+ * first Order card threw out of the action and the whole endpoint answered
27
+ * 500.
28
+ */
29
+ export async function collectDashboardStats(definitions: DashboardStatDefinition[]) {
30
+ const shown = definitions.filter(definition => definition.available?.() ?? true)
31
+ const results = await Promise.allSettled(shown.map(definition => Promise.resolve().then(definition.count)))
32
+ return { shown, results }
10
33
  }
11
34
 
12
35
  export function formatDashboardStat(
@@ -39,24 +62,27 @@ export default new Action({
39
62
  icon: 'i-hugeicons-shopping-cart-02',
40
63
  iconBg: 'success',
41
64
  count: () => Order.where('status', '!=', 'cancelled').count(),
65
+ available: () => loaded(Order),
42
66
  },
43
67
  {
44
68
  title: 'Blog Posts',
45
69
  icon: 'i-hugeicons-document-validation',
46
70
  iconBg: 'info',
47
71
  count: () => Post.count(),
72
+ available: () => loaded(Post),
48
73
  },
49
74
  {
50
75
  title: 'Customers',
51
76
  icon: 'i-hugeicons-user-multiple',
52
77
  iconBg: 'warning',
53
78
  count: () => Customer.count(),
79
+ available: () => loaded(Customer),
54
80
  },
55
81
  ]
56
82
 
57
- const results = await Promise.allSettled(definitions.map(definition => definition.count()))
58
- const stats = definitions.map((definition, index) => {
59
- const { count: _count, ...metadata } = definition
83
+ const { shown, results } = await collectDashboardStats(definitions)
84
+ const stats = shown.map((definition, index) => {
85
+ const { count: _count, available: _available, ...metadata } = definition
60
86
  // allSettled returns one result per input, but indexed access is typed
61
87
  // as possibly missing; a rejected placeholder keeps the shape honest.
62
88
  const result = results[index] ?? { status: 'rejected' as const, reason: new Error('missing result') }
@@ -64,11 +90,11 @@ export default new Action({
64
90
  })
65
91
  const issues = results.flatMap((result, index) => result.status === 'rejected'
66
92
  ? [{
67
- source: definitions[index]?.title ?? 'Unknown',
93
+ source: shown[index]?.title ?? 'Unknown',
68
94
  message: dashboardOperationalIssue(
69
95
  result.reason,
70
- `${definitions[index]?.title ?? 'Dashboard'} data could not be loaded.`,
71
- `DashboardStatsAction.${(definitions[index]?.title ?? 'unknown').toLowerCase().replaceAll(' ', '-')}`,
96
+ `${shown[index]?.title ?? 'Dashboard'} data could not be loaded.`,
97
+ `DashboardStatsAction.${(shown[index]?.title ?? 'unknown').toLowerCase().replaceAll(' ', '-')}`,
72
98
  ),
73
99
  }]
74
100
  : [])
@@ -118,6 +118,22 @@ function typeForColumn(column: string, values: unknown[]): ColumnMeta['type'] {
118
118
  return inferType(values)
119
119
  }
120
120
 
121
+ /**
122
+ * The columns a global search matches with LIKE: the ones the page is told
123
+ * are text, by the same rule.
124
+ *
125
+ * It used to take every column whose sampled value was a string. PostgreSQL
126
+ * answers BIGINT as a string, so `id` and every `*_id` qualified, and the
127
+ * search failed with `operator does not exist: bigint ~~ unknown` on any
128
+ * table with a row in it: `/models/team?q=PrimeSoft` answered 503.
129
+ */
130
+ export function searchColumnsFor(columns: Iterable<string>, sample: unknown): string[] {
131
+ return [...columns].filter((column) => {
132
+ const value = safeGet(sample, column, null)
133
+ return typeof value === 'string' && typeForColumn(column, [value]) === 'text'
134
+ })
135
+ }
136
+
121
137
  function queryValue(request: RequestInstance, key: string, fallback = ''): string {
122
138
  const value = request.get<unknown>(key, fallback)
123
139
  if (Array.isArray(value))
@@ -244,7 +260,7 @@ export default new Action({
244
260
  ? requestedSort
245
261
  : (allowed.has('id') ? 'id' : (response.columns[0] ?? ''))
246
262
  response.sort = sort
247
- const searchColumns = [...allowed].filter(c => typeof safeGet(first, c, null) === 'string')
263
+ const searchColumns = searchColumnsFor(allowed, first)
248
264
 
249
265
  const build = () => {
250
266
  let chain = Model.query() as any
@@ -71,8 +71,10 @@ fi
71
71
  PIPE_DIR="$(mktemp -d "\${TMPDIR:-/tmp}/stacks-install.XXXXXX")" || exit 1
72
72
  PIPE="$PIPE_DIR/setup.pipe"
73
73
  SETUP_PID=""
74
+ LOGGER_PID=""
74
75
  cleanup() {
75
- if [ -n "$SETUP_PID" ]; then kill -TERM -- "-$SETUP_PID" 2>/dev/null; fi
76
+ if [ -n "$SETUP_PID" ]; then kill -TERM -- "-$SETUP_PID" 2>/dev/null; wait "$SETUP_PID" 2>/dev/null; fi
77
+ if [ -n "$LOGGER_PID" ]; then kill -TERM -- "-$LOGGER_PID" 2>/dev/null; wait "$LOGGER_PID" 2>/dev/null; fi
76
78
  rm -rf "$PIPE_DIR"
77
79
  }
78
80
  trap cleanup EXIT
@@ -85,17 +87,22 @@ mkfifo "$PIPE" || exit 1
85
87
  # process group (job control) so an interrupted run can stop all of it, and
86
88
  # pipefail keeps the setup's own exit status rather than tee's.
87
89
  set -m
90
+ # Keep the reader in its own group too. Bash defers a trap while waiting for a
91
+ # foreground timestamp command; waiting for background jobs is interruptible.
92
+ ( while IFS= read -r line; do echo "$(date '+[%Y-%m-%d %H:%M:%S]') $line"; done < "$PIPE" >> "$LOG_PATH" ) &
93
+ LOGGER_PID=$!
88
94
  ( set -o pipefail; bun "$CLI_PATH" setup | tee "$PIPE" ) &
89
95
  SETUP_PID=$!
90
96
  set +m
91
97
 
92
- # Read from the pipe, add timestamps, and append to the file
93
- while IFS= read -r line; do echo "$(date '+[%Y-%m-%d %H:%M:%S]') $line"; done < "$PIPE" >> "$LOG_PATH"
94
-
95
98
  # Report the setup's exit status, not the cleanup's
96
99
  wait "$SETUP_PID"
97
100
  STATUS=$?
98
101
  SETUP_PID=""
102
+ wait "$LOGGER_PID"
103
+ LOGGER_STATUS=$?
104
+ LOGGER_PID=""
105
+ if [ "$STATUS" -eq 0 ]; then STATUS=$LOGGER_STATUS; fi
99
106
  exit "$STATUS"
100
107
  `
101
108
 
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.452",
5
+ "version": "0.75.458",
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.452",
5
+ "version": "0.75.458",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -45,7 +45,7 @@
45
45
  "dependencies": {
46
46
  "@iconify-json/f7": "^1.2.2",
47
47
  "@iconify-json/hugeicons": "^1.2.35",
48
- "@stacksjs/mobile": "0.75.452",
48
+ "@stacksjs/mobile": "0.75.458",
49
49
  "@stacksjs/sanitizer": "0.2.794",
50
50
  "@stacksjs/stx": "0.2.794",
51
51
  "@xterm/addon-fit": "^0.11.0",