@stacksjs/defaults 0.75.421 → 0.75.423

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.
@@ -198,10 +198,12 @@ zScore([1, 2, 3, 4], 3) // 0.447...
198
198
  percentile([1, 2, 3, 4, 5], 50) // 3 -- interpolated percentile
199
199
  percentile([1, 2, 3, 4], 25) // 1.75 -- linear interpolation
200
200
  // Note: takes percentile value (0-100), uses linear interpolation
201
+ // Throws for an empty array (like median) and a RangeError outside 0-100
201
202
 
202
203
  interquartileRange([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
203
204
  // Q3 median - Q1 median
204
- // Splits array at midpoint, computes median of each half
205
+ // Sorts, splits at the midpoint, computes the median of each half
206
+ // One number gives 0; an empty array throws
205
207
 
206
208
  covariance([1, 2, 3, 4], [1, 2, 3, 4]) // 1.25 -- positive correlation
207
209
  covariance([1, 2, 3, 4], [4, 3, 2, 1]) // -1.25 -- negative correlation
@@ -22,10 +22,11 @@ const products = await cache.mget<{ name: string }>(['product:42', 'product:43']
22
22
  // mget returns a record keyed by cache key, not an array.
23
23
  ~~~
24
24
 
25
- - TTL is in seconds. Zero means forever; omitted TTL uses the factory's
26
- stdTTL, which defaults to zero. The exported cache/memory singleton is a
27
- memory instance with no default expiry. Config's ttl value does not silently
28
- turn that singleton into a configured Redis instance.
25
+ - TTL is in seconds. Zero means forever; an omitted TTL uses the store's
26
+ default. For the `cache` export that is `ttl` from config/cache.ts (3600 as
27
+ shipped) on every driver, memory included, so a value set with no TTL
28
+ expires after an hour. The `memory` export is a separate in-process
29
+ instance with no default expiry.
29
30
  - `setForever` stores without expiry; `getTtl` reads remaining TTL and
30
31
  `ttl(key, seconds)` updates it. Missing values are undefined.
31
32
  - `mset([{ key, value, ttl? }])` writes entries. `del(keyOrKeys)` and
@@ -60,11 +61,14 @@ deploys, pointing `path` at a file the deploy preserves (the app's own SQLite
60
61
  database works; the table is the driver's alone). `createCache(driver,
61
62
  options?)` selects one of memory, redis, singlestore or sqlite.
62
63
 
63
- The `cache` export is the driver `config/cache.ts` selects (`driver`, with
64
- `prefix` and `ttl` applied to the non-memory drivers), resolved on first use
65
- and once the app's config has loaded. With the default `driver: 'memory'` it
66
- answers from the `memory` instance itself. `cacheFromConfig(settings?)` builds
67
- the same choice explicitly; `resetConfiguredCache()` forgets it.
64
+ The `cache` export is the driver `config/cache.ts` selects, with its `prefix`
65
+ and `ttl` applied on every driver (memory also takes `maxKeys`, `useClones`
66
+ and `drivers.memory`), resolved on first use and once the app's config has
67
+ loaded. It is the shared `memory` instance only when the config sets none of
68
+ those. The shipped config sets them, so there `cache` and `memory` are two
69
+ stores: a value written through one is not visible through the other.
70
+ `cacheFromConfig(settings?)` builds the same choice explicitly;
71
+ `resetConfiguredCache()` forgets it.
68
72
  `config/cache.ts` reads `REDIS_URL`, `REDIS_HOST`, `REDIS_PORT`,
69
73
  `REDIS_USERNAME`, `REDIS_PASSWORD` and `REDIS_DB`, as `config/queue.ts` does.
70
74
 
@@ -38,11 +38,13 @@ title, required allDay and optional description/address/timezone; the root entry
38
38
  does not re-export that type. Infer a literal or read src/types.ts when extending
39
39
  the package.
40
40
 
41
- The older single-event generator has its own timezone/time-format rules and
42
- does not emit a VTIMEZONE block. Its UID derives from event timing/title, so
43
- editing those changes the UID. Do not promise subscription update semantics
44
- from a generated single-event link. Prefer the feed builder for stable records,
45
- escaping and folded lines.
41
+ Single-event exports write a timed event as UTC instants (`...Z`), so a link
42
+ means the same on every host; `timezone` only sets the zone Google's compose
43
+ screen displays it in. All-day dates are the UTC calendar dates of from/to.
44
+ The ICS body escapes and folds its text as the feed builder does. Its UID
45
+ derives from the event's instants and title, so editing those changes the
46
+ UID. Do not promise subscription update semantics from a generated
47
+ single-event link; use the feed builder for stable records.
46
48
 
47
49
  ## Native subscribable feeds
48
50
 
@@ -59,13 +61,19 @@ control, even when the feed declares a suggested interval.
59
61
 
60
62
  ## Recurrence
61
63
 
62
- parseRRule(value) returns RecurrenceRule or null for unsupported frequency.
63
- expandRecurrence(rule, dtstart, windowStart, windowEnd) returns matching UTC
64
- start instants, capped defensively. Supported fields include DAILY/WEEKLY/
65
- MONTHLY/YEARLY, INTERVAL, COUNT, UNTIL, BYDAY and BYMONTHDAY. This is a subset;
66
- unknown fields are not a proof of full RFC conformance. Callers own timezone
67
- interpretation and DST policy. Calendar clients can expand a feed's raw rrule
68
- independently from the server subset.
64
+ parseRRule(value) returns a RecurrenceRule, or null for any rule it cannot
65
+ follow exactly: an unsupported frequency or part (BYMONTH, BYSETPOS, BYWEEKNO,
66
+ BYYEARDAY, BYHOUR...), a combination RFC 5545 rules out or this subset does
67
+ not cover, or a value it cannot read. Null means "do not expand this here",
68
+ never "expanded without the part". expandRecurrence(rule, dtstart, windowStart,
69
+ windowEnd) returns matching UTC start instants, capped at 1000.
70
+
71
+ The subset: DAILY/WEEKLY/MONTHLY/YEARLY, INTERVAL, COUNT or UNTIL, WKST, BYDAY
72
+ (a filter for DAILY and WEEKLY; within a month, `MO` is every Monday and `2TU`
73
+ or `-1FR` an ordinal) and BYMONTHDAY for DAILY or MONTHLY (`-1` is the last
74
+ day). Weeks start on WKST, Monday by default, as clients expand them. YEARLY
75
+ repeats dtstart's date, skipping years without it (Feb 29). Callers own
76
+ timezone interpretation and DST policy.
69
77
 
70
78
  ## Sources and evidence
71
79
 
@@ -95,7 +95,7 @@ abstract class BaseChatDriver implements ChatDriver {
95
95
 
96
96
  ```typescript
97
97
  interface ChatMessage {
98
- to: string | string[] // recipient (channel ID, user ID, etc.)
98
+ to?: string | string[] // a bot token's channel or user ID; omit for a webhook
99
99
  from?: { id?: string, name?: string, avatar?: string }
100
100
  subject?: string // title for rich messages
101
101
  content?: string // plain text content
@@ -181,8 +181,14 @@ interface SlackAttachment {
181
181
 
182
182
  ### Slack Sending Modes
183
183
 
184
- 1. **Webhook mode**: If `config.webhookUrl` is set, sends via `POST` to webhook URL. Payload includes `text`, `username`, `mrkdwn: true`. If `message.template` exists, builds Block Kit blocks.
185
- 2. **Bot token mode**: If `config.botToken` is set, sends via Slack API `https://slack.com/api/chat.postMessage` with `Authorization: Bearer <token>`. Returns `ts` (timestamp) as message ID.
184
+ 1. **Webhook mode**: If `config.webhookUrl` is set, sends via `POST` to webhook URL. Payload includes `text`, `username`, `mrkdwn: true`. If `message.template` exists, builds Block Kit blocks. Needs no `message.to`.
185
+ 2. **Bot token mode**: If `config.botToken` is set, sends via Slack API `https://slack.com/api/chat.postMessage` with `Authorization: Bearer <token>`, to the channel in `message.to` (required). Returns `ts` (timestamp) as message ID.
186
+
187
+ `send()` treats `content` as the plain text `ChatMessage` says it is: `&`, `<`
188
+ and `>` are escaped (`escapeSlackText`), so `<!channel>` or a disguised
189
+ `<url|label>` in user text arrives as literal text instead of pinging the
190
+ channel or hiding a link. Plain URLs still link. `sendWebhook(url, text)` is
191
+ raw, for Slack markup written on purpose.
186
192
  3. Throws `Error('Slack not configured: provide webhookUrl or botToken')` if neither is set.
187
193
 
188
194
  ### Direct Webhook Function
@@ -247,8 +253,15 @@ interface DiscordMessage {
247
253
 
248
254
  ### Discord Sending Modes
249
255
 
250
- 1. **Webhook mode**: POST to `config.webhookUrl`. Handles `204` (empty success) responses. Returns `id` from response.
251
- 2. **Bot token mode**: POST to `https://discord.com/api/v10/channels/{channelId}/messages` with `Authorization: Bot <token>`. Uses `message.to` as the channel ID.
256
+ 1. **Webhook mode**: POST to `config.webhookUrl`. Handles `204` (empty success) responses. Returns `id` from response. Needs no `message.to`.
257
+ 2. **Bot token mode**: POST to `https://discord.com/api/v10/channels/{channelId}/messages` with `Authorization: Bot <token>`. Uses `message.to` as the channel ID (required).
258
+
259
+ Every payload carries `allowed_mentions`, by default `{ parse: ['users', 'roles'] }`
260
+ (`DEFAULT_ALLOWED_MENTIONS`): people and roles named by ID ping, `@everyone`
261
+ and `@here` in content never do. `sendWebhook()`'s `allowedMentions` replaces
262
+ the default, and its camelCase options are sent under Discord's names
263
+ (`avatar_url`, `allowed_mentions`) by `discordPayload()`. With a subject or
264
+ template the body goes in the embed only, not also as `content`.
252
265
 
253
266
  ### Embed Building
254
267
  When `message.subject` or `message.template` is set, `buildEmbed()` creates an embed with:
@@ -457,10 +470,10 @@ All three drivers implement `sendWithRetry()`:
457
470
 
458
471
  Direct send returns ChatResult, with success false for a handled provider failure;
459
472
  inspect it before persisting sent state. Awaiting a send only proves the promise
460
- settled. Webhook configuration does not replace ChatMessage's to/content or
461
- template fields. The generic notify chat channel supplies a body-only shape and
462
- does not normalize every structured transport failure, so use this package's
463
- direct API when application behavior depends on valid chat delivery.
473
+ settled. A webhook send needs no `to`; a bot-token send needs the channel in
474
+ `to`. notify()'s chat channel sends the body as `content` and `chatRecipient`
475
+ as `to`, through `recipient.chatDriver` or `config.notification.chat.default`,
476
+ and a failed send is a failed NotifyResult.
464
477
 
465
478
  Settings resolve per send after app config readiness, with explicit configure
466
479
  overrides taking precedence. Retained request/config coverage lives under
@@ -133,6 +133,13 @@ Write `app/Desktop/launcher.ts` and `build:desktop` compiles that instead, the
133
133
  same way anything under `app/` overrides its framework default. `DESKTOP_URL`
134
134
  and `APP_URL` then become optional, because the launcher decides what to open.
135
135
 
136
+ Every launcher, the framework's or yours, compiles through
137
+ `desktopLauncherCompileArgs()` to bytecode as an ES module: parsing the bundle
138
+ was most of a launcher's start (Browser's agent reached its window host in
139
+ 379 ms as source, 146 ms as bytecode), for an executable about a quarter
140
+ larger. Pass `bytecode: false` only to compare. Compile any helper binary of
141
+ your own with the same function rather than hand-written `bun build` flags.
142
+
136
143
  ```ts
137
144
  // app/Desktop/launcher.ts - compiled to Contents/MacOS/<AppName>
138
145
  import { dirname, join } from 'node:path'
@@ -21,7 +21,7 @@ i18n/src/
21
21
  ├── translator.ts # I18n class, global API (t, tc, te, tm)
22
22
  ├── formatter.ts # Locale-aware formatting (dates, numbers, currency, lists)
23
23
  ├── loader.ts # File-based translation loader (JSON, YAML, JS/TS)
24
- └── pluralization.ts # CLDR plural rules for 25+ languages
24
+ └── pluralization.ts # CLDR plural rules, from the runtime's Intl.PluralRules
25
25
  ```
26
26
 
27
27
  ## Core Types
@@ -101,14 +101,13 @@ tc('items', 5) // '5 items'
101
101
 
102
102
  ### Supported Languages
103
103
 
104
- | Rule | Languages |
105
- |------|-----------|
106
- | One/Other | en, de, nl, es, it, pt, sv, da, no, fi, el, he, hu, tr |
107
- | French (0-1=one) | fr |
108
- | No plural | zh, ja, ko, vi, th, id, ms |
109
- | One/Few/Many/Other | ru, uk, pl |
110
- | One/Few/Other | cs, sk |
111
- | Full (zero/one/two/few/many/other) | ar, cy |
104
+ Every language the runtime's CLDR data covers, through `Intl.PluralRules`,
105
+ for the full locale (`pt` counts 0 as `one`, `pt-PT` does not). A language it
106
+ has no data for says `other` for every number; `hasPluralRule(locale)` tells
107
+ you which. `addPluralRule(locale, rule)` overrides a language. The rules were
108
+ a hand-written table of 33 languages until it turned out to leave out Catalan,
109
+ Croatian, Serbian, Bulgarian and `nb` (they said `other` for 1) and to get
110
+ Hebrew's `two` and Latvian's `zero` wrong.
112
111
 
113
112
  ```typescript
114
113
  import { getPluralCategory, addPluralRule, hasPluralRule } from '@stacksjs/i18n'
@@ -218,6 +217,6 @@ default:
218
217
  - **YAML parsed with Bun.YAML** - not a third-party parser
219
218
  - **Missing keys return the key itself** - not an error, not empty string
220
219
  - **Pluralization uses `|` separator** - not ICU MessageFormat
221
- - **CLDR rules are built-in** - no external data needed, 25+ languages hardcoded
220
+ - **CLDR rules come from the runtime** - `Intl.PluralRules`, no data shipped and no table to fall out of date
222
221
  - **HTML escaping is opt-in** - `escapeValues: true` in config
223
222
  - **Formatting uses Intl APIs** - delegates to `Intl.DateTimeFormat`, `Intl.NumberFormat`, etc.
@@ -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) | 1 |
17
17
  | `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 6 |
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) | 9 |
19
- | `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 6 |
19
+ | `@stacksjs/arrays` | [`stacks-arrays`](../stacks-arrays/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/arrays/src/index.ts) | 7 |
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) | 125 |
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 |
@@ -24,9 +24,9 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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) | 177 |
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) | 5 |
26
26
  | `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 23 |
27
- | `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
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
- | `@stacksjs/chat` | [`stacks-chat`](../stacks-chat/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/index.ts) | 5 |
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 |
30
30
  | `@stacksjs/cli` | [`stacks-cli`](../stacks-cli/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cli/src/index.ts) | 13 |
31
31
  | `@stacksjs/cloud` | [`stacks-cloud`](../stacks-cloud/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cloud/src/index.ts) | 10 |
32
32
  | `@stacksjs/cms` | [`stacks-cms`](../stacks-cms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cms/src/index.ts) | 5 |
@@ -56,20 +56,20 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
56
56
  | `@stacksjs/github` | [`stacks-git`](../stacks-git/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/github/src/index.ts) | 8 |
57
57
  | `@stacksjs/health` | [`stacks-health`](../stacks-health/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/health/src/index.ts) | 2 |
58
58
  | `@stacksjs/http` | [`stacks-http`](../stacks-http/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/http/src/index.ts) | 2 |
59
- | `@stacksjs/i18n` | [`stacks-i18n`](../stacks-i18n/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/index.ts) | 4 |
59
+ | `@stacksjs/i18n` | [`stacks-i18n`](../stacks-i18n/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/index.ts) | 5 |
60
60
  | `@stacksjs/image` | [`stacks-image`](../stacks-image/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/image/src/index.ts) | 3 |
61
61
  | `@stacksjs/lint` | [`stacks-lint`](../stacks-lint/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/lint/src/index.ts) | 3 |
62
62
  | `@stacksjs/logging` | [`stacks-logging`](../stacks-logging/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/logging/src/index.ts) | 14 |
63
63
  | `@stacksjs/mobile` | [`stacks-mobile`](../stacks-mobile/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/index.ts) | 23 |
64
64
  | `@stacksjs/model-meta` | [`stacks-models`](../stacks-models/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/model-meta/src/index.ts) | 1 |
65
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
- | `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 16 |
67
- | `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
66
+ | `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 17 |
67
+ | `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 5 |
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) | 75 |
69
69
  | `@stacksjs/pagination` | [`stacks-pagination`](../stacks-pagination/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/pagination/src/index.ts) | 0 |
70
70
  | `@stacksjs/path` | [`stacks-path`](../stacks-path/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/path/src/index.ts) | 13 |
71
- | `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 37 |
72
- | `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 6 |
71
+ | `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 38 |
72
+ | `@stacksjs/push` | [`stacks-push`](../stacks-push/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/index.ts) | 8 |
73
73
  | `@stacksjs/query-builder` | [`stacks-query-builder`](../stacks-query-builder/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/query-builder/src/index.ts) | 6 |
74
74
  | `@stacksjs/queue` | [`stacks-queue`](../stacks-queue/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/queue/src/index.ts) | 49 |
75
75
  | `@stacksjs/realtime` | [`stacks-realtime`](../stacks-realtime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/realtime/src/index.ts) | 12 |
@@ -87,16 +87,16 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
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) | 5 |
88
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
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) | 7 |
91
- | `@stacksjs/testing` | [`stacks-testing`](../stacks-testing/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/index.ts) | 21 |
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 |
91
+ | `@stacksjs/testing` | [`stacks-testing`](../stacks-testing/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/index.ts) | 22 |
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
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) | 17 |
97
+ | `@stacksjs/validation` | [`stacks-validation`](../stacks-validation/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/index.ts) | 19 |
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
- | `@stacksjs/whois` | [`stacks-whois`](../stacks-whois/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/index.ts) | 4 |
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
 
101
101
  ## Source surfaces
102
102
 
@@ -167,7 +167,7 @@ Declared runtime exports: `arr`.
167
167
 
168
168
  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).
