@stacksjs/defaults 0.75.111 → 0.75.113
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-cache/SKILL.md +10 -0
- package/ai/skills/stacks-commerce/SKILL.md +15 -0
- package/ai/skills/stacks-datetime/SKILL.md +8 -0
- package/ai/skills/stacks-native/CATALOG.md +17 -17
- package/ai/skills/stacks-notifications/SKILL.md +17 -17
- package/ai/skills/stacks-orm/SKILL.md +17 -0
- package/ai/skills/stacks-sms/SKILL.md +2 -0
- package/ai/skills/stacks-validation/SKILL.md +13 -0
- package/app/Actions/Commerce/commerce-action.test.ts +2 -1
- package/app/Actions/Commerce/commerce-action.ts +3 -2
- package/app/Actions/Dashboard/Content/content-input.ts +2 -3
- package/app/Actions/Dashboard/Content/content-record-input.test.ts +7 -0
- package/app/Actions/Dashboard/Content/post-input.ts +5 -5
- package/app/Actions/Dashboard/Teams/team-records.test.ts +1 -0
- package/app/Actions/Dashboard/Teams/team-records.ts +2 -2
- package/ide/vscode/package.json +1 -1
- package/package.json +2 -2
|
@@ -83,3 +83,13 @@ contract. `drivers/singlestore.ts` owns the experimental backend.
|
|
|
83
83
|
Retained tests: `ttl.test.ts`, `getorset-timeout.test.ts`,
|
|
84
84
|
`tagged-flush-race.test.ts`, `redis-contract.test.ts` and
|
|
85
85
|
`cache-factory.test.ts` under `core/cache/tests/`.
|
|
86
|
+
|
|
87
|
+
## Representation-aware keys
|
|
88
|
+
|
|
89
|
+
`cacheKey(namespace, dependencies)` creates a deterministic key from named
|
|
90
|
+
primitive dependencies. Include owner/tenant scope, content version and every
|
|
91
|
+
setting affecting the result (for example privacy, locale or theme). Property
|
|
92
|
+
order does not change it; delimiter-containing strings cannot collide. Null
|
|
93
|
+
and undefined remain distinct. This constructs identity; it does not observe
|
|
94
|
+
settings, grant authorization or invalidate already issued public URLs.
|
|
95
|
+
The narrow `@stacksjs/cache/key` entry is pure and browser-bundleable.
|
|
@@ -313,3 +313,18 @@ is the helper for when the count is genuinely what you want.
|
|
|
313
313
|
|
|
314
314
|
> Touching a money path? `/stacks-tdd` for the seam to test it at, and
|
|
315
315
|
> `/stacks-review` before it merges. `/stacks-payments` covers the Stripe side.
|
|
316
|
+
|
|
317
|
+
## Input and inventory abstractions
|
|
318
|
+
|
|
319
|
+
`parseSalesTaxSetup(body, { maxRate?, maxRates? })` requires an explicit rates
|
|
320
|
+
array, rejects coerced prices/text and duplicate normalized component codes,
|
|
321
|
+
and accepts [] only as deliberate removal. HQ-style stores can set maxRate
|
|
322
|
+
to 30; the general default is 100. This validates configuration, not the legal
|
|
323
|
+
rate applicable to a sale. `parseTaxRateWriteData` is also used by native tax
|
|
324
|
+
store/update/bulk operations so false form booleans cannot select a default.
|
|
325
|
+
|
|
326
|
+
`restockedQuantity(current, units, maximum?)` adds positive whole units,
|
|
327
|
+
refusing untracked stock and overflow. `commerce.products.items.restock(id, units)`
|
|
328
|
+
uses that rule under a row lock and reads back on its own connection;
|
|
329
|
+
`updateInventory` validates absolute quantities through the same boundary.
|
|
330
|
+
Pure narrow entries are commerce/inventory and commerce/tax-input.
|
|
@@ -283,3 +283,11 @@ now().startOfMonth().toDateString() // first of current month
|
|
|
283
283
|
- `endOfMonth()` uses the `new Date(year, month + 1, 0)` trick to find the last day
|
|
284
284
|
- Application timezone should be configured in `config/app.ts`
|
|
285
285
|
- Prefer `@stacksjs/datetime` over raw `Date` for framework consistency
|
|
286
|
+
|
|
287
|
+
## Site and organization clocks
|
|
288
|
+
|
|
289
|
+
`localDateTime(instant, ...timeZones)` resolves the first valid named zone, then
|
|
290
|
+
UTC, and returns `{ date, time, timeZone }` from one instant. Supply site and
|
|
291
|
+
organization zones in that order. Missing/invalid zones fall through; an
|
|
292
|
+
invalid instant throws. The output uses YYYY-MM-DD and HH:mm and is suitable
|
|
293
|
+
for comparing local schedule dates and end times, not for elapsed durations.
|
|
@@ -23,7 +23,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
23
23
|
| `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 7 |
|
|
24
24
|
| `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 142 |
|
|
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) | 2 |
|
|
26
|
-
| `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) |
|
|
26
|
+
| `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 11 |
|
|
27
27
|
| `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
|
|
28
28
|
| `@stacksjs/charts` | [`stacks-charts`](../stacks-charts/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/charts/src/index.ts) | 3 |
|
|
29
29
|
| `@stacksjs/chat` | [`stacks-chat`](../stacks-chat/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/chat/src/index.ts) | 5 |
|
|
@@ -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) | 15 |
|
|
37
37
|
| `@stacksjs/cron` | [`stacks-cron`](../stacks-cron/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cron/src/index.ts) | 4 |
|
|
38
38
|
| `@stacksjs/database` | [`stacks-database`](../stacks-database/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/database/src/index.ts) | 106 |
|
|
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) | 11 |
|
|
40
40
|
| `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 1 |
|
|
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) | 11 |
|
|
@@ -63,9 +63,9 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
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) | 11 |
|
|
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) |
|
|
66
|
+
| `@stacksjs/notifications` | [`stacks-notifications`](../stacks-notifications/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/index.ts) | 11 |
|
|
67
67
|
| `@stacksjs/objects` | [`stacks-objects`](../stacks-objects/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/objects/src/index.ts) | 4 |
|
|
68
|
-
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) |
|
|
68
|
+
| `@stacksjs/orm` | [`stacks-orm`](../stacks-orm/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/index.ts) | 60 |
|
|
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) | 9 |
|
|
71
71
|
| `@stacksjs/payments` | [`stacks-payments`](../stacks-payments/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/payments/src/index.ts) | 20 |
|
|
@@ -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) | 5 |
|
|
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) | 15 |
|
|
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) | 4 |
|
|
100
100
|
|
|
@@ -231,9 +231,9 @@ Guidance: [`stacks-cache`](../stacks-cache/SKILL.md). Source: [storage/framework
|
|
|
231
231
|
|
|
232
232
|
Read the entrypoint and package export map for re-exported or type-only surfaces.
|
|
233
233
|
|
|
234
|
-
Local source modules: [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/drivers/index.ts).
|
|
234
|
+
Local source modules: [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/drivers/index.ts), [src/key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/key.ts).
|
|
235
235
|
|
|
236
|
-
Evidence directory: [
|
|
236
|
+
Evidence directory: [11 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
237
237
|
|
|
238
238
|
### @stacksjs/calendar-api
|
|
239
239
|
|
|
@@ -307,9 +307,9 @@ Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/m
|
|
|
307
307
|
|
|
308
308
|
Guidance: [`stacks-commerce`](../stacks-commerce/SKILL.md). Source: [storage/framework/core/commerce/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/index.ts).
|
|
309
309
|
|
|
310
|
-
Declared runtime exports: `PriceFormatError`, `auctions`, `breakdownFor`, `carts`, `catalog`, `catalogImport`, `commerce`, `coupons`, `currencyExponent`, `customers`, `decimalToMinor`, `default`, `devices`, `errors`, `formatCurrency`, `formatMinor`, `giftCards`, `minorToDecimal`, `minorToInput`, `minorToMajor`, `money`, `moneyInputError`, `moneyInputStep`, `multiplierOf`, `orders`, `parseMoneyInput`, `payments`, `products`, `receipts`, `register`, `releases`, `restaurant`, `shippings`, `tax`, `waitlists`.
|
|
310
|
+
Declared runtime exports: `PriceFormatError`, `auctions`, `breakdownFor`, `carts`, `catalog`, `catalogImport`, `commerce`, `coupons`, `currencyExponent`, `customers`, `decimalToMinor`, `default`, `devices`, `errors`, `formatCurrency`, `formatMinor`, `giftCards`, `minorToDecimal`, `minorToInput`, `minorToMajor`, `money`, `moneyInputError`, `moneyInputStep`, `multiplierOf`, `orders`, `parseMoneyInput`, `parseSalesTaxSetup`, `parseTaxRateWriteData`, `payments`, `products`, `receipts`, `register`, `releases`, `restaurant`, `restockedQuantity`, `shippings`, `tax`, `waitlists`.
|
|
311
311
|
|
|
312
|
-
Local source modules: [src/auctions/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/auctions/index.ts), [src/carts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/carts/index.ts), [src/catalog.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/catalog.ts), [src/coupons/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/coupons/index.ts), [src/customers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/customers/index.ts), [src/devices/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/devices/index.ts), [src/errors/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/errors/index.ts), [src/gift-cards/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/gift-cards/index.ts), [src/imports/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/imports/index.ts), [src/money.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/money.ts), [src/orders/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/orders/index.ts), [src/payments/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/payments/index.ts), [src/products/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/products/index.ts), [src/receipts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/receipts/index.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/register.ts), [src/releases.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/releases.ts), [src/sales-tax.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/sales-tax.ts), [src/shippings/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/shippings/index.ts), [src/tax/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/tax/index.ts), [src/waitlists/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/index.ts), [src/waitlists/restaurant/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/restaurant/index.ts).
|
|
312
|
+
Local source modules: [src/auctions/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/auctions/index.ts), [src/carts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/carts/index.ts), [src/catalog.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/catalog.ts), [src/coupons/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/coupons/index.ts), [src/customers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/customers/index.ts), [src/devices/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/devices/index.ts), [src/errors/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/errors/index.ts), [src/gift-cards/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/gift-cards/index.ts), [src/imports/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/imports/index.ts), [src/inventory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/inventory.ts), [src/money.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/money.ts), [src/orders/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/orders/index.ts), [src/payments/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/payments/index.ts), [src/products/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/products/index.ts), [src/receipts/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/receipts/index.ts), [src/register.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/register.ts), [src/releases.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/releases.ts), [src/sales-tax.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/sales-tax.ts), [src/shippings/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/shippings/index.ts), [src/tax-input.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/tax-input.ts), [src/tax/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/tax/index.ts), [src/waitlists/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/index.ts), [src/waitlists/restaurant/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/src/waitlists/restaurant/index.ts).
|
|
313
313
|
|
|
314
314
|
Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/commerce/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
315
315
|
|
|
@@ -357,11 +357,11 @@ Evidence directory: [106 retained tests](https://github.com/stacksjs/stacks/blob
|
|
|
357
357
|
|
|
358
358
|
Guidance: [`stacks-datetime`](../stacks-datetime/SKILL.md). Source: [storage/framework/core/datetime/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts).
|
|
359
359
|
|
|
360
|
-
Declared runtime exports: `DateTime`, `addCalendarMonths`, `dateFormat`, `format`, `isoInZone`, `now`, `parse`, `zoneOffsetMinutes`, `zonedTimeToUtc`.
|
|
360
|
+
Declared runtime exports: `DateTime`, `addCalendarMonths`, `dateFormat`, `format`, `isoInZone`, `localDateTime`, `now`, `parse`, `zoneOffsetMinutes`, `zonedTimeToUtc`.
|
|
361
361
|
|
|
362
|
-
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/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/zone.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/zone.ts).
|
|
362
|
+
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/zone.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/zone.ts).
|
|
363
363
|
|
|
364
|
-
Evidence directory: [
|
|
364
|
+
Evidence directory: [11 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.
|
|
365
365
|
|
|
366
366
|
### @stacksjs/defaults
|
|
367
367
|
|
|
@@ -607,11 +607,11 @@ Evidence directory: [7 retained tests](https://github.com/stacksjs/stacks/blob/m
|
|
|
607
607
|
|
|
608
608
|
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).
|
|
609
609
|
|
|
610
|
-
Declared runtime exports: `BroadcastNotificationDriver`, `DatabaseNotificationDriver`, `bulkSetPreferences`, `emailParagraphs`, `ensureSuccessfulEmailResult`, `filterChannelsByPreferences`, `getNotificationPreferences`, `makeDeliveryRecord`, `notification`, `notificationEmailHtml`, `notificationEmailText`, `notify`, `recordNotificationDelivery`, `resolveDeliveryRecipient`, `setNotificationPreference`, `useBroadcast`, `useChat`, `useDatabase`, `useEmail`, `useNotification`, `usePush`, `useSMS`, `wherePreferenceCategory`.
|
|
610
|
+
Declared runtime exports: `BroadcastNotificationDriver`, `DatabaseNotificationDriver`, `bulkSetPreferences`, `emailParagraphs`, `ensureSuccessfulEmailResult`, `ensureSuccessfulNotificationResults`, `filterChannelsByPreferences`, `getNotificationPreferences`, `makeDeliveryRecord`, `notification`, `notificationEmailHtml`, `notificationEmailText`, `notify`, `recordNotificationDelivery`, `resolveDeliveryRecipient`, `setNotificationPreference`, `useBroadcast`, `useChat`, `useDatabase`, `useEmail`, `useNotification`, `usePush`, `useSMS`, `wherePreferenceCategory`.
|
|
611
611
|
|
|
612
612
|
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/preferences.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/notifications/src/preferences.ts).
|
|
613
613
|
|
|
614
|
-
Evidence directory: [
|
|
614
|
+
Evidence directory: [11 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.
|
|
615
615
|
|
|
616
616
|
### @stacksjs/objects
|
|
617
617
|
|
|
@@ -629,9 +629,9 @@ Guidance: [`stacks-orm`](../stacks-orm/SKILL.md). Source: [storage/framework/cor
|
|
|
629
629
|
|
|
630
630
|
Declared runtime exports: `Activity`, `AnalyticsEvent`, `Auction`, `AuctionItem`, `Author`, `Automation`, `AutomationRun`, `BILLABLE_INSTANCE_METHODS`, `Bid`, `Board`, `BoardColumn`, `Campaign`, `CampaignSend`, `CampaignVariant`, `Card`, `CardAttachment`, `CardComment`, `Cart`, `CartItem`, `Categorizable`, `Category`, `Comment`, `CommunicationSuppression`, `ConsentEvent`, `Coupon`, `Courier`, `CourierPing`, `Customer`, `DeliveryRoute`, `DeliveryStop`, `Deployment`, `DigitalDelivery`, `EmailIdempotency`, `EmailList`, `EmailListSubscriber`, `EmailSuppression`, `EmailWebhookEvent`, `ErrorModel`, `FailedJob`, `FeedbackToken`, `Form`, `FormField`, `FormSubmission`, `GdprRequest`, `GiftCard`, `Job`, `Label`, `LicenseKey`, `Log`, `LoyaltyPoint`, `LoyaltyReward`, `MagicLinkToken`, `MailPreference`, `Manufacturer`, `Menu`, `MenuItem`, `Notification`, `NotificationDelivery`, `Order`, `OrderIdempotency`, `OrderItem`, `Page`, `PageRevision`, `Payment`, `PaymentMethod`, `PaymentProduct`, `PaymentTransaction`, `PaymentWebhookEvent`, `PersonalAccessToken`, `Pledge`, `Post`, `PrintDevice`, `Product`, `ProductUnit`, `ProductVariant`, `QueryLog`, `Receipt`, `Redirect`, `Referral`, `ReferralCode`, `Release`, `Request`, `Review`, `SenderDomain`, `ShippingMethod`, `ShippingRate`, `ShippingZone`, `Site`, `SiteDomain`, `SmsOptOut`, `SocialAccount`, `SocialPost`, `StorageItem`, `StorageItemTask`, `Subscriber`, `SubscriberEmail`, `Subscription`, `SubscriptionNotOwnedError`, `Tag`, `TaxRate`, `Team`, `TeamInvitation`, `TeamMember`, `Transaction`, `UsageEvent`, `User`, `WaitlistProduct`, `WaitlistRestaurant`, `Websocket`, `buildDatabaseSchema`, `collectEncryptedAttributes`, `createAuditMethods`, `createCategorizableMethods`, `createCommentableMethods`, `createLikeableMethods`, `createTaggableMethods`, `customerOwnership`, `decryptValue`, `encryptValue`, `enrichPaginatorUrls`, `filterFillable`, `getWritableFields`, `isBillable`, `isCursorPaginator`, `isEncrypted`, `isPaginator`, `isSimplePaginator`, `isUniqueViolation`, `mapWriteError`, `modelGlobalNames`, `ormReady`, `parentOwnership`, `parseCursor`, `renderDatabaseTypeFile`, `resolveCursorArgs`, `resolvePageArgs`, `selfOwnership`, `setAuditUser`, `siteOwnership`, `teamMembershipOwnership`, `toCursorPaginator`, `toPaginator`, `toSimplePaginator`, `toSnakeCaseKeys`.
|
|
631
631
|
|
|
632
|
-
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/compiled-binary.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/compiled-binary.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
632
|
+
Local source modules: [src/auto-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/auto-crud.ts), [src/batch-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/batch-loader.ts), [src/db.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/db.ts), [src/define-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/define-model.ts), [src/extend-model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/extend-model.ts), [src/gdpr/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/gdpr/index.ts), [src/generate-database-schema.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/generate-database-schema.ts), [src/locked-row.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/locked-row.ts), [src/model-types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/model-types.ts), [src/ownership.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/ownership.ts), [src/paginator-request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/paginator-request.ts), [src/row-token.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/row-token.ts), [src/subquery.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/subquery.ts), [src/traits/audit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/audit.ts), [src/traits/billable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/billable.ts), [src/traits/categorizable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/categorizable.ts), [src/traits/commentable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/commentable.ts), [src/traits/likeable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/likeable.ts), [src/traits/taggable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/traits/taggable.ts), [src/transaction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/transaction.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/types.ts), [src/utils/compiled-binary.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/compiled-binary.ts), [src/utils/encrypted.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/encrypted.ts), [src/utils/prunable.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/src/utils/prunable.ts).
|
|
633
633
|
|
|
634
|
-
Evidence directory: [
|
|
634
|
+
Evidence directory: [60 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/orm/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
635
635
|
|
|
636
636
|
### @stacksjs/pagination
|
|
637
637
|
|
|
@@ -907,7 +907,7 @@ Declared runtime exports: `applyConditionals`, `isArray`, `isBoolean`, `isFuncti
|
|
|
907
907
|
|
|
908
908
|
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).
|
|
909
909
|
|
|
910
|
-
Evidence directory: [
|
|
910
|
+
Evidence directory: [15 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.
|
|
911
911
|
|
|
912
912
|
### @stacksjs/video
|
|
913
913
|
|
|
@@ -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 |
|
|
39
|
+
| chat | chatRecipient, a channel/user id or array | `@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` |
|
|
@@ -46,16 +46,13 @@ renders it through the framework layout. Use the exported `NotificationAction`
|
|
|
46
46
|
type for an action link. The broadcast fallback is `private-user.{userId}` or
|
|
47
47
|
public `notifications` when no user/channel is supplied. Its delivery is
|
|
48
48
|
best-effort; a missing realtime server is not a durable notification queue.
|
|
49
|
-
Read `stacks-chat`
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
and inspect its structured result. The generic chat body also differs from
|
|
57
|
-
ChatMessage's to/content contract; use direct chat send with a valid message.
|
|
58
|
-
Delivery logs inherit this result mapping and are not final receipt evidence.
|
|
49
|
+
Read `stacks-chat` to configure transport credentials. Notify maps body to
|
|
50
|
+
ChatMessage.content and chatRecipient to ChatMessage.to. Email, SMS, chat and
|
|
51
|
+
push structured failures and broadcast delivered:false produce failed
|
|
52
|
+
NotifyResult entries. Provider acceptance is not a final delivery receipt.
|
|
53
|
+
`ensureSuccessfulNotificationResults(results)` throws for an empty result list
|
|
54
|
+
or any failed channel, and accepts only a non-empty list of successes. Use it
|
|
55
|
+
when a queued worker must retry partial fan-out instead of marking it sent.
|
|
59
56
|
|
|
60
57
|
## Preferences and delivery tracking
|
|
61
58
|
|
|
@@ -86,8 +83,10 @@ and transport results rather than assuming a delivery log is provider proof.
|
|
|
86
83
|
- `useEmail(driver?)` returns a sendable transport. Without a driver it uses
|
|
87
84
|
the Mail singleton and `config/email.ts`. Unknown explicit drivers warn and
|
|
88
85
|
fall back to that singleton.
|
|
89
|
-
- `useSMS(
|
|
90
|
-
|
|
86
|
+
- `useSMS()` uses the configured SMS facade; `useSMS('twilio' | 'vonage')`
|
|
87
|
+
explicitly selects a provider after loading configuration. `useChat(driver?)`
|
|
88
|
+
selects Slack (default), Discord or Teams. Unknown drivers throw. Configure
|
|
89
|
+
those packages before sending.
|
|
91
90
|
- `useDatabase()` returns DatabaseNotificationDriver.
|
|
92
91
|
- `usePush()` returns the push namespace, and `useBroadcast()` the broadcast driver.
|
|
93
92
|
- `useNotification(type?, driver?)`/`notification()` select email, sms, chat
|
|
@@ -107,10 +106,11 @@ const count = await inbox.unreadCount(7)
|
|
|
107
106
|
await inbox.markAllAsRead(7)
|
|
108
107
|
~~~
|
|
109
108
|
|
|
110
|
-
Also available: `getUserNotifications(userId)`, `markAsRead(id)`,
|
|
111
|
-
`deleteNotification(id)` and `deleteAllNotifications(userId)`. These
|
|
112
|
-
|
|
113
|
-
the
|
|
109
|
+
Also available: `getUserNotifications(userId)`, `markAsRead(id, userId?)`,
|
|
110
|
+
`deleteNotification(id, userId?)` and `deleteAllNotifications(userId)`. These
|
|
111
|
+
single-row mutations accept an optional authenticated userId. Supply it to
|
|
112
|
+
enforce ownership in the mutation statement; id-only calls retain their trusted
|
|
113
|
+
internal-use behavior. Reads and mark-all/delete-all already require userId.
|
|
114
114
|
|
|
115
115
|
Rows contain id, user_id, type, data (JSON string), read_at, created_at and
|
|
116
116
|
updated_at. Parse data when reading; null read_at means unread. The native
|
|
@@ -139,3 +139,20 @@ Evidence includes `model-validation`, `mass-assignment`, `force-create-guarded`,
|
|
|
139
139
|
`casting`, `belongs-to-many`, `observed-writes`, `model-policy-wiring`,
|
|
140
140
|
`paginator-request`, and the inference type tests. Read their actual contracts
|
|
141
141
|
when a workflow depends on a dialect, trait, or return shape.
|
|
142
|
+
|
|
143
|
+
## Scoped locked operations and stored link credentials
|
|
144
|
+
|
|
145
|
+
`withLockedRow(table, scope, async (row, tx) => ..., { tx? })` locks and reads
|
|
146
|
+
a scoped row on one reserved connection. It returns null for a missing row.
|
|
147
|
+
Use the callback handle for every related read/write; `tx` reuses an enclosing
|
|
148
|
+
transaction. A scope must identify one row; empty or non-unique scopes are refused. This is the query-builder seam: model
|
|
149
|
+
casts, fillable filtering and lifecycle hooks remain the caller's responsibility.
|
|
150
|
+
|
|
151
|
+
`rowToken({ table, scope, column, action, tx?, timestampColumn? })` manages a
|
|
152
|
+
stored share/feed credential. Read returns the live token; enable preserves
|
|
153
|
+
it; rotate replaces it; disable clears it. Mutations serialize under the row
|
|
154
|
+
lock and join an enclosing transaction when supplied. Missing owners throw
|
|
155
|
+
`RowTokenNotFoundError` (404). The default timestamp column is updated_at;
|
|
156
|
+
pass false for a table without timestamps. Identifiers and scope must be
|
|
157
|
+
application-selected, and the caller must authorize that owner. This is for
|
|
158
|
+
stored public-link secrets, not hashed authentication tokens with expiry.
|
|
@@ -118,6 +118,8 @@ await sendBulk([msg1, msg2, msg3]) // returns SmsSendResult[]
|
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
`send()` and all sending functions call `ensureConfig()` first, which lazily loads `config/sms.ts` via dynamic import.
|
|
121
|
+
Runtime `configure()` overrides survive that lazy load and subsequent `init()`
|
|
122
|
+
calls, including credentials supplied before the first send.
|
|
121
123
|
|
|
122
124
|
## Message Status & Info
|
|
123
125
|
|
|
@@ -432,3 +432,16 @@ booleans and the explicit form values `true`, `false`, `1`, `0` and their string
|
|
|
432
432
|
The action still selects writable fields, requires creation fields and validates
|
|
433
433
|
relationships. Use the transaction callback executor for all atomic persistence.
|
|
434
434
|
Root and narrow input imports share the same error constructor.
|
|
435
|
+
|
|
436
|
+
## Reusable boundary and stored-value rules
|
|
437
|
+
|
|
438
|
+
`parseTextInput(value, field, required?, maxLength?)` rejects overlong text
|
|
439
|
+
rather than truncating it. `parseEnumInput(value, field, choices)` requires
|
|
440
|
+
exact string membership; it never stringifies an object or boolean.
|
|
441
|
+
`storedBoolean(value, fallback)` decodes SQL/form 0/1 and false/true; the
|
|
442
|
+
caller explicitly chooses the fallback for missing or corrupt stored data.
|
|
443
|
+
Partial model validation accepts attribute names and their snake-case column
|
|
444
|
+
spelling, including camel-case definitions.
|
|
445
|
+
|
|
446
|
+
`positiveIdOrNull(value)` is the nullable adapter for optional identifiers and
|
|
447
|
+
record serializers; it uses the same safe-integer and type rules as parsePositiveId.
|
|
@@ -2,7 +2,7 @@ import type { RequestInstance } from '@stacksjs/types'
|
|
|
2
2
|
import { describe, expect, test } from 'bun:test'
|
|
3
3
|
import { commerceIdentifier, commerceMinorAmountError, commerceNotFound } from './commerce-action'
|
|
4
4
|
|
|
5
|
-
function request(id:
|
|
5
|
+
function request(id: unknown): RequestInstance {
|
|
6
6
|
return {
|
|
7
7
|
getParam: () => id,
|
|
8
8
|
} as unknown as RequestInstance
|
|
@@ -11,6 +11,7 @@ function request(id: string): RequestInstance {
|
|
|
11
11
|
describe('commerce action responses', () => {
|
|
12
12
|
test('accepts safe positive route identifiers', () => {
|
|
13
13
|
expect(commerceIdentifier(request('42'), 'Courier')).toEqual({ id: 42 })
|
|
14
|
+
for (const value of [true, {}, [], Number.MAX_SAFE_INTEGER + 1]) expect(commerceIdentifier(request(value), 'Courier').error?.status).toBe(422)
|
|
14
15
|
})
|
|
15
16
|
|
|
16
17
|
test('returns 422 for invalid identifiers', async () => {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RequestInstance } from '@stacksjs/types'
|
|
2
|
+
import { positiveIdOrNull } from '@stacksjs/validation/input'
|
|
2
3
|
import { response } from '@stacksjs/router'
|
|
3
4
|
|
|
4
5
|
export type CommerceIdentifierResult =
|
|
@@ -9,8 +10,8 @@ export function commerceIdentifier(
|
|
|
9
10
|
request: RequestInstance,
|
|
10
11
|
resource: string,
|
|
11
12
|
): CommerceIdentifierResult {
|
|
12
|
-
const id =
|
|
13
|
-
if (
|
|
13
|
+
const id = positiveIdOrNull(request.getParam('id'))
|
|
14
|
+
if (id === null) {
|
|
14
15
|
return {
|
|
15
16
|
error: response.json({ message: `${resource} id must be a positive integer.` }, 422),
|
|
16
17
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RequestInstance } from '@stacksjs/types'
|
|
2
|
+
import { positiveIdOrNull } from '@stacksjs/validation/input'
|
|
2
3
|
import { db } from '@stacksjs/database/runtime'
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -28,9 +29,7 @@ export function insertedId(result: unknown): number {
|
|
|
28
29
|
|
|
29
30
|
/** The `{id}` route param, or 0 when it is not a usable row id. */
|
|
30
31
|
export function rowId(request: RequestInstance): number {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return Number.isInteger(id) && id > 0 ? id : 0
|
|
32
|
+
return positiveIdOrNull(request.getParam('id')) ?? 0
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
/** Matches the slug the dashboard dialogs generate client-side. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { RequestInstance } from '@stacksjs/types'
|
|
2
2
|
import { describe, expect, test } from 'bun:test'
|
|
3
|
+
import { rowId } from './content-input'
|
|
3
4
|
import { parseAuthorInput } from './author-input'
|
|
4
5
|
import { parsePageInput, parsePublished } from './page-input'
|
|
5
6
|
|
|
@@ -43,3 +44,9 @@ describe('dashboard content record input', () => {
|
|
|
43
44
|
expect(parsePublished(false)).toBe(false)
|
|
44
45
|
})
|
|
45
46
|
})
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
test('content identifiers use the shared safe-integer contract', () => {
|
|
50
|
+
for (const value of [true, {}, [], Number.MAX_SAFE_INTEGER + 1]) expect(rowId({ getParam: () => value } as unknown as RequestInstance)).toBe(0)
|
|
51
|
+
expect(rowId({ getParam: () => '42' } as unknown as RequestInstance)).toBe(42)
|
|
52
|
+
})
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { RequestInstance } from '@stacksjs/types'
|
|
2
|
+
import { positiveIdOrNull, storedBoolean } from '@stacksjs/validation/input'
|
|
2
3
|
import { db } from '@stacksjs/database/runtime'
|
|
3
4
|
import { insertedId, str, timestamp } from './content-input'
|
|
4
5
|
|
|
@@ -49,17 +50,16 @@ export async function findPost(id: number, database: typeof db = db): Promise<un
|
|
|
49
50
|
function ids(value: unknown): number[] {
|
|
50
51
|
const values = Array.isArray(value) ? value : value === undefined || value === null ? [] : [value]
|
|
51
52
|
return [...new Set(values
|
|
52
|
-
.map(
|
|
53
|
-
.filter(
|
|
53
|
+
.map(positiveIdOrNull)
|
|
54
|
+
.filter((item): item is number => item !== null))]
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
function optionalId(value: unknown): number | null {
|
|
57
|
-
|
|
58
|
-
return Number.isInteger(id) && id > 0 ? id : null
|
|
58
|
+
return positiveIdOrNull(value)
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function booleanValue(value: unknown): boolean {
|
|
62
|
-
return value ===
|
|
62
|
+
return storedBoolean(value === 'on' ? true : value, false)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
export function invalidPostContent(payload: PostPayload): string | null {
|
|
@@ -15,6 +15,7 @@ describe('team records', () => {
|
|
|
15
15
|
expect(parsePositiveId('42')).toBe(42)
|
|
16
16
|
expect(parsePositiveId('0')).toBeNull()
|
|
17
17
|
expect(parsePositiveId('4.2')).toBeNull()
|
|
18
|
+
for (const value of [true, false, {}, [], Number.MAX_SAFE_INTEGER + 1]) expect(parsePositiveId(value)).toBeNull()
|
|
18
19
|
expect(normalizeInvitationEmail(' Teammate@Example.COM ')).toBe('teammate@example.com')
|
|
19
20
|
expect(normalizeInvitationEmail('not-an-email')).toBeNull()
|
|
20
21
|
expect(normalizeInvitationRole(' ADMIN ')).toBe('admin')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { positiveIdOrNull } from '@stacksjs/validation/input'
|
|
1
2
|
import { createHash, randomBytes } from 'node:crypto'
|
|
2
3
|
|
|
3
4
|
export const TEAM_MEMBER_ROLES = ['owner', 'admin', 'member', 'viewer'] as const
|
|
@@ -9,8 +10,7 @@ export type TeamInvitationRole = typeof TEAM_INVITATION_ROLES[number]
|
|
|
9
10
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
|
10
11
|
|
|
11
12
|
export function parsePositiveId(value: unknown): number | null {
|
|
12
|
-
|
|
13
|
-
return Number.isInteger(id) && id > 0 ? id : null
|
|
13
|
+
return positiveIdOrNull(value)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function changedRows(result: unknown): number {
|
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.113",
|
|
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.113",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/stacksjs/stacks.git",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@iconify-json/f7": "^1.2.2",
|
|
57
57
|
"@iconify-json/hugeicons": "^1.2.35",
|
|
58
|
-
"@stacksjs/mobile": "^0.75.
|
|
58
|
+
"@stacksjs/mobile": "^0.75.113",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.422",
|
|
60
60
|
"@xterm/addon-fit": "^0.11.0",
|
|
61
61
|
"@xterm/xterm": "^6.0.0",
|