@stacksjs/defaults 0.75.445 → 0.75.450

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.
@@ -269,9 +269,11 @@ These standalone functions are also available through the root `arr` namespace:
269
269
  - `groupBy`, `keyBy`, `countBy` use selector functions and return typed records.
270
270
  Repeated keyBy keys overwrite earlier entries; groupBy accumulates them.
271
271
  - `sortBy(array, ...selectors)` copies before sorting, supports multiple keys,
272
- and accepts `{ by, order: 'desc' }` selectors.
272
+ and accepts `{ by, order: 'desc' }` selectors. Each selector runs once per element;
273
+ cached keys preserve stable ties.
273
274
  - `sumBy`, `meanBy`, `minBy`, `maxBy` aggregate selected values. `meanBy` returns
274
275
  undefined on an empty input; extrema return the selected element, not its value.
276
+ Extrema retain infinite endpoints and ignore NaN candidates; ties keep the first.
275
277
  - `zip`, `zipWith` stop at the shorter input; `unzip` splits pairs.
276
278
  - `difference` keeps first-input duplicates that are not excluded;
277
279
  `intersection` and `union` deduplicate by Set identity.
@@ -280,6 +282,12 @@ These standalone functions are also available through the root `arr` namespace:
280
282
  - `splitAt` supports negative indexes; `splitWhen` starts the second half at
281
283
  the first match; `times` requires a non-negative integer count.
282
284
 
285
+ `take`, `takeLast`, `drop` and `dropLast` truncate fractional counts toward zero,
286
+ clamp negatives/NaN to zero and treat Infinity as the entire array. Population
287
+ variance, standard deviation, covariance and z-scores use scaled centered arithmetic
288
+ for finite inputs. Standard deviation stays finite when only its square is outside
289
+ the number range; unrepresentable final results keep IEEE number behavior.
290
+
283
291
  Read `core/arrays/src/transform.ts` and `tests/transform.test.ts` for precise
284
292
  empty-input and selector behavior. These pure helpers are preferable to a new
285
293
  utility dependency for common native transformations.
@@ -737,13 +737,39 @@ not authenticate them. OAuth resource endpoints must explicitly use
737
737
  required scopes. Ordinary refresh also refuses delegated refresh credentials;
738
738
  use the OAuth token endpoint and the registered client's protocol authentication.
739
739
 
740
+ ### Userinfo and pairwise subjects
741
+
742
+ The provider has no id_token. A relying party that signs people in with this
743
+ provider reads `oauthUserInfoResponse(request, { scopes, resource, audience,
744
+ workspaceId, isSubjectEligible, pairwiseSecret, claims })`: the same delegated
745
+ token checks as any protected resource, then `{ ...claims, sub }`. `sub` comes
746
+ from `pairwiseOAuthSubject(secret, clientId, subject)`, an HMAC that differs per
747
+ client so two relying parties cannot join records on it; keep its secret apart
748
+ from rotating app keys. `claims({ sub, subject, clientId, scopes })` releases
749
+ only what the granted scopes cover, and null answers 401. The socials
750
+ `StacksIssuerProvider` is the matching client.
751
+
740
752
  ## Token-only recovery endpoints
741
753
 
742
754
  For high-entropy reset credentials, `mintPasswordResetToken()` returns `{ token, digest }`.
743
755
  Store the digest in `password_resets.token`, never the plaintext.
756
+ Prefer `issuePasswordResetToken(email, { throttleMs?, expiresAt?, eligible? })` when
757
+ issuing for an existing account. It locks that account before checking its current
758
+ email, the synchronous application eligibility predicate and the saved throttle.
759
+ It considers all supported legacy email-case variants when throttling, and retires
760
+ them together when replacing the credential. `throttleMs: 0` disables throttling.
761
+ It atomically replaces the digest and returns `{ issued: true, token, userId, email }`
762
+ or `{ issued: false }`. The latter deliberately combines unknown, ineligible and
763
+ throttled accounts; recovery endpoints must keep their public response generic.
764
+ Only send the returned credential after issuance commits.
765
+ Treat its value as opaque. It is bound to the issuing account, so reassigning an
766
+ email address cannot let an old recovery reset the address's new account.
744
767
  `consumePasswordResetToken(token, async claim => { ... })` locks the owner and token,
745
768
  checks the stored expiry and consumes it in the same transaction as callback writes.
746
769
  `claim` is `{ userId, email, hasExplicitExpiry }`; result is `{ consumed: false }` or
747
770
  `{ consumed: true, value }`. Failures roll back the credential and account changes.
748
771
  Use database work only in the callback, and send notifications after commit.
772
+ The credential is consumed before the callback, so it composes with
773
+ `revokeAccountCredentials(claim.userId)`. That sweep also removes any pending
774
+ password-reset links; changing a password must retire recovery credentials too.
749
775
  The existing `passwordResets(email)` flow supports email-addressed bcrypt tokens.
@@ -27,8 +27,9 @@ const products = await cache.mget<{ name: string }>(['product:42', 'product:43']
27
27
  shipped) on every driver, memory included, so a value set with no TTL
28
28
  expires after an hour. The `memory` export is a separate in-process
29
29
  instance with no default expiry.
30
- - `setForever` stores without expiry; `getTtl` reads remaining TTL and
31
- `ttl(key, seconds)` updates it. Missing values are undefined.
30
+ - `setForever` stores without expiry; `getTtl` reads the absolute expiry in epoch
31
+ milliseconds (zero for forever); `ttl(key, seconds)` updates it.
32
+ Missing or expired values are undefined.
32
33
  - `mset([{ key, value, ttl? }])` writes entries. `del(keyOrKeys)` and
33
34
  `deleteMany(keys)` return counts; `remove(key)` returns void.
34
35
  - `has/missing/take`, `keys(pattern?)`, `getStats`,
