@stacksjs/types 0.70.23 → 0.70.25
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/dist/index.js +1 -1
- package/dist/src/ai.d.ts +37 -0
- package/dist/src/analytics.d.ts +36 -0
- package/dist/src/api.d.ts +26 -0
- package/dist/src/app.d.ts +28 -0
- package/dist/src/attributes.d.ts +1 -0
- package/dist/src/auth.d.ts +49 -0
- package/dist/src/auto-imports.d.ts +8 -0
- package/dist/{binary.d.ts → src/binary.d.ts} +4 -1
- package/dist/src/cache.d.ts +79 -0
- package/dist/{cdn.d.ts → src/cdn.d.ts} +1 -1
- package/dist/{chat.d.ts → src/chat.d.ts} +29 -48
- package/dist/src/cli.d.ts +308 -0
- package/dist/{cloud.d.ts → src/cloud.d.ts} +81 -26
- package/dist/{components.d.ts → src/components.d.ts} +1 -4
- package/dist/{configure.d.ts → src/configure.d.ts} +1 -1
- package/dist/{cron-jobs.d.ts → src/cron-jobs.d.ts} +33 -37
- package/dist/src/dashboard.d.ts +33 -0
- package/dist/{database.d.ts → src/database.d.ts} +20 -12
- package/dist/src/dependencies.d.ts +17 -0
- package/dist/src/deploy.d.ts +16 -0
- package/dist/{dns.d.ts → src/dns.d.ts} +59 -59
- package/dist/src/docs.d.ts +23 -0
- package/dist/src/email.d.ts +201 -0
- package/dist/src/env.d.ts +1 -0
- package/dist/{errors.d.ts → src/errors.d.ts} +17 -24
- package/dist/src/events.d.ts +31 -0
- package/dist/src/exit-code.d.ts +10 -0
- package/dist/{file-systems.d.ts → src/file-systems.d.ts} +10 -6
- package/dist/{git.d.ts → src/git.d.ts} +9 -6
- package/dist/src/hashing.d.ts +57 -0
- package/dist/src/helpers.d.ts +1 -0
- package/dist/src/i18n.d.ts +65 -0
- package/dist/src/index.d.ts +70 -0
- package/dist/{library.d.ts → src/library.d.ts} +31 -33
- package/dist/src/logging.d.ts +12 -0
- package/dist/{manifest.d.ts → src/manifest.d.ts} +4 -1
- package/dist/src/model-names.d.ts +1 -0
- package/dist/src/model.d.ts +251 -0
- package/dist/{notifications.d.ts → src/notifications.d.ts} +1 -26
- package/dist/src/oauth.d.ts +290 -0
- package/dist/{pages.d.ts → src/pages.d.ts} +1 -1
- package/dist/src/payments.d.ts +322 -0
- package/dist/src/phone.d.ts +52 -0
- package/dist/src/ports.d.ts +20 -0
- package/dist/src/promise.d.ts +1 -0
- package/dist/src/push.d.ts +108 -0
- package/dist/src/queue.d.ts +310 -0
- package/dist/src/reactivity.d.ts +1 -0
- package/dist/src/realtime.d.ts +443 -0
- package/dist/src/request.d.ts +154 -0
- package/dist/{response.d.ts → src/response.d.ts} +1 -1
- package/dist/src/router.d.ts +105 -0
- package/dist/{saas.d.ts → src/saas.d.ts} +2 -2
- package/dist/src/scheduler.d.ts +1 -0
- package/dist/{search-engine.d.ts → src/search-engine.d.ts} +41 -45
- package/dist/{security.d.ts → src/security.d.ts} +4 -8
- package/dist/{server.d.ts → src/server.d.ts} +1 -1
- package/dist/src/services.d.ts +140 -0
- package/dist/{settings-config.d.ts → src/settings-config.d.ts} +1 -1
- package/dist/src/sms.d.ts +144 -0
- package/dist/src/stack-extensions.d.ts +137 -0
- package/dist/src/stacks.d.ts +40 -0
- package/dist/src/storage.d.ts +105 -0
- package/dist/src/table-names.d.ts +1 -0
- package/dist/src/tables.d.ts +34 -0
- package/dist/src/team.d.ts +7 -0
- package/dist/src/ui.d.ts +55 -0
- package/dist/src/utils.d.ts +39 -0
- package/package.json +13 -32
- package/src/ai.ts +20 -6
- package/src/analytics.ts +38 -1
- package/src/app.ts +38 -0
- package/src/attributes.ts +5 -1
- package/src/auth.ts +122 -0
- package/src/auto-imports.ts +8 -1
- package/src/cache.ts +226 -69
- package/src/chat.ts +0 -20
- package/src/cli.ts +24 -9
- package/src/cloud.ts +40 -1
- package/src/components.ts +3 -5
- package/src/cron-jobs.ts +1 -1
- package/src/dashboard.ts +40 -0
- package/src/database.ts +18 -2
- package/src/dns.ts +1 -1
- package/src/docs.ts +3 -3
- package/src/email.ts +303 -13
- package/src/errors.ts +2 -3
- package/src/events.ts +10 -5
- package/src/git.ts +3 -3
- package/src/hashing.ts +15 -19
- package/src/i18n.ts +105 -3
- package/src/index.ts +9 -5
- package/src/library.ts +0 -5
- package/src/model-names.ts +1 -1
- package/src/model.ts +87 -10
- package/src/oauth.ts +488 -0
- package/src/payments.ts +370 -27
- package/src/phone.ts +62 -0
- package/src/push.ts +107 -0
- package/src/queue.ts +386 -28
- package/src/reactivity.ts +1 -1
- package/src/realtime.ts +584 -0
- package/src/request.ts +344 -22
- package/src/router.ts +62 -4
- package/src/search-engine.ts +13 -13
- package/src/services.ts +100 -5
- package/src/sms.ts +263 -3
- package/src/stack-extensions.ts +184 -0
- package/src/stacks.ts +34 -4
- package/src/storage.ts +140 -6
- package/src/table-names.ts +1 -1
- package/src/ui.ts +20 -12
- package/src/utils.ts +1 -1
- package/dist/ai.d.ts +0 -20
- package/dist/analytics.d.ts +0 -13
- package/dist/api.d.ts +0 -26
- package/dist/app.d.ts +0 -32
- package/dist/attributes.d.ts +0 -1
- package/dist/auto-imports.d.ts +0 -1
- package/dist/build.d.ts +0 -2
- package/dist/cache.d.ts +0 -49
- package/dist/cli.d.ts +0 -310
- package/dist/dependencies.d.ts +0 -16
- package/dist/deploy.d.ts +0 -10
- package/dist/docs.d.ts +0 -26
- package/dist/email.d.ts +0 -107
- package/dist/events.d.ts +0 -5
- package/dist/exit-code.d.ts +0 -5
- package/dist/hashing.d.ts +0 -36
- package/dist/helpers.d.ts +0 -1
- package/dist/i18n.d.ts +0 -11
- package/dist/index.d.ts +0 -65
- package/dist/inspect.d.ts +0 -3
- package/dist/logging.d.ts +0 -6
- package/dist/model-names.d.ts +0 -1
- package/dist/model.d.ts +0 -232
- package/dist/payments.d.ts +0 -94
- package/dist/ports.d.ts +0 -13
- package/dist/promise.d.ts +0 -1
- package/dist/push.d.ts +0 -35
- package/dist/pwa.d.ts +0 -3
- package/dist/queue.d.ts +0 -45
- package/dist/reactivity.d.ts +0 -1
- package/dist/request.d.ts +0 -49
- package/dist/router.d.ts +0 -65
- package/dist/scheduler.d.ts +0 -1
- package/dist/services.d.ts +0 -81
- package/dist/ssg.d.ts +0 -3
- package/dist/stacks.d.ts +0 -54
- package/dist/storage.d.ts +0 -31
- package/dist/table-names.d.ts +0 -1
- package/dist/tables.d.ts +0 -34
- package/dist/team.d.ts +0 -8
- package/dist/ui.d.ts +0 -47
- package/dist/utils.d.ts +0 -27
- package/src/build.ts +0 -2
- package/src/inspect.ts +0 -10
- package/src/layout.ts +0 -8
- package/src/pwa.ts +0 -8
- package/src/ssg.ts +0 -3
package/src/request.ts
CHANGED
|
@@ -1,49 +1,371 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ModelRow } from '@stacksjs/orm'
|
|
2
|
+
import { User } from '@stacksjs/orm'
|
|
3
|
+
import type { UploadedFile } from '@stacksjs/storage'
|
|
4
|
+
import type { AuthToken, RouteParam } from '@stacksjs/types'
|
|
5
|
+
|
|
6
|
+
type UserJsonResponse = ModelRow<typeof User>
|
|
2
7
|
|
|
3
|
-
export type * from '../../../types/requests'
|
|
4
8
|
interface RequestData {
|
|
5
9
|
[key: string]: any
|
|
6
10
|
}
|
|
7
11
|
|
|
8
12
|
type RouteParams = { [key: string]: string | number } | null
|
|
9
13
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
14
|
+
type NumericField = 'id' | 'age' | 'count' | 'quantity' | 'amount' | 'price' | 'total' | 'score' | 'rating' | 'duration' | 'size' | 'weight' | 'height' | 'width' | 'length' | 'distance' | 'speed' | 'temperature' | 'volume' | 'capacity' | 'density' | 'pressure' | 'force' | 'energy' | 'power' | 'frequency' | 'voltage' | 'current' | 'resistance' | 'time' | 'date' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' | 'microsecond' | 'nanosecond'
|
|
15
|
+
|
|
16
|
+
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Collection interface for array data (Laravel-style)
|
|
20
|
+
*/
|
|
21
|
+
export interface Collection<T> {
|
|
22
|
+
items: T[]
|
|
23
|
+
count: () => number
|
|
24
|
+
first: () => T | undefined
|
|
25
|
+
last: () => T | undefined
|
|
26
|
+
map: <U>(fn: (item: T, index: number) => U) => Collection<U>
|
|
27
|
+
filter: (fn: (item: T, index: number) => boolean) => Collection<T>
|
|
28
|
+
find: (fn: (item: T, index: number) => boolean) => T | undefined
|
|
29
|
+
reduce: <U>(fn: (acc: U, item: T, index: number) => U, initial: U) => U
|
|
30
|
+
forEach: (fn: (item: T, index: number) => void) => void
|
|
31
|
+
toArray: () => T[]
|
|
32
|
+
isEmpty: () => boolean
|
|
33
|
+
isNotEmpty: () => boolean
|
|
34
|
+
pluck: <K extends keyof T>(key: K) => Collection<T[K]>
|
|
35
|
+
unique: () => Collection<T>
|
|
36
|
+
sortBy: <K extends keyof T>(key: K, direction?: 'asc' | 'desc') => Collection<T>
|
|
37
|
+
groupBy: <K extends keyof T>(key: K) => Map<T[K], Collection<T>>
|
|
38
|
+
chunk: (size: number) => Collection<Collection<T>>
|
|
39
|
+
take: (count: number) => Collection<T>
|
|
40
|
+
skip: (count: number) => Collection<T>
|
|
41
|
+
reverse: () => Collection<T>
|
|
42
|
+
sum: (key?: keyof T) => number
|
|
43
|
+
avg: (key?: keyof T) => number
|
|
44
|
+
min: (key?: keyof T) => T | undefined
|
|
45
|
+
max: (key?: keyof T) => T | undefined
|
|
13
46
|
}
|
|
14
47
|
|
|
15
|
-
|
|
16
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Safe validated data wrapper (Laravel-style)
|
|
50
|
+
*/
|
|
51
|
+
export interface SafeData<T extends Record<string, any> = Record<string, any>> {
|
|
52
|
+
only: <K extends keyof T>(keys: K[]) => Pick<T, K>
|
|
53
|
+
except: <K extends keyof T>(keys: K[]) => Omit<T, K>
|
|
54
|
+
merge: <U extends Record<string, unknown>>(data: U) => T & U
|
|
55
|
+
all: () => T
|
|
56
|
+
has: (key: keyof T) => boolean
|
|
57
|
+
get: <K extends keyof T>(key: K) => T[K]
|
|
17
58
|
}
|
|
18
59
|
|
|
19
|
-
|
|
20
|
-
|
|
60
|
+
/**
|
|
61
|
+
* RequestInstance - Generic, model-aware request interface with Laravel-style methods.
|
|
62
|
+
*
|
|
63
|
+
* When used bare (`RequestInstance`), all methods accept any string keys (backward compatible).
|
|
64
|
+
* When parameterized with model fields (`RequestInstance<{ title: string, views: number }>`),
|
|
65
|
+
* all input methods narrow to those fields with full autocomplete and type inference.
|
|
66
|
+
*
|
|
67
|
+
* The global type alias connects this to models:
|
|
68
|
+
* `RequestInstance<typeof Post>` → narrows to Post's fields automatically.
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* // Untyped (accepts any key)
|
|
72
|
+
* function handle(request: RequestInstance) {
|
|
73
|
+
* request.get('anything') // returns any
|
|
74
|
+
* }
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* // Model-aware (narrows to Post's fields)
|
|
78
|
+
* function handle(request: RequestInstance<typeof Post>) {
|
|
79
|
+
* request.get('title') // autocompletes, returns string
|
|
80
|
+
* request.get('views') // autocompletes, returns number
|
|
81
|
+
* request.get('invalid') // TS error!
|
|
82
|
+
* const data = await request.validate() // returns typed Post fields
|
|
83
|
+
* }
|
|
84
|
+
*/
|
|
85
|
+
/**
|
|
86
|
+
* Public alias for `RequestInstance<TFields>`. Use this in actions when
|
|
87
|
+
* you want to type the `request` argument explicitly (e.g. without
|
|
88
|
+
* pulling in a model object).
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { Action } from '@stacksjs/actions'
|
|
93
|
+
* import type { ActionRequest } from '@stacksjs/types'
|
|
94
|
+
*
|
|
95
|
+
* type CreatePostInput = { title: string; body: string }
|
|
96
|
+
*
|
|
97
|
+
* export default new Action({
|
|
98
|
+
* name: 'CreatePost',
|
|
99
|
+
* handle(request: ActionRequest<CreatePostInput>) {
|
|
100
|
+
* const { title, body } = request.only(['title', 'body'])
|
|
101
|
+
* // ^ inferred as { title: string; body: string }
|
|
102
|
+
* },
|
|
103
|
+
* })
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export type ActionRequest<TFields extends Record<string, any> = Record<string, any>> = RequestInstance<TFields>
|
|
21
107
|
|
|
22
|
-
|
|
108
|
+
export interface RequestInstance<TFields extends Record<string, any> = Record<string, any>> {
|
|
109
|
+
// ==========================================================================
|
|
110
|
+
// Native Request properties
|
|
111
|
+
// ==========================================================================
|
|
23
112
|
|
|
24
|
-
|
|
113
|
+
url: string
|
|
114
|
+
method: string
|
|
115
|
+
headers: Headers
|
|
25
116
|
|
|
26
|
-
|
|
117
|
+
// Raw data access (always untyped — use get()/input() for typed access)
|
|
118
|
+
query: RequestData
|
|
119
|
+
params: RouteParams
|
|
120
|
+
jsonBody?: any
|
|
121
|
+
formBody?: any
|
|
122
|
+
files: Record<string, File | File[]>
|
|
27
123
|
|
|
28
|
-
|
|
124
|
+
// ==========================================================================
|
|
125
|
+
// Model-aware Input Methods
|
|
126
|
+
//
|
|
127
|
+
// Keys narrow to `keyof TFields` when a model type is provided.
|
|
128
|
+
// Return types narrow to the field's actual type.
|
|
129
|
+
// ==========================================================================
|
|
29
130
|
|
|
30
|
-
|
|
131
|
+
/**
|
|
132
|
+
* Get input value from any source (query, body, params)
|
|
133
|
+
* @example request.get('title') // returns string (when model-aware)
|
|
134
|
+
* @example request.get('views', 0) // returns number with default
|
|
135
|
+
*/
|
|
136
|
+
get: <K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]) => TFields[K]
|
|
31
137
|
|
|
32
|
-
|
|
138
|
+
/**
|
|
139
|
+
* Alias for get() - Laravel compatibility
|
|
140
|
+
*/
|
|
141
|
+
input: <K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]) => TFields[K]
|
|
33
142
|
|
|
34
|
-
|
|
143
|
+
/**
|
|
144
|
+
* Get all input data (typed to model fields when model-aware)
|
|
145
|
+
*/
|
|
146
|
+
all: () => TFields
|
|
35
147
|
|
|
36
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Get only specified keys — returns a precisely picked type
|
|
150
|
+
* @example request.only(['title', 'views']) // { title: string, views: number }
|
|
151
|
+
*/
|
|
152
|
+
only: <K extends keyof TFields & string>(keys: K[]) => Pick<TFields, K>
|
|
37
153
|
|
|
38
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Get all except specified keys — returns a precisely omitted type
|
|
156
|
+
* @example request.except(['id', 'created_at']) // omits those fields
|
|
157
|
+
*/
|
|
158
|
+
except: <K extends keyof TFields & string>(keys: K[]) => Omit<TFields, K>
|
|
39
159
|
|
|
40
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Check if input has a key (or all keys if array) — keys narrowed to model fields
|
|
162
|
+
* @example request.has('title')
|
|
163
|
+
* @example request.has(['title', 'views'])
|
|
164
|
+
*/
|
|
165
|
+
has: (key: (keyof TFields & string) | (keyof TFields & string)[]) => boolean
|
|
41
166
|
|
|
42
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Check if input has any of the specified keys
|
|
169
|
+
* @example request.hasAny(['title', 'views'])
|
|
170
|
+
*/
|
|
171
|
+
hasAny: (keys: (keyof TFields & string)[]) => boolean
|
|
43
172
|
|
|
44
|
-
|
|
173
|
+
/**
|
|
174
|
+
* Check if input is filled (present and not empty)
|
|
175
|
+
* @example request.filled('title')
|
|
176
|
+
*/
|
|
177
|
+
filled: (key: (keyof TFields & string) | (keyof TFields & string)[]) => boolean
|
|
45
178
|
|
|
46
|
-
|
|
179
|
+
/**
|
|
180
|
+
* Check if input is missing
|
|
181
|
+
* @example request.missing('title')
|
|
182
|
+
*/
|
|
183
|
+
missing: (key: (keyof TFields & string) | (keyof TFields & string)[]) => boolean
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Merge additional data into input — accepts partial model fields
|
|
187
|
+
*/
|
|
188
|
+
merge: (data: Partial<TFields>) => void
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Get all input keys — returns model field names when model-aware
|
|
192
|
+
*/
|
|
193
|
+
keys: () => (keyof TFields & string)[]
|
|
194
|
+
|
|
195
|
+
// ==========================================================================
|
|
196
|
+
// Type-casting Methods — keys narrowed to model fields
|
|
197
|
+
// ==========================================================================
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get string input
|
|
201
|
+
* @example request.string('title')
|
|
202
|
+
*/
|
|
203
|
+
string: (key: keyof TFields & string, defaultValue?: string) => string
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Get integer input
|
|
207
|
+
* @example request.integer('views', 0)
|
|
208
|
+
*/
|
|
209
|
+
integer: (key: keyof TFields & string, defaultValue?: number) => number
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get float input
|
|
213
|
+
* @example request.float('price', 0.0)
|
|
214
|
+
*/
|
|
215
|
+
float: (key: keyof TFields & string, defaultValue?: number) => number
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Get boolean input
|
|
219
|
+
* @example request.boolean('is_active', false)
|
|
220
|
+
*/
|
|
221
|
+
boolean: (key: keyof TFields & string, defaultValue?: boolean) => boolean
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Get input as array
|
|
225
|
+
* @example request.array('tags')
|
|
226
|
+
*/
|
|
227
|
+
array: <T = unknown>(key: keyof TFields & string) => T[]
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Parse date input
|
|
231
|
+
* @example request.date('published_at')
|
|
232
|
+
*/
|
|
233
|
+
date: (key: keyof TFields & string, format?: string) => Date | null
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Parse enum input
|
|
237
|
+
* @example request.enum('status', StatusEnum)
|
|
238
|
+
*/
|
|
239
|
+
enum: <T extends Record<string, string | number>>(key: keyof TFields & string, enumType: T) => T[keyof T] | null
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get input as collection
|
|
243
|
+
* @example request.collect('items')
|
|
244
|
+
*/
|
|
245
|
+
collect: <T = unknown>(key: keyof TFields & string) => Collection<T>
|
|
246
|
+
|
|
247
|
+
// ==========================================================================
|
|
248
|
+
// Validation Methods — returns typed model fields when model-aware
|
|
249
|
+
// ==========================================================================
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* Validate the request data.
|
|
253
|
+
* When model-aware, rules are optional (uses model's attribute validation).
|
|
254
|
+
* Returns the validated data typed to model fields.
|
|
255
|
+
*
|
|
256
|
+
* @example await request.validate() // uses model rules
|
|
257
|
+
* @example await request.validate({ name: 'required' }) // custom rules
|
|
258
|
+
*/
|
|
259
|
+
validate: (rules?: Record<string, string>, messages?: Record<string, string>) => Promise<TFields>
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Get previously validated data, typed to model fields
|
|
263
|
+
*/
|
|
264
|
+
getValidated: () => TFields
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get safe validated data wrapper with typed access
|
|
268
|
+
* @example request.safe().only(['title', 'views']) // Pick<TFields, 'title' | 'views'>
|
|
269
|
+
* @example request.safe().get('title') // string
|
|
270
|
+
*/
|
|
271
|
+
safe: () => SafeData<TFields>
|
|
47
272
|
|
|
273
|
+
// ==========================================================================
|
|
274
|
+
// Conditional Methods — keys narrowed to model fields
|
|
275
|
+
// ==========================================================================
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Execute callback when input has a value
|
|
279
|
+
* @example request.whenHas('title', (value) => console.log(value))
|
|
280
|
+
*/
|
|
281
|
+
whenHas: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Execute callback when input is filled
|
|
285
|
+
* @example request.whenFilled('title', (value) => console.log(value))
|
|
286
|
+
*/
|
|
287
|
+
whenFilled: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Check if input matches a value
|
|
291
|
+
*/
|
|
292
|
+
isValue: (key: keyof TFields & string, value: unknown) => boolean
|
|
293
|
+
|
|
294
|
+
// ==========================================================================
|
|
295
|
+
// File Methods — not narrowed to model fields (files are independent)
|
|
296
|
+
// ==========================================================================
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Get an uploaded file by key
|
|
300
|
+
* @example const avatar = request.file('avatar')
|
|
301
|
+
* @example await avatar?.store('avatars')
|
|
302
|
+
*/
|
|
303
|
+
file: (key: string) => UploadedFile | null
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Get all uploaded files for a key (for multiple file inputs)
|
|
307
|
+
*/
|
|
308
|
+
getFiles: (key: string) => UploadedFile[]
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Check if a file was uploaded
|
|
312
|
+
*/
|
|
313
|
+
hasFile: (key: string) => boolean
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Get all uploaded files
|
|
317
|
+
*/
|
|
318
|
+
allFiles: () => Record<string, UploadedFile | UploadedFile[]>
|
|
319
|
+
|
|
320
|
+
// ==========================================================================
|
|
321
|
+
// Header Methods
|
|
322
|
+
// ==========================================================================
|
|
323
|
+
|
|
324
|
+
header: (key: string) => string | null
|
|
325
|
+
bearerToken: () => string | null | AuthToken
|
|
326
|
+
|
|
327
|
+
// ==========================================================================
|
|
328
|
+
// Route & Param Methods — not narrowed to model fields
|
|
329
|
+
// ==========================================================================
|
|
330
|
+
|
|
331
|
+
getParam: <K extends string>(key: K) => K extends NumericField ? number : string
|
|
332
|
+
route: (key: string) => number | string | null
|
|
333
|
+
getParams: () => RouteParams
|
|
48
334
|
getParamAsInt: (key: string) => number | null
|
|
335
|
+
|
|
336
|
+
// ==========================================================================
|
|
337
|
+
// Session/Flash Methods — keys narrowed to model fields
|
|
338
|
+
// ==========================================================================
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Get old input (for form repopulation)
|
|
342
|
+
*/
|
|
343
|
+
old: <T = unknown>(key: keyof TFields & string, defaultValue?: T) => T
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Flash input to session for form repopulation
|
|
347
|
+
*/
|
|
348
|
+
flashInput: (keys?: (keyof TFields & string)[]) => void
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Flash only specific keys
|
|
352
|
+
*/
|
|
353
|
+
flashInputOnly: (keys: (keyof TFields & string)[]) => void
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Flash except specific keys
|
|
357
|
+
*/
|
|
358
|
+
flashInputExcept: (keys: (keyof TFields & string)[]) => void
|
|
359
|
+
|
|
360
|
+
// ==========================================================================
|
|
361
|
+
// Utility Methods
|
|
362
|
+
// ==========================================================================
|
|
363
|
+
|
|
364
|
+
json: <T = any>() => Promise<T>
|
|
365
|
+
isEmpty: () => boolean
|
|
366
|
+
browser: () => string | null
|
|
367
|
+
ip: () => string | null
|
|
368
|
+
ipForRateLimit: () => string | null
|
|
369
|
+
getMethod: () => HttpMethod
|
|
370
|
+
user: () => Promise<UserJsonResponse | undefined>
|
|
49
371
|
}
|
package/src/router.ts
CHANGED
|
@@ -1,10 +1,30 @@
|
|
|
1
1
|
import type { Action } from '@stacksjs/actions'
|
|
2
|
+
type Request = any
|
|
3
|
+
import type { ValidationType } from '@stacksjs/ts-validation'
|
|
4
|
+
import type { HttpMethod } from './request'
|
|
2
5
|
|
|
3
6
|
type ActionPath = string
|
|
4
7
|
// need to refactor before, after, view to be a part of some other type
|
|
5
|
-
export type
|
|
8
|
+
export type RouteCallback = ((_params?: Record<string, any>) => any | string | object) | ((req: any, res: any) => Promise<void>)
|
|
6
9
|
|
|
7
|
-
export
|
|
10
|
+
export interface RequestData {
|
|
11
|
+
[key: string]: any
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ValidationField {
|
|
15
|
+
rule: ValidationType
|
|
16
|
+
message: Record<string, string>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type RouterAuthToken = `${number}:${number}:${string}`
|
|
20
|
+
|
|
21
|
+
export interface CustomAttributes {
|
|
22
|
+
[key: string]: ValidationField
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface RouteParams { [key: string]: string | number }
|
|
26
|
+
|
|
27
|
+
export type NumericField = 'id' | 'age' | 'count' | 'quantity' | 'amount' | 'price' | 'total' | 'score' | 'rating' | 'duration' | 'size' | 'weight' | 'height' | 'width' | 'length' | 'distance' | 'speed' | 'temperature' | 'volume' | 'capacity' | 'density' | 'pressure' | 'force' | 'energy' | 'power' | 'frequency' | 'voltage' | 'current' | 'resistance' | 'time' | 'date' | 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' | 'millisecond' | 'microsecond' | 'nanosecond'
|
|
8
28
|
|
|
9
29
|
export interface Route {
|
|
10
30
|
name: string
|
|
@@ -20,11 +40,22 @@ export interface Route {
|
|
|
20
40
|
statusCode?: StatusCode
|
|
21
41
|
}
|
|
22
42
|
|
|
43
|
+
export interface ServeOptions {
|
|
44
|
+
host?: string
|
|
45
|
+
port?: number
|
|
46
|
+
debug?: boolean
|
|
47
|
+
timezone?: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface Options {
|
|
51
|
+
statusCode?: StatusCode
|
|
52
|
+
}
|
|
53
|
+
|
|
23
54
|
export interface MiddlewareOptions {
|
|
24
55
|
name: string
|
|
25
56
|
description?: string
|
|
26
57
|
priority: number
|
|
27
|
-
handle: () => Promise<void>
|
|
58
|
+
handle: (request: Request) => Promise<void> | void
|
|
28
59
|
}
|
|
29
60
|
|
|
30
61
|
export type StatusCode = 200 | 201 | 202 | 204 | 301 | 302 | 304 | 400 | 401 | 403 | 404 | 500
|
|
@@ -32,7 +63,7 @@ export type RedirectCode = Extract<StatusCode, 301 | 302>
|
|
|
32
63
|
|
|
33
64
|
export interface RouteParam { [key: string]: string | number }
|
|
34
65
|
|
|
35
|
-
export type MiddlewareFn = () => void
|
|
66
|
+
export type MiddlewareFn = (_request: Request) => Promise<void>
|
|
36
67
|
|
|
37
68
|
export interface Middlewares {
|
|
38
69
|
logger: MiddlewareFn
|
|
@@ -64,3 +95,30 @@ export interface RouterInterface {
|
|
|
64
95
|
middleware: (middleware: Route['middleware']) => this
|
|
65
96
|
getRoutes: () => Promise<Route[]>
|
|
66
97
|
}
|
|
98
|
+
|
|
99
|
+
export interface RouterInstance {
|
|
100
|
+
query: any
|
|
101
|
+
params: RouteParams
|
|
102
|
+
headers: any
|
|
103
|
+
addQuery: (url: URL) => void
|
|
104
|
+
addBodies: (params: any) => void
|
|
105
|
+
addParam: (param: RouteParam) => void
|
|
106
|
+
addHeaders: (headerParams: Headers) => void
|
|
107
|
+
get: <K extends string>(element: K, defaultValue?: K extends NumericField ? number : string) => K extends NumericField ? number : string
|
|
108
|
+
all: () => any
|
|
109
|
+
validate: (attributes?: CustomAttributes) => Promise<void>
|
|
110
|
+
has: (element: string) => boolean
|
|
111
|
+
isEmpty: () => boolean
|
|
112
|
+
extractParamsFromRoute: (routePattern: string, pathname: string) => void
|
|
113
|
+
header: (headerParam: string) => string | number | boolean | null
|
|
114
|
+
getHeaders: () => any
|
|
115
|
+
Header: (headerParam: string) => string | number | boolean | null
|
|
116
|
+
getParam: <T>(key: string) => T
|
|
117
|
+
route: (key: string) => number | string | null
|
|
118
|
+
bearerToken: () => string | null | RouterAuthToken
|
|
119
|
+
getParams: () => RouteParams
|
|
120
|
+
getParamAsInt: (key: string) => number | null
|
|
121
|
+
browser: () => string | null
|
|
122
|
+
ip: () => string | null
|
|
123
|
+
ipForRateLimit: () => string | null
|
|
124
|
+
}
|
package/src/search-engine.ts
CHANGED
|
@@ -37,16 +37,10 @@ export interface SearchEngineOptions {
|
|
|
37
37
|
*
|
|
38
38
|
* The search engine to utilize.
|
|
39
39
|
*
|
|
40
|
-
* @default string '
|
|
41
|
-
* @see https://stacksjs.
|
|
40
|
+
* @default string 'meilisearch'
|
|
41
|
+
* @see https://stacksjs.com/docs/search-engine
|
|
42
42
|
*/
|
|
43
|
-
driver: 'opensearch'
|
|
44
|
-
// driver: 'meilisearch' | 'algolia' | 'typesense' | 'opensearch' wip
|
|
45
|
-
|
|
46
|
-
// meilisearch?: {
|
|
47
|
-
// host: string
|
|
48
|
-
// apiKey: string
|
|
49
|
-
// }
|
|
43
|
+
driver: 'meilisearch' | 'algolia' | 'opensearch'
|
|
50
44
|
|
|
51
45
|
opensearch?: {
|
|
52
46
|
host: string
|
|
@@ -57,10 +51,16 @@ export interface SearchEngineOptions {
|
|
|
57
51
|
|
|
58
52
|
meilisearch?: {
|
|
59
53
|
host: string
|
|
60
|
-
protocol
|
|
61
|
-
port
|
|
62
|
-
auth
|
|
54
|
+
protocol?: number
|
|
55
|
+
port?: number
|
|
56
|
+
auth?: string
|
|
57
|
+
apiKey: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
algolia?: {
|
|
61
|
+
appId: string
|
|
63
62
|
apiKey: string
|
|
63
|
+
searchOnlyApiKey?: string
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
filters?: {
|
|
@@ -79,6 +79,7 @@ export type SearchEngineConfig = Partial<SearchEngineOptions>
|
|
|
79
79
|
|
|
80
80
|
export interface SearchEngineDriver {
|
|
81
81
|
client: () => MeiliSearch
|
|
82
|
+
resetClient?: () => void
|
|
82
83
|
|
|
83
84
|
search: (index: string, params: any) => Promise<SearchResponse<Record<string, any>>>
|
|
84
85
|
|
|
@@ -116,7 +117,6 @@ export interface SearchEngineDriver {
|
|
|
116
117
|
getSettings: (index: string) => Promise<Settings>
|
|
117
118
|
updateSettings: (index: string, settings: Settings) => Promise<EnqueuedTask>
|
|
118
119
|
resetSettings: (index: string) => Promise<EnqueuedTask>
|
|
119
|
-
å
|
|
120
120
|
getPagination: (index: string) => Promise<PaginationSettings>
|
|
121
121
|
updatePagination: (index: string, pagination: PaginationSettings) => Promise<EnqueuedTask>
|
|
122
122
|
resetPagination: (index: string) => Promise<EnqueuedTask>
|
package/src/services.ts
CHANGED
|
@@ -11,6 +11,34 @@ export interface ServicesOptions {
|
|
|
11
11
|
region: string
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
github?: {
|
|
15
|
+
clientId: string
|
|
16
|
+
clientSecret: string
|
|
17
|
+
redirectUrl: string
|
|
18
|
+
scopes?: string[]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
google?: {
|
|
22
|
+
clientId: string
|
|
23
|
+
clientSecret: string
|
|
24
|
+
redirectUrl: string
|
|
25
|
+
scopes?: string[]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
facebook?: {
|
|
29
|
+
clientId: string
|
|
30
|
+
clientSecret: string
|
|
31
|
+
redirectUrl: string
|
|
32
|
+
scopes?: string[]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
twitter?: {
|
|
36
|
+
clientId: string
|
|
37
|
+
clientSecret: string
|
|
38
|
+
redirectUrl: string
|
|
39
|
+
scopes?: string[]
|
|
40
|
+
}
|
|
41
|
+
|
|
14
42
|
godaddy?: {
|
|
15
43
|
apiKey: string
|
|
16
44
|
apiSecret: string
|
|
@@ -68,17 +96,84 @@ export interface ServicesOptions {
|
|
|
68
96
|
retryTimeout?: number
|
|
69
97
|
}
|
|
70
98
|
|
|
99
|
+
/**
|
|
100
|
+
* SMTP Configuration for local development
|
|
101
|
+
* Works with HELO, Mailtrap Desktop, Mailhog, etc.
|
|
102
|
+
*/
|
|
103
|
+
smtp?: {
|
|
104
|
+
host: string
|
|
105
|
+
port: number
|
|
106
|
+
username?: string
|
|
107
|
+
password?: string
|
|
108
|
+
encryption?: 'tls' | 'ssl' | null
|
|
109
|
+
maxRetries?: number
|
|
110
|
+
retryTimeout?: number
|
|
111
|
+
}
|
|
112
|
+
|
|
71
113
|
slack?: {
|
|
72
|
-
appId
|
|
73
|
-
clientId
|
|
74
|
-
secretKey
|
|
114
|
+
appId?: string
|
|
115
|
+
clientId?: string
|
|
116
|
+
secretKey?: string
|
|
117
|
+
webhookUrl?: string
|
|
118
|
+
botToken?: string
|
|
75
119
|
maxRetries?: number
|
|
76
120
|
retryTimeout?: number
|
|
77
121
|
}
|
|
78
122
|
|
|
123
|
+
discord?: {
|
|
124
|
+
webhookUrl?: string
|
|
125
|
+
botToken?: string
|
|
126
|
+
maxRetries?: number
|
|
127
|
+
retryTimeout?: number
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
teams?: {
|
|
131
|
+
webhookUrl?: string
|
|
132
|
+
maxRetries?: number
|
|
133
|
+
retryTimeout?: number
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Push Notification Services
|
|
137
|
+
expo?: {
|
|
138
|
+
accessToken?: string
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
fcm?: {
|
|
142
|
+
serverKey?: string
|
|
143
|
+
projectId?: string
|
|
144
|
+
clientEmail?: string
|
|
145
|
+
privateKey?: string
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// AI Services
|
|
149
|
+
openai?: {
|
|
150
|
+
apiKey?: string
|
|
151
|
+
model?: string
|
|
152
|
+
embeddingModel?: string
|
|
153
|
+
baseUrl?: string
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
anthropic?: {
|
|
157
|
+
apiKey?: string
|
|
158
|
+
model?: string
|
|
159
|
+
maxTokens?: number
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
ollama?: {
|
|
163
|
+
host?: string
|
|
164
|
+
model?: string
|
|
165
|
+
embeddingModel?: string
|
|
166
|
+
}
|
|
167
|
+
|
|
79
168
|
stripe?: {
|
|
80
|
-
|
|
81
|
-
|
|
169
|
+
secretKey?: string
|
|
170
|
+
publicKey?: string
|
|
171
|
+
/**
|
|
172
|
+
* Pinned Stripe API version. Defaults to whatever the bundled SDK
|
|
173
|
+
* was compiled against; override here when rolling forward without
|
|
174
|
+
* a code change. Format: 'YYYY-MM-DD' or 'YYYY-MM-DD.preview'.
|
|
175
|
+
*/
|
|
176
|
+
apiVersion?: string
|
|
82
177
|
}
|
|
83
178
|
|
|
84
179
|
// supabase?: {
|