@stacksjs/types 0.70.45 → 0.70.53
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/LICENSE.md +21 -0
- package/dist/auth.d.ts +7 -0
- package/dist/cache.d.ts +10 -1
- package/dist/cli.d.ts +2 -1
- package/dist/cms.d.ts +12 -0
- package/dist/commerce.d.ts +14 -0
- package/dist/cors.d.ts +47 -0
- package/dist/dashboard.d.ts +75 -0
- package/dist/database.d.ts +10 -0
- package/dist/email.d.ts +6 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +1 -1
- package/dist/logging.d.ts +3 -0
- package/dist/marketing.d.ts +12 -0
- package/dist/model-dashboard-augmentation.d.ts +8 -0
- package/dist/model.d.ts +4 -1
- package/dist/monitoring.d.ts +12 -0
- package/dist/queue.d.ts +2 -0
- package/dist/realtime.d.ts +8 -8
- package/dist/request.d.ts +107 -4
- package/dist/search-engine.d.ts +8 -1
- package/dist/services.d.ts +9 -0
- package/dist/stacks.d.ts +6 -1
- package/package.json +5 -5
- package/src/auth.ts +39 -0
- package/src/cache.ts +49 -2
- package/src/cli.ts +1 -0
- package/src/cms.ts +14 -0
- package/src/commerce.ts +18 -0
- package/src/cors.ts +86 -0
- package/src/dashboard.ts +178 -0
- package/src/database.ts +14 -0
- package/src/email.ts +94 -0
- package/src/index.ts +9 -0
- package/src/logging.ts +32 -0
- package/src/marketing.ts +14 -0
- package/src/model-dashboard-augmentation.ts +51 -0
- package/src/model.ts +33 -1
- package/src/monitoring.ts +14 -0
- package/src/queue.ts +8 -0
- package/src/request.ts +166 -5
- package/src/search-engine.ts +32 -1
- package/src/services.ts +26 -0
- package/src/stacks.ts +46 -3
package/dist/search-engine.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ export type {
|
|
|
24
24
|
// type Sorts = any
|
|
25
25
|
// type Sort = any
|
|
26
26
|
export declare interface SearchEngineOptions {
|
|
27
|
-
driver: 'meilisearch' | 'algolia' | 'opensearch'
|
|
27
|
+
driver: 'meilisearch' | 'algolia' | 'opensearch' | 'typesense'
|
|
28
28
|
opensearch?: {
|
|
29
29
|
host: string
|
|
30
30
|
protocol: number
|
|
@@ -43,6 +43,12 @@ export declare interface SearchEngineOptions {
|
|
|
43
43
|
apiKey: string
|
|
44
44
|
searchOnlyApiKey?: string
|
|
45
45
|
}
|
|
46
|
+
typesense?: {
|
|
47
|
+
host?: string
|
|
48
|
+
port?: number
|
|
49
|
+
protocol?: string
|
|
50
|
+
apiKey?: string
|
|
51
|
+
}
|
|
46
52
|
filters?: {
|
|
47
53
|
[key: string]: string
|
|
48
54
|
}
|
|
@@ -118,5 +124,6 @@ export declare interface SearchOptions {
|
|
|
118
124
|
sortable: string[]
|
|
119
125
|
filterable: string[]
|
|
120
126
|
options?: SearchEngineOptions
|
|
127
|
+
denormalize?: Record<string, string>
|
|
121
128
|
}
|
|
122
129
|
export type SearchEngineConfig = Partial<SearchEngineOptions>;
|
package/dist/services.d.ts
CHANGED
|
@@ -21,6 +21,14 @@ export declare interface ServicesOptions {
|
|
|
21
21
|
redirectUrl: string
|
|
22
22
|
scopes?: string[]
|
|
23
23
|
}
|
|
24
|
+
apple?: {
|
|
25
|
+
clientId: string
|
|
26
|
+
teamId: string
|
|
27
|
+
keyId: string
|
|
28
|
+
privateKey: string
|
|
29
|
+
redirectUrl: string
|
|
30
|
+
scopes?: string[]
|
|
31
|
+
}
|
|
24
32
|
facebook?: {
|
|
25
33
|
clientId: string
|
|
26
34
|
clientSecret: string
|
|
@@ -134,6 +142,7 @@ export declare interface ServicesOptions {
|
|
|
134
142
|
stripe?: {
|
|
135
143
|
secretKey?: string
|
|
136
144
|
publicKey?: string
|
|
145
|
+
webhookSecret?: string
|
|
137
146
|
apiVersion?: string
|
|
138
147
|
}
|
|
139
148
|
}
|
package/dist/stacks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AiConfig, AnalyticsConfig, AppConfig, AuthConfig, BinaryConfig, CacheConfig, CloudConfig, DashboardConfig, DatabaseConfig, DnsConfig, DocsConfig, EmailConfig, ErrorConfig, FilesystemsConfig, GitConfig, HashingConfig, LibraryConfig, LoggingConfig, NotificationConfig, PaymentConfig, Ports, QueueConfig, RealtimeConfig, SaasConfig, SearchEngineConfig, SecurityConfig, ServicesConfig, Team, UiConfig } from '.';
|
|
1
|
+
import type { AiConfig, AnalyticsConfig, AppConfig, AuthConfig, BinaryConfig, CacheConfig, CloudConfig, CmsConfig, CommerceConfig, CorsConfig, DashboardConfig, DatabaseConfig, DnsConfig, DocsConfig, EmailConfig, ErrorConfig, FilesystemsConfig, GitConfig, HashingConfig, LibraryConfig, LoggingConfig, MarketingConfig, MonitoringConfig, NotificationConfig, PaymentConfig, Ports, QueueConfig, RealtimeConfig, SaasConfig, SearchEngineConfig, SecurityConfig, ServicesConfig, Team, UiConfig } from '.';
|
|
2
2
|
/**
|
|
3
3
|
* **Stacks Options**
|
|
4
4
|
*
|
|
@@ -11,10 +11,13 @@ export declare interface StacksOptions {
|
|
|
11
11
|
analytics: AnalyticsConfig
|
|
12
12
|
app: AppConfig
|
|
13
13
|
auth: AuthConfig
|
|
14
|
+
cors?: CorsConfig
|
|
14
15
|
realtime: RealtimeConfig
|
|
15
16
|
cache: CacheConfig
|
|
16
17
|
cli: BinaryConfig
|
|
17
18
|
cloud: CloudConfig
|
|
19
|
+
cms: CmsConfig
|
|
20
|
+
commerce: CommerceConfig
|
|
18
21
|
dashboard: DashboardConfig
|
|
19
22
|
database: DatabaseConfig
|
|
20
23
|
dns: DnsConfig
|
|
@@ -25,6 +28,8 @@ export declare interface StacksOptions {
|
|
|
25
28
|
hashing: HashingConfig
|
|
26
29
|
library: LibraryConfig
|
|
27
30
|
logging: LoggingConfig
|
|
31
|
+
marketing: MarketingConfig
|
|
32
|
+
monitoring: MonitoringConfig
|
|
28
33
|
notification: NotificationConfig
|
|
29
34
|
payment: PaymentConfig
|
|
30
35
|
ports: Ports
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/types",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.70.
|
|
4
|
+
"version": "0.70.53",
|
|
5
5
|
"description": "The Stacks framework types.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"prepublishOnly": "bun run build"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@stacksjs/bunpress": "^0.1.
|
|
49
|
-
"@stacksjs/ts-validation": "^0.
|
|
50
|
-
"bun-query-builder": "^0.1.
|
|
48
|
+
"@stacksjs/bunpress": "^0.1.11",
|
|
49
|
+
"@stacksjs/ts-validation": "^0.5.0",
|
|
50
|
+
"bun-query-builder": "^0.1.38"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@stacksjs/validation": "
|
|
53
|
+
"@stacksjs/validation": "0.70.53",
|
|
54
54
|
"@types/bun": "^1.3.11",
|
|
55
55
|
"typescript": "^5.9.3"
|
|
56
56
|
},
|
package/src/auth.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
export interface AuthOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Top-level feature gate. When `false`, the auth feature is inert at boot
|
|
4
|
+
* (no token/password-reset/email-verification flows wired up). Missing or
|
|
5
|
+
* `true` means auth is on.
|
|
6
|
+
*/
|
|
7
|
+
enabled?: boolean
|
|
8
|
+
/** Optional deploy-target gate, e.g. `['production']`. */
|
|
9
|
+
env?: string[]
|
|
2
10
|
/**
|
|
3
11
|
* The default authentication guard to use
|
|
4
12
|
*/
|
|
@@ -90,6 +98,37 @@ export interface AuthOptions {
|
|
|
90
98
|
* @default 60
|
|
91
99
|
*/
|
|
92
100
|
throttle: number
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Reset-link URL template. Supports `{token}` and `{email}`
|
|
104
|
+
* placeholders. Absolute templates (`https://…`) are used as-is;
|
|
105
|
+
* path templates are prefixed with the app URL. Lets apps whose
|
|
106
|
+
* reset page lives on a custom route reuse `passwordResets().sendEmail()`
|
|
107
|
+
* instead of hand-rolling the send.
|
|
108
|
+
* @default '/password/reset/{token}?email={email}'
|
|
109
|
+
*/
|
|
110
|
+
url?: string
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Email verification configuration
|
|
115
|
+
*/
|
|
116
|
+
emailVerification?: {
|
|
117
|
+
/**
|
|
118
|
+
* Token expiration time in minutes
|
|
119
|
+
* @default 60
|
|
120
|
+
*/
|
|
121
|
+
expire?: number
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Verification-link URL template. Supports `{id}` and `{token}`
|
|
125
|
+
* placeholders. Absolute templates (`https://…`) are used as-is;
|
|
126
|
+
* path templates are prefixed with the app URL. Lets apps whose
|
|
127
|
+
* verify page lives on a custom route reuse `sendVerificationEmail()`
|
|
128
|
+
* instead of hand-rolling the send.
|
|
129
|
+
* @default '/verify-email/{id}/{token}'
|
|
130
|
+
*/
|
|
131
|
+
url?: string
|
|
93
132
|
}
|
|
94
133
|
}
|
|
95
134
|
|
package/src/cache.ts
CHANGED
|
@@ -6,11 +6,15 @@ export interface CacheOptions {
|
|
|
6
6
|
* **Cache Driver**
|
|
7
7
|
*
|
|
8
8
|
* The cache driver that will be used by your application to store
|
|
9
|
-
* cached data. Supports 'memory' and '
|
|
9
|
+
* cached data. Supports 'memory', 'redis', and 'singlestore' drivers.
|
|
10
|
+
*
|
|
11
|
+
* The 'singlestore' driver persists cache entries in a SingleStore
|
|
12
|
+
* rowstore table (with epoch-based TTL) — useful when you want a single
|
|
13
|
+
* SingleStore cluster to back both your primary data and your cache.
|
|
10
14
|
*
|
|
11
15
|
* @default "memory"
|
|
12
16
|
*/
|
|
13
|
-
driver: 'memory' | 'redis'
|
|
17
|
+
driver: 'memory' | 'redis' | 'singlestore'
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* **Cache Prefix**
|
|
@@ -117,6 +121,49 @@ export interface CacheOptions {
|
|
|
117
121
|
*/
|
|
118
122
|
deleteOnExpire?: boolean
|
|
119
123
|
}
|
|
124
|
+
|
|
125
|
+
singlestore?: {
|
|
126
|
+
/**
|
|
127
|
+
* SingleStore host (MySQL wire protocol)
|
|
128
|
+
* @default "127.0.0.1"
|
|
129
|
+
*/
|
|
130
|
+
host?: string
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* SingleStore port
|
|
134
|
+
* @default 3306
|
|
135
|
+
*/
|
|
136
|
+
port?: number
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* SingleStore username
|
|
140
|
+
* @default "root"
|
|
141
|
+
*/
|
|
142
|
+
username?: string
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* SingleStore password
|
|
146
|
+
*/
|
|
147
|
+
password?: string
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Database that holds the cache table
|
|
151
|
+
* @default "stacks"
|
|
152
|
+
*/
|
|
153
|
+
database?: string
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Table used to store cache entries
|
|
157
|
+
* @default "stacks_cache"
|
|
158
|
+
*/
|
|
159
|
+
table?: string
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Enable TLS (required by managed SingleStore / Helios)
|
|
163
|
+
* @default false
|
|
164
|
+
*/
|
|
165
|
+
ssl?: boolean
|
|
166
|
+
}
|
|
120
167
|
}
|
|
121
168
|
}
|
|
122
169
|
|
package/src/cli.ts
CHANGED
package/src/cms.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **CMS Options**
|
|
3
|
+
*
|
|
4
|
+
* Top-level feature gate plus any future CMS-wide settings. The CMS bundle
|
|
5
|
+
* (Post / Page / Author / Comment / Tag / Category models + edit dashboards)
|
|
6
|
+
* stays inert at boot when `enabled` is `false`.
|
|
7
|
+
*/
|
|
8
|
+
export interface CmsOptions {
|
|
9
|
+
enabled?: boolean
|
|
10
|
+
/** Optional deploy-target gate, e.g. `['production']`. */
|
|
11
|
+
env?: string[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type CmsConfig = Partial<CmsOptions>
|
package/src/commerce.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Commerce Options**
|
|
3
|
+
*
|
|
4
|
+
* Top-level feature gate plus storefront defaults. The commerce bundle
|
|
5
|
+
* (Order / Cart / Product / Customer / Coupon / GiftCard / Shipping models +
|
|
6
|
+
* storefront API) stays inert at boot when `enabled` is `false`.
|
|
7
|
+
*/
|
|
8
|
+
export interface CommerceOptions {
|
|
9
|
+
enabled?: boolean
|
|
10
|
+
/** Optional deploy-target gate, e.g. `['production']`. */
|
|
11
|
+
env?: string[]
|
|
12
|
+
/** Default storefront currency (ISO 4217), e.g. `'USD'`. */
|
|
13
|
+
currency?: string
|
|
14
|
+
/** Default tax rate applied when no product/region rule overrides. */
|
|
15
|
+
defaultTaxRate?: number
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type CommerceConfig = Partial<CommerceOptions>
|
package/src/cors.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CORS configuration types (stacksjs/stacks#1859 H-2).
|
|
3
|
+
*
|
|
4
|
+
* Lives in `@stacksjs/types` so userland `config/cors.ts` files can
|
|
5
|
+
* `import type { CorsConfig } from '@stacksjs/types'` and get full
|
|
6
|
+
* IntelliSense, and so the Cors middleware can read
|
|
7
|
+
* `config.cors` with proper typing instead of an `as any` cast.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Raw CORS configuration — every field optional. Defaults fill in
|
|
12
|
+
* any field that's missing when the middleware resolves config.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* // config/cors.ts
|
|
17
|
+
* import type { CorsConfig } from '@stacksjs/types'
|
|
18
|
+
*
|
|
19
|
+
* export default {
|
|
20
|
+
* origin: ['https://app.example.com', 'https://admin.example.com'],
|
|
21
|
+
* credentials: true,
|
|
22
|
+
* methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
23
|
+
* allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token'],
|
|
24
|
+
* maxAge: 600,
|
|
25
|
+
* } satisfies CorsConfig
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export interface CorsConfig {
|
|
29
|
+
/**
|
|
30
|
+
* Allowed origins.
|
|
31
|
+
*
|
|
32
|
+
* - `'*'` permits any origin (incompatible with `credentials: true`).
|
|
33
|
+
* - A string array enumerates the explicit allow-list; the request's
|
|
34
|
+
* `Origin` header is reflected verbatim when it matches.
|
|
35
|
+
* - A predicate function lets you implement dynamic allow-lists
|
|
36
|
+
* (e.g. wildcards, regex, environment-dependent).
|
|
37
|
+
*/
|
|
38
|
+
origin?: '*' | string[] | ((origin: string) => boolean)
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* HTTP methods the server accepts cross-origin. Echoed back in
|
|
42
|
+
* preflight `Access-Control-Allow-Methods` responses.
|
|
43
|
+
*/
|
|
44
|
+
methods?: string[]
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Request headers the browser is allowed to send cross-origin.
|
|
48
|
+
* Echoed back in preflight `Access-Control-Allow-Headers` responses.
|
|
49
|
+
*/
|
|
50
|
+
allowedHeaders?: string[]
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Response headers the browser is allowed to expose to JS via
|
|
54
|
+
* `fetch(...).then(r => r.headers.get(...))`. Anything not listed
|
|
55
|
+
* here is hidden from the SPA even though it's on the wire.
|
|
56
|
+
*/
|
|
57
|
+
exposedHeaders?: string[]
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether cookies / Authorization headers may be included
|
|
61
|
+
* cross-origin. **Setting this to `true` is incompatible with
|
|
62
|
+
* `origin: '*'`** — the spec requires an explicit origin.
|
|
63
|
+
*/
|
|
64
|
+
credentials?: boolean
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* How long the browser may cache the preflight response, in
|
|
68
|
+
* seconds. Default 86_400 (24h). Lower values cost more preflights
|
|
69
|
+
* but pick up policy changes faster.
|
|
70
|
+
*/
|
|
71
|
+
maxAge?: number
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Resolved CORS configuration with all defaults applied. This is the
|
|
76
|
+
* shape the middleware passes through `applyCorsHeaders` /
|
|
77
|
+
* `buildPreflightResponse`.
|
|
78
|
+
*/
|
|
79
|
+
export interface ResolvedCorsConfig {
|
|
80
|
+
origin: '*' | string[] | ((origin: string) => boolean)
|
|
81
|
+
methods: string[]
|
|
82
|
+
allowedHeaders: string[]
|
|
83
|
+
exposedHeaders: string[]
|
|
84
|
+
credentials: boolean
|
|
85
|
+
maxAge: number
|
|
86
|
+
}
|
package/src/dashboard.ts
CHANGED
|
@@ -12,6 +12,14 @@
|
|
|
12
12
|
* row when there's no newsletter without losing the model viewer.
|
|
13
13
|
*/
|
|
14
14
|
export interface DashboardOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Top-level feature gate. When `false`, the entire admin SPA + dashboard
|
|
17
|
+
* routes stay un-registered at boot. Missing or `true` keeps the dashboard
|
|
18
|
+
* on — the framework default, since every Stacks app wants it.
|
|
19
|
+
*/
|
|
20
|
+
enabled?: boolean
|
|
21
|
+
/** Optional deploy-target gate, e.g. `['production']`. */
|
|
22
|
+
env?: string[]
|
|
15
23
|
/** Per-section visibility toggles. Omit a section to leave it enabled. */
|
|
16
24
|
sections?: {
|
|
17
25
|
library?: { enabled?: boolean }
|
|
@@ -35,6 +43,176 @@ export interface DashboardOptions {
|
|
|
35
43
|
allModels?: { enabled?: boolean }
|
|
36
44
|
}
|
|
37
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* CI tracking surface — GitHub Actions health across the configured orgs.
|
|
48
|
+
* Ports the standalone `repo-dashboard` app into the dashboard
|
|
49
|
+
* (stacksjs/stacks#1844). Defaults to off because most projects don't
|
|
50
|
+
* own multiple GitHub orgs; opt in by listing orgs and surfacing a
|
|
51
|
+
* `GITHUB_TOKEN` in the environment.
|
|
52
|
+
*/
|
|
53
|
+
ci?: {
|
|
54
|
+
enabled?: boolean
|
|
55
|
+
/** Orgs whose repos appear as per-tab CI cards. */
|
|
56
|
+
orgs?: string[]
|
|
57
|
+
/** Self-hosted runner caps per org. Defaults to {@link runnerCapDefault}. */
|
|
58
|
+
runnerCaps?: Record<string, number>
|
|
59
|
+
/** Fallback cap for orgs missing from `runnerCaps`. Defaults to 20. */
|
|
60
|
+
runnerCapDefault?: number
|
|
61
|
+
/** Repo names to exclude from the CI feed. */
|
|
62
|
+
ignoreRepos?: string[]
|
|
63
|
+
/**
|
|
64
|
+
* Failing-CI notification fan-out (stacksjs/stacks#1849).
|
|
65
|
+
*
|
|
66
|
+
* When enabled, the dashboard fires a notification through the
|
|
67
|
+
* configured channels every time a repo's CI transitions from
|
|
68
|
+
* success → failure (or first-time-seen → failure). Sticky-red
|
|
69
|
+
* repos don't keep firing; same-run-id polls don't re-fire; a
|
|
70
|
+
* 5-minute cooldown silences flap-storms.
|
|
71
|
+
*/
|
|
72
|
+
notifications?: {
|
|
73
|
+
enabled?: boolean
|
|
74
|
+
/**
|
|
75
|
+
* Channels to fan out through. Maps to the same values
|
|
76
|
+
* `notify()` from @stacksjs/notifications accepts. Defaults to
|
|
77
|
+
* `['chat']` — Slack via webhook — because that channel
|
|
78
|
+
* doesn't need a recipient list (it's already scoped to a
|
|
79
|
+
* Slack channel via env).
|
|
80
|
+
*/
|
|
81
|
+
channels?: Array<'email' | 'sms' | 'chat' | 'database'>
|
|
82
|
+
/**
|
|
83
|
+
* Per-channel recipients for the channels that need one
|
|
84
|
+
* (email/sms/database). Skipped for `chat`. Each entry must
|
|
85
|
+
* carry the field the named channel requires (`email`,
|
|
86
|
+
* `phone`, `userId`).
|
|
87
|
+
*/
|
|
88
|
+
recipients?: Array<{ email?: string, phone?: string, userId?: number }>
|
|
89
|
+
/**
|
|
90
|
+
* Minimum delay (minutes) between consecutive notifications for
|
|
91
|
+
* the same repo. Defaults to 5. Set to 0 to disable.
|
|
92
|
+
*/
|
|
93
|
+
cooldownMinutes?: number
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Runner-pressure alerts (stacksjs/stacks#1850).
|
|
97
|
+
*
|
|
98
|
+
* When an org's queued-job count stays at or above
|
|
99
|
+
* `queuedThreshold` for `windowMinutes`, the dashboard fires a
|
|
100
|
+
* notification through the configured channels. Hysteresis: an
|
|
101
|
+
* already-alerting org doesn't re-fire until the queue drops
|
|
102
|
+
* below threshold for a full window first.
|
|
103
|
+
*/
|
|
104
|
+
alerts?: {
|
|
105
|
+
enabled?: boolean
|
|
106
|
+
/** Queue depth at or above counts as pressure. Defaults to 8. */
|
|
107
|
+
queuedThreshold?: number
|
|
108
|
+
/** Duration the threshold must hold in either direction before
|
|
109
|
+
* the alert fires / clears. Defaults to 10 minutes. */
|
|
110
|
+
windowMinutes?: number
|
|
111
|
+
/** Same channel options as {@link notifications.channels}. */
|
|
112
|
+
channels?: Array<'email' | 'sms' | 'chat' | 'database'>
|
|
113
|
+
/** Same recipient shape as {@link notifications.recipients}. */
|
|
114
|
+
recipients?: Array<{ email?: string, phone?: string, userId?: number }>
|
|
115
|
+
/**
|
|
116
|
+
* How long the runner-sample time-series is kept on disk.
|
|
117
|
+
* Older samples are pruned during each refresh to bound
|
|
118
|
+
* storage. Defaults to 24h.
|
|
119
|
+
*/
|
|
120
|
+
retentionHours?: number
|
|
121
|
+
}
|
|
122
|
+
}
|
|
38
123
|
}
|
|
39
124
|
|
|
40
125
|
export type DashboardConfig = Partial<DashboardOptions>
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Per-model dashboard configuration (stacksjs/stacks#1843).
|
|
129
|
+
*
|
|
130
|
+
* Attach to a model definition to influence how the model surfaces in the
|
|
131
|
+
* dashboard sidebar without touching the framework's dashboard internals:
|
|
132
|
+
*
|
|
133
|
+
* ```ts
|
|
134
|
+
* defineModel({
|
|
135
|
+
* name: 'AuditLog',
|
|
136
|
+
* table: 'audit_logs',
|
|
137
|
+
* dashboard: {
|
|
138
|
+
* section: 'management',
|
|
139
|
+
* icon: 'shield',
|
|
140
|
+
* roles: ['admin'],
|
|
141
|
+
* description: 'Append-only audit trail (admin-only)',
|
|
142
|
+
* },
|
|
143
|
+
* attributes: { … },
|
|
144
|
+
* })
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* Resolution chain (most specific → fallback):
|
|
148
|
+
*
|
|
149
|
+
* 1. `dashboard.enabled === false` → model is hidden from the sidebar
|
|
150
|
+
* entirely. The dynamic ORM viewer (`/models/<id>`) still works for
|
|
151
|
+
* direct navigation, but the row is suppressed.
|
|
152
|
+
* 2. `dashboard.section` → pins the model to that section, overriding
|
|
153
|
+
* the path-based auto-categorisation (commerce/, Content/, etc.).
|
|
154
|
+
* 3. `dashboard.label` / `dashboard.icon` → display overrides; fall back
|
|
155
|
+
* to the model name and `iconMap` lookup.
|
|
156
|
+
* 4. `dashboard.roles` → role-gates the sidebar row. The server-side
|
|
157
|
+
* sidebar builder emits the row with role metadata; the client filters
|
|
158
|
+
* it out for users who lack a matching role. Permissive default
|
|
159
|
+
* (unauthenticated viewers see everything — see `useRole.ts`).
|
|
160
|
+
*/
|
|
161
|
+
export interface DashboardModelOptions {
|
|
162
|
+
/**
|
|
163
|
+
* Hide this model from the dashboard sidebar entirely. Direct
|
|
164
|
+
* navigation to `/models/<id>` still works — this only suppresses the
|
|
165
|
+
* sidebar row.
|
|
166
|
+
*
|
|
167
|
+
* Defaults to `true` (model is shown).
|
|
168
|
+
*/
|
|
169
|
+
enabled?: boolean
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Override the display name in the sidebar. Defaults to the model name.
|
|
173
|
+
*/
|
|
174
|
+
label?: string
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Override the icon. Defaults to the auto-derived one in `iconMap`.
|
|
178
|
+
* The string is whatever the active sidebar icon set expects
|
|
179
|
+
* (e.g., SF Symbol name for the native sidebar; Lucide-style name for
|
|
180
|
+
* the web sidebar).
|
|
181
|
+
*/
|
|
182
|
+
icon?: string
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Pin this model to a specific sidebar section instead of the
|
|
186
|
+
* auto-derived category. Useful when a "logs" model lives under
|
|
187
|
+
* `app/Models/` (userland) but should appear under Management rather
|
|
188
|
+
* than Data.
|
|
189
|
+
*/
|
|
190
|
+
section?:
|
|
191
|
+
| 'home'
|
|
192
|
+
| 'library'
|
|
193
|
+
| 'content'
|
|
194
|
+
| 'commerce'
|
|
195
|
+
| 'marketing'
|
|
196
|
+
| 'analytics'
|
|
197
|
+
| 'management'
|
|
198
|
+
| 'utilities'
|
|
199
|
+
| 'data'
|
|
200
|
+
| 'app'
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Role-gate the sidebar row. The row is rendered server-side with
|
|
204
|
+
* `data-required-roles="…"`; the client filters it out via
|
|
205
|
+
* `useRole()` if the viewer doesn't hold any of the listed roles.
|
|
206
|
+
*
|
|
207
|
+
* The dev-mode default in `useRole()` means unauthenticated viewers
|
|
208
|
+
* (e.g., the local dev dashboard) see role-gated rows as if they
|
|
209
|
+
* were a dev — see `composables/useRole.ts` for the full chain.
|
|
210
|
+
*/
|
|
211
|
+
roles?: string[]
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Short tooltip / hover description for the sidebar row. Optional —
|
|
215
|
+
* sidebars that don't support tooltips ignore it.
|
|
216
|
+
*/
|
|
217
|
+
description?: string
|
|
218
|
+
}
|
package/src/database.ts
CHANGED
|
@@ -13,6 +13,20 @@ export interface DatabaseOptions {
|
|
|
13
13
|
prefix?: string
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
// SingleStore is MySQL wire-compatible (port 3306); it shares MySQL's
|
|
17
|
+
// connection shape and adds an optional `ssl` flag for managed (Helios)
|
|
18
|
+
// endpoints, which require TLS.
|
|
19
|
+
singlestore?: {
|
|
20
|
+
url?: string
|
|
21
|
+
host?: string
|
|
22
|
+
port?: number
|
|
23
|
+
name?: string
|
|
24
|
+
username?: string
|
|
25
|
+
password?: string
|
|
26
|
+
prefix?: string
|
|
27
|
+
ssl?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
sqlite: {
|
|
17
31
|
url?: string
|
|
18
32
|
database?: string
|
package/src/email.ts
CHANGED
|
@@ -277,6 +277,23 @@ export interface EmailOptions {
|
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
mailboxes: string[] | MailboxConfig[]
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Auto-forwarding rules for received mail, provisioned to the mail server's
|
|
283
|
+
* readable `forwards.json` (re-read on every message — edits take effect
|
|
284
|
+
* with no restart).
|
|
285
|
+
*
|
|
286
|
+
* Key = the delivered mailbox: the full address for a per-domain isolated
|
|
287
|
+
* mailbox (e.g. `'no-reply@acme.com'`), or a bare local-part for a
|
|
288
|
+
* legacy role mailbox (e.g. `'postmaster'`).
|
|
289
|
+
* Value = destination addresses. Targets on a local domain are written
|
|
290
|
+
* straight to that mailbox's Maildir; external targets are relayed.
|
|
291
|
+
* A copy also stays in the source mailbox.
|
|
292
|
+
*
|
|
293
|
+
* @example { 'no-reply@acme.com': ['chris@acme.com'] }
|
|
294
|
+
*/
|
|
295
|
+
forwards?: Record<string, string[]>
|
|
296
|
+
|
|
280
297
|
domain?: string
|
|
281
298
|
|
|
282
299
|
url: string
|
|
@@ -286,6 +303,30 @@ export interface EmailOptions {
|
|
|
286
303
|
notifications?: EmailNotificationsConfig
|
|
287
304
|
|
|
288
305
|
default: 'log' | 'ses' | 'sendgrid' | 'mailgun' | 'mailtrap' | 'smtp'
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Suppression-list enforcement policy (stacksjs/stacks#1880).
|
|
309
|
+
*
|
|
310
|
+
* - `'strict'` — block all sends to suppressed
|
|
311
|
+
* recipients (default)
|
|
312
|
+
* - `'transactional-allowed'` — block broadcasts; allow messages
|
|
313
|
+
* with `tag: 'transactional'`
|
|
314
|
+
* - `'off'` — never block; the suppression
|
|
315
|
+
* table is just a tracking record
|
|
316
|
+
*
|
|
317
|
+
* The check is opt-in at the table level — apps that haven't
|
|
318
|
+
* created the `email_suppressions` table see "always allowed"
|
|
319
|
+
* with a one-shot warn.
|
|
320
|
+
*/
|
|
321
|
+
suppressionPolicy?: 'strict' | 'transactional-allowed' | 'off'
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* URL prefix the framework's default unsubscribe route mounts
|
|
325
|
+
* under (stacksjs/stacks#1880). Defaults to
|
|
326
|
+
* `/_stacks/email/unsubscribe`. The full link is built as
|
|
327
|
+
* `${app.url}${unsubscribeRoute}/${signed-token}`.
|
|
328
|
+
*/
|
|
329
|
+
unsubscribeRoute?: string
|
|
289
330
|
}
|
|
290
331
|
|
|
291
332
|
export type EmailConfig = Partial<EmailOptions>
|
|
@@ -340,6 +381,17 @@ export interface EmailMessage {
|
|
|
340
381
|
cc?: string | string[] | EmailAddress[]
|
|
341
382
|
/** Blind carbon copy recipient(s) */
|
|
342
383
|
bcc?: string | string[] | EmailAddress[]
|
|
384
|
+
/**
|
|
385
|
+
* Reply-To address(es) for the outgoing message.
|
|
386
|
+
*
|
|
387
|
+
* Drivers must propagate this to the provider's equivalent field
|
|
388
|
+
* (`ReplyToAddresses` on SES, `h:Reply-To` on Mailgun, `reply_to` on
|
|
389
|
+
* SendGrid, a `Reply-To:` header for SMTP). Previously the field
|
|
390
|
+
* lived as an `as any` stash on the message (stacksjs/stacks#1871 M-4)
|
|
391
|
+
* — promoting it to a first-class slot means drivers can be
|
|
392
|
+
* checked at compile time for coverage.
|
|
393
|
+
*/
|
|
394
|
+
replyTo?: EmailAddress | EmailAddress[] | string | string[]
|
|
343
395
|
/** Email subject line */
|
|
344
396
|
subject: string
|
|
345
397
|
/** Path to email template (Vue component) */
|
|
@@ -364,6 +416,48 @@ export interface EmailMessage {
|
|
|
364
416
|
onError?: (error: Error) => Promise<{ message: string }> | { message: string }
|
|
365
417
|
/** Optional custom handler */
|
|
366
418
|
handle?: () => Promise<{ message: string }> | { message: string }
|
|
419
|
+
/**
|
|
420
|
+
* Caller-supplied idempotency key (stacksjs/stacks#1871 M-8).
|
|
421
|
+
*
|
|
422
|
+
* When set, `mail.send()` consults an `email_idempotency` dedup
|
|
423
|
+
* table before dispatching to the driver:
|
|
424
|
+
* - hit: returns the cached EmailResult from the first send
|
|
425
|
+
* - miss: dispatches, then records the result under the key
|
|
426
|
+
*
|
|
427
|
+
* Why it matters: queued send retries (the framework retries 3×
|
|
428
|
+
* with backoff) and external retry loops (webhook handlers that
|
|
429
|
+
* re-fire on transient failures, request POSTs that the user
|
|
430
|
+
* double-clicks) can otherwise deliver the same email multiple
|
|
431
|
+
* times. The key turns those retries into safe no-ops.
|
|
432
|
+
*
|
|
433
|
+
* Construction guidance: derive the key from the business event
|
|
434
|
+
* the email represents — e.g. `welcome:${userId}`,
|
|
435
|
+
* `order-confirmation:${orderId}:${attempt}`, not from message
|
|
436
|
+
* content (which would collide across unrelated sends).
|
|
437
|
+
*
|
|
438
|
+
* The dedup table is opt-in. When the migration hasn't been run
|
|
439
|
+
* yet, the framework warns once and falls back to "send every
|
|
440
|
+
* time" so unrelated apps aren't broken by the new behavior.
|
|
441
|
+
*/
|
|
442
|
+
idempotencyKey?: string
|
|
443
|
+
/**
|
|
444
|
+
* Classification used by the suppression-policy check
|
|
445
|
+
* (stacksjs/stacks#1880). Set to `'transactional'` for messages
|
|
446
|
+
* that should bypass suppression when
|
|
447
|
+
* `email.suppressionPolicy: 'transactional-allowed'` is
|
|
448
|
+
* configured — password resets, billing receipts, magic-link
|
|
449
|
+
* sign-ins.
|
|
450
|
+
*
|
|
451
|
+
* Set to `'broadcast'` (or omit) for marketing / newsletter
|
|
452
|
+
* sends; those get blocked when the recipient is suppressed.
|
|
453
|
+
*
|
|
454
|
+
* Under the default `'strict'` policy this field has no effect
|
|
455
|
+
* — both transactional and broadcast sends get blocked. Apps
|
|
456
|
+
* that need to send password-reset emails to bounced addresses
|
|
457
|
+
* (rare, but legitimate) opt into `'transactional-allowed'` AND
|
|
458
|
+
* tag the message.
|
|
459
|
+
*/
|
|
460
|
+
tag?: 'transactional' | 'broadcast'
|
|
367
461
|
}
|
|
368
462
|
|
|
369
463
|
// Email interfaces
|