@stacksjs/defaults 0.75.262 → 0.75.264

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.
Files changed (29) hide show
  1. package/ai/skills/stacks-api/SKILL.md +5 -4
  2. package/ai/skills/stacks-browse/SKILL.md +1 -0
  3. package/ai/skills/stacks-browse/scripts/browse.ts +40 -4
  4. package/ai/skills/stacks-email/SKILL.md +12 -8
  5. package/ai/skills/stacks-env/SKILL.md +1 -1
  6. package/ai/skills/stacks-lint/SKILL.md +9 -0
  7. package/ai/skills/stacks-mail/SKILL.md +1 -1
  8. package/ai/skills/stacks-migrations/SKILL.md +32 -1
  9. package/ai/skills/stacks-models/SKILL.md +20 -0
  10. package/ai/skills/stacks-native/CATALOG.md +19 -19
  11. package/ai/skills/stacks-scheduler/SKILL.md +11 -0
  12. package/ai/skills/stacks-testing/SKILL.md +14 -0
  13. package/app/Models/Content/Author.ts +3 -3
  14. package/app/Models/User.ts +4 -4
  15. package/bootstrap.ts +122 -102
  16. package/ide/vscode/package.json +1 -1
  17. package/package.json +4 -4
  18. package/resources/components/Dashboard/Auth/AccessTokens.stx +57 -37
  19. package/resources/components/Dashboard/Billing/BillingTransactionHistory.stx +27 -33
  20. package/resources/components/Dashboard/Commerce/CommercePaymentsTable.stx +85 -49
  21. package/resources/components/Dashboard/Commerce/CommerceTaxesTable.stx +63 -66
  22. package/resources/components/Dashboard/Commerce/CommerceVariantsTable.stx +67 -23
  23. package/resources/components/Dashboard/Content/BlogDashboard.stx +73 -67
  24. package/resources/components/Dashboard/Content/FileManagerDashboard.stx +39 -12
  25. package/resources/components/Dashboard/Data/DataRecords.stx +85 -88
  26. package/resources/components/Dashboard/Deployments/DeploymentTable.stx +49 -64
  27. package/resources/components/Dashboard/Operations/RecoveryPointTable.stx +72 -61
  28. package/resources/components/Dashboard/Operations/SchedulerTaskTable.stx +74 -70
  29. package/resources/components/Dashboard/Queue/QueueDashboard.stx +27 -61
@@ -800,10 +800,11 @@ Models with `traits.useApi` automatically get CRUD routes via ORM actions:
800
800
  | DELETE | `/api/{model}/{id}` | Generated destroy | 204 |
801
801
 
802
802
  Which `useApi` models get these routes is `security.api.models` in
