@orieljs/framework 0.1.0-alpha.0 → 0.1.0-alpha.10

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.
Files changed (85) hide show
  1. package/LICENSE +202 -21
  2. package/NOTICE +16 -0
  3. package/README.md +13 -0
  4. package/TRADEMARKS.md +33 -0
  5. package/dist/chunk-7ZQZYDOC.js +3253 -0
  6. package/dist/chunk-7ZQZYDOC.js.map +1 -0
  7. package/dist/{chunk-P64C7IEP.js → chunk-GVNLZZTN.js} +11 -1
  8. package/dist/chunk-GVNLZZTN.js.map +1 -0
  9. package/dist/chunk-OXAATQA6.js +8433 -0
  10. package/dist/chunk-OXAATQA6.js.map +1 -0
  11. package/dist/chunk-VOYW3R5J.js +478 -0
  12. package/dist/chunk-VOYW3R5J.js.map +1 -0
  13. package/dist/contracts.d.ts +964 -196
  14. package/dist/contracts.js +11 -1
  15. package/dist/index.d-WQpfdIbG.d.ts +630 -0
  16. package/dist/index.d.ts +9398 -682
  17. package/dist/index.js +25374 -894
  18. package/dist/index.js.map +1 -1
  19. package/dist/jsx-runtime-6um4Mwfb.d.ts +300 -0
  20. package/dist/jsx-runtime.d.ts +3 -0
  21. package/dist/jsx-runtime.js +13 -0
  22. package/dist/jsx-runtime.js.map +1 -0
  23. package/dist/testing-CKwfWJGn.d.ts +1586 -0
  24. package/dist/testing.d.ts +3 -0
  25. package/dist/testing.js +113 -0
  26. package/dist/testing.js.map +1 -0
  27. package/docs/authentication.md +487 -0
  28. package/docs/authorization.md +435 -0
  29. package/docs/cache.md +647 -0
  30. package/docs/collections.md +2270 -0
  31. package/docs/configuration.md +334 -0
  32. package/docs/console.md +652 -0
  33. package/docs/container.md +430 -0
  34. package/docs/controllers.md +406 -0
  35. package/docs/csrf.md +126 -0
  36. package/docs/database-testing.md +144 -0
  37. package/docs/database.md +236 -0
  38. package/docs/deployment.md +276 -0
  39. package/docs/eloquent-collections.md +218 -0
  40. package/docs/eloquent-factories.md +255 -0
  41. package/docs/eloquent-mutators.md +254 -0
  42. package/docs/eloquent-observers.md +145 -0
  43. package/docs/eloquent-relationships.md +557 -0
  44. package/docs/eloquent.md +494 -0
  45. package/docs/encryption.md +104 -0
  46. package/docs/errors.md +318 -0
  47. package/docs/events.md +336 -0
  48. package/docs/facades.md +278 -0
  49. package/docs/hashing.md +118 -0
  50. package/docs/helpers.md +1281 -0
  51. package/docs/http-tests.md +386 -0
  52. package/docs/inertia.md +485 -0
  53. package/docs/installation.md +209 -0
  54. package/docs/lifecycle.md +234 -0
  55. package/docs/live-tests.md +226 -0
  56. package/docs/live.md +910 -0
  57. package/docs/logging.md +255 -0
  58. package/docs/mail.md +619 -0
  59. package/docs/middleware.md +384 -0
  60. package/docs/migrations.md +416 -0
  61. package/docs/mocking.md +264 -0
  62. package/docs/navigation.json +273 -0
  63. package/docs/notifications.md +225 -0
  64. package/docs/pagination.md +247 -0
  65. package/docs/passwords.md +207 -0
  66. package/docs/providers.md +187 -0
  67. package/docs/queries.md +600 -0
  68. package/docs/queues.md +330 -0
  69. package/docs/requests.md +533 -0
  70. package/docs/responses.md +444 -0
  71. package/docs/routing.md +738 -0
  72. package/docs/scheduling.md +277 -0
  73. package/docs/seeding.md +122 -0
  74. package/docs/session.md +409 -0
  75. package/docs/starter-kits.md +396 -0
  76. package/docs/storage.md +192 -0
  77. package/docs/structure.md +264 -0
  78. package/docs/testing.md +165 -0
  79. package/docs/time-travel.md +138 -0
  80. package/docs/validation.md +1792 -0
  81. package/docs/verification.md +152 -0
  82. package/docs/views.md +566 -0
  83. package/docs/vite.md +322 -0
  84. package/package.json +68 -10
  85. package/dist/chunk-P64C7IEP.js.map +0 -1
@@ -35,148 +35,32 @@ interface Container {
35
35
  }
36
36
  declare const Container: Token<Container>;
37
37
 
38
- interface ServiceProvider {
39
- /** Bind things into the container. Synchronous. Don't resolve other services here. */
40
- register?(): void;
41
- /** Runs after every provider is registered. May be async (e.g. importing route files). */
42
- boot?(): void | Promise<void>;
43
- }
44
- type ServiceProviderClass = new (app: Application) => ServiceProvider;
45
- interface Application extends Container {
46
- readonly version: string;
47
- basePath(path?: string): string;
48
- appPath(path?: string): string;
49
- bootstrapPath(path?: string): string;
50
- configPath(path?: string): string;
51
- databasePath(path?: string): string;
52
- publicPath(path?: string): string;
53
- resourcePath(path?: string): string;
54
- storagePath(path?: string): string;
55
- /** With no args returns the environment name. With args returns whether it matches any of them. */
56
- environment(): string;
57
- environment(...environments: string[]): boolean;
58
- isProduction(): boolean;
59
- isLocal(): boolean;
60
- runningInConsole(): boolean;
61
- /** Mark the app as running in the console (the CLI entry point calls this). Defaults to true. */
62
- setRunningInConsole(value?: boolean): void;
63
- runningUnitTests(): boolean;
64
- /** Registers the provider. If the app is already booted, the provider is booted immediately. */
65
- register(provider: ServiceProvider | ServiceProviderClass): Promise<ServiceProvider>;
66
- getProviders(): ServiceProvider[];
67
- boot(): Promise<void>;
68
- isBooted(): boolean;
69
- booting(callback: (app: Application) => void | Promise<void>): void;
70
- booted(callback: (app: Application) => void | Promise<void>): void;
71
- /** Handle one HTTP request in a fresh request scope via the bound HttpKernel. */
72
- handle(request: Request): Promise<Response>;
73
- /** Register a callback that terminate() runs, in registration order. */
74
- terminating(callback: () => void | Promise<void>): void;
75
- terminate(): Promise<void>;
76
- }
77
- declare const Application: Token<Application>;
78
- interface ExceptionHandler {
79
- report(error: unknown): Promise<void>;
80
- shouldReport(error: unknown): boolean;
81
- /** `request` is the scoped HttpRequest (Contracts/Http) when available, else the raw Request. */
82
- render(request: unknown, error: unknown): Promise<Response>;
83
- }
84
- declare const ExceptionHandler: Token<ExceptionHandler>;
85
- /** Paths passed to Application.configure().withRouting(). Routing (Wave 1) loads them. */
86
- interface RoutingPaths {
87
- web?: string;
88
- api?: string;
89
- console?: string;
90
- health?: string;
91
- apiPrefix: string;
92
- }
93
- declare const RoutingPaths: Token<RoutingPaths>;
94
- /** The object passed to Application.configure().withExceptions(e => …), like Laravel's Exceptions class. */
95
- interface ExceptionsConfigurator {
96
- /** Custom reporting. Return false to stop the default logging. */
97
- report(callback: (error: unknown) => void | boolean | Promise<void | boolean>): this;
98
- /** Custom rendering. Return undefined to fall through to the default rendering. */
99
- render(callback: (error: unknown, request: unknown) => Response | undefined | Promise<Response | undefined>): this;
100
- /** Never report errors of these classes. */
101
- dontReport(...classes: Array<abstract new (...args: never[]) => Error>): this;
102
- }
103
- /** Callbacks collected by withMiddleware()/withExceptions(); invoked by Http / the exception handler (Wave 1). */
104
- type ConfigCallbacks<T> = Array<(configurator: T) => void>;
105
- /** Typed as unknown here because MiddlewareConfigurator lives in Contracts/Http; Http casts on use. */
106
- declare const MiddlewareCallbacks: Token<ConfigCallbacks<unknown>>;
107
- declare const ExceptionCallbacks: Token<ConfigCallbacks<ExceptionsConfigurator>>;
108
-
109
- interface ConfigRepository {
110
- has(key: string): boolean;
111
- /** Dot notation: get('database.connections.sqlite.database'). */
112
- get<T = unknown>(key: string, defaultValue?: T): T;
113
- set(key: string, value: unknown): void;
114
- set(values: Record<string, unknown>): void;
115
- push(key: string, value: unknown): void;
116
- all(): Record<string, unknown>;
117
- }
118
- declare const ConfigRepository: Token<ConfigRepository>;
119
-
120
- interface Arrayable<T = unknown> {
121
- toArray(): T;
122
- }
123
- interface Jsonable {
124
- toJson(): string;
125
- }
126
- interface Htmlable {
127
- toHtml(): string;
128
- }
129
- /** Anything a controller can return that knows how to become a Response. */
130
- interface Responsable {
131
- toResponse(request: unknown): Response | Promise<Response>;
132
- }
133
- /** The minimal collection surface contracts rely on (implemented by @orieljs/collections). */
134
- interface Enumerable<T> extends Iterable<T>, Arrayable<unknown[]> {
135
- all(): T[];
136
- count(): number;
137
- isEmpty(): boolean;
138
- }
139
- interface ClassRegistry {
140
- /** Registers under `name` (default: cls.name). Throws if the name is already taken by a different class. */
141
- register(cls: Class<unknown>, name?: string): string;
142
- nameOf(cls: Class<unknown>): string | undefined;
143
- resolve<T = unknown>(name: string): Class<T>;
144
- has(name: string): boolean;
145
- }
146
- declare const ClassRegistry: Token<ClassRegistry>;
147
-
148
- type PipeNext<T> = (passable: T) => Promise<unknown>;
149
- type PipeClosure<T> = (passable: T, next: PipeNext<T>) => Promise<unknown> | unknown;
150
- /** A class resolved from the container whose `via` method (default 'handle') is called; or a string alias 'name:param1,param2'. */
151
- type Pipe<T> = PipeClosure<T> | Class<object> | string;
152
- interface Pipeline<T = unknown> {
153
- send(passable: T): this;
154
- through(pipes: ReadonlyArray<Pipe<T>>): this;
155
- pipe(...pipes: Array<Pipe<T>>): this;
156
- /** Method called on class pipes. Default 'handle'. */
157
- via(method: string): this;
158
- then<R>(destination: (passable: T) => R | Promise<R>): Promise<R>;
159
- thenReturn(): Promise<T>;
160
- }
161
- interface PipelineFactory {
162
- make<T>(): Pipeline<T>;
163
- }
164
- declare const PipelineFactory: Token<PipelineFactory>;
165
-
166
38
  /** The session of the current request (scoped). Loaded and saved by the StartSession middleware. */
