@stacksjs/types 0.70.86 → 0.70.88
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/package.json +19 -5
- package/dist/ai.d.ts +0 -37
- package/dist/analytics.d.ts +0 -36
- package/dist/api.d.ts +0 -26
- package/dist/app.d.ts +0 -28
- package/dist/attributes.d.ts +0 -1
- package/dist/auth.d.ts +0 -56
- package/dist/auto-imports.d.ts +0 -8
- package/dist/binary.d.ts +0 -11
- package/dist/cache.d.ts +0 -88
- package/dist/cdn.d.ts +0 -4
- package/dist/chat.d.ts +0 -69
- package/dist/cli.d.ts +0 -316
- package/dist/cloud.d.ts +0 -366
- package/dist/cms.d.ts +0 -12
- package/dist/commerce.d.ts +0 -14
- package/dist/components.d.ts +0 -9
- package/dist/configure.d.ts +0 -12
- package/dist/cors.d.ts +0 -47
- package/dist/cron-jobs.d.ts +0 -61
- package/dist/dashboard.d.ts +0 -108
- package/dist/database.d.ts +0 -76
- package/dist/dependencies.d.ts +0 -17
- package/dist/deploy.d.ts +0 -16
- package/dist/dns.d.ts +0 -362
- package/dist/docs.d.ts +0 -23
- package/dist/email.d.ts +0 -207
- package/dist/env.d.ts +0 -1
- package/dist/errors.d.ts +0 -84
- package/dist/events.d.ts +0 -31
- package/dist/exit-code.d.ts +0 -10
- package/dist/file-systems.d.ts +0 -60
- package/dist/git.d.ts +0 -60
- package/dist/hashing.d.ts +0 -57
- package/dist/helpers.d.ts +0 -1
- package/dist/i18n.d.ts +0 -65
- package/dist/index.d.ts +0 -79
- package/dist/index.js +0 -2
- package/dist/library.d.ts +0 -799
- package/dist/logging.d.ts +0 -15
- package/dist/manifest.d.ts +0 -9
- package/dist/marketing.d.ts +0 -12
- package/dist/model-dashboard-augmentation.d.ts +0 -8
- package/dist/model-names.d.ts +0 -1
- package/dist/model.d.ts +0 -256
- package/dist/monitoring.d.ts +0 -12
- package/dist/notifications.d.ts +0 -126
- package/dist/oauth.d.ts +0 -290
- package/dist/pages.d.ts +0 -10
- package/dist/payments.d.ts +0 -322
- package/dist/phone.d.ts +0 -65
- package/dist/ports.d.ts +0 -20
- package/dist/promise.d.ts +0 -1
- package/dist/push.d.ts +0 -108
- package/dist/queue.d.ts +0 -312
- package/dist/reactivity.d.ts +0 -1
- package/dist/realtime.d.ts +0 -443
- package/dist/request.d.ts +0 -265
- package/dist/response.d.ts +0 -15
- package/dist/router.d.ts +0 -105
- package/dist/saas.d.ts +0 -32
- package/dist/scheduler.d.ts +0 -1
- package/dist/search-engine.d.ts +0 -129
- package/dist/security.d.ts +0 -18
- package/dist/server.d.ts +0 -16
- package/dist/services.d.ts +0 -149
- package/dist/settings-config.d.ts +0 -9
- package/dist/sms.d.ts +0 -144
- package/dist/stack-extensions.d.ts +0 -137
- package/dist/stacks.d.ts +0 -45
- package/dist/storage.d.ts +0 -104
- package/dist/table-names.d.ts +0 -1
- package/dist/tables.d.ts +0 -34
- package/dist/team.d.ts +0 -7
- package/dist/ui.d.ts +0 -55
- package/dist/utils.d.ts +0 -39
- package/src/ai.ts +0 -41
- package/src/analytics.ts +0 -58
- package/src/api.ts +0 -77
- package/src/app.ts +0 -189
- package/src/attributes.ts +0 -5
- package/src/auth.ts +0 -161
- package/src/auto-imports.ts +0 -8
- package/src/binary.ts +0 -13
- package/src/cache.ts +0 -325
- package/src/cdn.ts +0 -17
- package/src/chat.ts +0 -193
- package/src/cli.ts +0 -445
- package/src/cloud.ts +0 -381
- package/src/cms.ts +0 -14
- package/src/commerce.ts +0 -18
- package/src/components.ts +0 -62
- package/src/configure.ts +0 -13
- package/src/cors.ts +0 -86
- package/src/cron-jobs.ts +0 -146
- package/src/dashboard.ts +0 -218
- package/src/database.ts +0 -117
- package/src/dependencies.ts +0 -69
- package/src/deploy.ts +0 -17
- package/src/dns.ts +0 -470
- package/src/docs.ts +0 -27
- package/src/email.ts +0 -511
- package/src/env.ts +0 -1
- package/src/errors.ts +0 -110
- package/src/events.ts +0 -37
- package/src/exit-code.ts +0 -10
- package/src/file-systems.ts +0 -70
- package/src/git.ts +0 -133
- package/src/hashing.ts +0 -127
- package/src/helpers.ts +0 -9
- package/src/i18n.ts +0 -121
- package/src/index.ts +0 -80
- package/src/library.ts +0 -911
- package/src/logging.ts +0 -62
- package/src/manifest.ts +0 -9
- package/src/marketing.ts +0 -14
- package/src/model-dashboard-augmentation.ts +0 -51
- package/src/model-names.ts +0 -1
- package/src/model.ts +0 -353
- package/src/monitoring.ts +0 -14
- package/src/native.ts +0 -0
- package/src/notifications.ts +0 -153
- package/src/oauth.ts +0 -488
- package/src/pages.ts +0 -10
- package/src/payments.ts +0 -440
- package/src/phone.ts +0 -78
- package/src/ports.ts +0 -20
- package/src/promise.ts +0 -1
- package/src/push.ts +0 -143
- package/src/queue.ts +0 -413
- package/src/reactivity.ts +0 -1
- package/src/realtime.ts +0 -584
- package/src/request.ts +0 -541
- package/src/response.ts +0 -16
- package/src/router.ts +0 -124
- package/src/saas.ts +0 -33
- package/src/scheduler.ts +0 -1
- package/src/search-engine.ts +0 -251
- package/src/security.ts +0 -23
- package/src/server.ts +0 -16
- package/src/services.ts +0 -211
- package/src/settings-config.ts +0 -10
- package/src/sms.ts +0 -265
- package/src/stack-extensions.ts +0 -184
- package/src/stacks.ts +0 -339
- package/src/storage.ts +0 -173
- package/src/table-names.ts +0 -1
- package/src/tables.ts +0 -57
- package/src/team.ts +0 -8
- package/src/ui.ts +0 -197
- package/src/utils.ts +0 -46
package/src/request.ts
DELETED
|
@@ -1,541 +0,0 @@
|
|
|
1
|
-
import { User } from '@stacksjs/orm'
|
|
2
|
-
import type { UploadedFile } from '@stacksjs/storage'
|
|
3
|
-
import type { AuthToken, RouteParam } from '@stacksjs/types'
|
|
4
|
-
// `Infer<T extends Validator<U>>` resolves to the validator's output
|
|
5
|
-
// type — `Infer<typeof schema.string()> → string`. Type-only import
|
|
6
|
-
// keeps this package free of a runtime ts-validation dependency.
|
|
7
|
-
import type { Infer } from '@stacksjs/ts-validation'
|
|
8
|
-
|
|
9
|
-
// Trait methods are attached dynamically by the Stacks model proxy. The
|
|
10
|
-
// open member bag reflects application-level traits that the framework's
|
|
11
|
-
// default User definition cannot know about ahead of time.
|
|
12
|
-
type UserJsonResponse = NonNullable<Awaited<ReturnType<typeof User.find>>> & Record<string, any>
|
|
13
|
-
|
|
14
|
-
interface RequestData {
|
|
15
|
-
[key: string]: any
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Loose route-param shape kept around for back-compat with code that
|
|
20
|
-
* predates {@link RequestInstance}'s `TParams` generic. New code should
|
|
21
|
-
* rely on the path-extracted `TParams` instead — see {@link ExtractParams}.
|
|
22
|
-
*
|
|
23
|
-
* @deprecated Use {@link ExtractParams}-driven typing on the action /
|
|
24
|
-
* route signature instead. URL route params are always strings at
|
|
25
|
-
* runtime; the `string | number` here misled callers into thinking
|
|
26
|
-
* the framework coerced numbers automatically (it doesn't —
|
|
27
|
-
* `Number(request.params.id)` is the correct pattern).
|
|
28
|
-
*/
|
|
29
|
-
type RouteParams = { [key: string]: string | number } | null
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Legacy hard-coded list of param names treated as `number` by
|
|
33
|
-
* {@link RequestInstance.getParam}. The name-match heuristic is
|
|
34
|
-
* brittle (`'judgeId'`, `'user_id'`, etc. all silently fall through
|
|
35
|
-
* to `string`) and will be retired in a future release.
|
|
36
|
-
*
|
|
37
|
-
* @deprecated The name-match returns `number` for these specific keys
|
|
38
|
-
* only — pass the value through {@link Number} or
|
|
39
|
-
* {@link RequestInstance.getParamAsInt} for explicit, predictable
|
|
40
|
-
* coercion. See stacksjs/stacks#1851 Phase 3.
|
|
41
|
-
*/
|
|
42
|
-
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'
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Cookie-access helper exposed via `request.cookies` on
|
|
46
|
-
* {@link RequestInstance}. The methods mirror bun-router's
|
|
47
|
-
* `CookieAccessor` — duplicated locally so this package doesn't
|
|
48
|
-
* have to depend on bun-router for a single type. Keep the surface
|
|
49
|
-
* in sync if bun-router extends its accessor.
|
|
50
|
-
*/
|
|
51
|
-
export interface RequestCookies {
|
|
52
|
-
get: (name: string) => string | undefined
|
|
53
|
-
set: (name: string, value: string, options?: {
|
|
54
|
-
path?: string
|
|
55
|
-
domain?: string
|
|
56
|
-
secure?: boolean
|
|
57
|
-
httpOnly?: boolean
|
|
58
|
-
sameSite?: 'strict' | 'lax' | 'none'
|
|
59
|
-
maxAge?: number
|
|
60
|
-
expires?: Date
|
|
61
|
-
}) => void
|
|
62
|
-
delete: (name: string, options?: { path?: string, domain?: string }) => void
|
|
63
|
-
getAll: () => Record<string, string>
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Template-literal helper that extracts named route params from a
|
|
68
|
-
* path string (stacksjs/stacks#1851 Phase 2a). Supports both Stacks's
|
|
69
|
-
* brace-style (`/users/{id}`) and Express-style (`/users/:id`) so a
|
|
70
|
-
* project using either gets typed `params` out of the box.
|
|
71
|
-
*
|
|
72
|
-
* @example
|
|
73
|
-
* ExtractParams<'/api/judges/{id}/follow'> // { id: string }
|
|
74
|
-
* ExtractParams<'/api/orders/:orderId/items/:itemId'> // { orderId: string, itemId: string }
|
|
75
|
-
* ExtractParams<'/api/health'> // Record<string, never>
|
|
76
|
-
*/
|
|
77
|
-
// Step 1: pull the next param name out of either `{name}` or `:name`,
|
|
78
|
-
// recurse on the rest, and union the keys.
|
|
79
|
-
type ExtractParamKeys<S extends string> =
|
|
80
|
-
// brace form: `…/{name}/…`
|
|
81
|
-
S extends `${string}{${infer Key}}${infer Rest}`
|
|
82
|
-
? Key | ExtractParamKeys<Rest>
|
|
83
|
-
// colon form: `…/:name/…` (colon must be at a segment boundary
|
|
84
|
-
// so we don't match `:` inside e.g. a port number; the `/` before
|
|
85
|
-
// it enforces that)
|
|
86
|
-
: S extends `${string}/:${infer Key}/${infer Rest}`
|
|
87
|
-
? KeyHead<Key> | ExtractParamKeys<`/${Rest}`>
|
|
88
|
-
// tail colon-form: `…/:name` (no trailing slash)
|
|
89
|
-
: S extends `${string}/:${infer Key}`
|
|
90
|
-
? KeyHead<Key>
|
|
91
|
-
: never
|
|
92
|
-
|
|
93
|
-
// `KeyHead<'name>'>` → `'name>'` because TS template literal infers
|
|
94
|
-
// the longest possible match. We need to handle params that are at
|
|
95
|
-
// the end of the path AND followed by a query string. This util
|
|
96
|
-
// truncates a captured key at the first non-name character.
|
|
97
|
-
type KeyHead<S extends string> =
|
|
98
|
-
S extends `${infer H}/${string}` ? H :
|
|
99
|
-
S extends `${infer H}?${string}` ? H :
|
|
100
|
-
S extends `${infer H}.${string}` ? H :
|
|
101
|
-
S
|
|
102
|
-
|
|
103
|
-
export type ExtractParams<S extends string> =
|
|
104
|
-
[ExtractParamKeys<S>] extends [never]
|
|
105
|
-
? Record<string, never>
|
|
106
|
-
: { [K in ExtractParamKeys<S>]: string }
|
|
107
|
-
|
|
108
|
-
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS' | 'CONNECT' | 'TRACE'
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Collection interface for array data (Laravel-style)
|
|
112
|
-
*/
|
|
113
|
-
export interface Collection<T> {
|
|
114
|
-
items: T[]
|
|
115
|
-
count: () => number
|
|
116
|
-
first: () => T | undefined
|
|
117
|
-
last: () => T | undefined
|
|
118
|
-
map: <U>(fn: (item: T, index: number) => U) => Collection<U>
|
|
119
|
-
filter: (fn: (item: T, index: number) => boolean) => Collection<T>
|
|
120
|
-
find: (fn: (item: T, index: number) => boolean) => T | undefined
|
|
121
|
-
reduce: <U>(fn: (acc: U, item: T, index: number) => U, initial: U) => U
|
|
122
|
-
forEach: (fn: (item: T, index: number) => void) => void
|
|
123
|
-
toArray: () => T[]
|
|
124
|
-
isEmpty: () => boolean
|
|
125
|
-
isNotEmpty: () => boolean
|
|
126
|
-
pluck: <K extends keyof T>(key: K) => Collection<T[K]>
|
|
127
|
-
unique: () => Collection<T>
|
|
128
|
-
sortBy: <K extends keyof T>(key: K, direction?: 'asc' | 'desc') => Collection<T>
|
|
129
|
-
groupBy: <K extends keyof T>(key: K) => Map<T[K], Collection<T>>
|
|
130
|
-
chunk: (size: number) => Collection<Collection<T>>
|
|
131
|
-
take: (count: number) => Collection<T>
|
|
132
|
-
skip: (count: number) => Collection<T>
|
|
133
|
-
reverse: () => Collection<T>
|
|
134
|
-
sum: (key?: keyof T) => number
|
|
135
|
-
avg: (key?: keyof T) => number
|
|
136
|
-
min: (key?: keyof T) => T | undefined
|
|
137
|
-
max: (key?: keyof T) => T | undefined
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Safe validated data wrapper (Laravel-style)
|
|
142
|
-
*/
|
|
143
|
-
export interface SafeData<T extends Record<string, any> = Record<string, any>> {
|
|
144
|
-
only: <K extends keyof T>(keys: K[]) => Pick<T, K>
|
|
145
|
-
except: <K extends keyof T>(keys: K[]) => Omit<T, K>
|
|
146
|
-
merge: <U extends Record<string, unknown>>(data: U) => T & U
|
|
147
|
-
all: () => T
|
|
148
|
-
has: (key: keyof T) => boolean
|
|
149
|
-
get: <K extends keyof T>(key: K) => T[K]
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* RequestInstance - Generic, model-aware request interface with Laravel-style methods.
|
|
154
|
-
*
|
|
155
|
-
* When used bare (`RequestInstance`), all methods accept any string keys (backward compatible).
|
|
156
|
-
* When parameterized with model fields (`RequestInstance<{ title: string, views: number }>`),
|
|
157
|
-
* all input methods narrow to those fields with full autocomplete and type inference.
|
|
158
|
-
*
|
|
159
|
-
* The global type alias connects this to models:
|
|
160
|
-
* `RequestInstance<typeof Post>` → narrows to Post's fields automatically.
|
|
161
|
-
*
|
|
162
|
-
* @example
|
|
163
|
-
* // Untyped (accepts any key)
|
|
164
|
-
* function handle(request: RequestInstance) {
|
|
165
|
-
* request.get('anything') // returns any
|
|
166
|
-
* }
|
|
167
|
-
*
|
|
168
|
-
* @example
|
|
169
|
-
* // Model-aware (narrows to Post's fields)
|
|
170
|
-
* function handle(request: RequestInstance<typeof Post>) {
|
|
171
|
-
* request.get('title') // autocompletes, returns string
|
|
172
|
-
* request.get('views') // autocompletes, returns number
|
|
173
|
-
* request.get('invalid') // TS error!
|
|
174
|
-
* const data = await request.validate() // returns typed Post fields
|
|
175
|
-
* }
|
|
176
|
-
*/
|
|
177
|
-
/**
|
|
178
|
-
* Public alias for `RequestInstance<TFields>`. Use this in actions when
|
|
179
|
-
* you want to type the `request` argument explicitly (e.g. without
|
|
180
|
-
* pulling in a model object).
|
|
181
|
-
*
|
|
182
|
-
* @example
|
|
183
|
-
* ```ts
|
|
184
|
-
* import { Action } from '@stacksjs/actions'
|
|
185
|
-
* import type { ActionRequest } from '@stacksjs/types'
|
|
186
|
-
*
|
|
187
|
-
* type CreatePostInput = { title: string; body: string }
|
|
188
|
-
*
|
|
189
|
-
* export default new Action({
|
|
190
|
-
* name: 'CreatePost',
|
|
191
|
-
* handle(request: ActionRequest<CreatePostInput>) {
|
|
192
|
-
* const { title, body } = request.only(['title', 'body'])
|
|
193
|
-
* // ^ inferred as { title: string; body: string }
|
|
194
|
-
* },
|
|
195
|
-
* })
|
|
196
|
-
* ```
|
|
197
|
-
*/
|
|
198
|
-
export type ActionRequest<
|
|
199
|
-
TFields extends Record<string, any> = Record<string, any>,
|
|
200
|
-
TParams extends Record<string, string> = Record<string, string>,
|
|
201
|
-
> = RequestInstance<TFields, TParams>
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Read the body shape declared by an action's `validations:` field as
|
|
205
|
-
* a TypeScript object type (stacksjs/stacks#1851 Phase 2b). Threaded
|
|
206
|
-
* into {@link RequestInstance}'s `TFields` so `request.all()` returns
|
|
207
|
-
* the body shape with the field types {@link Infer}'d from each
|
|
208
|
-
* `schema.X()` rule.
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* const validations = {
|
|
212
|
-
* email: { rule: schema.string().email() },
|
|
213
|
-
* password: { rule: schema.string().min(8) },
|
|
214
|
-
* remember: { rule: schema.boolean() },
|
|
215
|
-
* } as const
|
|
216
|
-
* type Body = InferValidations<typeof validations>
|
|
217
|
-
* // → { email: string, password: string, remember: boolean }
|
|
218
|
-
*/
|
|
219
|
-
export type InferValidations<V extends Record<string, { rule: any }>> = {
|
|
220
|
-
[K in keyof V]: Infer<V[K]['rule']>
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
export type RequestValidationRules = Record<string, string | {
|
|
224
|
-
rule: { validate: (value: any) => any }
|
|
225
|
-
message?: string | Record<string, string>
|
|
226
|
-
}>
|
|
227
|
-
|
|
228
|
-
export interface RequestInstance<
|
|
229
|
-
TFields extends Record<string, any> = Record<string, any>,
|
|
230
|
-
TParams extends Record<string, string> = Record<string, string>,
|
|
231
|
-
> {
|
|
232
|
-
// ==========================================================================
|
|
233
|
-
// Native Request properties
|
|
234
|
-
// ==========================================================================
|
|
235
|
-
|
|
236
|
-
url: string
|
|
237
|
-
method: string
|
|
238
|
-
headers: Headers
|
|
239
|
-
|
|
240
|
-
// Raw data access (always untyped — use get()/input() for typed access)
|
|
241
|
-
query: RequestData
|
|
242
|
-
/**
|
|
243
|
-
* Route parameters from the URL. When the action is bound to a path
|
|
244
|
-
* literal (via {@link ActionOptions.path} or a typed
|
|
245
|
-
* `route.get<TPath>(...)` overload), `TParams` narrows to the
|
|
246
|
-
* extracted keys so `request.params.id` is `string` with no `as any`.
|
|
247
|
-
*
|
|
248
|
-
* For un-narrowed callers (bare `RequestInstance`), this falls
|
|
249
|
-
* back to `Record<string, string>` — the runtime shape is always
|
|
250
|
-
* string-keyed even for "numeric" params, since URL segments are
|
|
251
|
-
* never coerced.
|
|
252
|
-
*/
|
|
253
|
-
params: TParams
|
|
254
|
-
jsonBody?: any
|
|
255
|
-
formBody?: any
|
|
256
|
-
files: Record<string, File | File[]>
|
|
257
|
-
/**
|
|
258
|
-
* Cookies parsed from the request. The accessor exposes
|
|
259
|
-
* `get`/`set`/`delete`/`getAll` helpers that mirror bun-router's
|
|
260
|
-
* cookie handling. Optional because not every request middleware
|
|
261
|
-
* stack runs the cookie parser.
|
|
262
|
-
*/
|
|
263
|
-
cookies?: RequestCookies
|
|
264
|
-
|
|
265
|
-
// ==========================================================================
|
|
266
|
-
// Model-aware Input Methods
|
|
267
|
-
//
|
|
268
|
-
// Keys narrow to `keyof TFields` when a model type is provided.
|
|
269
|
-
// Return types narrow to the field's actual type.
|
|
270
|
-
// ==========================================================================
|
|
271
|
-
|
|
272
|
-
/**
|
|
273
|
-
* Get input value from any source (query, body, params)
|
|
274
|
-
* @example request.get('title') // returns string (when model-aware)
|
|
275
|
-
* @example request.get('views', 0) // returns number with default
|
|
276
|
-
*/
|
|
277
|
-
get<K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]): TFields[K]
|
|
278
|
-
get<T = any>(key: string, defaultValue?: T): T
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* Alias for get() - Laravel compatibility
|
|
282
|
-
*/
|
|
283
|
-
input<K extends keyof TFields & string>(key: K, defaultValue?: TFields[K]): TFields[K]
|
|
284
|
-
input<T = any>(key: string, defaultValue?: T): T
|
|
285
|
-
|
|
286
|
-
/**
|
|
287
|
-
* Get all input data (typed to model fields when model-aware)
|
|
288
|
-
*/
|
|
289
|
-
all: () => TFields
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Get only specified keys — returns a precisely picked type
|
|
293
|
-
* @example request.only(['title', 'views']) // { title: string, views: number }
|
|
294
|
-
*/
|
|
295
|
-
only: <K extends keyof TFields & string>(keys: K[]) => Pick<TFields, K>
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Get all except specified keys — returns a precisely omitted type
|
|
299
|
-
* @example request.except(['id', 'created_at']) // omits those fields
|
|
300
|
-
*/
|
|
301
|
-
except: <K extends keyof TFields & string>(keys: K[]) => Omit<TFields, K>
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Check if input has a key (or all keys if array) — keys narrowed to model fields
|
|
305
|
-
* @example request.has('title')
|
|
306
|
-
* @example request.has(['title', 'views'])
|
|
307
|
-
*/
|
|
308
|
-
has: (key: string | string[]) => boolean
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Check if input has any of the specified keys
|
|
312
|
-
* @example request.hasAny(['title', 'views'])
|
|
313
|
-
*/
|
|
314
|
-
hasAny: (keys: string[]) => boolean
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Check if input is filled (present and not empty)
|
|
318
|
-
* @example request.filled('title')
|
|
319
|
-
*/
|
|
320
|
-
filled: (key: string | string[]) => boolean
|
|
321
|
-
|
|
322
|
-
/**
|
|
323
|
-
* Check if input is missing
|
|
324
|
-
* @example request.missing('title')
|
|
325
|
-
*/
|
|
326
|
-
missing: (key: string | string[]) => boolean
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Merge additional data into input — accepts partial model fields
|
|
330
|
-
*/
|
|
331
|
-
merge: (data: Partial<TFields>) => void
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Get all input keys — returns model field names when model-aware
|
|
335
|
-
*/
|
|
336
|
-
keys: () => (keyof TFields & string)[]
|
|
337
|
-
|
|
338
|
-
// ==========================================================================
|
|
339
|
-
// Type-casting Methods — keys narrowed to model fields
|
|
340
|
-
// ==========================================================================
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Get string input
|
|
344
|
-
* @example request.string('title')
|
|
345
|
-
*/
|
|
346
|
-
string: (key: keyof TFields & string, defaultValue?: string) => string
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Get integer input
|
|
350
|
-
* @example request.integer('views', 0)
|
|
351
|
-
*/
|
|
352
|
-
integer: (key: keyof TFields & string, defaultValue?: number) => number
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Get float input
|
|
356
|
-
* @example request.float('price', 0.0)
|
|
357
|
-
*/
|
|
358
|
-
float: (key: keyof TFields & string, defaultValue?: number) => number
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Get boolean input
|
|
362
|
-
* @example request.boolean('is_active', false)
|
|
363
|
-
*/
|
|
364
|
-
boolean: (key: keyof TFields & string, defaultValue?: boolean) => boolean
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Get input as array
|
|
368
|
-
* @example request.array('tags')
|
|
369
|
-
*/
|
|
370
|
-
array: <T = unknown>(key: keyof TFields & string) => T[]
|
|
371
|
-
|
|
372
|
-
/**
|
|
373
|
-
* Parse date input
|
|
374
|
-
* @example request.date('published_at')
|
|
375
|
-
*/
|
|
376
|
-
date: (key: keyof TFields & string, format?: string) => Date | null
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* Parse enum input
|
|
380
|
-
* @example request.enum('status', StatusEnum)
|
|
381
|
-
*/
|
|
382
|
-
enum: <T extends Record<string, string | number>>(key: keyof TFields & string, enumType: T) => T[keyof T] | null
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Get input as collection
|
|
386
|
-
* @example request.collect('items')
|
|
387
|
-
*/
|
|
388
|
-
collect: <T = unknown>(key: keyof TFields & string) => Collection<T>
|
|
389
|
-
|
|
390
|
-
// ==========================================================================
|
|
391
|
-
// Validation Methods — returns typed model fields when model-aware
|
|
392
|
-
// ==========================================================================
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* Validate the request data.
|
|
396
|
-
* When model-aware, rules are optional (uses model's attribute validation).
|
|
397
|
-
* Returns the validated data typed to model fields.
|
|
398
|
-
*
|
|
399
|
-
* @example await request.validate() // uses model rules
|
|
400
|
-
* @example await request.validate({ name: 'required' }) // custom rules
|
|
401
|
-
*/
|
|
402
|
-
validate: (rules?: RequestValidationRules, messages?: Record<string, string>) => Promise<TFields>
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Get previously validated data, typed to model fields
|
|
406
|
-
*/
|
|
407
|
-
getValidated: () => TFields
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Get safe validated data wrapper with typed access
|
|
411
|
-
* @example request.safe().only(['title', 'views']) // Pick<TFields, 'title' | 'views'>
|
|
412
|
-
* @example request.safe().get('title') // string
|
|
413
|
-
*/
|
|
414
|
-
safe: () => SafeData<TFields>
|
|
415
|
-
|
|
416
|
-
// ==========================================================================
|
|
417
|
-
// Conditional Methods — keys narrowed to model fields
|
|
418
|
-
// ==========================================================================
|
|
419
|
-
|
|
420
|
-
/**
|
|
421
|
-
* Execute callback when input has a value
|
|
422
|
-
* @example request.whenHas('title', (value) => console.log(value))
|
|
423
|
-
*/
|
|
424
|
-
whenHas: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
|
|
425
|
-
|
|
426
|
-
/**
|
|
427
|
-
* Execute callback when input is filled
|
|
428
|
-
* @example request.whenFilled('title', (value) => console.log(value))
|
|
429
|
-
*/
|
|
430
|
-
whenFilled: <T>(key: keyof TFields & string, callback: (value: T) => void, defaultCallback?: () => void) => void
|
|
431
|
-
|
|
432
|
-
/**
|
|
433
|
-
* Check if input matches a value
|
|
434
|
-
*/
|
|
435
|
-
isValue: (key: keyof TFields & string, value: unknown) => boolean
|
|
436
|
-
|
|
437
|
-
// ==========================================================================
|
|
438
|
-
// File Methods — not narrowed to model fields (files are independent)
|
|
439
|
-
// ==========================================================================
|
|
440
|
-
|
|
441
|
-
/**
|
|
442
|
-
* Get an uploaded file by key
|
|
443
|
-
* @example const avatar = request.file('avatar')
|
|
444
|
-
* @example await avatar?.store('avatars')
|
|
445
|
-
*/
|
|
446
|
-
file: (key: string) => UploadedFile | null
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* Get all uploaded files for a key (for multiple file inputs)
|
|
450
|
-
*/
|
|
451
|
-
getFiles: (key: string) => UploadedFile[]
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Check if a file was uploaded
|
|
455
|
-
*/
|
|
456
|
-
hasFile: (key: string) => boolean
|
|
457
|
-
|
|
458
|
-
/**
|
|
459
|
-
* Get all uploaded files
|
|
460
|
-
*/
|
|
461
|
-
allFiles: () => Record<string, UploadedFile | UploadedFile[]>
|
|
462
|
-
|
|
463
|
-
// ==========================================================================
|
|
464
|
-
// Header Methods
|
|
465
|
-
// ==========================================================================
|
|
466
|
-
|
|
467
|
-
header: (key: string) => string | null
|
|
468
|
-
bearerToken: () => string | null | AuthToken
|
|
469
|
-
|
|
470
|
-
// ==========================================================================
|
|
471
|
-
// Route & Param Methods
|
|
472
|
-
//
|
|
473
|
-
// `params` (the field above) is the typed primary surface — narrow
|
|
474
|
-
// it via the action's `path:` literal for full inference. These
|
|
475
|
-
// method-form helpers stay around for back-compat and for cases
|
|
476
|
-
// where the param key isn't statically known.
|
|
477
|
-
// ==========================================================================
|
|
478
|
-
|
|
479
|
-
/**
|
|
480
|
-
* Look up a single route param, optionally with a default. Narrows
|
|
481
|
-
* to {@link TParams} when the key is part of the path-extracted
|
|
482
|
-
* keyset; falls back to `string | undefined` otherwise (covers
|
|
483
|
-
* dynamic key access without `as any`).
|
|
484
|
-
*
|
|
485
|
-
* @example
|
|
486
|
-
* const id = request.param('id') // typed string (from path)
|
|
487
|
-
* const note = request.param('note', '') // string with default
|
|
488
|
-
*/
|
|
489
|
-
param: <K extends keyof TParams | string, D = string>(
|
|
490
|
-
key: K,
|
|
491
|
-
defaultValue?: D,
|
|
492
|
-
) => K extends keyof TParams ? TParams[K] : (string | D)
|
|
493
|
-
/**
|
|
494
|
-
* @deprecated Use {@link param} for typed param lookups, or
|
|
495
|
-
* `Number(request.params.id)` for explicit numeric coercion.
|
|
496
|
-
* The name-match heuristic returning `number` for {@link NumericField}
|
|
497
|
-
* keys (`id`, `count`, `amount`, …) is brittle: it silently falls
|
|
498
|
-
* through to `string` for `judgeId`, `user_id`, etc.
|
|
499
|
-
* See stacksjs/stacks#1851 Phase 3.
|
|
500
|
-
*/
|
|
501
|
-
getParam: <K extends string>(key: K) => K extends NumericField ? number : string
|
|
502
|
-
route: (key: string) => number | string | null
|
|
503
|
-
getParams: () => TParams
|
|
504
|
-
getParamAsInt: (key: string) => number | null
|
|
505
|
-
|
|
506
|
-
// ==========================================================================
|
|
507
|
-
// Session/Flash Methods — keys narrowed to model fields
|
|
508
|
-
// ==========================================================================
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Get old input (for form repopulation)
|
|
512
|
-
*/
|
|
513
|
-
old: <T = unknown>(key: keyof TFields & string, defaultValue?: T) => T
|
|
514
|
-
|
|
515
|
-
/**
|
|
516
|
-
* Flash input to session for form repopulation
|
|
517
|
-
*/
|
|
518
|
-
flashInput: (keys?: (keyof TFields & string)[]) => void
|
|
519
|
-
|
|
520
|
-
/**
|
|
521
|
-
* Flash only specific keys
|
|
522
|
-
*/
|
|
523
|
-
flashInputOnly: (keys: (keyof TFields & string)[]) => void
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Flash except specific keys
|
|
527
|
-
*/
|
|
528
|
-
flashInputExcept: (keys: (keyof TFields & string)[]) => void
|
|
529
|
-
|
|
530
|
-
// ==========================================================================
|
|
531
|
-
// Utility Methods
|
|
532
|
-
// ==========================================================================
|
|
533
|
-
|
|
534
|
-
json: <T = any>() => Promise<T>
|
|
535
|
-
isEmpty: () => boolean
|
|
536
|
-
browser: () => string | null
|
|
537
|
-
ip: () => string | null
|
|
538
|
-
ipForRateLimit: () => string | null
|
|
539
|
-
getMethod: () => HttpMethod
|
|
540
|
-
user: () => Promise<UserJsonResponse | undefined>
|
|
541
|
-
}
|
package/src/response.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export interface ResponseInstance {
|
|
2
|
-
json: (data: any, status?: number) => ResponseData
|
|
3
|
-
success: (data: any) => ResponseData
|
|
4
|
-
created: (data: any) => ResponseData
|
|
5
|
-
noContent: () => ResponseData
|
|
6
|
-
error: (message: string, status: number) => ResponseData
|
|
7
|
-
forbidden: (message: string) => ResponseData
|
|
8
|
-
unauthorized: (message: string) => ResponseData
|
|
9
|
-
notFound: (message: string) => ResponseData
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface ResponseData {
|
|
13
|
-
status: number
|
|
14
|
-
headers: { [key: string]: string }
|
|
15
|
-
body: string
|
|
16
|
-
}
|
package/src/router.ts
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
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'
|
|
5
|
-
|
|
6
|
-
type ActionPath = string
|
|
7
|
-
// need to refactor before, after, view to be a part of some other type
|
|
8
|
-
export type RouteCallback = ((_params?: Record<string, any>) => any | string | object) | ((req: any, res: any) => Promise<void>)
|
|
9
|
-
|
|
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'
|
|
28
|
-
|
|
29
|
-
export interface Route {
|
|
30
|
-
name: string
|
|
31
|
-
uri: string
|
|
32
|
-
url: string // used synonymously with uri, TODO: narrow this type by ensuring it's generated
|
|
33
|
-
path?: string
|
|
34
|
-
prefix?: string
|
|
35
|
-
method: HttpMethod
|
|
36
|
-
pattern: RegExp
|
|
37
|
-
callback: RouteCallback | ActionPath | Action | Promise<any> // we may be able to improve the `Promise<any>` if we could narrow this type `import('../app/Actions/BuddyAction')`
|
|
38
|
-
paramNames: string[]
|
|
39
|
-
middleware?: string | string[]
|
|
40
|
-
statusCode?: StatusCode
|
|
41
|
-
}
|
|
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
|
-
|
|
54
|
-
export interface MiddlewareOptions {
|
|
55
|
-
name: string
|
|
56
|
-
description?: string
|
|
57
|
-
priority: number
|
|
58
|
-
handle: (request: Request) => Promise<void> | void
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export type StatusCode = 200 | 201 | 202 | 204 | 301 | 302 | 304 | 400 | 401 | 403 | 404 | 500
|
|
62
|
-
export type RedirectCode = Extract<StatusCode, 301 | 302>
|
|
63
|
-
|
|
64
|
-
export interface RouteParam { [key: string]: string | number }
|
|
65
|
-
|
|
66
|
-
export type MiddlewareFn = (_request: Request) => Promise<void>
|
|
67
|
-
|
|
68
|
-
export interface Middlewares {
|
|
69
|
-
logger: MiddlewareFn
|
|
70
|
-
auth: MiddlewareFn
|
|
71
|
-
[key: string]: MiddlewareFn
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface RouteGroupOptions {
|
|
75
|
-
prefix?: string
|
|
76
|
-
middleware?: Route['middleware']
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
type Prefix = string
|
|
80
|
-
|
|
81
|
-
export interface RouterInterface {
|
|
82
|
-
get: (url: Route['url'], callback: Route['callback']) => this
|
|
83
|
-
post: (url: Route['url'], callback: Route['callback']) => this
|
|
84
|
-
view: (url: Route['url'], callback: Route['callback']) => this
|
|
85
|
-
redirect: (url: Route['url'], callback: Route['callback'], status?: RedirectCode) => this
|
|
86
|
-
delete: (url: Route['url'], callback: Route['callback']) => this
|
|
87
|
-
patch: (url: Route['url'], callback: Route['callback']) => this
|
|
88
|
-
put: (url: Route['url'], callback: Route['callback']) => this
|
|
89
|
-
email: (url: Route['url']) => Promise<this>
|
|
90
|
-
health: () => Promise<this>
|
|
91
|
-
job: (url: Route['url']) => Promise<this>
|
|
92
|
-
action: (url: Route['url']) => Promise<this>
|
|
93
|
-
group: (options: Prefix | RouteGroupOptions, callback: () => void) => this
|
|
94
|
-
name: (name: string) => this
|
|
95
|
-
middleware: (middleware: Route['middleware']) => this
|
|
96
|
-
getRoutes: () => Promise<Route[]>
|
|
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
|
-
}
|