803
- `config/security.ts` (`'all'` by default, `'own'`, `'none'`, or a list of model
804
- names that may include `'own'`), overridden by `STACKS_MODEL_APIS`. `'all'`
805
- includes the ~80 framework models, so an app that does not use commerce or
806
- CMS should set `'own'`. The OpenAPI schemas follow the same selection.
803
+ `config/security.ts` (`'own'` by default, `'all'`, `'none'`, or a list of model
804
+ names that may include `'own'`), overridden by `STACKS_MODEL_APIS`. The ~80
805
+ framework models publish nothing by default (#2954); an app that uses one
806
+ names it, `['own', 'Product']`, or sets `'all'`. The OpenAPI schemas follow
807
+ the same selection.
807
808
 
808
809
  Generated store and update handlers accept declared `fillable` attributes and
809
810
  the foreign-key attributes derived from `belongsTo`. For example,
@@ -121,6 +121,7 @@ On a failed step, execution stops and the report retains its number and error,
121
121
  the completed steps, final page state and requested screenshot.
122
122
  Use `{"action":"assert","selector":"...","absent":true}` to verify that an element is missing or hidden after an interaction.
123
123
  Use `{"action":"assert","selector":"button","text":"Save","focused":true}` to verify keyboard focus and focus restoration.
124
+ 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
125
 
125
126
  ### Crawl (whole-site browser audit)
126
127
  ```bash
@@ -600,9 +600,12 @@ interface ScenarioStep {
600
600
  key?: string
601
601
  ms?: number
602
602
  settle?: number
603
+ timeoutMs?: number
603
604
  }
604
605
 
605
- function parseScenarioStep(value: string): ScenarioStep {
606
+ class ScenarioAssertionError extends Error {}
607
+
608
+ export function parseScenarioStep(value: string): ScenarioStep {
606
609
  let parsed: unknown
607
610
  try {
608
611
  parsed = JSON.parse(value)
@@ -633,11 +636,41 @@ function parseScenarioStep(value: string): ScenarioStep {
633
636
  throw new TypeError('Scenario action "press" requires a key.')
634
637
  if (action === 'wait' && (!Number.isFinite(step.ms) || Number(step.ms) < 0 || Number(step.ms) > 30_000))
635
638
  throw new TypeError('Scenario action "wait" requires ms between 0 and 30000.')
639
+ if (step.timeoutMs !== undefined && (action !== 'assert' || !Number.isSafeInteger(step.timeoutMs) || Number(step.timeoutMs) < 0 || Number(step.timeoutMs) > 30_000))
640
+ throw new TypeError('Scenario timeoutMs is supported only by assert actions and must be an integer between 0 and 30000.')
636
641
 
637
642
  return step as unknown as ScenarioStep
638
643
  }
639
644
 
640
- async function runScenarioStep(cdp: Cdp, step: ScenarioStep): Promise<Record<string, unknown>> {
645
+ export async function runScenarioStep(cdp: Pick<Cdp, 'send'>, step: ScenarioStep): Promise<Record<string, unknown>> {
646
+ if (step.action === 'assert' && step.timeoutMs) {
647
+ const deadline = performance.now() + step.timeoutMs
648
+ let last: ScenarioAssertionError | undefined
649
+ const expired = () => new Error(`${last?.message || `Scenario assert failed (${step.selector || ''})`}; timed out after ${step.timeoutMs}ms`)
650
+ while (true) {
651
+ const budget = deadline - performance.now()
652
+ if (budget <= 0) throw expired()
653
+ let timeout: ReturnType<typeof setTimeout> | undefined
654
+ try {
655
+ const expiry = Promise.withResolvers<never>()
656
+ timeout = setTimeout(() => expiry.reject(expired()), budget)
657
+ const answer = await Promise.race([
658
+ runScenarioStep(cdp, { ...step, timeoutMs: 0 }),
659
+ expiry.promise,
660
+ ])
661
+ if (performance.now() > deadline) throw expired()
662
+ return answer
663
+ }
664
+ catch (error) {
665
+ if (!(error instanceof ScenarioAssertionError)) throw error
666
+ last = error
667
+ const remaining = deadline - performance.now()
668
+ if (remaining <= 0) throw error
669
+ await Bun.sleep(Math.min(50, remaining))
670
+ }
671
+ finally { if (timeout !== undefined) clearTimeout(timeout) }
672
+ }
673
+ }
641
674
  if (step.action === 'wait') {
642
675
  await Bun.sleep(Number(step.ms))
643
676
  return { action: step.action, ms: Number(step.ms), ok: true }
@@ -740,8 +773,11 @@ async function runScenarioStep(cdp: Cdp, step: ScenarioStep): Promise<Record<str
740
773
  returnByValue: true,
741
774
  })
742
775
  const value = result.result?.value as Record<string, unknown> | undefined
743
- if (!value?.ok)
776
+ if (!value?.ok) {
777
+ if (step.action === 'assert' && value)
778
+ throw new ScenarioAssertionError(`Scenario assert failed: ${String(value.error || 'unknown error')} (${step.selector || ''})`)
744
779
  throw new Error(`Scenario ${step.action} failed: ${String(value?.error || 'unknown error')} (${step.selector || step.key || ''})`)
780
+ }
745
781
  if (step.action === 'click') {
746
782
  const point = value.clickPoint as { x: number, y: number }
747
783
  await cdp.send('Input.dispatchMouseEvent', { type: 'mousePressed', x: point.x, y: point.y, button: 'left', clickCount: 1 })
@@ -1196,7 +1232,7 @@ async function main() {
1196
1232
  }
1197
1233
  }
1198
1234
 
1199
- main().catch((e) => {
1235
+ if (import.meta.main) main().catch((e) => {
1200
1236
  console.error('browse error:', e?.message || e)
1201
1237
  process.exit(1)
1202
1238
  })
@@ -47,7 +47,9 @@ so `MAIL_MAILER` must be one of `smtp`, `ses`, `sendgrid`, `mailgun`,
47
47
  ```typescript
48
48
  import { mail } from '@stacksjs/email'
49
49
 
50
- await mail.send({
50
+ // Throws EmailDeliveryError when it was not delivered. The default choice:
51
+ // a try/catch around it means what it looks like.
52
+ await mail.sendOrFail({
51
53
  from: { name: 'App', address: 'noreply@app.com' },
52
54
  to: 'user@example.com',
53
55
  subject: 'Welcome',
@@ -55,19 +57,21 @@ await mail.send({
55
57
  text: 'Hello!'
56
58
  })
57
59
 
58
- // Use this when later state depends on successful provider delivery.
59
- await mail.sendOrFail({
60
- to: 'user@example.com',
61
- subject: 'Your invitation',
62
- text: 'Open the invitation link.'
63
- })
60
+ // send() does NOT throw on a failed delivery; it resolves with success: false.
61
+ // For callers that aggregate outcomes, and they must check it.
62
+ const result = await mail.send({ to: 'user@example.com', subject: 'Digest', text: '...' })
63
+ if (!result.success)
64
+ failed.push(result.message)
64
65
 
65
66
  // Switch driver
66
67
  const sendgridMail = mail.use('sendgrid')
67
68
  await sendgridMail.send(message)
68
69
  ```
69
70
 
70
- `mail.send()` always returns an `EmailResult`. Provider rejection is represented
71
+ `mail.send()` always returns an `EmailResult`, typed as `EmailSent | EmailFailed`,
72
+ and `sendOrFail()` resolves with `EmailSent`. Never wrap `send()` in `try`/`catch`
73
+ and count the absence of an exception as delivered: a newsletter was recorded as
74
+ sent while its SMTP host was unreachable that way (#2930). Provider rejection is represented
71
75
  as `{ success: false, message, provider }`, which is useful for campaign jobs
72
76
  that aggregate individual outcomes. It may still throw for invalid framework
73
77
  configuration. `mail.sendOrFail()` returns the same successful result and throws
@@ -224,7 +224,7 @@ const decrypted = decryptValue(encrypted, keypair.privateKey)
224
224
 
225
225
  ```bash
226
226
  buddy env:get APP_NAME # get single var
227
- buddy env:get --all --format json # all vars as JSON
227
+ buddy env:get --all --format json # every var in the file as JSON (never the process env)
228
228
  buddy env:set APP_NAME "My App" # set var
229
229
  buddy env:encrypt # encrypt .env file
230
230
  buddy env:decrypt # decrypt .env file
@@ -19,6 +19,15 @@ it does not wrap ESLint. ESLint-style disable comments are compatibility syntax.
19
19
  - `./buddy format`: write formatting; `./buddy format --check` checks without writing.
20
20
  - `./buddy lint --stx`: run the separate stx conformance checks from `config/lint.ts`.
21
21
 
22
+ All four take paths and lint only what you name: `./buddy lint:fix app/Jobs/Foo.ts`
23
+ fixes that file, `./buddy lint app/Jobs docs` covers those two directories, and
24
+ naming none covers the project. Scope `lint:fix` this way whenever you are
25
+ fixing something specific, because its project-wide run also applies rules you
26
+ are not working on (class ordering across `resources/`, markdown in `docs/`),
27
+ and those land in your diff. A path that matches nothing is an error rather
28
+ than a silent fallback to the project, so a typo cannot widen the run.
29
+ `--stx` grades the project against the config baselines and refuses paths.
30
+
22
31
  For direct CLI use, run `bunx --bun pickier .`, adding `--fix` for supported
23
32
  fixes. Re-run without `--fix` to confirm remaining findings. Only apply fixes
24
33
  that preserve the source behavior; investigate false positives at Pickier's source.
@@ -81,7 +81,7 @@ export async function sendSubscriptionConfirmation({ to, subscriberUuid }: Optio
81
81
  }
82
82
  })
83
83
 
84
- await mail.send({
84
+ await mail.sendOrFail({
85
85
  from: { name: config.app.name, address: config.email.from.address },
86
86
  to,
87
87
  subject: 'Confirm your subscription',
@@ -18,7 +18,9 @@ Schema change management via migration files.
18
18
  ## CLI Commands
19
19
 
20
20
  ```bash
21
- buddy migrate # run pending migrations
21
+ buddy migrate # run pending migrations (and generate new ones from the models, in an interactive terminal only)
22
+ buddy migrate --generate # generate from the models even when not interactive
23
+ buddy migrate --no-generate # apply committed migrations only, even in a terminal
22
24
  buddy migrate --diff # show SQL without running
23
25
  buddy migrate --auth # include auth tables
24
26
  buddy migrate:fresh # drop ALL tables and re-migrate
@@ -26,12 +28,33 @@ buddy migrate:fresh --seed # drop, migrate, then seed
26
28
  buddy make:migration <name> # create new migration file
27
29
  buddy seed # seed database
28
30
  buddy generate:migrations # generate migrations from model diffs
31
+ buddy generate:migrations --dialect postgres # into another dialect's corpus, no Postgres needed
32
+ buddy generate:migrations --dialect all # the connected dialect and every other corpus
29
33
  buddy migrate:regenerate <dialect> # rebuild the whole corpus from the models
30
34
  buddy migrate:status # corpus vs ledger vs live schema; lists hand-written files
31
35
  buddy migrate:align # plan repairs of a database that drifted from the models
32
36
  buddy migrate:align --apply # rename legacy indexes, add missing indexes/FKs/columns, widen losslessly
33
37
  ```
34
38
 
39
+ An app that develops on one dialect and deploys on another keeps a corpus per
40
+ dialect (`database/migrations/<dialect>/`, each with its own snapshot). A plain
41
+ `generate:migrations` moves only the connected dialect and then warns, naming
42
+ any other corpus the models have left behind; `--dialect <name>` or `--dialect
43
+ all` brings it up to date from the models and that dialect's snapshot, without a
44
+ database of that dialect (#2949).
45
+
46
+ `buddy migrate` never writes the committed migration files. What it adapts for
47
+ the connected database (idempotent ALTERs on Postgres, statements SQLite cannot
48
+ run, gated features) happens to a copy of the corpus made for that run, so a
49
+ SQLite app's migrations stay SQLite after a migrate against Postgres (#2929).
50
+
51
+ A non-interactive `buddy migrate` (CI, a deploy step) generates nothing unless
52
+ given `--generate` (#2948). Generating there authored a migration nobody
53
+ reviewed and applied it in the same run, and on a deploy box the file then
54
+ vanished with the release directory. Generate locally, commit the files, and let
55
+ the deploy apply them; add `--strict` in CI to fail when the models have drifted
56
+ from the committed migrations.
57
+
35
58
  ## Creating a Schema Migration
36
59
 
37
60
  ```bash
@@ -62,6 +85,14 @@ schema and excludes framework demo tables. Set
62
85
  wants the merged registry; application models override matching framework names.
63
86
  Discovered package model roots also contribute their declared models.
64
87
 
88
+ The framework's default routes follow the same exclusion. At boot, a default
89
+ route whose framework action uses an excluded model is not registered when the
90
+ database has no table for that model, and one warning names each such route
91
+ (#2943). Before this, those routes answered 500. If the table exists (for
92
+ example, the app created it before the exclusion), the route registers as usual.
93
+ Publish the model (`buddy publish model <Name>`) to serve the route from the
94
+ app's own schema.
95
+
65
96
  The generator diffs the resolved registry against the committed dialect snapshot.
66
97
  An application does not need an `app/Models/` directory for fallback framework
67
98
  model migrations to be discovered. Inspect the resolved scope with verbose output
@@ -376,6 +376,26 @@ traits: {
376
376
  },
377
377
  ```
378
378
 
379
+ A factory receives `faker`, the attributes generated above it, and a context
380
+ whose `pick(model, column = 'id')` resolves to a value from a row that already
381
+ exists. Use it for a column whose valid values another row decides, such as a
382
+ polymorphic `subject_id`, which `belongsTo` cannot express because its foreign
383
+ key would forbid most of the values. List every model a factory picks from in
384
+ `useSeeder.after` so it seeds first:
385
+
386
+ ```ts
387
+ traits: { useSeeder: { count: 30, after: ['Issue', 'PullRequest'] } },
388
+ attributes: {
389
+ subjectType: { required: true, factory: faker => faker.helpers.arrayElement(['Issue', 'PullRequest']) },
390
+ subjectId: { required: true, factory: (faker, { subjectType }, { pick }) => pick(subjectType) },
391
+ },
392
+ ```
393
+
394
+ A pick that cannot be satisfied (no rows yet, or the model seeds later and is
395
+ missing from `after`) fails that model with the fix in its message, and so does
396
+ a factory that leaves a required column `null`. Neither invents a value
397
+ (#2951).
398
+
379
399
  `buddy seed` walks every model carrying the trait and fills its table from the
380
400
  attribute factories. Model fixture data needs no separate seeder or registration.
381
401
  Idempotent application bootstrap work can live in `database/seeders` as a
@@ -11,7 +11,7 @@ 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) | 82 |
14
+ | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 84 |
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) | 17 |
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) | 1 |
17
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 |
@@ -21,7 +21,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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) | 119 |
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) | 159 |
24
+ | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 162 |
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 |
@@ -35,7 +35,7 @@ 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) | 4 |
38
- | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 126 |
38
+ | `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 130 |
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) | 13 |
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 |
@@ -65,21 +65,21 @@ 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) | 69 |
68
+ | `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 71 |
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 |
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) | 6 |
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) | 6 |
74
- | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 48 |
74
+ | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 49 |
75
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 |
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
- | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 94 |
79
- | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 13 |
78
+ | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 96 |
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) | 24 |
82
+ | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 25 |
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 |
@@ -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/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: [82 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: [84 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
 
@@ -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: [159 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.
218
+ Evidence directory: [162 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
 
@@ -347,11 +347,11 @@ Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/m
347
347
 
348
348
  Guidance: [`stacks-database`](../stacks-database/SKILL.md). Source: [storage/framework/core/database/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts).
349
349
 
350
- Declared runtime exports: `BUN_BROKEN_MYSQL_POOL_MESSAGE`, `BUN_BROKEN_POSTGRES_POOL_MESSAGE`, `Database`, `EntityQueryBuilder`, `__flushAfterCommitNow`, `__pendingAfterCommitCount`, `addColumnSafely`, `auditForeignKeys`, `auditSchemaDrift`, `auditUniqueIndexes`, `backfillInBatches`, `buildKey`, `classifyDeclaredFKs`, `comparableIndexKey`, `createDatabase`, `createDynamo`, `createMysqlDatabase`, `createPostgresDatabase`, `createQueryBuilder`, `createSqliteDatabase`, `createTursoDatabase`, `describeIgnoreRule`, `detectDriver`, `driverDefaults`, `dynamo`, `enqueueAfterCommit`, `ensureNotificationForeignKeys`, `findFkOrphans`, `findIgnoredMigrations`, `fkKey`, `formatIgnoredMigrations`, `formatSchemaDrift`, `generateKeyPattern`, `getBrokenDatabasePools`, `getConfigFromEnv`, `getConnectionString`, `getDeclaredFKs`, `getDeclaredUniques`, `getLiveFKs`, `getLiveTables`, `getLiveUniqueIndexes`, `isBrokenBunPoolError`, `isInTransaction`, `logQuery`, `marshall`, `matchedRows`, `mergeWithDefaults`, `migrateNotificationTables`, `migrateRbacTables`, `mutationCount`, `parseKeyPattern`, `postgresIndexStatement`, `renameColumnSafely`, `runInTransactionScope`, `setConfig`, `setQueryTracker`, `trackIgnoredGeneratedMigrations`, `unmarshall`, `validateDriverConfig`.
350
+ Declared runtime exports: `BUN_BROKEN_MYSQL_POOL_MESSAGE`, `BUN_BROKEN_POSTGRES_POOL_MESSAGE`, `Database`, `EntityQueryBuilder`, `__flushAfterCommitNow`, `__pendingAfterCommitCount`, `addColumnSafely`, `auditForeignKeys`, `auditSchemaDrift`, `auditUniqueIndexes`, `backfillInBatches`, `buildKey`, `classifyDeclaredFKs`, `comparableIndexKey`, `createDatabase`, `createDynamo`, `createMysqlDatabase`, `createPostgresDatabase`, `createQueryBuilder`, `createSqliteDatabase`, `createTursoDatabase`, `describeIgnoreRule`, `detectDriver`, `driverDefaults`, `dynamo`, `enqueueAfterCommit`, `ensureNotificationForeignKeys`, `findFkOrphans`, `findIgnoredMigrations`, `fkKey`, `formatIgnoredMigrations`, `formatSchemaDrift`, `frameworkRouteAdmission`, `generateKeyPattern`, `getBrokenDatabasePools`, `getConfigFromEnv`, `getConnectionString`, `getDeclaredFKs`, `getDeclaredUniques`, `getLiveFKs`, `getLiveTables`, `getLiveUniqueIndexes`, `isBrokenBunPoolError`, `isInTransaction`, `logQuery`, `marshall`, `matchedRows`, `mergeWithDefaults`, `migrateNotificationTables`, `migrateRbacTables`, `mutationCount`, `parseKeyPattern`, `postgresIndexStatement`, `renameColumnSafely`, `runInTransactionScope`, `setConfig`, `setQueryTracker`, `trackIgnoredGeneratedMigrations`, `unmarshall`, `validateDriverConfig`.
351
351
 
352
- 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/broken-pool.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/broken-pool.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/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-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/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).
352
+ 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/broken-pool.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/broken-pool.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-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/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).
353
353
 
354
- Evidence directory: [126 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.
354
+ Evidence directory: [130 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.
355
355
 
356
356
  ### @stacksjs/datetime
357
357
 
@@ -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: [69 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.
636
+ Evidence directory: [71 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
 
@@ -687,7 +687,7 @@ Declared runtime exports: `Batch`, `DispatchedBatch`, `FailedJobNotifier`, `JOB_
687
687
 
688
688
  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/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).
689
689
 
690
- Evidence directory: [48 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.
690
+ Evidence directory: [49 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.
691
691
 
692
692
  ### @stacksjs/realtime
693
693
 
@@ -719,11 +719,11 @@ Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/m
719
719
 
720
720
  Guidance: [`stacks-router`](../stacks-router/SKILL.md). Source: [storage/framework/core/router/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts).
721
721
 
722
- Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withTraceId`, `wrapAction`.
722
+ Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withRouteAdmission`, `withTraceId`, `wrapAction`.
723
723
 
724
724
  Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/body.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/json.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/json.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/security-settings.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/security-settings.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
725
725
 
726
- Evidence directory: [94 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
726
+ Evidence directory: [96 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
727
727
 
728
728
  ### @stacksjs/scheduler
729
729
 
@@ -733,7 +733,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
733
733
 
734
734
  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).
735
735
 
736
- Evidence directory: [13 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.
736
+ Evidence directory: [14 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.
737
737
 
738
738
  ### @stacksjs/search-engine
739
739
 
@@ -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: [24 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.
766
+ Evidence directory: [25 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
 
@@ -81,9 +81,20 @@ Each sets an internal cron pattern. Once a timing method is called, the schedule
81
81
  | `weekly()` | `0 0 * * 0` | Sunday at midnight |
82
82
  | `monthly()` | `0 0 1 * *` | 1st of month at midnight |
83
83
  | `yearly()` / `annually()` | `0 0 1 1 *` | Jan 1 at midnight |
84
+ | `weekdays()` | `0 0 * * 1-5` | Monday to Friday |
84
85
  | `onDays(days: number[])` | `0 0 * * {days}` | e.g. `onDays([1,3,5])` => `0 0 * * 1,3,5` |
85
86
  | `at(time: string)` | `{min} {hr} * * *` | e.g. `at('14:30')` => `30 14 * * *` |
86
87
 
88
+ The patterns above are what each method answers on its own. Chained, they
89
+ compose on two independent axes and the order does not matter: the time of day
90
+ (`at`, `hourly`, `every*Minutes`) and the days it runs on (`daily`, `weekly`,
91
+ `monthly`, `yearly`, `weekdays`, `onDays`). Each method writes its own axis and
92
+ keeps the other, so `.at('09:00').onDays([2])` and `.onDays([2]).at('09:00')`
93
+ are both `0 9 * * 2`. Two calls on the same axis means the last one wins, so
94
+ `.monthly().weekly()` is weekly. A `cron()` expression replaces both axes, and
95
+ `everySecond()` leaves cron entirely (any cadence method after it returns to a
96
+ cron pattern).
97
+
87
98
  ### Configuration Methods (chainable, returns `this`)
88
99
 
89
100
  ```typescript
@@ -297,6 +297,8 @@ expect(pageAuditClean(report)).toBe(true) // no duplicate /api/ requests, failed
297
297
  buddy test # run all tests
298
298
  buddy test --unit # unit tests only
299
299
  buddy test --feature # feature tests only
300
+ buddy test tests/unit/auth.test.ts # just that file
301
+ buddy test storage/framework/core/scheduler/tests # just that directory
300
302
  bun run test # via npm script
301
303
  bun run test:ui # UI tests
302
304
  bun run test:coverage # with coverage
@@ -305,6 +307,18 @@ buddy test:page-audit --url /,/dashboard --base http://localhost:3000 # duplica
305
307
  buddy test:page-audit --url http://localhost:3000/pricing --mobile --json
306
308
  ```
307
309
 
310
+ Name a path to run only what is under it, file or directory, anywhere in the
311
+ repo. A path matching no test file is an error rather than a fallback to the
312
+ whole suite, which matters because the fallback used to report `0 fail` and
313
+ exit 0 for a file it never opened. `test:unit` and `test:feature` narrow a
314
+ named path to their own suite and say so when it holds none of their tests.
315
+
316
+ Running `bun test` directly needs the `./` prefix: bunfig sets
317
+ `[test] root = "tests"`, so `bun test storage/.../foo.test.ts` from the repo
318
+ root matches nothing and reports a clean run over no files, while
319
+ `bun test ./storage/.../foo.test.ts` works. `buddy test` adds the prefix for
320
+ you, so prefer it.
321
+
308
322
  `test:page-audit` exits 1 when any page has duplicates, failed same-origin requests or errors, or
309
323
  never settles.
310
324
 
@@ -23,9 +23,9 @@ export default defineModel({
23
23
  useUuid: true,
24
24
  useTimestamps: true, // defaults to true, `timestampable` used as an alias
25
25
  useSearch: {
26
- displayable: ['id', 'name', 'email'], // the fields to become d (defaults to all fields)
27
- searchable: ['name', 'email'], // the fields to become searchable (defaults to all fields)
28
- sortable: ['created_at', 'updated_at'], // the fields to become sortable (defaults to all fields)
26
+ displayable: ['id', 'name', 'email'], // the fields a hit returns
27
+ searchable: ['name', 'email'], // the fields a query matches against
28
+ sortable: ['created_at', 'updated_at'], // the fields results can be ordered by
29
29
  filterable: [],
30
30
  },
31
31
 
@@ -41,10 +41,10 @@ export default defineModel({
41
41
  useTimestamps: true, // defaults to true, `timestampable` used as an alias
42
42
  useSocials: ['github'],
43
43
  useSearch: {
44
- displayable: ['id', 'name', 'email'], // the fields to become d (defaults to all fields)
45
- searchable: ['name', 'email'], // the fields to become searchable (defaults to all fields)
46
- sortable: ['created_at', 'updated_at'], // the fields to become sortable (defaults to all fields)
47
- filterable: [], // the fields to become filterable (defaults to all fields)
44
+ displayable: ['id', 'name', 'email'], // the fields a hit returns
45
+ searchable: ['name', 'email'], // the fields a query matches against
46
+ sortable: ['created_at', 'updated_at'], // the fields results can be ordered by
47
+ filterable: [], // the fields results can be narrowed by
48
48
  // options: {}, // you may pass options to the search engine
49
49
  },
50
50