@stacksjs/defaults 0.75.164 → 0.75.166
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.
|
@@ -25,6 +25,13 @@ accepted input; fetchSubmissions and exportSubmissionsCsv serve administrative
|
|
|
25
25
|
reads. Supply the site identity from trusted request context. A null site id is
|
|
26
26
|
the single-site/global context, not a tenant identity from a client.
|
|
27
27
|
|
|
28
|
+
Public endpoints that are not persisted forms (a lead or contact form an app
|
|
29
|
+
stores itself) use `checkSubmissionSpam({ honeypot, renderedAtMs }, policy)`
|
|
30
|
+
from `@stacksjs/forms/spam`: `honeypot` (answer as if it worked, store nothing),
|
|
31
|
+
`too_fast` (under `minSubmitSeconds`, default 3) or null. submitForm uses the
|
|
32
|
+
same check with `config.forms.spam`. No CAPTCHA, no third-party script; still
|
|
33
|
+
rate-limit per address or IP.
|
|
34
|
+
|
|
28
35
|
## Uploads, notifications, and paid forms
|
|
29
36
|
|
|
30
37
|
Use resolveUploadLimits, checkUpload, fileFieldNamed, formUploadPrefix and
|
|
@@ -229,6 +229,12 @@ every reading natively, screen locked or app closed, until `stopRecording()`
|
|
|
229
229
|
hands them back. iOS only, behind `capabilities.heartRate` (which adds the
|
|
230
230
|
`bluetooth-central` background mode); Bluetooth needs no network.
|
|
231
231
|
|
|
232
|
+
`capabilities.backgroundAudio` (iOS) adds the `audio` background mode, so a
|
|
233
|
+
soundscape played with Web Audio keeps going with the screen locked: a sleep
|
|
234
|
+
timer built on stx's `useAmbientSound().fadeOut(seconds, after)` then fades it
|
|
235
|
+
out on the audio clock. App Review expects audible content from an app that
|
|
236
|
+
asks for it.
|
|
237
|
+
|
|
232
238
|
```ts
|
|
233
239
|
import { createRouteRecorder, heartRate, location } from '@stacksjs/mobile'
|
|
234
240
|
|
|
@@ -250,6 +256,51 @@ with fixes recorded separately. In a browser and on Android `isAvailable()` is
|
|
|
250
256
|
false, the state says `available: false` and nothing fires. Word iOS's prompt
|
|
251
257
|
with `ios.usageDescriptions.NSBluetoothAlwaysUsageDescription`.
|
|
252
258
|
|
|
259
|
+
## Apple Watch scheduled workouts
|
|
260
|
+
|
|
261
|
+
`scheduledWorkouts` puts structured workouts on the paired Apple Watch through
|
|
262
|
+
WorkoutKit's scheduler (iOS 17+): each appears in the watch's Workout app on
|
|
263
|
+
its day, with its warmup, repeated blocks, cooldown, goals and alerts. iOS
|
|
264
|
+
only, behind `capabilities.scheduledWorkouts`; only an app with it compiles in
|
|
265
|
+
and links WorkoutKit. The calls work on the page and on native stx screens.
|
|
266
|
+
A plan is plain JSON in SI units, its `id` a UUID the app keeps for it.
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
import { scheduledWorkouts } from '@stacksjs/mobile'
|
|
270
|
+
|
|
271
|
+
if (await scheduledWorkouts.isSupported()) { // false off an iPhone, never rejects
|
|
272
|
+
await scheduledWorkouts.requestAuthorization() // iOS's prompt, once; call it from a tap
|
|
273
|
+
const kept = await scheduledWorkouts.list() // [{ id, date, hour, minute, complete }]
|
|
274
|
+
await scheduledWorkouts.schedule({
|
|
275
|
+
id: '6f1c2b8e-5a7d-4c3e-9b1a-2d4e6f8a0b1c',
|
|
276
|
+
date: '2026-10-20', hour: 6, minute: 30, // local; 07:00 without a time
|
|
277
|
+
workout: {
|
|
278
|
+
activity: 'running', location: 'outdoor', displayName: '4 x 1 km',
|
|
279
|
+
warmup: { goal: { type: 'time', seconds: 600 } },
|
|
280
|
+
blocks: [{ iterations: 4, steps: [
|
|
281
|
+
{ purpose: 'work', step: { goal: { type: 'distance', meters: 1000 }, alert: { type: 'speed', min: 4.1, max: 4.4 } } },
|
|
282
|
+
{ purpose: 'recovery', step: { goal: { type: 'time', seconds: 120 } } },
|
|
283
|
+
] }],
|
|
284
|
+
},
|
|
285
|
+
})
|
|
286
|
+
await scheduledWorkouts.remove(kept[0].id) // every day it is on
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Goals are `open`, `time` (seconds), `distance` (meters) and `energy`
|
|
291
|
+
(kilocalories); alerts `heartRate`, `power`, `speed` (m/s), `cadence` ranges and
|
|
292
|
+
`heartRateZone` / `powerZone`. An activity or goal WorkoutKit refuses rejects
|
|
293
|
+
the call with a message naming it; an alert it refuses is left out and named
|
|
294
|
+
in the result's `droppedAlerts`. `schedule` also rejects LIMIT_REACHED (the
|
|
295
|
+
watch holds 15) and NOT_SCHEDULED when nothing kept the plan, as without a
|
|
296
|
+
paired watch. In a browser and on Android `isSupported()` is false and every
|
|
297
|
+
other call rejects `unsupported`.
|
|
298
|
+
|
|
299
|
+
For tests, `createScheduledWorkoutsFake()` from `@stacksjs/mobile/testing` is a
|
|
300
|
+
`craft.scheduledWorkouts` that answers like the shell. On the iOS simulator,
|
|
301
|
+
which never has a watch, the app's `CraftFakeWorkoutScheduler` default makes
|
|
302
|
+
the shell keep plans itself (`xcrun simctl spawn <device> defaults write <bundle id> CraftFakeWorkoutScheduler -bool YES`).
|
|
303
|
+
|
|
253
304
|
## Apple Music (now playing)
|
|
254
305
|
|
|
255
306
|
`music` shows what the Music app is playing (title, artist, album, a small
|
|
@@ -422,7 +473,10 @@ energy, distance, heart rate, resting heart rate, HRV, weight and sleep.
|
|
|
422
473
|
`health.getHeartRateSamples(range)` returns every heart-rate reading (bpm,
|
|
423
474
|
start/end, source and device) and `health.getSleepIntervals(range)` the night's
|
|
424
475
|
in-bed, awake and asleep stages; check `health.supports(method)` first, since an
|
|
425
|
-
app build that predates a read resolves `[]` for it.
|
|
476
|
+
app build that predates a read resolves `[]` for it. Mindful minutes go through
|
|
477
|
+
`health.saveMindfulSession({ id, startDate, endDate })` (the `mindful` grant;
|
|
478
|
+
the id is the sample's external UUID, so a repeat save keeps the first) and come
|
|
479
|
+
back from `health.getMindfulSessions(range)` with `ownApp` on this app's own. Completed
|
|
426
480
|
recordings can be written back with `health.saveWorkout(...)`; treat permission
|
|
427
481
|
revocation as a normal runtime state and never block saving the application's
|
|
428
482
|
own activity when a health write fails.
|
|
@@ -51,7 +51,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
51
51
|
| `@stacksjs/faker` | [`stacks-faker`](../stacks-faker/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/faker/src/index.ts) | 1 |
|
|
52
52
|
| `@stacksjs/feature-flags` | [`stacks-feature-flags`](../stacks-feature-flags/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/feature-flags/src/index.ts) | 7 |
|
|
53
53
|
| `@stacksjs/features` | [`stacks-features`](../stacks-features/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/features/src/index.ts) | 1 |
|
|
54
|
-
| `@stacksjs/forms` | [`stacks-forms`](../stacks-forms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/index.ts) |
|
|
54
|
+
| `@stacksjs/forms` | [`stacks-forms`](../stacks-forms/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/index.ts) | 4 |
|
|
55
55
|
| `@stacksjs/git` | [`stacks-git`](../stacks-git/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/git/src/index.ts) | 1 |
|
|
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) | 7 |
|
|
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 |
|
|
@@ -60,10 +60,10 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
|
|
|
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) | 2 |
|
|
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
|
-
| `@stacksjs/mobile` | [`stacks-mobile`](../stacks-mobile/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/index.ts) |
|
|
63
|
+
| `@stacksjs/mobile` | [`stacks-mobile`](../stacks-mobile/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/index.ts) | 17 |
|
|
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) | 15 |
|
|
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
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 |
|
|
@@ -497,11 +497,11 @@ Evidence directory: [1 retained tests](https://github.com/stacksjs/stacks/blob/m
|
|
|
497
497
|
|
|
498
498
|
Guidance: [`stacks-forms`](../stacks-forms/SKILL.md). Source: [storage/framework/core/forms/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/index.ts).
|
|
499
499
|
|
|
500
|
-
Declared runtime exports: `checkUpload`, `completeSubmissionPayment`, `computeAmountCents`, `createForm`, `dispatchSubmissionNotifications`, `evaluateConditions`, `exportSubmissionsCsv`, `extensionOf`, `fetchSubmissions`, `fileFieldNamed`, `formUploadPrefix`, `isOwnedUploadPath`, `loadFormByHandle`, `loadFormByUuid`, `publicDefinition`, `resolveUploadLimits`, `submissionIdentity`, `submitForm`, `toCreateFields`, `validateSubmission`, `visibleFields`.
|
|
500
|
+
Declared runtime exports: `checkSubmissionSpam`, `checkUpload`, `completeSubmissionPayment`, `computeAmountCents`, `createForm`, `dispatchSubmissionNotifications`, `evaluateConditions`, `exportSubmissionsCsv`, `extensionOf`, `fetchSubmissions`, `fileFieldNamed`, `formUploadPrefix`, `isOwnedUploadPath`, `loadFormByHandle`, `loadFormByUuid`, `publicDefinition`, `resolveUploadLimits`, `submissionIdentity`, `submitForm`, `toCreateFields`, `validateSubmission`, `visibleFields`.
|
|
501
501
|
|
|
502
|
-
Local source modules: [src/conditions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/conditions.ts), [src/create.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/create.ts), [src/definition.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/definition.ts), [src/notifications.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/notifications.ts), [src/submissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/submissions.ts), [src/uploads.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/uploads.ts), [src/validate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/validate.ts).
|
|
502
|
+
Local source modules: [src/conditions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/conditions.ts), [src/create.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/create.ts), [src/definition.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/definition.ts), [src/notifications.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/notifications.ts), [src/spam.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/spam.ts), [src/submissions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/submissions.ts), [src/uploads.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/uploads.ts), [src/validate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/src/validate.ts).
|
|
503
503
|
|
|
504
|
-
Evidence directory: [
|
|
504
|
+
Evidence directory: [4 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/forms/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
505
505
|
|
|
506
506
|
### @stacksjs/git
|
|
507
507
|
|
|
@@ -581,9 +581,9 @@ Guidance: [`stacks-mobile`](../stacks-mobile/SKILL.md). Source: [storage/framewo
|
|
|
581
581
|
|
|
582
582
|
Declared runtime exports: `appReview`, `biometrics`, `brightness`, `camera`, `deepLinks`, `device`, `getNativeMobileBridge`, `haptics`, `health`, `heartRate`, `isNativeMobile`, `keepAwake`, `lifecycle`, `liveActivities`, `location`, `mobile`, `music`, `network`, `normalizeDeepLinkURL`, `notifications`, `onMobileReady`, `permissions`, `pushNotifications`, `secureStorage`, `share`, `snapshots`, `speech`, `splash`, `watchConnectivity`, `whenNativeMobile`, `withNativeFeedback`.
|
|
583
583
|
|
|
584
|
-
Local source modules: [src/bridge.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/bridge.ts), [src/controls.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/controls.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/events.ts), [src/gestures.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/gestures.ts), [src/indoor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/indoor.ts), [src/native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/native.ts), [src/navigation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/navigation.ts), [src/refresh-control.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/refresh-control.ts), [src/route.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/route.ts), [src/session-clock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/session-clock.ts), [src/sheet-gesture.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheet-gesture.ts), [src/sheets.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheets.ts), [src/shell.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/shell.ts), [src/spotlight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/spotlight.ts), [src/tab-bar.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/tab-bar.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/types.ts).
|
|
584
|
+
Local source modules: [src/bridge.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/bridge.ts), [src/controls.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/controls.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/events.ts), [src/gestures.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/gestures.ts), [src/indoor.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/indoor.ts), [src/native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/native.ts), [src/navigation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/navigation.ts), [src/refresh-control.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/refresh-control.ts), [src/route.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/route.ts), [src/scheduled-workouts.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/scheduled-workouts.ts), [src/session-clock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/session-clock.ts), [src/sheet-gesture.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheet-gesture.ts), [src/sheets.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/sheets.ts), [src/shell.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/shell.ts), [src/spotlight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/spotlight.ts), [src/tab-bar.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/tab-bar.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/src/types.ts).
|
|
585
585
|
|
|
586
|
-
Evidence directory: [
|
|
586
|
+
Evidence directory: [17 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/mobile/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
|
|
587
587
|
|
|
588
588
|
### @stacksjs/model-meta
|
|
589
589
|
|
|
@@ -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`, `DEFAULT_SMS_OPT_OUT`, `DEFAULT_UNSUBSCRIBE_NOTICE`, `DatabaseNotificationDriver`, `NOTIFICATION_FRAME_STRINGS`, `SMS_SENDER_MAX_LENGTH`, `accountNotificationTemplates`, `bulkSetPreferences`, `commerceNotificationTemplates`, `createNotificationTemplates`, `defineNotificationTemplates`, `emailParagraphs`, `ensureSuccessfulEmailResult`, `ensureSuccessfulNotificationResults`, `filterChannelsByPreferences`, `getNotificationPreferences`, `interpolateNotificationText`, `listUnsubscribeHeaders`, `makeDeliveryRecord`, `notification`, `notificationChannel`, `notificationEmailHtml`, `notificationEmailMessage`, `notificationEmailText`, `notificationFrameStrings`, `notificationLanguageTag`, `notificationSmsBody`, `notificationTemplateVariables`, `notificationUnsubscribeLinks`, `notificationUnsubscribeToken`, `notify`, `parseNotificationUnsubscribeToken`, `recordNotificationDelivery`, `renderNotificationTemplate`, `resolveDeliveryRecipient`, `resolveNotificationLocale`, `setNotificationPreference`, `smsSenderPrefix`, `subscriptionNotificationTemplates`, `unsubscribeTokenFromRequest`, `unsubscribeWithToken`, `useBroadcast`, `useChat`, `useDatabase`, `useEmail`, `useNotification`, `usePush`, `useSMS`, `wherePreferenceCategory`.
|
|
610
|
+
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`.
|
|
611
611
|
|
|
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/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/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).
|
|
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/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).
|
|
613
613
|
|
|
614
|
-
Evidence directory: [
|
|
614
|
+
Evidence directory: [15 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
|
|
|
@@ -186,6 +186,34 @@ const { subject, body, action } = templates.render('password_changed', { app: 'H
|
|
|
186
186
|
- `account_created` carries a credential link: send it directly, not through a
|
|
187
187
|
stored queue that keeps the body.
|
|
188
188
|
|
|
189
|
+
## Sequences: steps with waits and quiet hours
|
|
190
|
+
|
|
191
|
+
`@stacksjs/notifications/sequences` (pure; also exported from the root) is the
|
|
192
|
+
timing engine for journeys such as "email now, wait two days, text, then a call
|
|
193
|
+
task for staff". It never sends or stores anything: the app keeps each
|
|
194
|
+
person's next step index and due time, and on each tick asks what to do now.
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { advanceSequence, sequenceTimeline } from '@stacksjs/notifications/sequences'
|
|
198
|
+
|
|
199
|
+
const quietHours = { start: '21:00', end: '08:00', timeZone: 'Europe/Berlin' }
|
|
200
|
+
const { run, next } = advanceSequence(steps, enrollment.step_index, new Date(), {
|
|
201
|
+
quietHours,
|
|
202
|
+
respectsQuietHours: step => step.type === 'email' || step.type === 'sms',
|
|
203
|
+
})
|
|
204
|
+
// perform `run` in order, then store next?.index / next?.at (null: finished)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
- A step is `{ type, minutes? }` plus whatever the app needs. `type: 'wait'`
|
|
208
|
+
with `minutes` sets when the sequence continues; a zero wait is skipped.
|
|
209
|
+
- A step that respects quiet hours (default: every non-wait) is held until the
|
|
210
|
+
window ends in its zone (`nextSendableTime`); `isQuietTime` answers for one
|
|
211
|
+
instant. Windows may cross midnight; DST comes from the runtime's tz data.
|
|
212
|
+
- `sequenceTimeline(steps, start, options)` lays the steps out in time for a
|
|
213
|
+
preview.
|
|
214
|
+
- Consent, unsubscribes and STOP are still the sender's checks (`notify()`,
|
|
215
|
+
preferences); the engine only decides when.
|
|
216
|
+
|
|
189
217
|
## Channel factories
|
|
190
218
|
|
|
191
219
|
- `useEmail(driver?)` returns a sendable transport. Without a driver it uses
|
|
@@ -231,7 +259,7 @@ delivery log, not extra columns on the inbox.
|
|
|
231
259
|
`storage/framework/core/notifications/src/index.ts` defines the real
|
|
232
260
|
signatures. `preferences.ts`, `delivery.ts` and `drivers/database.ts`
|
|
233
261
|
own their persistence; the query builder is bun-query-builder.
|
|
234
|
-
`notifications.test.ts`, `delivery-tracking.test.ts`,
|
|
262
|
+
`notifications.test.ts`, `delivery-tracking.test.ts`, `sequences.test.ts`,
|
|
235
263
|
`broadcast.test.ts`, `email-body.test.ts` and `frame-locale.test.ts` cover
|
|
236
264
|
retained behavior; `frame-strings.ts` holds the frame's languages.
|
|
237
265
|
For provider status, consult `config/src/capabilities.ts` and each channel
|
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.166",
|
|
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.166",
|
|
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.166",
|
|
59
59
|
"@stacksjs/sanitizer": "^0.2.483",
|
|
60
60
|
"@xterm/addon-fit": "^0.11.0",
|
|
61
61
|
"@xterm/xterm": "^6.0.0",
|