@@ -61,6 +62,15 @@ deploys, pointing `path` at a file the deploy preserves (the app's own SQLite
61
62
  database works; the table is the driver's alone). `createCache(driver,
62
63
  options?)` selects one of memory, redis, singlestore or sqlite.
63
64
 
65
+ SQLite TTLs, including `stdTTL`, must be finite non-negative seconds with
66
+ representable expiry timestamps. Zero alone means forever; fractions work.
67
+ Invalid TTLs throw RangeError before publication; invalid `mset` entries roll
68
+ back the batch. `getTtl` evicts expired entries instead of reporting stale
69
+ metadata. `mget` preserves special keys such as `__proto__` as own properties.
70
+ SQLite key globs are case-sensitive, with only `*` a wildcard; `?`, brackets,
71
+ percent, underscore and backslash are literal. An empty pattern matches an
72
+ empty key, while an omitted pattern lists all live keys in the prefix.
73
+
64
74
  The `cache` export is the driver `config/cache.ts` selects, with its `prefix`
65
75
  and `ttl` applied on every driver (memory also takes `maxKeys`, `useClones`
66
76
  and `drivers.memory`), resolved on first use and once the app's config has
@@ -258,6 +258,11 @@ offset; the named IANA zone converts it into an instant. `isoInZone` retains
258
258
  that zone's offset in serialized output rather than merely displaying a date.
259
259
  `addCalendarMonths` clones and clamps the day; ordinary `DateTime.addMonths`
260
260
  preserves native Date overflow instead. Do not interchange those contracts.
261
+ Calendar-month clamping keeps literal early years in local and UTC mode and throws
262
+ RangeError for an out-of-range result. A zero-month shift preserves the exact instant.
263
+ Named-zone conversion rejects impossible calendar and clock fields before applying
264
+ DST disambiguation. Era-aware offsets support year zero and BCE instants; `isoInZone`
265
+ retains seconds for expanded ISO years.
261
266
 
262
267
  `zonedTimeToUtc` resolves DST edges the same way in every zone (RFC 5545 and
263
268
  Temporal's `'compatible'` rule):
@@ -309,6 +314,7 @@ minutesUntil('2026-10-25', '09:00', 'Europe/Berlin', new Date('2026-10-24T22:00:
309
314
  - `minutesUntil` keeps the seconds of `now` as a fraction; round where you
310
315
  display or compare. Negative once the moment has passed.
311
316
  - `addDays` refuses a result past 9999-12-31.
317
+ - `todayIn` returns canonical dates from 0000 through 9999 and rejects BCE or expanded-year dates.
312
318
 
313
319
  ### Reading `DATE` columns: `parseSqlDate` (`@stacksjs/database`)
314
320
 
@@ -363,6 +369,8 @@ clockMinutes, addClockMinutes and timeWindowsCover. Recurrence validation
363
369
  rejects invalid weekday entries; expansion refuses excessive ranges and
364
370
  midnight-crossing durations instead of silently truncating them. Adjacent
365
371
  windows can cover one continuous slot. ScheduleInputError carries status 422.
372
+ Every supplied availability window is validated before checking coverage, even
373
+ when an earlier valid window already covers the slot.
366
374
 
367
375
  localDateRange(from, to, ...zones) converts inclusive calendar days to an
368
376
  exclusive-end UTC instant range in a selected valid zone, including DST days.
@@ -16,14 +16,14 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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
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 |
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
- | `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 10 |
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
- | `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 126 |
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) | 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) | 9 |
24
24
  | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 179 |
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
- | `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 23 |
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 |
28
28
  | `@stacksjs/charts` | [`stacks-charts`](../stacks-charts/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/charts/src/index.ts) | 3 |
29
29
  | `@stacksjs/chat` | [`stacks-chat`](../stacks-chat/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/index.ts) | 6 |
@@ -36,7 +36,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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
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 |
39
- | `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 21 |
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 |
@@ -64,9 +64,9 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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
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) | 18 |
67
- | `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 6 |
67
+ | `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 8 |
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) | 76 |
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 |
69
+ | `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 1 |
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) | 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 |
@@ -85,16 +85,16 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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 |
86
86
  | `@stacksjs/slug` | [`stacks-slug`](../stacks-slug/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/slug/src/index.ts) | 5 |
87
87
  | `@stacksjs/sms` | [`stacks-sms`](../stacks-sms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sms/src/index.ts) | 6 |
88
- | `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 17 |
89
- | `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) | 47 |
90
- | `@stacksjs/strings` | [`stacks-strings`](../stacks-strings/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/index.ts) | 10 |
88
+ | `@stacksjs/socials` | [`stacks-socials`](../stacks-socials/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/index.ts) | 18 |
89
+ | `@stacksjs/storage` | [`stacks-storage`](../stacks-storage/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/index.ts) | 48 |
90
+ | `@stacksjs/strings` | [`stacks-strings`](../stacks-strings/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/index.ts) | 11 |
91
91
  | `@stacksjs/testing` | [`stacks-testing`](../stacks-testing/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/index.ts) | 24 |
92
92
  | `@stacksjs/tinker` | [`stacks-repl`](../stacks-repl/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/tinker/src/index.ts) | 1 |
93
93
  | `@stacksjs/tunnel` | [`stacks-tunnel`](../stacks-tunnel/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/tunnel/src/index.ts) | 1 |
94
94
  | `@stacksjs/types` | [`stacks-types`](../stacks-types/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/index.ts) | 2 |
95
95
  | `@stacksjs/ui` | [`stacks-ui`](../stacks-ui/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ui/src/index.ts) | 6 |
96
- | `@stacksjs/utils` | [`stacks-utils`](../stacks-utils/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/index.ts) | 15 |
97
- | `@stacksjs/validation` | [`stacks-validation`](../stacks-validation/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/index.ts) | 22 |
96
+ | `@stacksjs/utils` | [`stacks-utils`](../stacks-utils/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/index.ts) | 22 |
97
+ | `@stacksjs/validation` | [`stacks-validation`](../stacks-validation/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/index.ts) | 25 |
98
98
  | `@stacksjs/video` | [`stacks-video`](../stacks-video/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/video/src/index.ts) | 3 |
99
99
  | `@stacksjs/whois` | [`stacks-whois`](../stacks-whois/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/index.ts) | 5 |