167
39
  interface Session {
168
40
  getId(): string;
169
41
  start(): Promise<void>;
170
42
  save(): Promise<void>;
171
43
  all(): Record<string, unknown>;
44
+ only(keys: string[]): Record<string, unknown>;
45
+ except(keys: string[]): Record<string, unknown>;
46
+ /** Whether every key is present, even with a null value. */
47
+ exists(...keys: string[]): boolean;
48
+ missing(...keys: string[]): boolean;
49
+ /** Whether the key is present and not null. */
172
50
  has(key: string): boolean;
173
51
  get<T = unknown>(key: string, defaultValue?: T): T;
174
52
  put(key: string | Record<string, unknown>, value?: unknown): void;
175
53
  push(key: string, value: unknown): void;
54
+ /** Adds `amount` (default 1) to the number under the key and returns the new value. */
55
+ increment(key: string, amount?: number): number;
56
+ decrement(key: string, amount?: number): number;
176
57
  pull<T = unknown>(key: string, defaultValue?: T): T;
58
+ /** Forgets the key and returns its value. */
59
+ remove<T = unknown>(key: string): T;
177
60
  forget(...keys: string[]): void;
178
61
  flush(): void;
179
- flash(key: string, value: unknown): void;
62
+ /** Puts the value (true when omitted) for the next request only. */
63
+ flash(key: string, value?: unknown): void;
180
64
  now(key: string, value: unknown): void;
181
65
  reflash(): void;
182
66
  keep(...keys: string[]): void;
@@ -198,6 +82,406 @@ interface SessionHandler {
198
82
  gc(maxLifetimeSeconds: number): Promise<void>;
199
83
  }
200
84
 
85
+ /**
86
+ * What one rule tells the validated data's type about a value that passed it. Every member is optional:
87
+ * - `value`: the type of a passing value. A field's type is the intersection of its rules' values
88
+ * (`'string|in:a,b'` is `'a' | 'b'`); a field whose rules set none is `unknown`.
89
+ * - `presence`: `'required'` puts the key in the data and rules out null (`required`, `accepted`); `'present'` puts
90
+ * the key in the data; `'filled'` rules out null without putting the key in; `'excluded'` leaves the key out;
91
+ * `'optional'` may leave the key out whatever else would put it in (`sometimes` skips a missing key, and a rule that
92
+ * excludes the field under a condition drops it with its children), so the key is optional and doesn't put its
93
+ * parent in. A key nothing puts in is optional, as the validated data has only the keys the input had.
94
+ * - `each`: on a field that also has `array`, the type of each item instead of `value` (`in` checks every item of an
95
+ * array: `'array|in:a,b'` is `Array<'a' | 'b'>`).
96
+ * - `nullable`: null passes, unless a `'required'` or `'filled'` rule says otherwise.
97
+ */
98
+ interface RuleTyping {
99
+ value?: unknown;
100
+ each?: unknown;
101
+ presence?: 'required' | 'present' | 'filled' | 'excluded' | 'optional';
102
+ nullable?: true;
103
+ }
104
+ /** A number, or the text of one: a form sends every field as text, and `integer` and `numeric` accept both. */
105
+ type NumericValue = number | `${number}`;
106
+ /** `a,b,c` → `'a' | 'b' | 'c'`: a rule's comma-separated parameters, as Validator splits them. */
107
+ type RuleParameterList<P extends string> = P extends `${infer Head},${infer Tail}` ? Head | RuleParameterList<Tail> : P;
108
+ /**
109
+ * What `in` (and `Rule.in()`) lets through: it compares the value's text with each listed value, so `'1'` lets the
110
+ * number 1 through too, and `'true'` the boolean. A list known only as `string` (`` `in:${list.join(',')}` ``) says
111
+ * nothing, as any value whose text is listed passes.
112
+ */
113
+ type InValue<V> = string extends V ? unknown : V extends string ? V | (V extends `${infer N extends number}` ? N : never) | (V extends 'true' ? true : V extends 'false' ? false : never) : V extends number | boolean ? V | `${V}` : V;
114
+ /**
115
+ * The string rules that tell the validated data's type something, by name, each a RuleTyping. `Parameters` is the
116
+ * rule's text after the colon (`'a,b'` for `in:a,b`). A rule that only checks a value it doesn't change the type of
117
+ * (`max`, `confirmed`, `unique`) has no entry. Add a member for a new type-setting rule; an app adds its own
118
+ * `Validator.extend()` rules by declaration merging, with the same type parameter.
119
+ */
120
+ interface ValidationRuleTypes<Parameters extends string = string> {
121
+ required: {
122
+ presence: 'required';
123
+ };
124
+ /** Skips the field when the key is missing, so the key may be left out even with `required`. */
125
+ sometimes: {
126
+ presence: 'optional';
127
+ };
128
+ nullable: {
129
+ nullable: true;
130
+ };
131
+ accepted: {
132
+ presence: 'required';
133
+ value: true | 1 | 'yes' | 'on' | '1' | 'true';
134
+ };
135
+ declined: {
136
+ presence: 'required';
137
+ value: false | 0 | 'no' | 'off' | '0' | 'false';
138
+ };
139
+ present: {
140
+ presence: 'present';
141
+ };
142
+ filled: {
143
+ presence: 'filled';
144
+ };
145
+ missing: {
146
+ presence: 'excluded';
147
+ };
148
+ exclude: {
149
+ presence: 'excluded';
150
+ };
151
+ /** Drop the field, children and all, under a condition, so the key may be left out even with `required`. */
152
+ exclude_if: {
153
+ presence: 'optional';
154
+ };
155
+ exclude_unless: {
156
+ presence: 'optional';
157
+ };
158
+ exclude_with: {
159
+ presence: 'optional';
160
+ };
161
+ exclude_without: {
162
+ presence: 'optional';
163
+ };
164
+ /**
165
+ * Passes only when the field is missing or empty, so a value that is there is null, blank or whitespace-only text,
166
+ * [] or {}.
167
+ */
168
+ prohibited: {
169
+ value: null | string | [] | Record<string, never>;
170
+ };
171
+ string: {
172
+ value: string;
173
+ };
174
+ /** `integer:strict` and `numeric:strict` refuse the text of a number. */
175
+ integer: {
176
+ value: Parameters extends 'strict' ? number : NumericValue;
177
+ };
178
+ numeric: {
179
+ value: Parameters extends 'strict' ? number : NumericValue;
180
+ };
181
+ /** `boolean:strict` lets only true and false through. */
182
+ boolean: {
183
+ value: Parameters extends 'strict' ? boolean : boolean | 0 | 1 | '0' | '1';
184
+ };
185
+ /** `array` is a list; `array:a,b` an object whose keys are among those named. */
186
+ array: {
187
+ value: Parameters extends '' ? unknown[] : {
188
+ [K in RuleParameterList<Parameters>]?: unknown;
189
+ };
190
+ };
191
+ list: {
192
+ value: unknown[];
193
+ };
194
+ contains: {
195
+ value: unknown[];
196
+ };
197
+ doesnt_contain: {
198
+ value: unknown[];
199
+ };
200
+ required_array_keys: {
201
+ value: {
202
+ [K in RuleParameterList<Parameters>]: unknown;
203
+ };
204
+ };
205
+ in_array_keys: {
206
+ value: Record<string, unknown>;
207
+ };
208
+ email: {
209
+ value: string;
210
+ };
211
+ url: {
212
+ value: string;
213
+ };
214
+ uuid: {
215
+ value: string;
216
+ };
217
+ alpha: {
218
+ value: string;
219
+ };
220
+ alpha_num: {
221
+ value: string;
222
+ };
223
+ alpha_dash: {
224
+ value: string;
225
+ };
226
+ regex: {
227
+ value: string;
228
+ };
229
+ lowercase: {
230
+ value: string | number;
231
+ };
232
+ uppercase: {
233
+ value: string | number;
234
+ };
235
+ ascii: {
236
+ value: string | number;
237
+ };
238
+ hex_color: {
239
+ value: string;
240
+ };
241
+ json: {
242
+ value: string;
243
+ };
244
+ ip: {
245
+ value: string;
246
+ };
247
+ ipv4: {
248
+ value: string;
249
+ };
250
+ ipv6: {
251
+ value: string;
252
+ };
253
+ mac_address: {
254
+ value: string;
255
+ };
256
+ ulid: {
257
+ value: string;
258
+ };
259
+ timezone: {
260
+ value: string;
261
+ };
262
+ active_url: {
263
+ value: string;
264
+ };
265
+ digits: {
266
+ value: NumericValue;
267
+ };
268
+ digits_between: {
269
+ value: NumericValue;
270
+ };
271
+ max_digits: {
272
+ value: NumericValue;
273
+ };
274
+ min_digits: {
275
+ value: NumericValue;
276
+ };
277
+ decimal: {
278
+ value: NumericValue;
279
+ };
280
+ multiple_of: {
281
+ value: NumericValue;
282
+ };
283
+ date: {
284
+ value: string;
285
+ };
286
+ /** A number passes a format made of digits (`Y`, `U`), as in Laravel. */
287
+ date_format: {
288
+ value: string | number;
289
+ };
290
+ /** A number passes the comparisons as a timestamp, as in Laravel; with `date` in the set, the value is text. */
291
+ before: {
292
+ value: string | number;
293
+ };
294
+ before_or_equal: {
295
+ value: string | number;
296
+ };
297
+ after: {
298
+ value: string | number;
299
+ };
300
+ after_or_equal: {
301
+ value: string | number;
302
+ };
303
+ date_equals: {
304
+ value: string | number;
305
+ };
306
+ current_password: {
307
+ value: string;
308
+ };
309
+ in: {
310
+ value: InValue<RuleParameterList<Parameters>>;
311
+ each: InValue<RuleParameterList<Parameters>>;
312
+ };
313
+ file: {
314
+ value: UploadedFile;
315
+ };
316
+ image: {
317
+ value: UploadedFile;
318
+ };
319
+ mimes: {
320
+ value: UploadedFile;
321
+ };
322
+ mimetypes: {
323
+ value: UploadedFile;
324
+ };
325
+ extensions: {
326
+ value: UploadedFile;
327
+ };
328
+ dimensions: {
329
+ value: UploadedFile;
330
+ };
331
+ }
332
+ /**
333
+ * A rule object that tells the validated data's type what it lets through, as a string rule's entry in
334
+ * ValidationRuleTypes does. `__typing` is never set or read at run time: declare it (`declare readonly __typing?:
335
+ * { value: string }`). A rule object without it changes nothing, so its field takes the type of the string rules
336
+ * beside it (`['required', 'string', new Uppercase()]` is a string).
337
+ */
338
+ interface TypedValidationRule<T extends RuleTyping = RuleTyping> extends ValidationRule {
339
+ readonly __typing?: T;
340
+ }
341
+ type RuleName<R extends string> = R extends `${infer Name}:${string}` ? Name : R;
342
+ type RuleParameters<R extends string> = R extends `${string}:${infer Parameters}` ? Parameters : '';
343
+ type PipeRules<S extends string> = S extends `${infer Head}|${infer Tail}` ? Head | PipeRules<Tail> : S;
344
+ /** What a rule without an entry, or a rule object without `__typing`, says: nothing. */
345
+ type NoTyping = Record<never, never>;
346
+ type StringRuleTyping<R extends string> = R extends unknown ? RuleName<R> extends keyof ValidationRuleTypes ? ValidationRuleTypes<RuleParameters<R>>[RuleName<R>] : NoTyping : never;
347
+ type ObjectRuleTyping<O> = '__typing' extends keyof O ? Exclude<O['__typing' & keyof O], undefined> : NoTyping;
348
+ type ItemTyping<I> = I extends string ? StringRuleTyping<I> : ObjectRuleTyping<I>;
349
+ /** The typings of one field's rules, as a union: `'required|string'` or `['required', 'string', rule]`. */
350
+ type SpecTypings<Spec> = Spec extends string ? StringRuleTyping<PipeRules<Spec>> : Spec extends ReadonlyArray<infer Item> ? ItemTyping<Item> : NoTyping;
351
+ /** A rule string the compiler only knows as `string` (rules written without `as const`) says nothing. */
352
+ type IsWide<Spec> = Spec extends string ? (string extends Spec ? true : false) : Spec extends ReadonlyArray<infer Item> ? (string extends Extract<Item, string> ? true : false) : false;
353
+ type Intersect<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void ? I : never;
354
+ type Boxed<T> = T extends {
355
+ value: infer V;
356
+ } ? {
357
+ v: V;
358
+ } : never;
359
+ type BoxedEach<T> = T extends {
360
+ each: infer E;
361
+ } ? {
362
+ v: E;
363
+ } : never;
364
+ type Unbox<B> = [B] extends [never] ? unknown : Intersect<B> extends {
365
+ v: infer V;
366
+ } ? V : never;
367
+ type WithoutEach<T> = T extends {
368
+ each: unknown;
369
+ } ? never : T;
370
+ /** The intersection of the rules' values; on an array, the rules with `each` type its items instead. */
371
+ type ValueOf<T> = [BoxedEach<T>] extends [never] ? Unbox<Boxed<T>> : Unbox<Boxed<WithoutEach<T>>> extends readonly unknown[] ? Array<Unbox<BoxedEach<T>>> : Unbox<Boxed<T>>;
372
+ type PresenceOf<T> = T extends {
373
+ presence: infer P;
374
+ } ? P : never;
375
+ type NullableOf<T> = T extends {
376
+ nullable: true;
377
+ } ? true : never;
378
+ interface FieldInfo {
379
+ value: unknown;
380
+ required: boolean;
381
+ optional: boolean;
382
+ nullable: boolean;
383
+ excluded: boolean;
384
+ }
385
+ type FieldFrom<T, Optional = [Extract<PresenceOf<T>, 'optional'>] extends [never] ? false : true> = {
386
+ value: ValueOf<T>;
387
+ required: Optional extends true ? false : [Extract<PresenceOf<T>, 'required' | 'present'>] extends [never] ? false : true;
388
+ optional: Optional;
389
+ nullable: [NullableOf<T>] extends [never] ? false : [Extract<PresenceOf<T>, 'required' | 'filled'>] extends [never] ? true : false;
390
+ excluded: [Extract<PresenceOf<T>, 'excluded'>] extends [never] ? false : true;
391
+ };
392
+ /** Rules the compiler only knows as `string` say nothing, not even that the key is there. */
393
+ type FieldOf<Spec> = IsWide<Spec> extends true ? NoRules : FieldFrom<SpecTypings<Spec>>;
394
+ type NoRules = {
395
+ value: unknown;
396
+ required: false;
397
+ optional: false;
398
+ nullable: false;
399
+ excluded: false;
400
+ };
401
+ type Keys<R> = Extract<keyof R, string>;
402
+ type Head<K extends string> = K extends `${infer H}.${string}` ? H : K;
403
+ type Heads<R> = Head<Keys<R>>;
404
+ type Children<R, H extends string> = {
405
+ [K in Keys<R> as K extends `${H}.${infer Rest}` ? Rest : never]: R[K];
406
+ };
407
+ type HasChildren<R, H extends string> = [Keys<Children<R, H>>] extends [never] ? false : true;
408
+ type Own<R, H extends string> = H extends keyof R ? FieldOf<R[H]> : NoRules;
409
+ type OrNull<T, Nullable> = Nullable extends true ? T | null : T;
410
+ /**
411
+ * A wildcard's rules (`items.*.name`) make an array of what they describe; dotted keys (`author.name`) an object.
412
+ * Without a rule that makes the parent a list (`array`, `list`), validated() may give an object instead: an object
413
+ * sent under `items.*` stays one, and a sparse match (`{ items: [{}, { qty: 1 }] }`) keeps its index keys.
414
+ */
415
+ type Structure<C, Parent> = '*' extends Heads<C> ? Items<ValueAt<C, '*'>, Parent> : Shape<C>;
416
+ type Items<V, Parent> = [Parent] extends [readonly unknown[]] ? V[] : V[] | Record<string, V>;
417
+ type ValueAt<R, H extends string, F extends FieldInfo = Own<R, H>> = OrNull<HasChildren<R, H> extends true ? Structure<Children<R, H>, F['value']> : F['value'], F['nullable']>;
418
+ /**
419
+ * A key is in the data when a rule puts it there, or when a child key without a wildcard is required, unless a rule
420
+ * may leave it out.
421
+ */
422
+ type IsRequired<R, H extends string> = Own<R, H>['optional'] extends true ? false : Own<R, H>['required'] extends true ? true : HasChildren<R, H> extends true ? '*' extends Heads<Children<R, H>> ? false : [RequiredHeads<Children<R, H>>] extends [never] ? false : true : false;
423
+ type RequiredHeads<R> = {
424
+ [H in Heads<R>]: Own<R, H>['excluded'] extends true ? never : IsRequired<R, H> extends true ? H : never;
425
+ }[Heads<R>];
426
+ type Simplify<T> = {
427
+ [K in keyof T]: T[K];
428
+ } & {};
429
+ type Shape<R> = string extends Keys<R> ? Record<string, unknown> : Simplify<{
430
+ [H in Heads<R> as Own<R, H>['excluded'] extends true ? never : IsRequired<R, H> extends true ? H : never]: ValueAt<R, H>;
431
+ } & {
432
+ [H in Heads<R> as Own<R, H>['excluded'] extends true ? never : IsRequired<R, H> extends true ? never : H]?: ValueAt<R, H>;
433
+ }>;
434
+ /**
435
+ * The type of one field's passing value, from its rule string: `'nullable|integer'` → `number | \`${number}\` | null`.
436
+ * A rule string the compiler only knows as `string` gives unknown.
437
+ */
438
+ type InferRuleType<S extends string> = string extends S ? unknown : OrNull<FieldOf<S>['value'], FieldOf<S>['nullable']>;
439
+ /**
440
+ * The validated data a Rules object gives: nested as Validator's validated() nests it (`author.name` → `{ author: {
441
+ * name } }`, `tags.*` → an array, or an object too unless `tags` has `array` or `list`), each key optional unless a
442
+ * rule puts it in, each value typed by its rules. Rules known only as `Rules` (or any `Record<string, …>`) give
443
+ * `Record<string, unknown>`, and rule strings known only as `string` give optional keys of unknown. Write a
444
+ * FormRequest's `rules()` with `as const` so its rule strings keep their text; `request().validate({ … })` needs
445
+ * nothing.
446
+ */
447
+ type InferValidatedType<R> = R extends unknown ? Shape<R> : never;
448
+
449
+ /** A rule object (Laravel's ValidationRule). Call fail() to reject the value. */
450
+ interface ValidationRule {
451
+ validate(attribute: string, value: unknown, fail: (message: string) => void, data: Record<string, unknown>): void | Promise<void>;
452
+ }
453
+ /** 'required|string|max:255', or an array mixing strings and rule objects. Keys support dot + `*` wildcards. */
454
+ type Rules = Record<string, string | ReadonlyArray<string | ValidationRule>>;
455
+ interface MessageBag {
456
+ add(key: string, message: string): void;
457
+ has(key: string): boolean;
458
+ first(key?: string): string | undefined;
459
+ get(key: string): string[];
460
+ all(): string[];
461
+ isEmpty(): boolean;
462
+ count(): number;
463
+ toObject(): Record<string, string[]>;
464
+ }
465
+ /** `R` is the rules' type: `validated()` is typed from them, as `request().validate()` is. */
466
+ interface Validator<R extends Rules = Rules> {
467
+ passes(): Promise<boolean>;
468
+ fails(): Promise<boolean>;
469
+ /** Only the keys that have rules. Throws ValidationError (Exceptions.ts) on failure. */
470
+ validated<T = InferValidatedType<R>>(): Promise<T>;
471
+ /** Valid only after passes()/fails()/validated() has run. */
472
+ errors(): MessageBag;
473
+ after(callback: (validator: Validator) => void | Promise<void>): this;
474
+ /** Adds a failure message for `field` (from an after() hook). */
475
+ fail(field: string, message: string): void;
476
+ }
477
+ type RuleCallback = (attribute: string, value: unknown, parameters: string[], data: Record<string, unknown>) => boolean | Promise<boolean>;
478
+ interface ValidationFactory {
479
+ make<const R extends Rules>(data: Record<string, unknown>, rules: R, messages?: Record<string, string>, attributes?: Record<string, string>): Validator<R>;
480
+ /** Registers a string rule, e.g. extend('uppercase', fn, ':attribute must be uppercase'). */
481
+ extend(name: string, callback: RuleCallback, message?: string): void;
482
+ }
483
+ declare const ValidationFactory: Token<ValidationFactory>;
484
+
201
485
  /** Web-standard body/headers init types, derived from the runtime's global Response/Headers (no DOM lib needed). */
202
486
  type BodyInit = ConstructorParameters<typeof Response>[0];
203
487
  type HeadersInit = ConstructorParameters<typeof Headers>[0];
@@ -206,7 +490,13 @@ interface UploadedFile {
206
490
  readonly mimeType: string;
207
491
  readonly size: number;
208
492
  extension(): string;
493
+ /** The extension of the name the browser gave the file, lower-cased ('' without one). */
494
+ clientExtension(): string;
495
+ /** A random 40-character name with extension(): the name store() gives the file. */
496
+ hashName(): string;
209
497
  arrayBuffer(): Promise<ArrayBuffer>;
498
+ text(): Promise<string>;
499
+ stream(): ReadableStream<Uint8Array>;
210
500
  /** Stores on a Filesystem disk. Returns the stored path. */
211
501
  store(directory: string, disk?: string): Promise<string>;
212
502
  storeAs(directory: string, name: string, disk?: string): Promise<string>;
@@ -229,6 +519,8 @@ interface HttpRequest {
229
519
  header(name: string, defaultValue: string): string;
230
520
  bearerToken(): string | undefined;
231
521
  ip(): string | undefined;
522
+ /** The raw body as text (Laravel's getContent()); '' when there is none. */
523
+ content(): string;
232
524
  expectsJson(): boolean;
233
525
  ajax(): boolean;
234
526
  query<T = unknown>(key?: string, defaultValue?: T): T;
@@ -243,12 +535,23 @@ interface HttpRequest {
243
535
  merge(values: Record<string, unknown>): this;
244
536
  file(key: string): UploadedFile | undefined;
245
537
  cookie(name: string): string | undefined;
538
+ /** Replace the parsed request cookies (EncryptCookies calls this after decrypting). */
539
+ setCookies(cookies: Record<string, string>): void;
246
540
  /** Route parameter (after model binding), or every parameter when called with no key. */
247
541
  route<T = unknown>(key?: string): T;
248
542
  session(): Session;
249
- /** The user resolved earlier by auth middleware. Undefined for guests. Use `await Auth.user()` to resolve lazily. */
250
- user<T = unknown>(guard?: string): T | undefined;
543
+ /**
544
+ * The signed-in user, found through the request's guard (the default one, or the one named) the first time it is
545
+ * asked for, then the same instance for the rest of the request. Undefined for a guest.
546
+ */
547
+ user<T = unknown>(guard?: string): Promise<T | undefined>;
548
+ /** How user() finds the user (Auth sets it). The resolver may return a promise. */
251
549
  setUserResolver(resolver: (guard?: string) => unknown): void;
550
+ /**
551
+ * Validates this request's input via the ValidationFactory; throws a Validation OrielError (422) on failure. The
552
+ * validated data is typed from the rules: `validate({ title: 'required|string' })` is `{ title: string }`.
553
+ */
554
+ validate<const R extends Rules>(rules: R, messages?: Record<string, string>, attributes?: Record<string, string>): Promise<InferValidatedType<R>>;
252
555
  }
253
556
  declare const HttpRequest: Token<HttpRequest>;
254
557
  type Next = (request: HttpRequest) => Promise<Response>;
@@ -277,6 +580,8 @@ interface MiddlewareConfigurator {
277
580
  except: string[];
278
581
  }): this;
279
582
  redirectGuestsTo(url: string | ((request: HttpRequest) => string)): this;
583
+ /** Where the `guest` middleware sends a signed-in user. */
584
+ redirectUsersTo(url: string | ((request: HttpRequest) => string)): this;
280
585
  }
281
586
  interface HttpKernel {
282
587
  handle(request: Request): Promise<Response>;
@@ -287,25 +592,171 @@ interface ResponseFactory {
287
592
  make(content?: BodyInit | null, status?: number, headers?: HeadersInit): Response;
288
593
  json(data: unknown, status?: number, headers?: HeadersInit): Response;
289
594
  noContent(status?: number): Response;
595
+ /** Renders the view into an HTML response. */
596
+ view(name: string, data?: Record<string, unknown>, status?: number, headers?: HeadersInit): Promise<Response>;
290
597
  download(path: string, name?: string, headers?: HeadersInit): Promise<Response>;
598
+ /** Sends the file inline, for the browser to show (download() sends it as an attachment). */
599
+ file(path: string, headers?: HeadersInit): Promise<Response>;
291
600
  stream(body: ReadableStream, status?: number, headers?: HeadersInit): Response;
292
601
  }
293
602
  declare const ResponseFactory: Token<ResponseFactory>;
294
603
 
604
+ interface ServiceProvider {
605
+ /** Bind things into the container. Synchronous. Don't resolve other services here. */
606
+ register?(): void;
607
+ /** Runs after every provider is registered. May be async (e.g. importing route files). */
608
+ boot?(): void | Promise<void>;
609
+ }
610
+ type ServiceProviderClass = new (app: Application) => ServiceProvider;
611
+ interface Application extends Container {
612
+ readonly version: string;
613
+ basePath(path?: string): string;
614
+ appPath(path?: string): string;
615
+ bootstrapPath(path?: string): string;
616
+ configPath(path?: string): string;
617
+ databasePath(path?: string): string;
618
+ publicPath(path?: string): string;
619
+ resourcePath(path?: string): string;
620
+ storagePath(path?: string): string;
621
+ /** With no args returns the environment name. With args returns whether it matches any of them. */
622
+ environment(): string;
623
+ environment(...environments: string[]): boolean;
624
+ isProduction(): boolean;
625
+ isLocal(): boolean;
626
+ runningInConsole(): boolean;
627
+ /** Mark the app as running in the console (the CLI entry point calls this). Defaults to true. */
628
+ setRunningInConsole(value?: boolean): void;
629
+ runningUnitTests(): boolean;
630
+ /** Registers the provider. If the app is already booted, the provider is booted immediately. */
631
+ register(provider: ServiceProvider | ServiceProviderClass): Promise<ServiceProvider>;
632
+ getProviders(): ServiceProvider[];
633
+ boot(): Promise<void>;
634
+ isBooted(): boolean;
635
+ booting(callback: (app: Application) => void | Promise<void>): void;
636
+ booted(callback: (app: Application) => void | Promise<void>): void;
637
+ /** Handle one HTTP request in a fresh request scope via the bound HttpKernel. */
638
+ handle(request: Request): Promise<Response>;
639
+ /** Register a callback that terminate() runs, in registration order. */
640
+ terminating(callback: () => void | Promise<void>): void;
641
+ terminate(): Promise<void>;
642
+ /**
643
+ * Register a callback that shutdown() runs once, before the process exits: close pools and clients, write out
644
+ * files. terminating() callbacks run after every request; these run once, at the end.
645
+ */
646
+ onShutdown(callback: () => void | Promise<void>): void;
647
+ /** Runs the shutdown callbacks once, newest first; a failing one is printed and the rest still run. Never rejects. */
648
+ shutdown(): Promise<void>;
649
+ }
650
+ declare const Application: Token<Application>;
651
+ interface ExceptionHandler {
652
+ report(error: unknown): Promise<void>;
653
+ shouldReport(error: unknown): boolean;
654
+ /** `request` is the scoped HttpRequest (Contracts/Http) when available, else the raw Request. */
655
+ render(request: unknown, error: unknown): Promise<Response>;
656
+ }
657
+ declare const ExceptionHandler: Token<ExceptionHandler>;
658
+ /** Paths passed to Application.configure().withRouting(). Routing (Wave 1) loads them. */
659
+ interface RoutingPaths {
660
+ /** One route file or several, loaded in order (Laravel's `withRouting(web: [...])`). */
661
+ web?: string | string[];
662
+ api?: string | string[];
663
+ console?: string;
664
+ health?: string;
665
+ apiPrefix: string;
666
+ }
667
+ declare const RoutingPaths: Token<RoutingPaths>;
668
+ /** The object passed to Application.configure().withExceptions(e => …), like Laravel's Exceptions class. */
669
+ interface ExceptionsConfigurator {
670
+ /** Custom reporting. Return false to stop the default logging. */
671
+ report(callback: (error: unknown) => void | boolean | Promise<void | boolean>): this;
672
+ /** Custom rendering. Return undefined to fall through to the default rendering. */
673
+ render(callback: (error: unknown, request: unknown) => Response | undefined | Promise<Response | undefined>): this;
674
+ /** Never report errors of these classes. */
675
+ dontReport(...classes: Array<abstract new (...args: never[]) => Error>): this;
676
+ /** Render errors as JSON when the callback returns true, whatever the Accept header. */
677
+ shouldRenderJsonWhen(callback: (request: HttpRequest, error: unknown) => boolean): this;
678
+ }
679
+ /** Callbacks collected by withMiddleware()/withExceptions(); invoked by Http / the exception handler (Wave 1). */
680
+ type ConfigCallbacks<T> = Array<(configurator: T) => void>;
681
+ /** Typed as unknown here because MiddlewareConfigurator lives in Contracts/Http; Http casts on use. */
682
+ declare const MiddlewareCallbacks: Token<ConfigCallbacks<unknown>>;
683
+ declare const ExceptionCallbacks: Token<ConfigCallbacks<ExceptionsConfigurator>>;
684
+
685
+ interface ConfigRepository {
686
+ has(key: string): boolean;
687
+ /** Dot notation: get('database.connections.sqlite.database'). */
688
+ get<T = unknown>(key: string, defaultValue?: T): T;
689
+ set(key: string, value: unknown): void;
690
+ set(values: Record<string, unknown>): void;
691
+ push(key: string, value: unknown): void;
692
+ all(): Record<string, unknown>;
693
+ }
694
+ declare const ConfigRepository: Token<ConfigRepository>;
695
+
696
+ interface Arrayable<T = unknown> {
697
+ toArray(): T;
698
+ }
699
+ interface Jsonable {
700
+ toJson(): string;
701
+ }
702
+ interface Htmlable {
703
+ toHtml(): string;
704
+ }
705
+ /** Anything a controller can return that knows how to become a Response. */
706
+ interface Responsable {
707
+ toResponse(request: unknown): Response | Promise<Response>;
708
+ }
709
+ /** The minimal collection surface contracts rely on (implemented by @orieljs/collections). */
710
+ interface Enumerable<T> extends Iterable<T>, Arrayable<unknown[]> {
711
+ all(): T[];
712
+ count(): number;
713
+ isEmpty(): boolean;
714
+ }
715
+ interface ClassRegistry {
716
+ /** Registers under `name` (default: cls.name). Throws if the name is already taken by a different class. */
717
+ register(cls: Class<unknown>, name?: string): string;
718
+ nameOf(cls: Class<unknown>): string | undefined;
719
+ resolve<T = unknown>(name: string): Class<T>;
720
+ has(name: string): boolean;
721
+ }
722
+ declare const ClassRegistry: Token<ClassRegistry>;
723
+
724
+ type PipeNext<T> = (passable: T) => Promise<unknown>;
725
+ type PipeClosure<T> = (passable: T, next: PipeNext<T>) => Promise<unknown> | unknown;
726
+ /** A class resolved from the container whose `via` method (default 'handle') is called; or a string alias 'name:param1,param2'. */
727
+ type Pipe<T> = PipeClosure<T> | Class<object> | string;
728
+ interface Pipeline<T = unknown> {
729
+ send(passable: T): this;
730
+ through(pipes: ReadonlyArray<Pipe<T>>): this;
731
+ pipe(...pipes: Array<Pipe<T>>): this;
732
+ /** Method called on class pipes. Default 'handle'. */
733
+ via(method: string): this;
734
+ then<R>(destination: (passable: T) => R | Promise<R>): Promise<R>;
735
+ thenReturn(): Promise<T>;
736
+ }
737
+ interface PipelineFactory {
738
+ make<T>(): Pipeline<T>;
739
+ }
740
+ declare const PipelineFactory: Token<PipelineFactory>;
741
+
295
742
  /** Public method names of a controller (excludes non-function members). */
296
743
  type ActionMethods<C> = {
297
744
  [K in keyof C]: C[K] extends (...args: any[]) => unknown ? K : never;
298
745
  }[keyof C] & string;
299
746
  type ControllerAction<C> = readonly [Class<C>, ActionMethods<C>];
300
747
  type RouteClosure = (...args: any[]) => unknown;
301
- type RouteAction = RouteClosure | ControllerAction<any>;
748
+ /** A class with __invoke(): Route.get('/counter', Counter) (single-action controllers, full-page Live components). */
749
+ type InvokableClass = Class<{
750
+ __invoke(...args: any[]): unknown;
751
+ }>;
752
+ type RouteAction = RouteClosure | ControllerAction<any> | InvokableClass;
302
753
  type MiddlewareReference = string | MiddlewareClass;
303
754
  interface Route {
304
755
  readonly methods: readonly string[];
305
756
  readonly uri: string;
306
757
  getName(): string | undefined;
307
758
  name(name: string): this;
308
- middleware(...middleware: MiddlewareReference[]): this;
759
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): this;
309
760
  withoutMiddleware(...middleware: MiddlewareReference[]): this;
310
761
  where(parameter: string, pattern: string): this;
311
762
  where(patterns: Record<string, string>): this;
@@ -313,7 +764,7 @@ interface Route {
313
764
  interface RouteRegistrar {
314
765
  prefix(prefix: string): RouteRegistrar;
315
766
  name(prefix: string): RouteRegistrar;
316
- middleware(...middleware: MiddlewareReference[]): RouteRegistrar;
767
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): RouteRegistrar;
317
768
  controller(controller: Class<unknown>): RouteRegistrar;
318
769
  group(routes: () => void | Promise<void>): Promise<void>;
319
770
  }
@@ -323,31 +774,51 @@ interface ResourceOptions {
323
774
  parameters?: Record<string, string>;
324
775
  names?: Record<string, string>;
325
776
  }
777
+ /** The route matched for the current request (scope-local; set by the router before route middleware runs). */
778
+ interface CurrentRoute {
779
+ readonly route: Route;
780
+ /** Route parameters after model binding, in URI order. */
781
+ readonly parameters: Record<string, unknown>;
782
+ /** Resolved route middleware instances, for HttpKernel.terminate(). */
783
+ readonly middleware: Middleware[];
784
+ }
785
+ declare const CurrentRoute: Token<CurrentRoute>;
326
786
  interface Router {
327
- get<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
328
- post<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
329
- put<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
330
- patch<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
331
- delete<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
332
- options<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
333
- any<C>(uri: string, action: ControllerAction<C> | RouteClosure): Route;
334
- match<C>(methods: string[], uri: string, action: ControllerAction<C> | RouteClosure): Route;
787
+ get<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
788
+ post<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
789
+ put<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
790
+ patch<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
791
+ delete<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
792
+ options<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
793
+ any<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
794
+ match<C>(methods: string[], uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
335
795
  redirect(from: string, to: string, status?: number): Route;
336
796
  view(uri: string, view: string, data?: Record<string, unknown>): Route;
797
+ /** Route.inertia('/about', 'About', props): a GET route that renders an Inertia page (Laravel's Route::inertia). */
798
+ inertia(uri: string, component: string, props?: Record<string, unknown>): Route;
337
799
  resource(name: string, controller: Class<unknown>, options?: ResourceOptions): void;
338
800
  apiResource(name: string, controller: Class<unknown>, options?: ResourceOptions): void;
339
801
  fallback(action: RouteAction): Route;
340
802
  prefix(prefix: string): RouteRegistrar;
341
803
  name(prefix: string): RouteRegistrar;
342
- middleware(...middleware: MiddlewareReference[]): RouteRegistrar;
804
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): RouteRegistrar;
343
805
  controller(controller: Class<unknown>): RouteRegistrar;
344
806
  /** Explicit model binding: Route.model('author', User). */
345
807
  model(parameter: string, model: Class<unknown>): void;
346
808
  /** Custom binding resolver. */
347
809
  bind(parameter: string, resolver: (value: string) => unknown | Promise<unknown>): void;
348
810
  pattern(parameter: string, pattern: string): void;
811
+ /** Name a middleware class, e.g. aliasMiddleware('auth', Authenticate). */
812
+ aliasMiddleware(name: string, middleware: MiddlewareClass): this;
813
+ /** Define (or replace) a middleware group such as 'web' or 'api'. */
814
+ middlewareGroup(name: string, middleware: MiddlewareReference[]): this;
815
+ /** Append to a group unless it is already present. */
816
+ pushMiddlewareToGroup(group: string, middleware: MiddlewareReference): this;
817
+ getMiddlewareGroups(): Record<string, MiddlewareReference[]>;
349
818
  getRoutes(): readonly Route[];
350
819
  current(): Route | undefined;
820
+ /** Match the request, bind parameters, run the route middleware and the action. Called by the Http kernel. */
821
+ dispatch(request: HttpRequest): Promise<Response>;
351
822
  }
352
823
  declare const Router: Token<Router>;
353
824
  /**
@@ -360,6 +831,36 @@ interface RouteModelResolver {
360
831
  resolveExplicit(model: Class<unknown>, value: string, field?: string): Promise<unknown>;
361
832
  }
362
833
  declare const RouteModelResolver: Token<RouteModelResolver>;
834
+ /**
835
+ * Route name → parameters, for the typed route() and redirect().route() helpers. Empty until `oriel route:types`
836
+ * augments it (types/routes.d.ts); while it is empty any string is accepted. The contracts themselves keep taking
837
+ * strings: the framework builds route names at run time.
838
+ */
839
+ interface RouteList {
840
+ }
841
+ /** A route name: the generated ones, or any string before `oriel route:types` has run. */
842
+ type RouteName = [keyof RouteList] extends [never] ? string : Extract<keyof RouteList, string>;
843
+ /** A route parameter's value: a scalar, or a model (its route key, or the `{post:slug}` column, goes in the URL). */
844
+ type RouteParameter = string | number | bigint | boolean | {
845
+ getRouteKey(): unknown;
846
+ };
847
+ type GeneratedParameters<N extends keyof RouteList> = {
848
+ [K in keyof RouteList[N]]: RouteParameter;
849
+ };
850
+ type RequiredParameters<P> = {
851
+ [K in keyof P]-?: Record<never, never> extends Pick<P, K> ? never : K;
852
+ }[keyof P];
853
+ /**
854
+ * A named route's parameters: named (`{ post }`, extra keys become the query string), one value (it fills the first
855
+ * parameter), or values in URI order (`[post, comment]`).
856
+ */
857
+ type RouteParameters<N extends string> = N extends keyof RouteList ? (GeneratedParameters<N> & Record<string, unknown>) | RouteParameter | readonly RouteParameter[] : unknown;
858
+ /**
859
+ * The arguments after a route name in route() and redirect().route(): the parameters, required when the route has a
860
+ * required one, then `Rest` (route()'s `absolute`, redirect().route()'s `status`). Before `oriel route:types` has
861
+ * named the route, anything is accepted.
862
+ */
863
+ type RouteArguments<N extends string, Rest extends unknown[] = [absolute?: boolean]> = N extends keyof RouteList ? [RequiredParameters<RouteList[N]>] extends [never] ? [parameters?: RouteParameters<N>, ...rest: Rest] : [parameters: RouteParameters<N>, ...rest: Rest] : [parameters?: unknown, ...rest: Rest];
363
864
  interface UrlGenerator {
364
865
  to(path: string, query?: Record<string, unknown>, absolute?: boolean): string;
365
866
  route(name: string, parameters?: unknown, absolute?: boolean): string;
@@ -367,21 +868,34 @@ interface UrlGenerator {
367
868
  current(): string;
368
869
  previous(fallback?: string): string;
369
870
  hasRoute(name: string): boolean;
871
+ /** A URL to a named route with a `signature` query (HMAC-SHA256 keyed by APP_KEY); `expiration` adds `expires`. */
872
+ signedRoute(name: string, parameters?: unknown, expiration?: Date | number, absolute?: boolean): string;
873
+ /** signedRoute() that expires: a Date, or seconds from now. */
874
+ temporarySignedRoute(name: string, expiration: Date | number, parameters?: unknown, absolute?: boolean): string;
875
+ /** Whether the request URL carries a valid, unexpired signature (`absolute: false` signs the path only). */
876
+ hasValidSignature(request: HttpRequest, absolute?: boolean): boolean;
370
877
  }
371
878
  declare const UrlGenerator: Token<UrlGenerator>;
372
879
  interface RedirectResponse extends Responsable {
373
880
  readonly targetUrl: string;
374
881
  with(key: string | Record<string, unknown>, value?: unknown): this;
375
- withErrors(errors: Record<string, string | string[]>, bag?: string): this;
882
+ /** Flashes the errors (a record, or a validator's `errors()`) into the bag, `default` unless named. */
883
+ withErrors(errors: Record<string, string | string[]> | MessageBag, bag?: string): this;
376
884
  withInput(input?: Record<string, unknown>): this;
377
885
  withCookie(name: string, value: string, minutes?: number): this;
886
+ header(name: string, value: string): this;
378
887
  }
379
888
  interface Redirector {
380
889
  to(path: string, status?: number): RedirectResponse;
381
890
  route(name: string, parameters?: unknown, status?: number): RedirectResponse;
382
891
  back(fallback?: string, status?: number): RedirectResponse;
383
- intended(fallback?: string): RedirectResponse;
892
+ intended(fallback?: string, status?: number): RedirectResponse;
384
893
  away(url: string, status?: number): RedirectResponse;
894
+ /** Remembers the URL a guest was going to (for intended()), then redirects to `path`. */
895
+ guest(path: string, status?: number): RedirectResponse;
896
+ /** Redirects to the current URL. */
897
+ refresh(status?: number): RedirectResponse;
898
+ setIntendedUrl(url: string): void;
385
899
  }
386
900
  declare const Redirector: Token<Redirector>;
387
901
 
@@ -438,6 +952,8 @@ interface ViewFactory {
438
952
  exists(name: string): boolean;
439
953
  share(key: string | Record<string, unknown>, value?: unknown): void;
440
954
  composer(views: string | string[], composer: (view: View) => void | Promise<void>): void;
955
+ /** Renders TSX (an element, a string, an Htmlable, a View, promises of them) to HTML, like Blade::render(). */
956
+ renderToString(node: unknown): Promise<string>;
441
957
  }
442
958
  declare const ViewFactory: Token<ViewFactory>;
443
959
 
@@ -458,10 +974,12 @@ interface Logger {
458
974
  interface LogManager extends Logger {
459
975
  channel(name?: string): Logger;
460
976
  stack(channels: string[]): Logger;
977
+ /** Writes out and closes the channels opened so far (log files are written asynchronously); a script awaits it last. */
978
+ flush(): Promise<void>;
461
979
  }
462
980
  declare const LogManager: Token<LogManager>;
463
981
 
464
- type ErrorKind = 'Http' | 'ModelNotFound' | 'Validation' | 'Authentication' | 'Authorization' | 'TokenMismatch' | 'BindingResolution' | 'CircularDependency' | 'ContainerNotAvailable';
982
+ type ErrorKind = 'Http' | 'Server' | 'ModelNotFound' | 'Validation' | 'Authentication' | 'Authorization' | 'TokenMismatch' | 'BindingResolution' | 'CircularDependency' | 'ContainerNotAvailable';
465
983
  /** Every error thrown by the framework implements this. The exception handler switches on `kind`. */
466
984
  interface OrielError extends Error {
467
985
  readonly kind: ErrorKind;
@@ -513,6 +1031,11 @@ interface QueryBuilder<T = Row> {
513
1031
  count(): Promise<number>;
514
1032
  exists(): Promise<boolean>;
515
1033
  insert(values: Row | Row[]): Promise<void>;
1034
+ /**
1035
+ * Inserts rows, skipping any that violate a unique key instead of failing (Laravel's insertOrIgnore). Returns the
1036
+ * number of rows inserted. Nothing is thrown for a duplicate, so a caller's transaction stays usable on Postgres.
1037
+ */
1038
+ insertOrIgnore(values: Row | Row[]): Promise<number>;
516
1039
  insertGetId(values: Row, keyName?: string): Promise<number | string>;
517
1040
  update(values: Row): Promise<number>;
518
1041
  upsert(values: Row | Row[], uniqueBy: string[], update?: string[]): Promise<number>;
@@ -529,10 +1052,22 @@ interface DatabaseConnection {
529
1052
  statement(sql: string, bindings?: readonly unknown[]): Promise<void>;
530
1053
  /** Nested calls use savepoints. Rolls back if fn throws. */
531
1054
  transaction<R>(fn: (connection: DatabaseConnection) => Promise<R>): Promise<R>;
1055
+ /**
1056
+ * Start a transaction that stays open, for every caller of this connection, until commit()/rollBack().
1057
+ * Nested calls use savepoints. Meant for test isolation (RefreshDatabase); app code uses transaction(fn).
1058
+ */
1059
+ beginTransaction(): Promise<void>;
1060
+ commit(): Promise<void>;
1061
+ /** Rolls back the innermost level opened by beginTransaction(). Does nothing when none is open. */
1062
+ rollBack(): Promise<void>;
1063
+ /** 0 outside a transaction. */
1064
+ transactionLevel(): number;
532
1065
  }
533
1066
  interface DatabaseManager extends DatabaseConnection {
534
1067
  connection(name?: string): DatabaseConnection;
535
1068
  disconnect(name?: string): Promise<void>;
1069
+ /** Closes every open connection and forgets them (the application's shutdown, the end of a test). */
1070
+ disconnectAll(): Promise<void>;
536
1071
  }
537
1072
  declare const DatabaseManager: Token<DatabaseManager>;
538
1073
  /** What non-Database components may rely on from a model instance. */
@@ -543,6 +1078,8 @@ interface ModelInstance {
543
1078
  getTable(): string;
544
1079
  getRouteKey(): unknown;
545
1080
  getRouteKeyName(): string;
1081
+ /** The value stored in a polymorphic `*_type` column for this model: its morph map alias, else its class name. */
1082
+ getMorphClass(): string;
546
1083
  getAttribute<T = unknown>(key: string): T;
547
1084
  setAttribute(key: string, value: unknown): this;
548
1085
  fill(attributes: Row): this;
@@ -558,38 +1095,19 @@ interface ModelStatic<M extends ModelInstance = ModelInstance> {
558
1095
  find(id: unknown): Promise<M | undefined>;
559
1096
  findOrFail(id: unknown): Promise<M>;
560
1097
  }
561
-
562
- /** A rule object (Laravel's ValidationRule). Call fail() to reject the value. */
563
- interface ValidationRule {
564
- validate(attribute: string, value: unknown, fail: (message: string) => void, data: Record<string, unknown>): void | Promise<void>;
565
- }
566
- /** 'required|string|max:255', or an array mixing strings and rule objects. Keys support dot + `*` wildcards. */
567
- type Rules = Record<string, string | ReadonlyArray<string | ValidationRule>>;
568
- interface MessageBag {
569
- has(key: string): boolean;
570
- first(key?: string): string | undefined;
571
- get(key: string): string[];
572
- all(): string[];
573
- isEmpty(): boolean;
574
- count(): number;
575
- toObject(): Record<string, string[]>;
576
- }
577
- interface Validator {
578
- passes(): Promise<boolean>;
579
- fails(): Promise<boolean>;
580
- /** Only the keys that have rules. Throws ValidationError (Exceptions.ts) on failure. */
581
- validated<T = Record<string, unknown>>(): Promise<T>;
582
- /** Valid only after passes()/fails()/validated() has run. */
583
- errors(): MessageBag;
584
- after(callback: (validator: Validator) => void | Promise<void>): this;
585
- }
586
- type RuleCallback = (attribute: string, value: unknown, parameters: string[], data: Record<string, unknown>) => boolean | Promise<boolean>;
587
- interface ValidationFactory {
588
- make(data: Record<string, unknown>, rules: Rules, messages?: Record<string, string>, attributes?: Record<string, string>): Validator;
589
- /** Registers a string rule, e.g. extend('uppercase', fn, ':attribute must be uppercase'). */
590
- extend(name: string, callback: RuleCallback, message?: string): void;
1098
+ /**
1099
+ * What decides a paginator's page and the path of its links when the request doesn't (Laravel's
1100
+ * Paginator::currentPageResolver and currentPathResolver, which Livewire's WithPagination replaces). Live binds one for
1101
+ * the application, which answers while a WithPagination component mounts, runs an update's hooks and actions, or
1102
+ * renders. Unbound, or `undefined` from a method, the paginators read the request (`?page=` and its URL).
1103
+ */
1104
+ interface PaginationState {
1105
+ /** The page to show for `pageName` ('page' by default). */
1106
+ currentPage(pageName: string): number | undefined;
1107
+ /** The base path of the page links. */
1108
+ currentPath(): string | undefined;
591
1109
  }
592
- declare const ValidationFactory: Token<ValidationFactory>;
1110
+ declare const PaginationState: Token<PaginationState>;
593
1111
 
594
1112
  interface Authenticatable {
595
1113
  getAuthIdentifierName(): string;
@@ -658,6 +1176,11 @@ interface MustVerifyEmail {
658
1176
 
659
1177
  /** Options a job class may declare as public fields. Their presence (or implementing ShouldQueue) makes things queueable. */
660
1178
  interface ShouldQueue {
1179
+ /**
1180
+ * Marks the class as queued at run time: `implements ShouldQueue` leaves no trace once compiled, so the interface
1181
+ * asks for `readonly shouldQueue = true`. Jobs, listeners, mailables and notifications carrying it are queued.
1182
+ */
1183
+ readonly shouldQueue: true;
661
1184
  connection?: string;
662
1185
  queue?: string;
663
1186
  /** Seconds. */
@@ -667,7 +1190,11 @@ interface ShouldQueue {
667
1190
  backoff?: number | number[];
668
1191
  /** Seconds. */
669
1192
  timeout?: number;
670
- uniqueId?(): string;
1193
+ /**
1194
+ * Laravel's ShouldBeUnique: while a job with this id is pending, another one is dropped. A queued listener's
1195
+ * receives the event (Laravel 13); a number is used as its string.
1196
+ */
1197
+ uniqueId?(...args: never[]): string | number;
671
1198
  }
672
1199
  /** A job: public fields are its serialized data; handle() runs on the worker (inject() works inside it). */
673
1200
  interface Job extends Partial<ShouldQueue> {
@@ -688,6 +1215,10 @@ interface QueuePayload {
688
1215
  pushedAt: number;
689
1216
  batchId?: string;
690
1217
  chain?: QueuePayload[];
1218
+ /** Unix ms after which the job fails instead of retrying. */
1219
+ retryUntil?: number;
1220
+ /** Mark the job failed (instead of releasing it) when it times out. */
1221
+ failOnTimeout?: boolean;
691
1222
  }
692
1223
  interface QueueJob {
693
1224
  getJobId(): string;
@@ -770,6 +1301,31 @@ interface BusDispatcher {
770
1301
  findBatch(id: string): Promise<Batch | undefined>;
771
1302
  }
772
1303
  declare const BusDispatcher: Token<BusDispatcher>;
1304
+ /** What PendingBatch hands to the repository. Callbacks are jobs, because closures can't be serialized. */
1305
+ interface PendingBatchOptions {
1306
+ name: string;
1307
+ then: Job[];
1308
+ catch: Job[];
1309
+ finally: Job[];
1310
+ allowFailures: boolean;
1311
+ connection?: string;
1312
+ queue?: string;
1313
+ }
1314
+ /** Stores batches and runs their bookkeeping (Laravel's BatchRepository). Bound by the Queue component. */
1315
+ interface BatchRepository {
1316
+ store(options: PendingBatchOptions): Promise<Batch>;
1317
+ find(id: string): Promise<Batch | undefined>;
1318
+ /** Adds `amount` to both total and pending jobs, before the jobs are pushed. */
1319
+ incrementTotalJobs(id: string, amount: number): Promise<void>;
1320
+ /** A batched job succeeded: decrement pending, then run then/finally callbacks when due. */
1321
+ recordSuccessfulJob(id: string, jobUuid: string): Promise<void>;
1322
+ /** A batched job failed for good: count it, cancel unless failures are allowed, run catch/finally when due. */
1323
+ recordFailedJob(id: string, jobUuid: string, error: unknown): Promise<void>;
1324
+ markAsFinished(id: string): Promise<void>;
1325
+ cancel(id: string): Promise<void>;
1326
+ delete(id: string): Promise<void>;
1327
+ }
1328
+ declare const BatchRepository: Token<BatchRepository>;
773
1329
 
774
1330
  /** A CLI command. Signature uses Laravel syntax: 'mail:send {user} {--queue=default}'. */
775
1331
  interface Command {
@@ -777,6 +1333,29 @@ interface Command {
777
1333
  readonly description: string;
778
1334
  handle(): number | void | Promise<number | void>;
779
1335
  }
1336
+ type OptionValue = string | boolean | string[] | undefined;
1337
+ /** `this` inside a closure command (Laravel's Command API). */
1338
+ interface CommandContext extends Command {
1339
+ argument(name: string): string | string[] | undefined;
1340
+ arguments(): Record<string, string | string[]>;
1341
+ option(name: string): OptionValue;
1342
+ options(): Record<string, OptionValue>;
1343
+ info(message: string): void;
1344
+ line(message?: string): void;
1345
+ comment(message: string): void;
1346
+ warn(message: string): void;
1347
+ error(message: string): void;
1348
+ newLine(count?: number): void;
1349
+ table(headers: string[], rows: string[][]): void;
1350
+ ask(question: string, defaultValue?: string): Promise<string>;
1351
+ secret(question: string): Promise<string>;
1352
+ confirm(question: string, defaultValue?: boolean): Promise<boolean>;
1353
+ choice(question: string, choices: string[], defaultIndex?: number): Promise<string>;
1354
+ }
1355
+ /** What ConsoleKernel.command() returns. */
1356
+ interface ClosureCommand extends CommandContext {
1357
+ purpose(description: string): this;
1358
+ }
780
1359
  interface ConsoleKernel {
781
1360
  /** Returns the exit code. */
782
1361
  handle(argv: string[]): Promise<number>;
@@ -784,29 +1363,89 @@ interface ConsoleKernel {
784
1363
  /** Output buffered from the last call(). */
785
1364
  output(): string;
786
1365
  all(): Record<string, Command>;
1366
+ /** Register command classes or instances (components call this from their provider's boot()). */
1367
+ register(...commands: Array<Command | (new () => Command)>): void;
1368
+ /** Closure command, like Artisan::command() in routes/console.ts. `this` is the command (argument(), info(), …). */
1369
+ command(signature: string, handler: (this: CommandContext, ...args: unknown[]) => number | void | Promise<number | void>): ClosureCommand;
787
1370
  }
788
1371
  declare const ConsoleKernel: Token<ConsoleKernel>;
1372
+ /** A callback a scheduled event runs before or after itself (before(), after(), onSuccess(), onFailure()). */
1373
+ type ScheduleHook = () => unknown;
789
1374
  interface ScheduledEvent {
790
1375
  readonly expression: string;
1376
+ /**
1377
+ * What a Schedule.command() event runs: the command and its parameters ('posts:announce --force'), without the
1378
+ * runtime and `oriel` in front. Undefined for call() and job() events. Laravel's `$event->command`.
1379
+ */
1380
+ readonly command: string | undefined;
1381
+ /** Whether withoutOverlapping() was called. Laravel's `$event->withoutOverlapping`, a method's name here. */
1382
+ readonly preventsOverlapping: boolean;
1383
+ /** Minutes the withoutOverlapping() lock is kept at most (1440 unless withoutOverlapping() says). Laravel's `$event->expiresAt`. */
1384
+ readonly expiresAt: number;
791
1385
  cron(expression: string): this;
1386
+ /**
1387
+ * Runs every N seconds: the event is due every minute, and schedule:run (or schedule:work) keeps running it until
1388
+ * the minute ends. N divides 60.
1389
+ */
1390
+ everySecond(): this;
1391
+ everyTwoSeconds(): this;
1392
+ everyFiveSeconds(): this;
1393
+ everyTenSeconds(): this;
1394
+ everyFifteenSeconds(): this;
1395
+ everyTwentySeconds(): this;
1396
+ everyThirtySeconds(): this;
792
1397
  everyMinute(): this;
1398
+ everyTwoMinutes(): this;
1399
+ everyThreeMinutes(): this;
1400
+ everyFourMinutes(): this;
793
1401
  everyFiveMinutes(): this;
1402
+ everyTenMinutes(): this;
794
1403
  everyFifteenMinutes(): this;
795
1404
  everyThirtyMinutes(): this;
796
1405
  hourly(): this;
797
- hourlyAt(minute: number): this;
1406
+ /** At these minutes past every hour. */
1407
+ hourlyAt(minute: number | readonly number[]): this;
1408
+ /** Every odd hour (1, 3, … 23), at `minute` past (0 by default). */
1409
+ everyOddHour(minute?: number | readonly number[]): this;
1410
+ everyTwoHours(minute?: number | readonly number[]): this;
1411
+ everyThreeHours(minute?: number | readonly number[]): this;
1412
+ everyFourHours(minute?: number | readonly number[]): this;
1413
+ everySixHours(minute?: number | readonly number[]): this;
798
1414
  daily(): this;
1415
+ /** The same as dailyAt(). */
1416
+ at(time: string): this;
799
1417
  dailyAt(time: string): this;
800
1418
  twiceDaily(first?: number, second?: number): this;
1419
+ /** At hours `first` and `second`, `minute` past. */
1420
+ twiceDailyAt(first?: number, second?: number, minute?: number): this;
1421
+ weekdays(): this;
1422
+ weekends(): this;
1423
+ mondays(): this;
1424
+ tuesdays(): this;
1425
+ wednesdays(): this;
1426
+ thursdays(): this;
1427
+ fridays(): this;
1428
+ saturdays(): this;
1429
+ sundays(): this;
801
1430
  weekly(): this;
802
- weeklyOn(day: number, time?: string): this;
1431
+ /** On these days of the week (0 = Sunday … 6 = Saturday), at `time` ('0:0' by default). */
1432
+ weeklyOn(day: number | readonly number[], time?: string): this;
803
1433
  monthly(): this;
804
- monthlyOn(day: number, time?: string): this;
1434
+ monthlyOn(day?: number, time?: string): this;
1435
+ twiceMonthly(first?: number, second?: number, time?: string): this;
1436
+ /** On the last day of every month, at `time`. */
1437
+ lastDayOfMonth(time?: string): this;
1438
+ quarterly(): this;
1439
+ /** On day `day` of the first month of each quarter, at `time`. */
1440
+ quarterlyOn(day?: number, time?: string): this;
805
1441
  yearly(): this;
806
- weekdays(): this;
807
- weekends(): this;
1442
+ yearlyOn(month?: number, day?: number, time?: string): this;
1443
+ /** On these days of the week (0 = Sunday … 6 = Saturday): `days([1, 3])` or `days(1, 3)`. */
1444
+ days(days: number | readonly number[], ...more: number[]): this;
808
1445
  timezone(timezone: string): this;
809
1446
  between(start: string, end: string): this;
1447
+ /** Skips the event between these times (a window may cross midnight: '23:00', '4:00'). */
1448
+ unlessBetween(start: string, end: string): this;
810
1449
  when(callback: () => boolean | Promise<boolean>): this;
811
1450
  skip(callback: () => boolean | Promise<boolean>): this;
812
1451
  /** Uses a cache lock (default 1440 minutes). */
@@ -816,6 +1455,22 @@ interface ScheduledEvent {
816
1455
  runInBackground(): this;
817
1456
  name(name: string): this;
818
1457
  description(description: string): this;
1458
+ /** Runs before the event, once its filters and locks let it run. */
1459
+ before(callback: ScheduleHook): this;
1460
+ /** Runs after the event, whether it succeeded or failed (also then()). */
1461
+ after(callback: ScheduleHook): this;
1462
+ then(callback: ScheduleHook): this;
1463
+ /** Runs after the event when it succeeded: a command exited 0, a closure neither threw nor returned false. */
1464
+ onSuccess(callback: ScheduleHook): this;
1465
+ /** Runs after the event when it failed: a command exited non-zero, a closure threw or returned false. */
1466
+ onFailure(callback: ScheduleHook): this;
1467
+ /** The name, else the description: the command, the job's class, or 'Closure'. schedule:list shows it. */
1468
+ getSummaryForDisplay(): string;
1469
+ /**
1470
+ * The cache lock withoutOverlapping() holds: `framework/schedule-` and the sha1 of the expression and the command,
1471
+ * or of the name for call() and job() events (Laravel's mutexName()). schedule:clear-cache deletes it.
1472
+ */
1473
+ mutexName(): string;
819
1474
  isDue(now: Date): boolean;
820
1475
  run(): Promise<void>;
821
1476
  }
@@ -854,6 +1509,8 @@ interface Content {
854
1509
  text?: string;
855
1510
  /** Raw HTML (used when no view is given). */
856
1511
  htmlString?: string;
1512
+ /** Raw plain-text body (used when no text view is given). */
1513
+ textString?: string;
857
1514
  with?: Record<string, unknown>;
858
1515
  }
859
1516
  interface Attachment {
@@ -892,6 +1549,8 @@ interface PendingMail {
892
1549
  cc(recipients: MailRecipient | MailRecipient[]): this;
893
1550
  bcc(recipients: MailRecipient | MailRecipient[]): this;
894
1551
  send(mailable: Mailable): Promise<SentMessage | undefined>;
1552
+ /** Sends at once, even when the mailable is queueable (Laravel's sendNow()). A fake resolves undefined. */
1553
+ sendNow(mailable: Mailable): Promise<SentMessage | undefined>;
895
1554
  queue(mailable: Mailable): Promise<void>;
896
1555
  later(delaySeconds: number, mailable: Mailable): Promise<void>;
897
1556
  }
@@ -899,6 +1558,8 @@ interface Mailer {
899
1558
  to(recipients: MailRecipient | MailRecipient[]): PendingMail;
900
1559
  /** Sends to the recipients given in the mailable's envelope. Queues it if the mailable is queueable. */
901
1560
  send(mailable: Mailable): Promise<SentMessage | undefined>;
1561
+ /** Sends to the envelope's recipients at once, even when the mailable is queueable (Laravel's sendNow()). */
1562
+ sendNow(mailable: Mailable): Promise<SentMessage | undefined>;
902
1563
  queue(mailable: Mailable): Promise<void>;
903
1564
  }
904
1565
  interface MailManager extends Mailer {
@@ -934,13 +1595,35 @@ interface NotificationDispatcher {
934
1595
  extend(channel: string, factory: () => NotificationChannel): void;
935
1596
  }
936
1597
  declare const NotificationDispatcher: Token<NotificationDispatcher>;
1598
+ /**
1599
+ * A stored database notification (Laravel's DatabaseNotification model): one row of the `notifications` table, with
1600
+ * its snake_case columns. `user.notifications()`, `unreadNotifications()` and `readNotifications()` query these,
1601
+ * newest first.
1602
+ */
1603
+ interface DatabaseNotification extends ModelInstance {
1604
+ /** A UUID. */
1605
+ readonly id: string;
1606
+ /** The notification's class name. */
1607
+ readonly type: string;
1608
+ /** What the notification's toDatabase() (or toArray()) returned. */
1609
+ readonly data: Record<string, unknown>;
1610
+ read_at: Date | null;
1611
+ readonly created_at: Date | null;
1612
+ readonly updated_at: Date | null;
1613
+ /** Sets read_at to now and saves, unless it is already read. */
1614
+ markAsRead(): Promise<void>;
1615
+ /** Clears read_at and saves, unless it is already unread. */
1616
+ markAsUnread(): Promise<void>;
1617
+ read(): boolean;
1618
+ unread(): boolean;
1619
+ }
937
1620
 
938
1621
  interface Lock {
939
1622
  /** Tries once. Returns whether it was acquired. */
940
1623
  get(): Promise<boolean>;
941
1624
  /** Tries once. Runs the callback and releases if acquired, else returns false. */
942
1625
  get<T>(callback: () => T | Promise<T>): Promise<T | false>;
943
- /** Waits up to `seconds` to acquire. Throws LockTimeout (an OrielError, kind 'Http', status 423) on timeout. */
1626
+ /** Waits up to `seconds` to acquire. Throws LockTimeoutError (an OrielError, kind 'Server', status 500) on timeout. */
944
1627
  block<T>(seconds: number, callback?: () => T | Promise<T>): Promise<T | true>;
945
1628
  release(): Promise<boolean>;
946
1629
  forceRelease(): Promise<void>;
@@ -973,6 +1656,18 @@ interface CacheManager extends CacheRepository {
973
1656
  extend(driver: string, factory: (config: Record<string, unknown>) => CacheRepository): void;
974
1657
  }
975
1658
  declare const CacheManager: Token<CacheManager>;
1659
+ /** Laravel's RateLimiter: hits per key, kept in the default cache store. */
1660
+ interface RateLimiter {
1661
+ tooManyAttempts(key: string, maxAttempts: number): Promise<boolean>;
1662
+ /** Adds a hit; the window starts at the first hit and lasts `decaySeconds` (default 60). Returns the hit count. */
1663
+ hit(key: string, decaySeconds?: number): Promise<number>;
1664
+ attempts(key: string): Promise<number>;
1665
+ remaining(key: string, maxAttempts: number): Promise<number>;
1666
+ /** Seconds until the key's window resets. */
1667
+ availableIn(key: string): Promise<number>;
1668
+ clear(key: string): Promise<void>;
1669
+ }
1670
+ declare const RateLimiter: Token<RateLimiter>;
976
1671
 
977
1672
  type ListenerClass<E> = Class<{
978
1673
  handle(event: E): unknown;
@@ -1029,38 +1724,99 @@ interface FilesystemManager extends Filesystem {
1029
1724
  }
1030
1725
  declare const FilesystemManager: Token<FilesystemManager>;
1031
1726
 
1032
- /** The Inertia page object (protocol v2). */
1727
+ /** Infinite-scroll metadata for one prop (page.scrollProps[path]). */
1728
+ interface InertiaScrollProp {
1729
+ pageName: string;
1730
+ previousPage: string | number | null;
1731
+ nextPage: string | number | null;
1732
+ currentPage: string | number | null;
1733
+ reset: boolean;
1734
+ }
1735
+ /** A once prop the client keeps between visits (page.onceProps[key]). `expiresAt` is epoch milliseconds. */
1736
+ interface InertiaOnceProp {
1737
+ prop: string;
1738
+ expiresAt: number | null;
1739
+ }
1740
+ /**
1741
+ * The Inertia page object (protocol v3, @inertiajs/core 3.x). Only component, props, url and version are always
1742
+ * present; the other fields are left out when empty or false.
1743
+ */
1033
1744
  interface InertiaPage {
1034
1745
  component: string;
1035
1746
  props: Record<string, unknown>;
1747
+ /** Path and query, never absolute: '/posts?page=2'. */
1036
1748
  url: string;
1037
- version: string | null;
1038
- encryptHistory?: boolean;
1039
- clearHistory?: boolean;
1749
+ /** '' when the app has no asset version. */
1750
+ version: string;
1751
+ sharedProps?: string[];
1040
1752
  mergeProps?: string[];
1753
+ prependProps?: string[];
1754
+ deepMergeProps?: string[];
1755
+ /** '<prop path>.<key field>', e.g. 'posts.data.id'. */
1756
+ matchPropsOn?: string[];
1757
+ /** Group name → prop paths loaded after the first render. */
1041
1758
  deferredProps?: Record<string, string[]>;
1759
+ rescuedProps?: string[];
1760
+ scrollProps?: Record<string, InertiaScrollProp>;
1761
+ onceProps?: Record<string, InertiaOnceProp>;
1762
+ clearHistory?: true;
1763
+ encryptHistory?: true;
1764
+ flash?: Record<string, unknown>;
1765
+ preserveFragment?: true;
1042
1766
  }
1043
1767
  interface InertiaResponse extends Responsable {
1044
1768
  with(key: string | Record<string, unknown>, value?: unknown): this;
1045
1769
  withViewData(key: string | Record<string, unknown>, value?: unknown): this;
1770
+ rootView(view: string): this;
1771
+ /** Flash data for the next page (page.flash), stored in the session. */
1772
+ flash(key: string | Record<string, unknown>, value?: unknown): this;
1046
1773
  }
1047
1774
  type PropCallback<T = unknown> = () => T | Promise<T>;
1775
+ /** The SSR result spliced into the root view: the `head` tags and the rendered `body`. */
1776
+ interface InertiaSsrResponse {
1777
+ head: string;
1778
+ body: string;
1779
+ }
1780
+ /** Sends a page to the SSR server. Resolves to undefined when SSR is off, unreachable or failing. */
1781
+ interface InertiaSsrGateway {
1782
+ dispatch(page: InertiaPage): Promise<InertiaSsrResponse | undefined>;
1783
+ }
1784
+ declare const InertiaSsrGateway: Token<InertiaSsrGateway>;
1048
1785
  interface InertiaFactory {
1049
1786
  render(component: string, props?: Record<string, unknown>): InertiaResponse;
1050
1787
  share(key: string | Record<string, unknown>, value?: unknown): void;
1788
+ /** A shared once prop: sent on the first visit, then kept by the client. */
1789
+ shareOnce(key: string, callback: PropCallback): void;
1051
1790
  getShared(key?: string): unknown;
1052
- version(version: string | (() => string | Promise<string>)): void;
1791
+ flushShared(): void;
1792
+ version(version: string | null | (() => string | null | Promise<string | null>)): void;
1793
+ getVersion(): Promise<string>;
1794
+ setRootView(view: string): void;
1053
1795
  /** Only evaluated on partial reloads that ask for it. */
1054
1796
  optional<T>(callback: PropCallback<T>): unknown;
1055
1797
  /** Loaded in a follow-up request after the first render. */
1056
1798
  defer<T>(callback: PropCallback<T>, group?: string): unknown;
1057
1799
  /** Always included, even in partial reloads. */
1058
1800
  always<T>(value: T | PropCallback<T>): unknown;
1059
- /** Merged with the existing client-side value instead of replacing it. */
1801
+ /** Appended to the existing client-side value instead of replacing it. */
1060
1802
  merge<T>(value: T | PropCallback<T>): unknown;
1061
- /** 409 + X-Inertia-Location for external redirects. */
1803
+ /** Deep-merged with the existing client-side value. */
1804
+ deepMerge<T>(value: T | PropCallback<T>): unknown;
1805
+ /** Resolved once, then remembered by the client. */
1806
+ once<T>(callback: PropCallback<T>): unknown;
1807
+ /** Infinite scroll over a paginator: merged page by page, with scroll metadata. */
1808
+ scroll<T>(value: T | PropCallback<T>, wrapper?: string): unknown;
1809
+ /** Flash data for the next page (page.flash), stored in the session. */
1810
+ flash(key: string | Record<string, unknown>, value?: unknown): this;
1811
+ encryptHistory(encrypt?: boolean): void;
1812
+ /** The next page tells the client to clear its encrypted history. */
1813
+ clearHistory(): void;
1814
+ /** The next page keeps the URL fragment of the request that redirected to it. */
1815
+ preserveFragment(): void;
1816
+ /** 409 + X-Inertia-Location for Inertia requests, a plain 302 otherwise. */
1062
1817
  location(url: string): Response;
1063
- setRootView(view: string): void;
1818
+ /** Redirect back (Inertia.flash('saved', true).back()). */
1819
+ back(fallback?: string, status?: number): RedirectResponse;
1064
1820
  }
1065
1821
  declare const InertiaFactory: Token<InertiaFactory>;
1066
1822
 
@@ -1080,11 +1836,18 @@ interface LiveSnapshot {
1080
1836
  }
1081
1837
  interface LiveEffects {
1082
1838
  html?: string;
1839
+ /** Browser events from this.dispatch(); `self` keeps one on this component, `to` sends it to one component name. */
1083
1840
  dispatches?: Array<{
1084
1841
  name: string;
1085
- params: unknown[];
1842
+ params: Record<string, unknown>;
1843
+ self?: true;
1844
+ to?: string;
1086
1845
  }>;
1846
+ /** Events this component listens to (@On, static listeners); sent with the first render. */
1847
+ listeners?: string[];
1087
1848
  redirect?: string;
1849
+ /** Follow `redirect` with o:navigate instead of a full page load. */
1850
+ redirectUsingNavigate?: true;
1088
1851
  returns?: unknown[];
1089
1852
  }
1090
1853
  interface LiveUpdateRequest {
@@ -1106,12 +1869,17 @@ interface LiveUpdateResponse {
1106
1869
  }
1107
1870
  interface LiveManager {
1108
1871
  register(component: Class<unknown>, name?: string): void;
1109
- /** Server-renders the first HTML (snapshot embedded). */
1110
- mount(component: string | Class<unknown>, params?: Record<string, unknown>): Promise<string>;
1872
+ /** Server-renders the first HTML (snapshot embedded). `key` identifies a child inside its parent (o:key). */
1873
+ mount(component: string | Class<unknown>, params?: Record<string, unknown>, key?: string): Promise<string>;
1111
1874
  /** Checks checksums and CSRF, then applies updates and calls, re-renders and returns new snapshots. */
1112
1875
  update(request: LiveUpdateRequest): Promise<LiveUpdateResponse>;
1876
+ /**
1877
+ * A full-page component (Route.get('/counter', Counter)): mounts `component` (a component instance) with the current route's parameters and
1878
+ * returns the response, its layout view or a redirect.
1879
+ */
1880
+ page(component: object): Promise<unknown>;
1113
1881
  isLiveRequest(request: HttpRequest): boolean;
1114
1882
  }
1115
1883
  declare const LiveManager: Token<LiveManager>;
1116
1884
 
1117
- export { type AbilityCallback, type Abstract, type ActionMethods, type Address, Application, type Arrayable, type Attachment, AuthFactory, type Authenticatable, type AuthenticationError, type Batch, type BodyInit, BusDispatcher, CacheManager, type CacheRepository, type Class, ClassRegistry, type Command, type Concrete, type ConfigCallbacks, ConfigRepository, ConsoleKernel, Container, type Content, type ControllerAction, type Cookie, CookieJar, type Credentials, type DatabaseConnection, DatabaseManager, type DriverName, Encrypter, type Enumerable, type Envelope, type ErrorKind, EventDispatcher, ExceptionCallbacks, ExceptionHandler, type ExceptionsConfigurator, type Factory, type FailedJob, FailedJobProvider, type Filesystem, FilesystemManager, Gate, type Guard, Hasher, type HeadersInit, type Htmlable, HttpKernel, HttpRequest, InertiaFactory, type InertiaPage, type InertiaResponse, type Job, type Jsonable, type Listener, type ListenerClass, type LiveEffects, LiveManager, type LiveSnapshot, type LiveUpdateRequest, type LiveUpdateResponse, type Lock, type LogLevel, LogManager, type Logger, MailManager, type MailRecipient, type MailTransport, type Mailable, type Mailer, type MessageBag, type Middleware, MiddlewareCallbacks, type MiddlewareClass, type MiddlewareConfigurator, type MiddlewareReference, type ModelInstance, type ModelNotFoundError, type ModelStatic, type MustVerifyEmail, type Next, type Notifiable, type Notification, type NotificationChannel, NotificationDispatcher, type Operator, type OrielError, type OutgoingMessage, PasswordBroker, type PasswordStatus, type PendingBatch, type PendingChain, type PendingMail, type Pipe, type PipeClosure, type PipeNext, type Pipeline, PipelineFactory, type PropCallback, type PutOptions, type QueryBuilder, type Queue, type QueueJob, QueueManager, type QueuePayload, type RedirectResponse, Redirector, type ResourceOptions, type Responsable, ResponseFactory, type Route, type RouteAction, type RouteClosure, RouteModelResolver, type RouteRegistrar, Router, RoutingPaths, type Row, type RuleCallback, type Rules, Schedule, type ScheduledEvent, type SentMessage, type ServiceProvider, type ServiceProviderClass, Session, type SessionHandler, type ShouldQueue, type StatefulGuard, type Token, type UploadedFile, UrlGenerator, type UserProvider, type ValidationError, ValidationFactory, type ValidationRule, type Validator, type View, ViewFactory, token };
1885
+ export { type AbilityCallback, type Abstract, type ActionMethods, type Address, Application, type Arrayable, type Attachment, AuthFactory, type Authenticatable, type AuthenticationError, type Batch, BatchRepository, type BodyInit, BusDispatcher, CacheManager, type CacheRepository, type Class, ClassRegistry, type ClosureCommand, type Command, type CommandContext, type Concrete, type ConfigCallbacks, ConfigRepository, ConsoleKernel, Container, type Content, type ControllerAction, type Cookie, CookieJar, type Credentials, CurrentRoute, type DatabaseConnection, DatabaseManager, type DatabaseNotification, type DriverName, Encrypter, type Enumerable, type Envelope, type ErrorKind, EventDispatcher, ExceptionCallbacks, ExceptionHandler, type ExceptionsConfigurator, type Factory, type FailedJob, FailedJobProvider, type Filesystem, FilesystemManager, Gate, type Guard, Hasher, type HeadersInit, type Htmlable, HttpKernel, HttpRequest, type InValue, InertiaFactory, type InertiaOnceProp, type InertiaPage, type InertiaResponse, type InertiaScrollProp, InertiaSsrGateway, type InertiaSsrResponse, type InferRuleType, type InferValidatedType, type InvokableClass, type Job, type Jsonable, type Listener, type ListenerClass, type LiveEffects, LiveManager, type LiveSnapshot, type LiveUpdateRequest, type LiveUpdateResponse, type Lock, type LogLevel, LogManager, type Logger, MailManager, type MailRecipient, type MailTransport, type Mailable, type Mailer, type MessageBag, type Middleware, MiddlewareCallbacks, type MiddlewareClass, type MiddlewareConfigurator, type MiddlewareReference, type ModelInstance, type ModelNotFoundError, type ModelStatic, type MustVerifyEmail, type Next, type Notifiable, type Notification, type NotificationChannel, NotificationDispatcher, type NumericValue, type Operator, type OptionValue, type OrielError, type OutgoingMessage, PaginationState, PasswordBroker, type PasswordStatus, type PendingBatch, type PendingBatchOptions, type PendingChain, type PendingMail, type Pipe, type PipeClosure, type PipeNext, type Pipeline, PipelineFactory, type PropCallback, type PutOptions, type QueryBuilder, type Queue, type QueueJob, QueueManager, type QueuePayload, RateLimiter, type RedirectResponse, Redirector, type ResourceOptions, type Responsable, ResponseFactory, type Route, type RouteAction, type RouteArguments, type RouteClosure, type RouteList, RouteModelResolver, type RouteName, type RouteParameter, type RouteParameters, type RouteRegistrar, Router, RoutingPaths, type Row, type RuleCallback, type RuleParameterList, type RuleTyping, type Rules, Schedule, type ScheduleHook, type ScheduledEvent, type SentMessage, type ServiceProvider, type ServiceProviderClass, Session, type SessionHandler, type ShouldQueue, type StatefulGuard, type Token, type TypedValidationRule, type UploadedFile, UrlGenerator, type UserProvider, type ValidationError, ValidationFactory, type ValidationRule, type ValidationRuleTypes, type Validator, type View, ViewFactory, token };