169
169
 
170
- Evidence directory: [6 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.
170
+ Evidence directory: [7 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.
171
171
 
172
172
  ### @stacksjs/audio
173
173
 
@@ -245,7 +245,7 @@ Declared runtime exports: `buildCalendarFeed`, `calendarFeedHeaders`, `escapeIcs
245
245
 
246
246
  Local source modules: [src/feed.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/feed.ts), [src/generators/google.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/generators/google.ts), [src/generators/ics.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/generators/ics.ts), [src/generators/weboutlook.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/generators/weboutlook.ts), [src/generators/yahoo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/generators/yahoo.ts), [src/recurrence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/recurrence.ts).
247
247
 
248
- Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
248
+ Evidence directory: [5 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
249
249
 
250
250
  ### @stacksjs/charts
251
251
 
@@ -265,7 +265,7 @@ Declared runtime exports: `MessagingError`, `configureDiscord`, `configureSlack`
265
265
 
266
266
  Local source modules: [src/drivers/discord.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/drivers/discord.ts), [src/drivers/slack.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/drivers/slack.ts), [src/drivers/teams.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/drivers/teams.ts), [src/inbox/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/inbox/index.ts).
267
267
 
268
- Evidence directory: [5 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
268
+ Evidence directory: [6 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
269
269
 
270
270
  ### @stacksjs/cli
271
271
 
@@ -551,7 +551,7 @@ Declared runtime exports: `I18n`, `addTranslations`, `applyRequestLocale`, `crea
551
551
 
552
552
  Local source modules: [src/bootstrap.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/bootstrap.ts), [src/formatter.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/formatter.ts), [src/loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/loader.ts), [src/locale-switch.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/locale-switch.ts), [src/pluralization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/pluralization.ts), [src/translator.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/translator.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/src/types.ts).
553
553
 
554
- Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
554
+ Evidence directory: [5 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/i18n/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
555
555
 
556
556
  ### @stacksjs/image
557
557
 
@@ -611,11 +611,11 @@ Evidence directory: [7 retained tests](https://github.com/stacksjs/stacks/blob/m
611
611
 
612
612
  Guidance: [`stacks-notifications`](../stacks-notifications/SKILL.md). Source: [storage/framework/core/notifications/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts).
613
613
 
614
- Declared runtime exports: `BroadcastNotificationDriver`, `DEFAULT_SMS_OPT_OUT`, `DEFAULT_UNSUBSCRIBE_NOTICE`, `DatabaseNotificationDriver`, `NOTIFICATION_FRAME_STRINGS`, `SMS_SENDER_MAX_LENGTH`, `accountNotificationTemplates`, `advanceSequence`, `bulkSetPreferences`, `commerceNotificationTemplates`, `createNotificationTemplates`, `defineNotificationTemplates`, `emailParagraphs`, `ensureSuccessfulEmailResult`, `ensureSuccessfulNotificationResults`, `filterChannelsByPreferences`, `getNotificationPreferences`, `interpolateNotificationText`, `isQuietTime`, `listUnsubscribeHeaders`, `makeDeliveryRecord`, `nextSendableTime`, `notification`, `notificationChannel`, `notificationEmailHtml`, `notificationEmailMessage`, `notificationEmailText`, `notificationFrameStrings`, `notificationLanguageTag`, `notificationSmsBody`, `notificationTemplateVariables`, `notificationUnsubscribeLinks`, `notificationUnsubscribeToken`, `notify`, `parseNotificationUnsubscribeToken`, `recordNotificationDelivery`, `renderNotificationTemplate`, `resolveDeliveryRecipient`, `resolveNotificationLocale`, `sequenceTimeline`, `setNotificationPreference`, `smsSenderPrefix`, `subscriptionNotificationTemplates`, `unsubscribeTokenFromRequest`, `unsubscribeWithToken`, `useBroadcast`, `useChat`, `useDatabase`, `useEmail`, `useNotification`, `usePush`, `useSMS`, `wherePreferenceCategory`.
614
+ Declared runtime exports: `BroadcastNotificationDriver`, `DEFAULT_SMS_OPT_OUT`, `DEFAULT_UNSUBSCRIBE_NOTICE`, `DatabaseNotificationDriver`, `NOTIFICATION_FRAME_STRINGS`, `SMS_SENDER_MAX_LENGTH`, `accountNotificationTemplates`, `advanceSequence`, `bulkSetPreferences`, `commerceNotificationTemplates`, `configuredChatDriver`, `createNotificationTemplates`, `defineNotificationTemplates`, `emailParagraphs`, `ensureSuccessfulEmailResult`, `ensureSuccessfulNotificationResults`, `filterChannelsByPreferences`, `getNotificationPreferences`, `interpolateNotificationText`, `isQuietTime`, `listUnsubscribeHeaders`, `makeDeliveryRecord`, `nextSendableTime`, `notification`, `notificationChannel`, `notificationEmailHtml`, `notificationEmailMessage`, `notificationEmailText`, `notificationFrameStrings`, `notificationLanguageTag`, `notificationSmsBody`, `notificationTemplateVariables`, `notificationUnsubscribeLinks`, `notificationUnsubscribeToken`, `notify`, `parseNotificationUnsubscribeToken`, `recordNotificationDelivery`, `renderNotificationTemplate`, `resolveDeliveryRecipient`, `resolveNotificationLocale`, `sequenceTimeline`, `setNotificationPreference`, `smsSenderPrefix`, `subscriptionNotificationTemplates`, `unsubscribeTokenFromRequest`, `unsubscribeWithToken`, `useBroadcast`, `useChat`, `useDatabase`, `useEmail`, `useNotification`, `usePush`, `useSMS`, `wherePreferenceCategory`.
615
615
 
616
616
  Local source modules: [src/delivery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/delivery.ts), [src/drivers/broadcast.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/drivers/broadcast.ts), [src/drivers/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/drivers/database.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/drivers/index.ts), [src/email-body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/email-body.ts), [src/frame-strings.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/frame-strings.ts), [src/preferences.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/preferences.ts), [src/sequences.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/sequences.ts), [src/templates.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/templates.ts), [src/unsubscribe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/unsubscribe.ts).
617
617
 
618
- Evidence directory: [16 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
618
+ Evidence directory: [17 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
619
619
 
620
620
  ### @stacksjs/objects
621
621
 
@@ -625,7 +625,7 @@ Declared runtime exports: `clearUndefined`, `deepMerge`, `hasOwnProperty`, `isKe
625
625
 
626
626
  Local source modules: [src/transform.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/transform.ts).
627
627
 
628
- Evidence directory: [4 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.
628
+ Evidence directory: [5 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.
629
629
 
630
630
  ### @stacksjs/orm
631
631
 
@@ -661,7 +661,7 @@ Declared runtime exports: `Payment`, `freshIdempotencyKey`, `stacksIdempotencyKe
661
661
 
662
662
  Local source modules: [src/billable/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/billable/index.ts), [src/checkout-outcome.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/checkout-outcome.ts), [src/connect/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/connect/index.ts), [src/direct-debit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/direct-debit.ts), [src/driver/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/driver/index.ts), [src/drivers/stripe.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/drivers/stripe.ts), [src/idempotency.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/idempotency.ts), [src/payment.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/payment.ts), [src/subscription-state.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/subscription-state.ts), [src/terminal.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/terminal.ts).
663
663
 
664
- Evidence directory: [37 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
664
+ Evidence directory: [38 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
665
665
 
666
666
  ### @stacksjs/push
667
667
 
@@ -671,7 +671,7 @@ Declared runtime exports: `apns`, `buildVapidHeaders`, `configureAPNS`, `configu
671
671
 
672
672
  Local source modules: [src/drivers/apns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/drivers/apns.ts), [src/drivers/expo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/drivers/expo.ts), [src/drivers/fcm.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/drivers/fcm.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/drivers/index.ts), [src/drivers/web-push.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/src/drivers/web-push.ts).
673
673
 
674
- Evidence directory: [6 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
674
+ Evidence directory: [8 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/push/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
675
675
 
676
676
  ### @stacksjs/query-builder
677
677
 
@@ -843,7 +843,7 @@ Declared runtime exports: `string`.
843
843
 
844
844
  Local source modules: [src/string.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/strings/src/string.ts).
845
845
 
846
- Evidence directory: [7 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.
846
+ 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.
847
847
 
848
848
  ### @stacksjs/testing
849
849
 
@@ -853,7 +853,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
853
853
 
854
854
  Local source modules: [src/console.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/console.ts), [src/disposable-database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/disposable-database.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/events.ts), [src/feature.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/feature.ts), [src/isolated.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/isolated.ts), [src/mail.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/mail.ts), [src/schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/schema.ts), [src/service.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/service.ts), [src/time.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/src/time.ts).
855
855
 
856
- Evidence directory: [21 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
856
+ Evidence directory: [22 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/testing/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
857
857
 
858
858
  ### @stacksjs/tinker
859
859
 
@@ -909,9 +909,9 @@ Guidance: [`stacks-validation`](../stacks-validation/SKILL.md). Source: [storage
909
909
 
910
910
  Declared runtime exports: `applyConditionals`, `isArray`, `isBoolean`, `isFunction`, `isNull`, `isNullOrUndefined`, `isNumber`, `isObject`, `isString`, `isUndefined`, `objectWithContext`, `schema`, `shouldApplyConditional`, `withConditionals`.
911
911
 
912
- Local source modules: [src/input.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/validation/src/input.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).
912
+ 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).
913
913
 
914
- Evidence directory: [17 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.
914
+ Evidence directory: [19 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.
915
915
 
916
916
  ### @stacksjs/video
917
917
 
@@ -931,4 +931,4 @@ Declared runtime exports: `SocksClient`, `WhoIsParser`, `batchWhois`, `findWhoIs
931
931
 
932
932
  Local source modules: [src/constants.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/constants.ts), [src/socks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/socks.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/types.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/src/utils.ts).
933
933
 
934
- Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
934
+ Evidence directory: [5 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/whois/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
@@ -36,7 +36,7 @@ optional `error`. A resolved call does not imply every channel succeeded.
36
36
  |---|---|---|
37
37
  | email | email | `@stacksjs/email` |
38
38
  | sms | phone | `@stacksjs/sms` |
39
- | chat | chatRecipient, a channel/user id or array | `@stacksjs/chat` |
39
+ | chat | chatRecipient for a bot token's channel; none for a webhook | `@stacksjs/chat` |
40
40
  | database | userId | database notification inbox |
41
41
  | push | pushTokens, a string or string array | `@stacksjs/push`, default Expo |
42
42
  | broadcast | broadcastChannel or userId | `@stacksjs/realtime` |
@@ -48,7 +48,11 @@ type for an action link. The broadcast fallback is `private-user.{userId}` or
48
48
  public `notifications` when no user/channel is supplied. Its delivery is
49
49
  best-effort; a missing realtime server is not a durable notification queue.
50
50
  Read `stacks-chat` to configure transport credentials. Notify maps body to
51
- ChatMessage.content and chatRecipient to ChatMessage.to. Email, SMS, chat and
51
+ ChatMessage.content and chatRecipient to ChatMessage.to, through
52
+ `recipient.chatDriver`, else `config.notification.chat.default` (`msTeams` is
53
+ Teams), else Slack. A webhook needs no chatRecipient, so `notify({}, payload,
54
+ ['chat'])` posts to the configured webhook; a bot-token send without one fails
55
+ naming the field. Email, SMS, chat and
52
56
  push structured failures and broadcast delivered:false produce failed
53
57
  NotifyResult entries. Provider acceptance is not a final delivery receipt.
54
58
  `ensureSuccessfulNotificationResults(results)` throws for an empty result list
@@ -210,10 +210,15 @@ Retained evidence: `core/objects/tests/transform.test.ts`.
210
210
  - `objectPick` creates a NEW object -- original is not affected.
211
211
  - `objectMap` creates a NEW object via `Object.fromEntries`.
212
212
  - `deepMerge` does NOT deeply merge arrays -- arrays from source replace arrays in target entirely.
213
+ - `deepMerge` merges only plain objects key by key: a Date, Map, Set or class instance from a source is assigned as
214
+ is, and a string, array or number in the target is replaced by a source's object.
213
215
  - `deepMerge` uses `isObject()` from `@stacksjs/validation` combined with `!Array.isArray()` to determine mergeability.
216
+ - A `"__proto__"` key is data, never a prototype. `JSON.parse` and the router's request input keep one as an own key:
217
+ `deepMerge` skips it and merges only into the target's own properties, and the transform helpers keep it as an own
218
+ key (`Object.fromEntries`), so input that carries one cannot set a prototype.
214
219
  - `objectMap` can filter entries by returning `undefined` from the callback -- filtered via `notNullish` from `@stacksjs/utils`.
215
220
  - `objectKeys` return type uses a template literal type to handle non-string keys.
216
221
  - `clearUndefined` only removes `undefined` -- `null` values are preserved.
217
222
  - `hasOwnProperty` accepts `null`/`undefined` objects without throwing.
218
223
  - `objectPick` with `omitUndefined=false` (default) includes keys even if their values are `undefined`, as long as the key exists in the object.
219
- - These utilities are also re-exported through `@stacksjs/utils`.
224
+ - `@stacksjs/utils` does not re-export these. Its `merge` / `defu` is a separate merge that builds a new object.
@@ -717,8 +717,10 @@ when the app declares no portal.
717
717
 
718
718
  ```typescript
719
719
  Payment.formatAmount(2999, 'usd') // '$29.99' (uses Intl.NumberFormat)
720
- Payment.toCents(29.99) // 2999
721
- Payment.toDollars(2999) // 29.99
720
+ Payment.formatAmount(1000, 'jpy') // '¥1,000': JPY has no minor unit
721
+ Payment.minorUnitExponent('jpy') // 0 (Stripe's table on the Stripe driver; ISO 4217 otherwise)
722
+ Payment.toCents(29.99) // 2999, two-decimal currencies only
723
+ Payment.toDollars(2999) // 29.99, two-decimal currencies only
722
724
  ```
723
725
 
724
726
  ### Client-Side Billing (useBillable)
@@ -918,7 +920,7 @@ The instance methods are exactly the keys of `createBillableMethods` in
918
920
  its original raw payload before applying domain events.
919
921
  - Stripe API keys MUST be in `.env` as `STRIPE_SECRET_KEY` and `STRIPE_PUBLISHABLE_KEY` -- never hardcode them in config files
920
922
  - The Stripe client is created lazily, on first use: importing `@stacksjs/payments` without `STRIPE_SECRET_KEY` (or without the opt-in `stripe` package) is fine, and the first Stripe call throws naming what is missing
921
- - All amounts are in cents -- use `toCents()` and `toDollars()` for conversion
923
+ - All amounts are in the currency's minor unit: cents for USD, whole yen for JPY (Stripe's zero-decimal list), hundredths for ISK and UGX (Stripe's special cases). `toCents()` and `toDollars()` are for two-decimal currencies; `minorUnitExponent(currency)` says how many decimals an amount has, and `formatAmount()` uses it
922
924
  - `Payment.charge()` (Stripe driver) creates AND confirms the PaymentIntent in one step
923
925
  - `subscribe()` resolves the price via `lookup_key`, not a direct Stripe price ID
924
926
  - `Payment.removePaymentMethod()` and the billable instance method `removePaymentMethod()` both take the provider's id (string); `managePaymentMethod.deletePaymentMethod()` takes the local row id (number)
@@ -42,8 +42,9 @@ Routes to the appropriate driver based on `options.driver` (default: `'expo'`).
42
42
 
43
43
  - For **Expo**: Passes the notification directly to `expo.send()` with all fields mapped.
44
44
  - For **FCM** with single token: Calls `fcm.send()` with notification mapped to `{ to, notification: { title, body }, data, priority }`.
45
- - For **FCM** with multiple tokens: Calls `fcm.sendMulticast()` and returns an aggregated result with success count.
46
- - FCM priority mapping: `'default'` is converted to `'normal'`; `'high'` and `'normal'` pass through.
45
+ - For **FCM** with multiple tokens: Calls `fcm.sendMulticast()` and returns an aggregated result with success count, and `data: { results }`, one per token in order, so a dead token (404 `UNREGISTERED`) can be told from a transient failure.
46
+ - FCM priority mapping: `'default'` is converted to `'normal'`; `'high'` and `'normal'` pass through. Unset means `high`, on Android and iOS alike.
47
+ - `data` is the same for every driver. FCM takes only strings, so a non-string value is sent as its JSON text (`{ orderId: 42 }` arrives as `"42"`).
47
48
 
48
49
  ## PushNotification Interface (index.ts)
49
50
 
@@ -128,12 +129,16 @@ async function send(message: ExpoPushMessage): Promise<PushResult>
128
129
  ```
129
130
 
130
131
  - Endpoint: `https://exp.host/--/api/v2/push/send`
131
- - Validates tokens with `isExpoPushToken()` before sending
132
- - Filters out invalid tokens and warns via `log.warn()`
132
+ - Validates tokens with `isExpoPushToken()` before sending; an invalid token
133
+ is warned about via `log.warn()`, not sent, and counted as a failure
133
134
  - Returns early with failure if no valid tokens remain
134
135
  - Creates one payload entry per token (fans out `to` array into individual messages)
136
+ - Sends them in requests of at most 100, one after another: Expo refuses a
137
+ larger request outright, so a send to 101 devices used to reach none. A
138
+ refused request fails its own messages and the rest still go
135
139
  - Default `sound: 'default'`, default `priority: 'high'`
136
- - Returns `PushResult` with `data: { tickets }` containing the full ticket array
140
+ - Returns `PushResult` with `data: { tickets }`: one ticket per token in `to`,
141
+ in the same order, so each ticket can be matched to its token
137
142
  - `success` is `true` only if zero tickets have `status: 'error'`
138
143
  - `messageId` is the first ticket's `id` (if any)
139
144
 
@@ -147,13 +152,13 @@ Validates token format: matches `Expo(nent)?PushToken[...]` pattern OR alphanume
147
152
  ```typescript
148
153
  async function getReceipts(ticketIds: string[]): Promise<Record<string, ExpoPushReceipt>>
149
154
  ```
150
- Endpoint: `https://exp.host/--/api/v2/push/getReceipts`. Checks delivery status for previously sent notifications.
155
+ Endpoint: `https://exp.host/--/api/v2/push/getReceipts`. Checks delivery status for previously sent notifications, asking 1000 IDs per request (Expo's limit) and merging the answers.
151
156
 
152
157
  #### sendBatch()
153
158
  ```typescript
154
159
  async function sendBatch(messages: ExpoPushMessage[], chunkSize?: number): Promise<PushResult[]>
155
160
  ```
156
- Sends multiple messages in chunks (default chunk size: 100, per Expo's recommendation). Processes chunks sequentially, messages within each chunk in parallel via `Promise.all`.
161
+ Sends several messages, `chunkSize` (default 100) at a time: chunks sequentially, messages within a chunk in parallel via `Promise.all`. Each message's own tokens are split into requests of 100 by `send()`.
157
162
 
158
163
  ### Exports
159
164
  - `send`, `sendBatch`, `getReceipts`, `isExpoPushToken` functions
@@ -192,7 +197,7 @@ interface FCMMessage {
192
197
  clickAction?: string
193
198
  tag?: string
194
199
  }
195
- data?: Record<string, string> // NOTE: values must be strings for FCM
200
+ data?: Record<string, unknown> // sent as strings: a non-string value as its JSON text
196
201
  priority?: 'high' | 'normal'
197
202
  ttl?: number
198
203
  collapseKey?: string
@@ -221,7 +226,7 @@ endpoint it used to fall back to is gone.
221
226
  1. Generates JWT with RS256 signing using the service account private key
222
227
  2. Exchanges JWT for OAuth2 access token at `https://oauth2.googleapis.com/token`
223
228
  3. Sends to `https://fcm.googleapis.com/v1/projects/{projectId}/messages:send`
224
- 4. Includes Android priority settings and APNS headers (`apns-priority: 10` for high, `5` for normal)
229
+ 4. Includes Android priority settings and APNS headers (`apns-priority: 10` for high, `5` for normal); an unset priority is high on both
225
230
  5. Supports `to` (token), `topic`, or `condition` targeting
226
231
 
227
232
  **JWT generation details:**
@@ -100,9 +100,9 @@ interface TitleCaseOptions {
100
100
  locale?: string | string[]
101
101
  sentenceCase?: boolean // only capitalize first word + after terminators
102
102
  sentenceTerminators?: Set<string> // default: '.', '!', '?'
103
- titleTerminators?: Set<string> // default: '.', '!', '?', ':', '"', "'", '"'
103
+ titleTerminators?: Set<string> // default: '.', '!', '?', ':', '"', "'", and a closing curly quote (U+201D)
104
104
  smallWords?: Set<string> // words not capitalized (see SMALL_WORDS)
105
- wordSeparators?: Set<string> // default: '---', '--', '-', '---', '/'
105
+ wordSeparators?: Set<string> // default: em dash (U+2014), en dash (U+2013), '-', horizontal bar (U+2015), '/'
106
106
  }
107
107
  ```
108
108
 
@@ -196,6 +196,7 @@ Extensive built-in character map covering:
196
196
  - Vietnamese diacritics
197
197
  - Currency symbols ($, EUR, GBP, YEN, etc.)
198
198
  - Special characters (trademark, copyright, etc.)
199
+ - An en dash (U+2013) becomes a hyphen and so separates words; an em dash is still removed (#3112)
199
200
 
200
201
  ### Locale Support
201
202
  Locale-specific character mappings for: `bg`, `de`, `es`, `fr`, `pt`, `uk`, `vi`, `da`, `nb`, `it`, `nl`, `sv`.
@@ -241,7 +242,7 @@ Native TypeScript implementations (no external validator dependency). All accept
241
242
  ### Core Validators
242
243
  ```typescript
243
244
  isEmail('user@example.com') // true -- regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
244
- isStrongPassword('Abc123!@#') // true -- min 8 chars, upper, lower, digit, symbol
245
+ isStrongPassword('Abc123!@#') // true -- min 8 chars, upper, lower, digit, symbol (any non-letter, non-number)
245
246
  isAlphanumeric('abc123') // true -- /^[a-zA-Z0-9]+$/
246
247
  isAlpha('abcdef') // true -- /^[a-zA-Z]+$/
247
248
  isNumeric('123') // true -- /^[0-9]+$/ (whole numbers only)
@@ -256,16 +257,16 @@ isBase64('SGVsbG8=') // true -- btoa(atob(x)) === x
256
257
  isBase32('MFZWI===') // true -- /^[A-Z2-7]+=*$/
257
258
  isAscii('hello') // true -- /^[\x00-\x7F]*$/
258
259
  isJSON('{"key":"value"}') // true -- JSON.parse succeeds
259
- isHSL('hsl(0, 100%, 50%)') // true
260
+ isHSL('hsl(0, 100%, 50%)') // true -- comma syntax: hsl(hue, saturation%, lightness%)
260
261
  isMimeType('text/html') // true -- /^[a-z]+\/[a-z0-9\-+.]+$/i
261
- isDataURI('data:text/plain;base64,...') // true
262
+ isDataURI('data:text/plain;base64,...') // true -- RFC 2397: the media type and ;base64 are both optional
262
263
  isJWT('eyJhbGciOiJIUzI1NiJ9.e30.c2ln') // true -- shape check only, not signature verification
263
264
  ```
264
265
 
265
266
  ### Network Validators
266
267
  ```typescript
267
268
  isIP('192.168.1.1') // true -- IPv4 and IPv6
268
- isIPRange('192.168.1.0/24') // true -- CIDR notation (IPv4: 0-32, IPv6: 0-128)
269
+ isIPRange('192.168.1.0/24') // true -- CIDR notation, a whole-number prefix (IPv4: 0-32, IPv6: 0-128)
269
270
  isMACAddress('00:11:22:33:44:55') // true -- colon or hyphen separated
270
271
  isFQDN('example.com') // true -- fully qualified domain name
271
272
  ```
@@ -282,7 +283,7 @@ isISSN('0378-5955') // true -- mod 11 check
282
283
 
283
284
  ### Geographic Validators
284
285
  ```typescript
285
- isLatLong('40.7128,-74.0060') // true -- lat: -90..90, long: -180..180
286
+ isLatLong('40.7128,-74.0060') // true -- plain decimal numbers; lat: -90..90, long: -180..180
286
287
  isLatitude('40.7128') // true
287
288
  isLongitude('-74.0060') // true
288
289
  isPostalCode('12345') // true -- US, UK, Canada, generic formats
@@ -291,8 +292,8 @@ isPostalCode('12345') // true -- US, UK, Canada, generic for
291
292
  ### Phone, Identity, Date Validators
292
293
  ```typescript
293
294
  isMobilePhone('+1234567890') // true -- international format, min 7 digits
294
- isUUID('550e8400-e29b-41d4-a716-446655440000') // true -- full value required
295
- isISO8601('2024-01-01T00:00:00Z') // true -- with Date validity check
295
+ isUUID('550e8400-e29b-41d4-a716-446655440000') // true -- versions 1-8 (RFC 9562), nil and max; full value required
296
+ isISO8601('2024-01-01T00:00:00Z') // true -- the day must exist in its month; any number of fraction digits
296
297
  isIdentityCard('AB123456') // true -- generic 5-20 alphanumeric
297
298
  isISRC('USRC17607839') // true
298
299
  isISO31661Alpha2('US') // true
@@ -404,7 +405,12 @@ interface PluralizeOptions { count?, inclusive? }
404
405
  ```
405
406
 
406
407
  ## Gotchas
407
- - Case conversion uses Unicode-aware word boundary detection (`\p{Ll}`, `\p{Lu}`) -- handles international characters
408
+ - Case conversion uses Unicode-aware word boundary detection (`\p{Ll}`, `\p{Lu}`) -- handles international characters.
409
+ Combining marks stay with their letter and digits from any script are kept, so `kebabCase('नमस्ते दुनिया')`
410
+ is `'नमस्ते-दुनिया'`
411
+ - `truncate(str, length, end)` never returns more than `length` characters, `end` included; with a `length`
412
+ shorter than `end` it returns as much of `end` as fits. It and `mask` count code points, so an emoji is one
413
+ character and is never cut in half
408
414
  - `slug()` calls `slugify()` under the hood but defaults to `{ lower: true, strict: true }`; `slugify()` defaults to `{ lower: false, strict: false }`
409
415
  - `pascalCase` and `camelCase` accept `PascalCaseOptions` with `mergeAmbiguousCharacters` to control number-prefixed word handling
410
416
  - All case functions support `prefixCharacters`/`suffixCharacters` to preserve leading/trailing non-word characters
@@ -278,7 +278,11 @@ expect(pageAuditClean(report)).toBe(true) // no duplicate /api/ requests, failed
278
278
  pattern holds with no listener stays held (a hanging request on purpose).
279
279
  `matchesUrlPattern(pattern, url)` and `pausedRequestMatches(pattern, paused)` are Chrome's
280
280
  matching rules (`*`, `?`, `\` escape; stage and resource type).
281
- - `settle(cdp, { quietMs, timeoutMs })` resolves false (not throws) when a page never goes quiet.
281
+ - `settle(cdp, { quietMs, timeoutMs, includeSpeculative? })` resolves false (not throws) when a page never goes quiet.
282
+ By default all finite requests count. `includeSpeculative: false` uses `cdp.foregroundInFlight`,
283
+ excluding only Chrome `Prefetch` requests and explicit `Purpose` / `Sec-Purpose: prefetch`
284
+ declarations. The raw `inFlight` map and all HTTP, duplicate API, console and runtime audit
285
+ failures remain observable. `navigate` and `auditPage` accept the same option.
282
286
  - `click(cdp, selector | { selector, text }, { timeoutMs? })` scrolls the unique target into view,
283
287
  waits for layout, enabled state and an unobscured hit test, then uses Chrome's real mouse input.
284
288
  Use it for journey controls instead of local coordinate-click helpers or DOM-dispatched clicks.
@@ -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.
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.
49
49
 
50
50
  ```typescript
51
51
  import { merge, mergeDefaults, createMerger, defu } from '@stacksjs/utils'
@@ -249,6 +249,17 @@ export default defineModel({
249
249
  })
250
250
  ```
251
251
 
252
+ ### Custom messages
253
+
254
+ A rule's `message` is one string for any failure of the field, or an object keyed
255
+ by rule name: `min`, `max`, `email`, `enum`, `required` and so on. `messageKeys(rule)`
256
+ lists the keys a validator takes; `timestamp()` and `date()` take `timestamp` and
257
+ `date`. A key named after the field covers failures no rule key matched, unless the
258
+ validator has a rule of that name (`email: { email: ... }` is the email rule's).
259
+ Action `validations`, `request.validate()`, `validateField()` and model writes all
260
+ apply them through `fieldErrorMessages()` from `@stacksjs/validation/messages`, after
261
+ validation; none of them sets ts-validation's process-wide message provider.
262
+
252
263
  ## Model Validation (`validator.ts`)
253
264
 
254
265
  ### `validateField(modelFile, params)`
@@ -402,6 +413,8 @@ they are. Inferred object shapes are native, not a hand-written request interfac
402
413
  schema.file().required().image().mimeTypes([...]).maxBytes(n).minBytes(n).
403
414
  extensions([...]).custom(fn) provides FileLike validation. Client MIME/extension
404
415
  checks do not prove the bytes; use stacks-storage's MIME verification where needed.
416
+ An upload is a class instance (the router's `UploadedFile`); a plain object, which
417
+ is what a JSON body gives for the same field name, is refused.
405
418
 
406
419
  registerRule/getCustomRule, unique(table,column,exceptId?), exists(table,column)
407
420
  and validateFieldAsync support application async validation. Current unique/exists
@@ -437,9 +450,11 @@ validateModelInput(MyModel, { title })
437
450
 
438
451
  Failures throw `InputValidationError` with `status: 422`. JSON must be an object;
439
452
  text never coerces objects or silently truncates; numeric input rejects booleans,
440
- non-finite values and unsafe whole numbers. Optional text/number input returns
453
+ non-finite values, unsafe whole numbers and anything but decimal notation (`0x10`
454
+ is not 16), and an identifier is decimal digits only. Optional text/number input returns
441
455
  null, and absent boolean input returns undefined. Boolean input accepts JSON
442
- booleans and the explicit form values `true`, `false`, `1`, `0` and their strings.
456
+ booleans and the explicit form values `true`, `false`, `1`, `0` and their strings,
457
+ and a checkbox's `on` and `off`.
443
458
 
444
459
  `validateModelInput` checks only supplied fields using `getDefinition()` rules.
445
460
  The action still selects writable fields, requires creation fields and validates
@@ -449,9 +464,10 @@ Root and narrow input imports share the same error constructor.
449
464
  ## Reusable boundary and stored-value rules
450
465
 
451
466
  `parseTextInput(value, field, required?, maxLength?)` rejects overlong text
452
- rather than truncating it. `parseEnumInput(value, field, choices)` requires
467
+ rather than truncating it; `maxLength` counts characters, as a database column
468
+ does, not UTF-16 units. `parseEnumInput(value, field, choices)` requires
453
469
  exact string membership; it never stringifies an object or boolean.
454
- `storedBoolean(value, fallback)` decodes SQL/form 0/1 and false/true; the
470
+ `storedBoolean(value, fallback)` decodes SQL/form 0/1, false/true and on/off; the
455
471
  caller explicitly chooses the fallback for missing or corrupt stored data.
456
472
  Partial model validation accepts attribute names and their snake-case column
457
473
  spelling, including camel-case definitions.
@@ -133,11 +133,12 @@ When `outputData` is `null`, `parseData()` uses this default template:
133
133
  }
134
134
  ```
135
135
 
136
- The parser iterates character by character through raw WHOIS text:
137
- - Keys are identified when a line matches a key in `outputData`
138
- - Values follow after `": "` separator
136
+ The parser reads raw WHOIS text a line at a time:
137
+ - A line's field is everything before its first colon; it counts when it is a key in `outputData`
138
+ - The value is everything after that colon, as written, so `2024-08-14T07:01:34Z` and `https://...` keep their colons
139
+ - A field with nothing after its colon takes the next non-empty line as its value (registries that print `Registrar:` with the name below)
139
140
  - Array-typed fields (like `Domain Status`) accumulate multiple values
140
- - Parsing stops at `"Record maintained by"` or `">>>"` markers
141
+ - Parsing stops at a line starting with `"Record maintained by"` or `">>>"`
141
142
 
142
143
  Custom parse templates: pass an object with the field names you want extracted. Use empty string `''` for single values, use `[]` for fields with multiple values.
143
144
 
@@ -59,7 +59,7 @@ function optionalId(value: unknown): number | null {
59
59
  }
60
60
 
61
61
  function booleanValue(value: unknown): boolean {
62
- return storedBoolean(value === 'on' ? true : value, false)
62
+ return storedBoolean(value, false)
63
63
  }
64
64
 
65
65
  export function invalidPostContent(payload: PostPayload): string | null {
@@ -216,7 +216,7 @@ export default defineModel({
216
216
  validation: {
217
217
  rule: schema.enum(['published', 'draft', 'archived']),
218
218
  message: {
219
- oneOf: 'Status must be either published, draft, or archived',
219
+ enum: 'Status must be either published, draft, or archived',
220
220
  },
221
221
  },
222
222
  factory: faker => faker.helpers.arrayElement(['published', 'draft', 'archived']),
@@ -71,7 +71,7 @@ export default defineModel({
71
71
  validation: {
72
72
  rule: schema.number(),
73
73
  message: {
74
- string: 'status must be a number',
74
+ number: 'status must be a number',
75
75
  },
76
76
  },
77
77
  factory: faker => faker.number.int({ min: 400, max: 500 }),
package/app/Models/Log.ts CHANGED
@@ -53,7 +53,7 @@ export default defineModel({
53
53
  // (stacksjs/stacks#2996).
54
54
  rule: schema.unix().required(),
55
55
  message: {
56
- date: 'Timestamp must be a valid date',
56
+ unix: 'Timestamp must be a valid Unix timestamp',
57
57
  },
58
58
  },
59
59
  factory: faker => faker.date.recent().getTime(),
@@ -50,7 +50,7 @@ export default defineModel({
50
50
  validation: {
51
51
  rule: schema.string().required().max(50),
52
52
  message: {
53
- number: 'brand must be a number',
53
+ string: 'brand must be a string',
54
54
  required: 'brand is required',
55
55
  },
56
56
  },
@@ -63,7 +63,7 @@ export default defineModel({
63
63
  validation: {
64
64
  rule: schema.number().required(),
65
65
  message: {
66
- string: 'exp_month must be a number',
66
+ number: 'exp_month must be a number',
67
67
  required: 'exp_month is required',
68
68
  },
69
69
  },
@@ -76,7 +76,7 @@ export default defineModel({
76
76
  validation: {
77
77
  rule: schema.number().required(),
78
78
  message: {
79
- string: 'exp_year must be a number',
79
+ number: 'exp_year must be a number',
80
80
  required: 'exp_year is required',
81
81
  },
82
82
  },
@@ -55,7 +55,7 @@ export default defineModel({
55
55
  validation: {
56
56
  rule: schema.number().required(),
57
57
  message: {
58
- string: 'expires must be a string',
58
+ number: 'unit_price must be a number',
59
59
  required: 'expires is required',
60
60
  },
61
61
  },
@@ -70,7 +70,7 @@ export default defineModel({
70
70
  validation: {
71
71
  rule: schema.number().required(),
72
72
  message: {
73
- string: 'unit_price must be a number',
73
+ number: 'unit_price must be a number',
74
74
  required: 'unit_price is required',
75
75
  },
76
76
  },
@@ -100,7 +100,7 @@ export default defineModel({
100
100
  validation: {
101
101
  rule: schema.unix(),
102
102
  message: {
103
- invalid: 'Invalid timestamp format',
103
+ unix: 'Invalid timestamp format',
104
104
  },
105
105
  },
106
106
  factory: faker => faker.date.recent().getTime(),
@@ -79,7 +79,7 @@ export default defineModel({
79
79
  validation: {
80
80
  rule: schema.timestampTz().required(),
81
81
  message: {
82
- invalid: 'Invalid date format',
82
+ timestampTz: 'Invalid date format',
83
83
  },
84
84
  },
85
85
  factory: faker => faker.date.recent().toISOString(),
@@ -33,7 +33,7 @@ export default defineModel({
33
33
  validation: {
34
34
  rule: schema.enum(['disconnection', 'error', 'success']),
35
35
  message: {
36
- in: 'Type must be one of: disconnection, error, success',
36
+ enum: 'Type must be one of: disconnection, error, success',
37
37
  },
38
38
  },
39
39
  factory: faker => faker.helpers.arrayElement(['success', 'success', 'success', 'disconnection', 'error']),
@@ -77,7 +77,7 @@ export default defineModel({
77
77
  // and MySQL (stacksjs/stacks#2996).
78
78
  rule: schema.unix(),
79
79
  message: {
80
- date: 'Time must be a valid timestamp',
80
+ unix: 'Time must be a valid timestamp',
81
81
  },
82
82
  },
83
83
  factory: faker => faker.date.recent().getTime(),
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.421",
5
+ "version": "0.75.423",
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.421",
5
+ "version": "0.75.423",
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.421",
49
- "@stacksjs/sanitizer": "0.2.783",
50
- "@stacksjs/stx": "0.2.783",
48
+ "@stacksjs/mobile": "0.75.423",
49
+ "@stacksjs/sanitizer": "0.2.784",
50
+ "@stacksjs/stx": "0.2.784",
51
51
  "@xterm/addon-fit": "^0.11.0",
52
52
  "@xterm/xterm": "^6.0.0",
53
53
  "ts-qr-codes": "^0.1.8"