100
100
 
@@ -169,7 +169,7 @@ Declared runtime exports: `arr`.
169
169
 
170
170
  Local source modules: [src/arr.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/arr.ts), [src/macro.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/macro.ts).
171
171
 
172
- Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
172
+ Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
173
173
 
174
174
  ### @stacksjs/audio
175
175
 
@@ -187,9 +187,9 @@ Guidance: [`stacks-auth`](../stacks-auth/SKILL.md). Source: [storage/framework/c
187
187
 
188
188
  Declared runtime exports: `DEFAULT_ROLE_PACKS`, `createBqbRbacStore`, `generateTOTP`, `generateTOTPSecret`, `requestImpersonation`, `seedDefaultRoles`, `totpKeyUri`, `verifyTOTP`.
189
189
 
190
- Local source modules: [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/impersonation-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-auth.ts), [src/impersonation-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-store.ts), [src/impersonation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset-token.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
190
+ Local source modules: [src/authentication.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authentication.ts), [src/authenticator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authenticator.ts), [src/authorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/authorizable.ts), [src/browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/browser-session.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/client.ts), [src/cookie-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/cookie-auth.ts), [src/credential-user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/credential-user.ts), [src/email-verification.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/email-verification.ts), [src/gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/gate.ts), [src/impersonation-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-auth.ts), [src/impersonation-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation-store.ts), [src/impersonation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/impersonation.ts), [src/magic-link.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/magic-link.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/middleware.ts), [src/oauth-authorization-codes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-codes.ts), [src/oauth-authorization-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-endpoint.ts), [src/oauth-authorization-requests.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-requests.ts), [src/oauth-authorization-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization-response.ts), [src/oauth-authorization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-authorization.ts), [src/oauth-browser-session.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-browser-session.ts), [src/oauth-client-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-client-registration.ts), [src/oauth-consent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-consent.ts), [src/oauth-delegated-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-delegated-access.ts), [src/oauth-dynamic-registration.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-dynamic-registration.ts), [src/oauth-grants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-grants.ts), [src/oauth-introspection.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-introspection.ts), [src/oauth-metadata.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-metadata.ts), [src/oauth-pkce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pkce.ts), [src/oauth-protected-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-protected-resource.ts), [src/oauth-provider.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-provider.ts), [src/oauth-pruning.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-pruning.ts), [src/oauth-revocation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-revocation.ts), [src/oauth-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-server.ts), [src/oauth-token-endpoint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-endpoint.ts), [src/oauth-token-exchange.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-exchange.ts), [src/oauth-token-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-request.ts), [src/oauth-token-response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-token-response.ts), [src/oauth-userinfo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/oauth-userinfo.ts), [src/page-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/page-gate.ts), [src/passkey.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkey.ts), [src/passkeys.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/passkeys.ts), [src/password/reset-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset-token.ts), [src/password/reset.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/password/reset.ts), [src/permissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/permissions.ts), [src/policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/policy.ts), [src/rate-limiter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rate-limiter.ts), [src/rbac-seed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-seed.ts), [src/rbac-store-bqb.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac-store-bqb.ts), [src/rbac.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/rbac.ts), [src/referrals.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/referrals.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/register.ts), [src/request-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/request-token.ts), [src/session-auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-auth.ts), [src/session-handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/session-handoff.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/socials.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/team.ts), [src/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/tokens.ts), [src/two-factor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/two-factor.ts), [src/user.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/user.ts).
191
191
 
192
- Evidence directory: [126 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
192
+ Evidence directory: [127 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
193
193
 
194
194
  ### @stacksjs/browser
195
195
 
@@ -239,7 +239,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
239
239
 
240
240
  Local source modules: [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/drivers/index.ts), [src/key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/key.ts).
241
241
 
242
- Evidence directory: [23 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
242
+ Evidence directory: [24 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
243
243
 
244
244
  ### @stacksjs/calendar-api
245
245
 
@@ -367,7 +367,7 @@ Declared runtime exports: `DateTime`, `addCalendarMonths`, `addDays`, `dateForma
367
367
 
368
368
  Local source modules: [src/calendar.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/calendar.ts), [src/format.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/format.ts), [src/local.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/local.ts), [src/now.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/now.ts), [src/parse.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/parse.ts), [src/schedule.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/schedule.ts), [src/zone.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/zone.ts).
369
369
 
370
- Evidence directory: [21 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
370
+ Evidence directory: [22 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
371
371
 
372
372
  ### @stacksjs/defaults
373
373
 
@@ -631,7 +631,7 @@ Declared runtime exports: `clearUndefined`, `deepMerge`, `hasOwnProperty`, `isKe
631
631
 
632
632
  Local source modules: [src/transform.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/transform.ts).
633
633
 
634
- Evidence directory: [6 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
634
+ Evidence directory: [8 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
635
635
 
636
636
  ### @stacksjs/orm
637
637
 
@@ -649,6 +649,8 @@ Guidance: [`stacks-pagination`](../stacks-pagination/SKILL.md). Source: [storage
649
649
 
650
650
  Declared runtime exports: `isCursorPaginator`, `isPaginator`, `isSimplePaginator`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`.
651
651
 
652
+ Evidence directory: [1 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
653
+
652
654
  ### @stacksjs/path
653
655
 
654
656
  Guidance: [`stacks-path`](../stacks-path/SKILL.md). Source: [storage/framework/core/path/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts).
@@ -831,7 +833,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
831
833
 
832
834
  Local source modules: [src/abstract.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/abstract.ts), [src/authorize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/authorize.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/drivers/index.ts), [src/exceptions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/exceptions.ts), [src/flows.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/flows.ts), [src/handoff.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/handoff.ts), [src/identities.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/identities.ts), [src/meta-graph.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/meta-graph.ts), [src/publish.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/publish.ts), [src/registry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/registry.ts), [src/token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/token.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/src/types.ts).
833
835
 
834
- Evidence directory: [17 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
836
+ Evidence directory: [18 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/socials/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
835
837
 
836
838
  ### @stacksjs/storage
837
839
 
@@ -841,7 +843,7 @@ Declared runtime exports: `PathSanitizeError`, `Storage`, `StorageManager`, `Upl
841
843
 
842
844
  Local source modules: [src/adapters/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/adapters/index.ts), [src/bounded-text-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/bounded-text-file.ts), [src/completed-artifact-directory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/completed-artifact-directory.ts), [src/copy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/copy.ts), [src/delete.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/delete.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/drivers/index.ts), [src/facade.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/facade.ts), [src/file-info.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/file-info.ts), [src/files.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/files.ts), [src/folders.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/folders.ts), [src/fs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/fs.ts), [src/glob.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/glob.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/hash.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/helpers.ts), [src/mime-verify.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/mime-verify.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/path-sanitize.ts), [src/provision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/provision.ts), [src/s3-presigned-post.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/s3-presigned-post.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/signed-url.ts), [src/static-serve.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/static-serve.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/storage.ts), [src/temporary-workspaces.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/temporary-workspaces.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types.ts), [src/types/filesystem.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/types/filesystem.ts), [src/uploaded-file.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/uploaded-file.ts), [src/zip.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/src/zip.ts).
843
845
 
844
- Evidence directory: [47 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
846
+ Evidence directory: [48 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/storage/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
845
847
 
846
848
  ### @stacksjs/strings
847
849
 
@@ -851,7 +853,7 @@ Declared runtime exports: `string`.
851
853
 
852
854
  Local source modules: [src/string.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/string.ts).
853
855
 
854
- Evidence directory: [10 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
856
+ Evidence directory: [11 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
855
857
 
856
858
  ### @stacksjs/testing
857
859
 
@@ -909,7 +911,7 @@ Declared runtime exports: `browserUtils`, `clamp`, `notNullish`, `retry`, `useOn
909
911
 
910
912
  Local source modules: [src/bytes.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/bytes.ts), [src/clean.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/clean.ts), [src/colors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/colors.ts), [src/config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/config.ts), [src/debounce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/debounce.ts), [src/detect.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/detect.ts), [src/equal.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/equal.ts), [src/errors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/errors.ts), [src/export-size.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/export-size.ts), [src/find.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/find.ts), [src/git.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/git.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/hash.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/helpers.ts), [src/macroable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/macroable.ts), [src/markdown.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/markdown.ts), [src/merge.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/merge.ts), [src/observer.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/observer.ts), [src/pipe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/pipe.ts), [src/pipeline.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/pipeline.ts), [src/safe-json.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/safe-json.ts), [src/size.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/size.ts), [src/versions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/src/versions.ts).
911
913
 
912
- Evidence directory: [15 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
914
+ Evidence directory: [22 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/utils/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
913
915
 
914
916
  ### @stacksjs/validation
915
917
 
@@ -919,7 +921,7 @@ Declared runtime exports: `applyConditionals`, `isArray`, `isBoolean`, `isFuncti
919
921
 
920
922
  Local source modules: [src/input.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/input.ts), [src/messages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/messages.ts), [src/reporter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/reporter.ts), [src/schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/schema.ts), [src/validator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/validator.ts).
921
923
 
922
- Evidence directory: [22 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
924
+ Evidence directory: [25 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
923
925
 
924
926
  ### @stacksjs/video
925
927
 
@@ -81,16 +81,10 @@ const result = deepMerge(target, source)
81
81
  const merged = deepMerge(defaults, userConfig, overrides)
82
82
  ```
83
83
 
84
- The `DeepMerge<T, S>` type (from `@stacksjs/types`) provides full type inference:
85
- ```typescript
86
- type DeepMerge<F, S> = MergeInsertions<{
87
- [K in keyof F | keyof S]: K extends keyof S & keyof F
88
- ? DeepMerge<F[K], S[K]>
89
- : K extends keyof S ? S[K]
90
- : K extends keyof F ? F[K]
91
- : never
92
- }>
93
- ```
84
+ The `DeepMerge<T, S>` type from `@stacksjs/types` preserves primitive, array and
85
+ built-in instance values while merging record keys recursively. A replaced Date
86
+ target no longer exposes Date methods. The authoritative type is in
87
+ `core/types/src/utils.ts`; verify consumers against built declarations.
94
88
 
95
89
  ### objectPick -- Pick Properties by Key
96
90
  ```typescript
@@ -153,7 +147,7 @@ if (isKeyOf(config, key)) {
153
147
 
154
148
  ### objectKeys -- Strictly Typed Object.keys
155
149
  ```typescript
156
- function objectKeys<T extends object>(obj: T): Array<`${keyof T & (string | number | boolean | null | undefined)}`>
150
+ function objectKeys<T extends object>(obj: T): Array<ObjectStringKey<T>>
157
151
  ```
158
152
 
159
153
  Returns `Object.keys(obj)` with a stricter return type than the built-in `Object.keys()` (which returns `string[]`).
@@ -166,10 +160,13 @@ const keys = objectKeys(user)
166
160
 
167
161
  ### objectEntries -- Strictly Typed Object.entries
168
162
  ```typescript
169
- function objectEntries<T extends object>(obj: T): Array<[keyof T, T[keyof T]]>
163
+ function objectEntries<T extends object>(obj: T): Array<ObjectStringEntry<T>>
170
164
  ```
171
165
 
172
166
  Returns `Object.entries(obj)` with a stricter return type than the built-in `Object.entries()` (which returns `[string, any][]`).
167
+ `ObjectStringKey<T>` stringifies numeric keys and excludes symbols;
168
+ `ObjectStringEntry<T>` pairs those keys with the visited values. Both functions
169
+ declare their return types explicitly so built declarations preserve the arrays.
173
170
 
174
171
  ```typescript
175
172
  const user = { name: 'John', age: 30 }
@@ -197,9 +194,14 @@ The root also exports `omit`, `pickBy`, `omitBy`, `mapValues`, `mapKeys`,
197
194
  `invert`, `isEmptyObject`, `getPath` and `setPath` from `transform.ts`.
198
195
  Use a path array such as `['items', 0, 'name']`, not an assumed dot-string
199
196
  parser. `getPath(source, path, fallback?)` reads a nested value;
197
+ `getPath` returns `unknown` even with a fallback; narrow a present value before use.
198
+ `mapValues` preserves optional properties and omits symbol keys in its result type,
199
+ matching its enumerable string-key traversal. The pure `@stacksjs/objects/transform`
200
+ entry ships both JavaScript and declarations.
200
201
  `setPath(source, path, value)` performs a persistent update by copying containers
201
202
  along the path and sharing unaffected siblings. Treat paths as application-owned
202
- inputs; this helper is not a path authorization boundary. Choose `objectPick` for key-based selection and
203
+ inputs; this helper is not a path authorization boundary. Array `length` updates
204
+ use native length semantics on the copy and reject invalid lengths. Choose `objectPick` for key-based selection and
203
205
  `pickBy` for predicate selection. Read transform signatures for callback
204
206
  argument order; `objectMap`'s `(key, value)` is not a universal convention.
205
207
  Retained evidence: `core/objects/tests/transform.test.ts`.
@@ -212,6 +214,7 @@ Retained evidence: `core/objects/tests/transform.test.ts`.
212
214
  - `deepMerge` does NOT deeply merge arrays -- arrays from source replace arrays in target entirely.
213
215
  - `deepMerge` merges only plain objects key by key: a Date, Map, Set or class instance from a source is assigned as
214
216
  is, and a string, array or number in the target is replaced by a source's object.
217
+ A non-plain nested target also gives way to a plain source record.
215
218
  - `deepMerge` uses `isObject()` from `@stacksjs/validation` combined with `!Array.isArray()` to determine mergeability.
216
219
  - A `"__proto__"` key is data, never a prototype. `JSON.parse` and the router's request input keep one as an own key:
217
220
  `deepMerge` skips it and merges only into the target's own properties, and the transform helpers keep it as an own
@@ -25,7 +25,14 @@ native parser. Do not treat a cursor as a trusted SQL fragment.
25
25
 
26
26
  toPaginator, toSimplePaginator and toCursorPaginator adapt source results.
27
27
  isPaginator/isSimplePaginator/isCursorPaginator identify the canonical shapes;
28
- they do not authenticate a source or validate every row.
28
+ they require every mandatory metadata field, safe positive page integers,
29
+ non-negative integer totals and correctly typed optional links. They do not
30
+ authenticate a source or validate rows. Empty out-of-range pages remain valid.
31
+
32
+ BigInt cursors serialize as exact decimal strings. Composite cursors encode
33
+ BigInts as decimal string entries inside a JSON array. Keep those tokens intact
34
+ through query parameters; the ORM parser restores tuples and SQL bindings
35
+ accept decimal strings without a lossy Number conversion.
29
36
 
30
37
  ## HTTP and UI
31
38
 
@@ -34,6 +34,20 @@ instance redirect. X always uses PKCE; its verifier lives in the base class
34
34
  (getPkceVerifier/withCodeVerifier), so a callback on a fresh instance can
35
35
  restore it. Registry descriptors say `pkce` (X) and `nonce` (Apple).
36
36
 
37
+ ## Signing in with another Stacks application
38
+
39
+ `StacksIssuerProvider({ issuer, clientId, clientSecret, redirectUrl, scopes,
40
+ resource, userInfoUrl })` signs people in with another Stacks app that runs
41
+ `oauthProvider`: Authorization Code with S256 PKCE (always on, so carry
42
+ `getPkceVerifier()` in the flow and restore it with `withCodeVerifier()`) and
43
+ client_secret_basic. Send `resource` whenever the issuer binds scopes to one.
44
+ `getTokens(code)` keeps the refresh token that `getAccessToken` drops;
45
+ `refreshTokens(rt)` rotates it, `revokeToken(rt)` unlinks (RFC 7009) and
46
+ `getClaims(token)` / `getUserByToken(token)` read the issuer's
47
+ `oauthUserInfoResponse` endpoint, keyed by its pairwise `sub`. Only a boolean
48
+ `email_verified` counts as verified. It is constructed directly, not through the
49
+ registry.
50
+
37
51
  ## Flow state (login CSRF)
38
52
 
39
53
  A callback that exchanges any `code` signs the victim into the attacker's
@@ -291,6 +291,14 @@ const local = createLocalStorage({ root: './storage' })
291
291
  - MIME type detection is extension-based (supports txt, html, css, js, json, xml, pdf, zip, jpg, jpeg, png, gif, svg, mp4, mp3, wav)
292
292
  - `list()` returns an async iterable; supports `deep: true` for recursive listing
293
293
 
294
+ ### Memory adapter stream lifecycle
295
+
296
+ A move to the same normalized path is a no-op for an existing file, preserving
297
+ bytes, visibility and modification time. A missing source still throws.
298
+ `putStream` aborts pending reads promptly, cancels the reader and never publishes
299
+ partial contents. Stream writes release reader locks on success, failure and
300
+ abort. Existing destination contents survive a failed or aborted upload.
301
+
294
302
  ### S3 Adapter (`S3StorageAdapter`)
295
303
 
296
304
  ```typescript
@@ -429,6 +429,8 @@ interface PluralizeOptions { count?, inclusive? }
429
429
  - `helpers.ts` exports `toString()` (Object.prototype.toString, not ordinary
430
430
  string coercion) and `mask(value, character, index, length?)`. Mask supports
431
431
  a negative starting index and uses the first character of its mask string.
432
+ Index and explicit length must be safe integers, otherwise it throws RangeError.
433
+ Negative integer lengths mask nothing. Coordinates count Unicode code points.
432
434
 
433
435
  ## CSV exports
434
436
 
@@ -45,7 +45,7 @@ export { clamp, notNullish, retry, useOnline } from '@stacksjs/browser'
45
45
 
46
46
  ## Deep Merge (`merge.ts`)
47
47
 
48
- Replacement for `defu`. Arrays are concatenated, objects are recursively merged, special objects (Date, RegExp, Error, Promise, Map, Set, WeakMap, WeakSet, ArrayBuffer views) are NOT deeply merged. A `"__proto__"` key is skipped, as defu skips it, so a parsed request body cannot set the result's prototype.
48
+ Replacement for `defu`. Only own enumerable string keys are read. Arrays concatenate; plain records recursively merge. Non-plain nested values (including URL, ArrayBuffer, Blob and class instances) retain identity. A plain record replaces a non-plain target rather than copying its indices or prototype fields. A `"__proto__"` key is skipped, as defu skips it, so a parsed request body cannot set the result's prototype.
49
49
 
50
50
  ```typescript
51
51
  import { merge, mergeDefaults, createMerger, defu } from '@stacksjs/utils'
@@ -79,6 +79,13 @@ throttledFn.cancel() // cancel pending invocation
79
79
  await delay(1000) // sleep for 1 second (returns Promise<void>)
80
80
  ```
81
81
 
82
+ Calls and debounce `flush()` return `ReturnType<T> | undefined`: before any
83
+ invocation there is no result; suppressed calls return the last result,
84
+ including a Promise for async callbacks. Both preserve the callback receiver.
85
+ Pending arguments are consumed before invoking, so reentrant calls survive.
86
+ `cancel()` clears pending work; throttle cancellation also resets its interval.
87
+ Manual debounce `flush()` invokes pending work even with `trailing: false`.
88
+
82
89
  Note: unlike some implementations, this debounce does NOT support `maxWait`. The throttle uses `Date.now()` for timing, not setTimeout stacking.
83
90
 
84
91
  ## Color Output (`colors.ts`)
@@ -156,6 +163,10 @@ readableSize(1024) // alias for formatBytes
156
163
 
157
164
  Units: B, KB, MB, GB, TB, PB, EB, ZB, YB (decimal) or B, KiB, MiB, GiB, TiB, PiB, EiB, ZiB, YiB (binary).
158
165
 
166
+ `parseBytes` accepts a complete decimal with an optional known decimal or
167
+ binary unit (case-insensitive). It rejects partial numbers, unknown units,
168
+ trailing text and non-finite output. Fractions and negative values are allowed.
169
+
159
170
  ## Export Size Calculation (`size.ts`)
160
171
 
161
172
  ```typescript
@@ -433,19 +444,27 @@ Glob belongs to `@stacksjs/storage`; it is not re-exported from the utils root.
433
444
 
434
445
  ## Safe serialization and typed composition
435
446
 
436
- `safeJsonParse(text, fallback?)`, `safeJsonParseResult`, and
437
- `safeJsonStringify(value, space?)` make parse failure behavior explicit. Their
438
- generic result type is a caller annotation, not validation of untrusted JSON.
447
+ `safeJsonParse(text, fallback?)` and `safeJsonParseResult` make parse failure
448
+ behavior explicit. A parse generic result type is a caller annotation, not
449
+ validation of untrusted JSON.
439
450
  Validate decoded objects at the request boundary before treating them as a
440
451
  model, config, or provider payload.
441
452
 
453
+ `safeJsonStringify` returns `string | undefined`, matching JSON for unsupported
454
+ roots (undefined, functions and symbols). Shared non-cyclic objects serialize
455
+ at every occurrence; only ancestor cycles become `[Circular]`. BigInts become
456
+ decimal strings. User getters and `toJSON` methods can still throw.
457
+
442
458
  `pipe(value, ...steps)` applies ordinary typed unary functions left to right.
443
459
  `piped(...steps)` returns the composed function and `tap(effect)` returns a
444
460
  pass-through step. These differ from middleware-style `Pipeline`, whose pipes
445
461
  receive a next function. Choose the simple function seam for data transforms.
446
462
 
447
463
  `isDeepEqual` now compares Date, RegExp, Map, Set, typed arrays and ArrayBuffers
448
- by value and tracks circular pairs. Host objects and Errors remain identity
464
+ by value and tracks active circular pairs. Cycle topology/sharing need not
465
+ match when fields are structurally equal. Objects require matching own
466
+ enumerable string keys. Arrays distinguish a hole from an own undefined slot;
467
+ two corresponding holes compare equal. Host objects and Errors remain identity
449
468
  comparisons. Read retained equal tests for a non-plain object rather than
450
469
  assuming every object with similar printable fields is equal.
451
470
 
@@ -274,14 +274,17 @@ const result = await validateField('User', { name: 'John', email: 'john@example.
274
274
  ```
275
275
 
276
276
  Behavior:
277
- 1. Finds the model file by name in user models or framework defaults
277
+ 1. Finds exact model filenames or qualified paths recursively, preferring app overrides
278
278
  2. Extracts validation rules from model attributes
279
- 3. Converts attribute names to snake_case for validation
280
- 4. Sets custom error messages via `MessageProvider`
281
- 5. Validates using `schema.object(ruleObject).validate(params)`
279
+ 3. Accepts attribute and snake-case column names, preferring the attribute spelling when both are supplied
280
+ 4. Applies custom messages to reported failures without executing predicates again or replacing the shared provider
281
+ 5. Validates through the context-aware object schema
282
282
  6. Throws `HttpError(422)` with error JSON on validation failure
283
283
  7. Throws `HttpError(404)` if model not found
284
- 8. Skips validation for attributes with default values unless `isRequired` is true
284
+ 8. An optional default excuses absence, never a supplied invalid value
285
+
286
+ Ambiguous bare model names require a qualified path. Declared fields and conditional
287
+ siblings use own properties; inherited values never count as submitted input.
285
288
 
286
289
  ### `customValidate(attributes, params)`
287
290
 
@@ -314,13 +317,17 @@ isObjectNotEmpty(undefined) // false
314
317
 
315
318
  ## Error Reporter (`reporter.ts`)
316
319
 
317
- Process-local latest-error reporter for validation:
320
+ Validation operations start an async-local latest-error scope before their first await.
321
+ Successful operations clear prior failures; `getErrors()` returns an independent snapshot.
322
+ Standalone adapters that report directly create a scope with `withValidationContext()`:
318
323
 
319
324
  ```typescript
320
- import { reportError, getErrors } from '@stacksjs/validation'
325
+ import { reportError, getErrors, withValidationContext } from '@stacksjs/validation'
321
326
 
322
- reportError([{ message: 'Invalid', value: '', field: 'email' }])
323
- const errors = getErrors() // returns the latest MessageObject[]; reportError replaces it
327
+ withValidationContext(() => {
328
+ reportError([{ message: 'Invalid', value: '', field: 'email' }])
329
+ const errors = getErrors() // this scope's latest MessageObject[]
330
+ })
324
331
  ```
325
332
 
326
333
  Interface: `{ message: string, value: string, field: string }`
@@ -388,7 +395,7 @@ type ValidationString = ValidationRule
388
395
  - Numeric classification functions (`isEvenOrOdd`, etc.) return string defaults for non-numbers rather than throwing
389
396
  - Schema validators map to database column types -- `schema.integer()` creates an integer column, `schema.string()` creates a varchar, etc.
390
397
  - `validateField` converts attribute names to snake_case using `snakeCase()` from `@stacksjs/strings`
391
- - `validateField` skips attributes with default values unless `isRequired` is explicitly set
398
+ - `validateField` validates supplied values even when their attributes declare defaults
392
399
  - Validation error messages are customizable per-rule in model definitions via the `message` object
393
400
  - The schema export is Stacks' proxy over the underlying validation instance, with typed object/array/enum inference, file validation and conditionals; it is not the same object as the upstream v export
394
401
  - Custom validators can be added with `schema.custom<T>(fn, message)` for types not covered by built-in validators
@@ -397,16 +404,23 @@ type ValidationString = ValidationRule
397
404
 
398
405
  ## Request, conditional and file validation
399
406
 
400
- The root validate(requestOrRecord, rules) is async, returns the validated payload
407
+ The root validate(requestOrRecord, rules, options?) is async, returns the validated payload
401
408
  and throws HttpError(422) with normalized field errors on failure. Rules are
402
- validators or { rule, message? }; enhanced request.all supplies native input,
403
- otherwise query/body/route data are merged by request-validator.ts. Do not
404
- substitute a boolean check or ignore the returned validated data at a boundary.
409
+ validators or { rule, message? }. Plain records are application data, including URL,
410
+ query and params fields. Native Request bodies and enhanced request.all() are read
411
+ directly; jsonBody/formBody adapters remain supported. URL/query/params-only adapters
412
+ select { source: 'request' }; { source: 'data' } forces data interpretation.
413
+ Returned values contain declared supplied fields, recursively through object shapes
414
+ and array.each() elements. Opaque validators retain their accepted values. Use the
415
+ returned cleaned payload at the boundary, including action getValidated()/safe().
405
416
 
406
417
  Schema declarations can use the narrow `@stacksjs/validation/runtime` entry.
407
418
  The schema proxy adds typed object/array/enum inference and conditional rules:
408
419
  when(sibling, literalOrPredicate, refine) applies cross-field refinements through
409
- objectWithContext; sometimes has the underlying optional/empty-value semantics.
420
+ objectWithContext, action validations, model writes and validateModelInput.
421
+ Model contexts recognize attribute/column aliases. Creates include declared defaults;
422
+ partial updates validate supplied fields and siblings without loading stored values.
423
+ Refinements preserve reusable schemas. sometimes has the underlying optional/empty-value semantics.
410
424
  Read object-with-context.ts before treating presence-only rules as stricter than
411
425
  they are. Inferred object shapes are native, not a hand-written request interface.
412
426
 
@@ -417,19 +431,17 @@ An upload is a class instance (the router's `UploadedFile`); a plain object, whi
417
431
  is what a JSON body gives for the same field name, is refused.
418
432
 
419
433
  registerRule/getCustomRule, unique(table,column,exceptId?), exists(table,column)
420
- and validateFieldAsync support application async validation. Current unique/exists
421
- helpers return allowed when the database cannot be queried, so they are advisory
422
- validation, not authorization or a replacement for database constraints. Validate
434
+ and validateFieldAsync support application async validation. These helpers propagate query failures
435
+ instead of approving unchecked values. Keep operational failures separate from invalid input. Validate
423
436
  uniqueness at the durable write boundary and handle a uniqueness violation there.
424
437
 
425
- The latest-error reporter is shared process state; do not use getErrors as
426
- request-local concurrent state. Read errors on the returned/raised validation
427
- result instead. Local is.ts helpers and legacy rules/type declarations are not
438
+ Local is.ts helpers and legacy rules/type declarations are not
428
439
  automatically all public exports from the root.
429
440
 
430
441
  Source: `storage/framework/core/validation/src/index.ts`, runtime.ts,
431
442
  schema.ts, request-validator.ts, conditional.ts, file-validator.ts and validator.ts.
432
- Tests: conditional.test.ts, file-validator.test.ts, async-rules.test.ts,
443
+ Tests: conditional.test.ts, conditional-boundaries.test.ts, input-contracts.test.ts,
444
+ boundary-e2e.test.ts, file-validator.test.ts, async-rules.test.ts,
433
445
  runtime-entry.test.ts and type-inference.test-d.ts under core/validation/tests.
434
446
 
435
447
  ## Custom action input
@@ -456,6 +468,11 @@ null, and absent boolean input returns undefined. Boolean input accepts JSON
456
468
  booleans and the explicit form values `true`, `false`, `1`, `0` and their strings,
457
469
  and a checkbox's `on` and `off`.
458
470
 
471
+ Numeric bounds reject NaN and inverted intervals; -Infinity and Infinity explicitly
472
+ mean an unbounded lower/upper endpoint. Text maxLength requires a nonnegative safe
473
+ integer. Invalid configuration throws RangeError even for absent optional input.
474
+ Unsafe whole numbers are rejected whether or not integer-only input was requested.
475
+
459
476
  `validateModelInput` checks only supplied fields using `getDefinition()` rules.
460
477
  The action still selects writable fields, requires creation fields and validates
461
478
  relationships. Use the transaction callback executor for all atomic persistence.
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.445",
5
+ "version": "0.75.450",
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.445",
5
+ "version": "0.75.450",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -45,9 +45,9 @@
45
45
  "dependencies": {
46
46
  "@iconify-json/f7": "^1.2.2",
47
47
  "@iconify-json/hugeicons": "^1.2.35",
48
- "@stacksjs/mobile": "0.75.445",
49
- "@stacksjs/sanitizer": "0.2.789",
50
- "@stacksjs/stx": "0.2.789",
48
+ "@stacksjs/mobile": "0.75.450",
49
+ "@stacksjs/sanitizer": "0.2.792",
50
+ "@stacksjs/stx": "0.2.792",
51
51
  "@xterm/addon-fit": "^0.11.0",
52
52
  "@xterm/xterm": "^6.0.0",
53
53
  "ts-qr-codes": "^0.1.8"
@@ -3,12 +3,13 @@ interface AvatarProps {
3
3
  src?: string
4
4
  alt?: string
5
5
  name?: string
6
+ initials?: string
6
7
  size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'
7
8
  rounded?: 'sm' | 'md' | 'lg' | 'full'
8
9
  status?: 'online' | 'offline' | 'away' | 'busy'
9
10
  }
10
11
 
11
- const { src = '', alt = '', name = '', size = 'md', rounded = 'full', status = '' } = defineProps<AvatarProps>()
12
+ const { src = '', alt = '', name = '', initials: suppliedInitials = '', size = 'md', rounded = 'full', status = '' } = defineProps<AvatarProps>()
12
13
 
13
14
  const sizeClasses = {
14
15
  xs: 'h-5 w-5 text-[10px]',
@@ -50,10 +51,10 @@ function getInitials(fullName: string) {
50
51
  return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
51
52
  }
52
53
 
53
- const initials = getInitials(name)
54
+ const initials = suppliedInitials || getInitials(name)
54
55
 
55
56
  // Background colors for initials (consistent based on name)
56
- const bgColors = [
57
+ export const bgColors = [
57
58
  'bg-red-500/15 text-red-600 dark:bg-red-400/20 dark:text-red-400',
58
59
  'bg-orange-500/15 text-orange-600 dark:bg-orange-400/20 dark:text-orange-400',
59
60
  'bg-yellow-500/15 text-yellow-600 dark:bg-yellow-400/20 dark:text-yellow-400',
@@ -66,33 +67,42 @@ const bgColors = [
66
67
  'bg-pink-500/15 text-pink-600 dark:bg-pink-400/20 dark:text-pink-400'
67
68
  ]
68
69
 
69
- function getBgColorIndex(fullName: string) {
70
- if (!fullName) return 0
70
+ defineClientPayload({ bgColors })
71
+ </script>
72
+ <script client>
73
+ const avatarSrc = useReactiveProp('src', {{ src }})
74
+ const avatarAlt = useReactiveProp('alt', {{ alt }})
75
+ const avatarName = useReactiveProp('name', {{ name }})
76
+ const avatarInitials = useReactiveProp('initials', {{ suppliedInitials }})
77
+ const avatarDescription = derived(() => avatarAlt() || avatarName() || 'Avatar')
78
+ const avatarFallback = derived(() => {
79
+ if (avatarInitials()) return avatarInitials()
80
+ const parts = String(avatarName() || '').trim().split(/\s+/).filter(Boolean)
81
+ if (!parts.length) return ''
82
+ return (parts.length === 1 ? parts[0].slice(0, 2) : parts[0][0] + parts[parts.length - 1][0]).toUpperCase()
83
+ })
84
+ const avatarColor = derived(() => {
85
+ const name = String(avatarName() || '')
86
+ if (!name) return 'bg-black/[0.06] text-neutral-500 dark:bg-white/10 dark:text-neutral-400'
71
87
  let hash = 0
72
- for (let i = 0; i < fullName.length; i++) {
73
- hash = fullName.charCodeAt(i) + ((hash << 5) - hash)
74
- }
75
- return Math.abs(hash) % bgColors.length
76
- }
77
-
78
- const bgColor = name ? bgColors[getBgColorIndex(name)] : 'bg-black/[0.06] text-neutral-500 dark:bg-white/10 dark:text-neutral-400'
88
+ for (let i = 0; i < name.length; i++) hash = name.charCodeAt(i) + ((hash << 5) - hash)
89
+ const colors = bgColors
90
+ return colors[Math.abs(hash) % colors.length]
91
+ })
79
92
  </script>
80
93
  <div class="inline-flex relative flex-shrink-0">
81
- @if(src)
82
94
  <img
95
+ :if="avatarSrc"
83
96
  src="{{ src }}"
97
+ :src="avatarSrc"
84
98
  alt="{{ alt || name || 'Avatar' }}"
99
+ :alt="avatarDescription"
85
100
  class="object-cover {{ sizeClasses[size] }} {{ radiusClasses[rounded] }}"
86
101
  >
87
- @else
88
- <div class="inline-flex items-center justify-center font-medium {{ sizeClasses[size] }} {{ radiusClasses[rounded] }} {{ bgColor }}">
89
- @if(initials)
90
- <span>{{ initials }}</span>
91
- @else
92
- <span aria-hidden="true" class="h-1/2 w-1/2 text-neutral-400 i-hugeicons-user"></span>
93
- @endif
102
+ <div :if="!avatarSrc" :class="avatarColor" class="inline-flex items-center justify-center font-medium {{ sizeClasses[size] }} {{ radiusClasses[rounded] }}">
103
+ <span :if="avatarFallback" :text="avatarFallback">{{ initials }}</span>
104
+ <span :if="!avatarFallback" aria-hidden="true" class="h-1/2 w-1/2 text-neutral-400 i-hugeicons-user"></span>
94
105
  </div>
95
- @endif
96
106
 
97
107
  @if(status)
98
108
  <span class="absolute bottom-0 right-0 rounded-full ring-2 ring-white dark:ring-neutral-900 {{ statusColors[status] }} {{ statusSizes[size] }}"></span>