@stacksjs/defaults 0.75.445 → 0.75.447
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/skills/stacks-arrays/SKILL.md +9 -1
- package/ai/skills/stacks-datetime/SKILL.md +8 -0
- package/ai/skills/stacks-native/CATALOG.md +8 -8
- package/ai/skills/stacks-objects/SKILL.md +16 -13
- package/ai/skills/stacks-validation/SKILL.md +39 -22
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
- package/resources/components/Dashboard/UI/Avatar.stx +31 -21
|
@@ -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.
|
|
@@ -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,7 +16,7 @@ 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) |
|
|
19
|
+
| `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 12 |
|
|
20
20
|
| `@stacksjs/audio` | [`stacks-audio`](../stacks-audio/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/audio/src/index.ts) | 3 |
|
|
21
21
|
| `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 126 |
|
|
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 |
|
|
@@ -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) |
|
|
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,7 +64,7 @@ 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) |
|
|
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
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 |
|
|
@@ -94,7 +94,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
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
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) |
|
|
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: [
|
|
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
|
|
|
@@ -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: [
|
|
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: [
|
|
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
|
|
|
@@ -919,7 +919,7 @@ Declared runtime exports: `applyConditionals`, `isArray`, `isBoolean`, `isFuncti
|
|
|
919
919
|
|
|
920
920
|
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
921
|
|
|
922
|
-
Evidence directory: [
|
|
922
|
+
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
923
|
|
|
924
924
|
### @stacksjs/video
|
|
925
925
|
|
|
@@ -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
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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
|
|
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<
|
|
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.
|
|
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
|
|
@@ -274,14 +274,17 @@ const result = await validateField('User', { name: 'John', email: 'john@example.
|
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
Behavior:
|
|
277
|
-
1. Finds
|
|
277
|
+
1. Finds exact model filenames or qualified paths recursively, preferring app overrides
|
|
278
278
|
2. Extracts validation rules from model attributes
|
|
279
|
-
3.
|
|
280
|
-
4.
|
|
281
|
-
5. Validates
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
323
|
-
|
|
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`
|
|
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? }
|
|
403
|
-
|
|
404
|
-
|
|
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
|
|
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.
|
|
421
|
-
|
|
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
|
-
|
|
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,
|
|
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.
|
package/ide/vscode/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"publisher": "Stacks",
|
|
3
3
|
"name": "vscode-stacks",
|
|
4
4
|
"displayName": "Stacks",
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.447",
|
|
6
6
|
"description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"funding": "https://github.com/sponsors/chrisbbreuer",
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/defaults",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.447",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@iconify-json/f7": "^1.2.2",
|
|
47
47
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
48
|
-
"@stacksjs/mobile": "0.75.
|
|
48
|
+
"@stacksjs/mobile": "0.75.447",
|
|
49
49
|
"@stacksjs/sanitizer": "0.2.789",
|
|
50
50
|
"@stacksjs/stx": "0.2.789",
|
|
51
51
|
"@xterm/addon-fit": "^0.11.0",
|
|
@@ -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
|
-
|
|
70
|
-
|
|
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 <
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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>
|