@orieljs/framework 0.1.0-alpha.3 → 0.1.0-alpha.5

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.
@@ -2,9 +2,9 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-WEGTH46M.js";
6
- import "./chunk-HU43NADT.js";
7
- import "./chunk-S7YC43IH.js";
5
+ } from "./chunk-A5XRLEWM.js";
6
+ import "./chunk-PM5YTG57.js";
7
+ import "./chunk-BSQKOLSK.js";
8
8
  export {
9
9
  Fragment,
10
10
  jsx,
@@ -37,6 +37,44 @@ interface Container$1 {
37
37
  }
38
38
  declare const Container$1: Token$1<Container$1>;
39
39
 
40
+ /** The session of the current request (scoped). Loaded and saved by the StartSession middleware. */
41
+ interface Session$1 {
42
+ getId(): string;
43
+ start(): Promise<void>;
44
+ save(): Promise<void>;
45
+ all(): Record<string, unknown>;
46
+ has(key: string): boolean;
47
+ get<T = unknown>(key: string, defaultValue?: T): T;
48
+ put(key: string | Record<string, unknown>, value?: unknown): void;
49
+ push(key: string, value: unknown): void;
50
+ pull<T = unknown>(key: string, defaultValue?: T): T;
51
+ forget(...keys: string[]): void;
52
+ flush(): void;
53
+ flash(key: string, value: unknown): void;
54
+ now(key: string, value: unknown): void;
55
+ reflash(): void;
56
+ keep(...keys: string[]): void;
57
+ getOldInput<T = unknown>(key?: string, defaultValue?: T): T;
58
+ flashInput(input: Record<string, unknown>): void;
59
+ token(): string;
60
+ regenerateToken(): void;
61
+ regenerate(destroy?: boolean): Promise<void>;
62
+ invalidate(): Promise<void>;
63
+ previousUrl(): string | undefined;
64
+ setPreviousUrl(url: string): void;
65
+ }
66
+ declare const Session$1: Token$2<Session$1>;
67
+ interface UploadedFile$1 {
68
+ readonly clientName: string;
69
+ readonly mimeType: string;
70
+ readonly size: number;
71
+ extension(): string;
72
+ arrayBuffer(): Promise<ArrayBuffer>;
73
+ /** Stores on a Filesystem disk. Returns the stored path. */
74
+ store(directory: string, disk?: string): Promise<string>;
75
+ storeAs(directory: string, name: string, disk?: string): Promise<string>;
76
+ }
77
+
40
78
  interface ServiceProvider$2 {
41
79
  /** Bind things into the container. Synchronous. Don't resolve other services here. */
42
80
  register?(): void;
@@ -98,44 +136,6 @@ interface Enumerable<T> extends Iterable<T>, Arrayable<unknown[]> {
98
136
  isEmpty(): boolean;
99
137
  }
100
138
 
101
- /** The session of the current request (scoped). Loaded and saved by the StartSession middleware. */
102
- interface Session$1 {
103
- getId(): string;
104
- start(): Promise<void>;
105
- save(): Promise<void>;
106
- all(): Record<string, unknown>;
107
- has(key: string): boolean;
108
- get<T = unknown>(key: string, defaultValue?: T): T;
109
- put(key: string | Record<string, unknown>, value?: unknown): void;
110
- push(key: string, value: unknown): void;
111
- pull<T = unknown>(key: string, defaultValue?: T): T;
112
- forget(...keys: string[]): void;
113
- flush(): void;
114
- flash(key: string, value: unknown): void;
115
- now(key: string, value: unknown): void;
116
- reflash(): void;
117
- keep(...keys: string[]): void;
118
- getOldInput<T = unknown>(key?: string, defaultValue?: T): T;
119
- flashInput(input: Record<string, unknown>): void;
120
- token(): string;
121
- regenerateToken(): void;
122
- regenerate(destroy?: boolean): Promise<void>;
123
- invalidate(): Promise<void>;
124
- previousUrl(): string | undefined;
125
- setPreviousUrl(url: string): void;
126
- }
127
- declare const Session$1: Token$2<Session$1>;
128
- interface UploadedFile$1 {
129
- readonly clientName: string;
130
- readonly mimeType: string;
131
- readonly size: number;
132
- extension(): string;
133
- arrayBuffer(): Promise<ArrayBuffer>;
134
- /** Stores on a Filesystem disk. Returns the stored path. */
135
- store(directory: string, disk?: string): Promise<string>;
136
- storeAs(directory: string, name: string, disk?: string): Promise<string>;
137
- }
138
-
139
139
  interface Encrypter {
140
140
  /** JSON-serializes unless serialize=false (then value must be a string). AES-256-GCM, keyed by APP_KEY. */
141
141
  encrypt(value: unknown, serialize?: boolean): string;
@@ -233,6 +233,8 @@ interface ModelInstance {
233
233
  getTable(): string;
234
234
  getRouteKey(): unknown;
235
235
  getRouteKeyName(): string;
236
+ /** The value stored in a polymorphic `*_type` column for this model: its morph map alias, else its class name. */
237
+ getMorphClass(): string;
236
238
  getAttribute<T = unknown>(key: string): T;
237
239
  setAttribute(key: string, value: unknown): this;
238
240
  fill(attributes: Row): this;
@@ -285,6 +287,11 @@ declare const AuthFactory: Token$2<AuthFactory>;
285
287
 
286
288
  /** Options a job class may declare as public fields. Their presence (or implementing ShouldQueue) makes things queueable. */
287
289
  interface ShouldQueue {
290
+ /**
291
+ * Marks the class as queued at run time: `implements ShouldQueue` leaves no trace once compiled, so the interface
292
+ * asks for `readonly shouldQueue = true`. Jobs, listeners, mailables and notifications carrying it are queued.
293
+ */
294
+ readonly shouldQueue: true;
288
295
  connection?: string;
289
296
  queue?: string;
290
297
  /** Seconds. */
@@ -962,6 +969,12 @@ declare class HttpClient {
962
969
  request(method: string, uri: string, options?: RequestOptions): Promise<TestResponse>;
963
970
  /** Runs `fn` in a scope prepared like a request's (carried session, actingAs users), e.g. for assertAuthenticated(). */
964
971
  inScope<T>(fn: (scope: Container$1) => T | Promise<T>): Promise<T>;
972
+ /**
973
+ * Runs `run` in a request scope like this client's requests have (a request for `method uri` bound, the carried
974
+ * session, actingAs users), then carries the session and the users on, as after a request. Live.test() runs its
975
+ * mount and updates through it.
976
+ */
977
+ withinRequest<T>(run: () => Promise<T>, method?: string, uri?: string): Promise<T>;
965
978
  /** Runs the request through the app's real HttpKernel, in a request scope this client owns. */
966
979
  protected send(request: Request): Promise<TestResponse>;
967
980
  /** Prepares the request scope: recorders, the carried session and actingAs users. */
@@ -1035,6 +1048,11 @@ declare abstract class InteractsWithApplication {
1035
1048
  protected defineEnvironment(_app: Application$1): void | Promise<void>;
1036
1049
  setUp(): Promise<void>;
1037
1050
  tearDown(): Promise<void>;
1051
+ /**
1052
+ * Laravel's withoutVite(): in this test's requests vite([...]) and viteReactRefresh() render nothing, so feature
1053
+ * tests of pages pass before `vite build` has written public/build/manifest.json.
1054
+ */
1055
+ withoutVite(): this;
1038
1056
  /** Runs in tearDown(), before the application is thrown away (in registration order). */
1039
1057
  beforeApplicationDestroyed(callback: Callback): void;
1040
1058
  }
@@ -1046,6 +1064,8 @@ declare abstract class MakesHttpRequests extends InteractsWithApplication {
1046
1064
  /** The current test's HTTP client (created on first use). */
1047
1065
  protected get http(): HttpClient;
1048
1066
  protected createHttpClient(): HttpClient;
1067
+ /** Live.test() runs in this test's request scope (Live reads the same token: no import between the packages). */
1068
+ setUp(): Promise<void>;
1049
1069
  tearDown(): Promise<void>;
1050
1070
  withHeaders(headers: Headers$1): this;
1051
1071
  withHeader(name: string, value: string): this;
@@ -1467,6 +1487,7 @@ interface StoredFile {
1467
1487
  mimeType: string | undefined;
1468
1488
  modified: Date;
1469
1489
  }
1490
+ /** By the extension as PHP's pathinfo() reads it: after the last dot of the base name ('.pdf' is a PDF, 'pdf' isn't). */
1470
1491
  declare function guessMimeType(path: string): string | undefined;
1471
1492
  /**
1472
1493
  * An in-memory disk implementing the Filesystem contract, with Laravel's fake-disk assertions. (Laravel's fake
@@ -1487,7 +1508,12 @@ declare class FakeDisk implements Filesystem {
1487
1508
  readStream(path: string): Promise<ReadableStream<Uint8Array>>;
1488
1509
  put(path: string, contents: string | Uint8Array | ReadableStream<Uint8Array>, options?: PutOptions): Promise<boolean>;
1489
1510
  putFile(directory: string, file: UploadedFile$1, options?: PutOptions): Promise<string>;
1511
+ /**
1512
+ * The upload's own type, as the S3 disk sends it: its extension(), never the MIME type the client sent as such nor
1513
+ * the stored name's type.
1514
+ */
1490
1515
  putFileAs(directory: string, file: UploadedFile$1, name: string, options?: PutOptions): Promise<string>;
1516
+ private write;
1491
1517
  delete(paths: string | string[]): Promise<boolean>;
1492
1518
  copy(from: string, to: string): Promise<boolean>;
1493
1519
  move(from: string, to: string): Promise<boolean>;
@@ -1547,9 +1573,17 @@ declare class StorageFake implements FilesystemManager {
1547
1573
 
1548
1574
  /** Laravel's UploadedFile::fake(): File objects to post as multipart uploads (t.post(uri, { avatar: file })). */
1549
1575
  declare const FakeFile: {
1550
- /** A file of `kilobytes` KiB (zero bytes), typed by `mimeType` or the extension. */
1576
+ /**
1577
+ * A file of `kilobytes` KiB typed by `mimeType` or the name's extension. Validation reads a file's bytes, so the
1578
+ * file starts like its type (a PDF's `%PDF-`, a PNG's signature, text for text types) and passes `mimes` for its
1579
+ * name, as Laravel's fakes do. It is at least its type's leading bytes and never empty, whatever the size asked for.
1580
+ * An image made this way has no readable size: use image() for `dimensions`.
1581
+ */
1551
1582
  create(name: string, kilobytes?: number, mimeType?: string): File;
1552
- /** A real PNG image of the given size (typed by the name's extension, like Laravel's image()). */
1583
+ /**
1584
+ * A real white image of the given size in the format the name's extension asks for: png, jpg/jpeg, gif, webp or
1585
+ * bmp (any other name gets a JPEG, as Laravel's fakes do), so image, mimes and dimensions pass on it.
1586
+ */
1553
1587
  image(name: string, width?: number, height?: number): File;
1554
1588
  };
1555
1589
 
@@ -1589,50 +1623,6 @@ interface Container {
1589
1623
  }
1590
1624
  declare const Container: Token<Container>;
1591
1625
 
1592
- interface ServiceProvider$1 {
1593
- /** Bind things into the container. Synchronous. Don't resolve other services here. */
1594
- register?(): void;
1595
- /** Runs after every provider is registered. May be async (e.g. importing route files). */
1596
- boot?(): void | Promise<void>;
1597
- }
1598
- type ServiceProviderClass = new (app: Application) => ServiceProvider$1;
1599
- interface Application extends Container {
1600
- readonly version: string;
1601
- basePath(path?: string): string;
1602
- appPath(path?: string): string;
1603
- bootstrapPath(path?: string): string;
1604
- configPath(path?: string): string;
1605
- databasePath(path?: string): string;
1606
- publicPath(path?: string): string;
1607
- resourcePath(path?: string): string;
1608
- storagePath(path?: string): string;
1609
- /** With no args returns the environment name. With args returns whether it matches any of them. */
1610
- environment(): string;
1611
- environment(...environments: string[]): boolean;
1612
- isProduction(): boolean;
1613
- isLocal(): boolean;
1614
- runningInConsole(): boolean;
1615
- /** Mark the app as running in the console (the CLI entry point calls this). Defaults to true. */
1616
- setRunningInConsole(value?: boolean): void;
1617
- runningUnitTests(): boolean;
1618
- /** Registers the provider. If the app is already booted, the provider is booted immediately. */
1619
- register(provider: ServiceProvider$1 | ServiceProviderClass): Promise<ServiceProvider$1>;
1620
- getProviders(): ServiceProvider$1[];
1621
- boot(): Promise<void>;
1622
- isBooted(): boolean;
1623
- booting(callback: (app: Application) => void | Promise<void>): void;
1624
- booted(callback: (app: Application) => void | Promise<void>): void;
1625
- /** Handle one HTTP request in a fresh request scope via the bound HttpKernel. */
1626
- handle(request: Request): Promise<Response>;
1627
- /** Register a callback that terminate() runs, in registration order. */
1628
- terminating(callback: () => void | Promise<void>): void;
1629
- terminate(): Promise<void>;
1630
- }
1631
- declare const Application: Token$2<Application>;
1632
- interface Htmlable {
1633
- toHtml(): string;
1634
- }
1635
-
1636
1626
  /** The session of the current request (scoped). Loaded and saved by the StartSession middleware. */
1637
1627
  interface Session {
1638
1628
  getId(): string;
@@ -1704,6 +1694,8 @@ interface HttpRequest {
1704
1694
  header(name: string, defaultValue: string): string;
1705
1695
  bearerToken(): string | undefined;
1706
1696
  ip(): string | undefined;
1697
+ /** The raw body as text (Laravel's getContent()); '' when there is none. */
1698
+ content(): string;
1707
1699
  expectsJson(): boolean;
1708
1700
  ajax(): boolean;
1709
1701
  query<T = unknown>(key?: string, defaultValue?: T): T;
@@ -1730,6 +1722,130 @@ interface HttpRequest {
1730
1722
  validate<T = Record<string, unknown>>(rules: Rules, messages?: Record<string, string>, attributes?: Record<string, string>): Promise<T>;
1731
1723
  }
1732
1724
  declare const HttpRequest: Token$2<HttpRequest>;
1725
+ type Next = (request: HttpRequest) => Promise<Response>;
1726
+ interface Middleware {
1727
+ handle(request: HttpRequest, next: Next, ...parameters: string[]): Promise<Response>;
1728
+ terminate?(request: HttpRequest, response: Response): Promise<void>;
1729
+ }
1730
+ type MiddlewareClass = new (...args: any[]) => Middleware;
1731
+
1732
+ interface ServiceProvider$1 {
1733
+ /** Bind things into the container. Synchronous. Don't resolve other services here. */
1734
+ register?(): void;
1735
+ /** Runs after every provider is registered. May be async (e.g. importing route files). */
1736
+ boot?(): void | Promise<void>;
1737
+ }
1738
+ type ServiceProviderClass = new (app: Application) => ServiceProvider$1;
1739
+ interface Application extends Container {
1740
+ readonly version: string;
1741
+ basePath(path?: string): string;
1742
+ appPath(path?: string): string;
1743
+ bootstrapPath(path?: string): string;
1744
+ configPath(path?: string): string;
1745
+ databasePath(path?: string): string;
1746
+ publicPath(path?: string): string;
1747
+ resourcePath(path?: string): string;
1748
+ storagePath(path?: string): string;
1749
+ /** With no args returns the environment name. With args returns whether it matches any of them. */
1750
+ environment(): string;
1751
+ environment(...environments: string[]): boolean;
1752
+ isProduction(): boolean;
1753
+ isLocal(): boolean;
1754
+ runningInConsole(): boolean;
1755
+ /** Mark the app as running in the console (the CLI entry point calls this). Defaults to true. */
1756
+ setRunningInConsole(value?: boolean): void;
1757
+ runningUnitTests(): boolean;
1758
+ /** Registers the provider. If the app is already booted, the provider is booted immediately. */
1759
+ register(provider: ServiceProvider$1 | ServiceProviderClass): Promise<ServiceProvider$1>;
1760
+ getProviders(): ServiceProvider$1[];
1761
+ boot(): Promise<void>;
1762
+ isBooted(): boolean;
1763
+ booting(callback: (app: Application) => void | Promise<void>): void;
1764
+ booted(callback: (app: Application) => void | Promise<void>): void;
1765
+ /** Handle one HTTP request in a fresh request scope via the bound HttpKernel. */
1766
+ handle(request: Request): Promise<Response>;
1767
+ /** Register a callback that terminate() runs, in registration order. */
1768
+ terminating(callback: () => void | Promise<void>): void;
1769
+ terminate(): Promise<void>;
1770
+ }
1771
+ declare const Application: Token$2<Application>;
1772
+ interface Htmlable {
1773
+ toHtml(): string;
1774
+ }
1775
+
1776
+ /** Public method names of a controller (excludes non-function members). */
1777
+ type ActionMethods<C> = {
1778
+ [K in keyof C]: C[K] extends (...args: any[]) => unknown ? K : never;
1779
+ }[keyof C] & string;
1780
+ type ControllerAction<C> = readonly [Class<C>, ActionMethods<C>];
1781
+ type RouteClosure = (...args: any[]) => unknown;
1782
+ /** A class with __invoke(): Route.get('/counter', Counter) (single-action controllers, full-page Live components). */
1783
+ type InvokableClass = Class<{
1784
+ __invoke(...args: any[]): unknown;
1785
+ }>;
1786
+ type RouteAction = RouteClosure | ControllerAction<any> | InvokableClass;
1787
+ type MiddlewareReference = string | MiddlewareClass;
1788
+ interface Route {
1789
+ readonly methods: readonly string[];
1790
+ readonly uri: string;
1791
+ getName(): string | undefined;
1792
+ name(name: string): this;
1793
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): this;
1794
+ withoutMiddleware(...middleware: MiddlewareReference[]): this;
1795
+ where(parameter: string, pattern: string): this;
1796
+ where(patterns: Record<string, string>): this;
1797
+ }
1798
+ interface RouteRegistrar {
1799
+ prefix(prefix: string): RouteRegistrar;
1800
+ name(prefix: string): RouteRegistrar;
1801
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): RouteRegistrar;
1802
+ controller(controller: Class<unknown>): RouteRegistrar;
1803
+ group(routes: () => void | Promise<void>): Promise<void>;
1804
+ }
1805
+ interface ResourceOptions {
1806
+ only?: string[];
1807
+ except?: string[];
1808
+ parameters?: Record<string, string>;
1809
+ names?: Record<string, string>;
1810
+ }
1811
+ interface Router {
1812
+ get<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1813
+ post<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1814
+ put<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1815
+ patch<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1816
+ delete<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1817
+ options<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1818
+ any<C>(uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1819
+ match<C>(methods: string[], uri: string, action: ControllerAction<C> | RouteClosure | InvokableClass | string): Route;
1820
+ redirect(from: string, to: string, status?: number): Route;
1821
+ view(uri: string, view: string, data?: Record<string, unknown>): Route;
1822
+ /** Route.inertia('/about', 'About', props): a GET route that renders an Inertia page (Laravel's Route::inertia). */
1823
+ inertia(uri: string, component: string, props?: Record<string, unknown>): Route;
1824
+ resource(name: string, controller: Class<unknown>, options?: ResourceOptions): void;
1825
+ apiResource(name: string, controller: Class<unknown>, options?: ResourceOptions): void;
1826
+ fallback(action: RouteAction): Route;
1827
+ prefix(prefix: string): RouteRegistrar;
1828
+ name(prefix: string): RouteRegistrar;
1829
+ middleware(...middleware: Array<MiddlewareReference | readonly MiddlewareReference[]>): RouteRegistrar;
1830
+ controller(controller: Class<unknown>): RouteRegistrar;
1831
+ /** Explicit model binding: Route.model('author', User). */
1832
+ model(parameter: string, model: Class<unknown>): void;
1833
+ /** Custom binding resolver. */
1834
+ bind(parameter: string, resolver: (value: string) => unknown | Promise<unknown>): void;
1835
+ pattern(parameter: string, pattern: string): void;
1836
+ /** Name a middleware class, e.g. aliasMiddleware('auth', Authenticate). */
1837
+ aliasMiddleware(name: string, middleware: MiddlewareClass): this;
1838
+ /** Define (or replace) a middleware group such as 'web' or 'api'. */
1839
+ middlewareGroup(name: string, middleware: MiddlewareReference[]): this;
1840
+ /** Append to a group unless it is already present. */
1841
+ pushMiddlewareToGroup(group: string, middleware: MiddlewareReference): this;
1842
+ getMiddlewareGroups(): Record<string, MiddlewareReference[]>;
1843
+ getRoutes(): readonly Route[];
1844
+ current(): Route | undefined;
1845
+ /** Match the request, bind parameters, run the route middleware and the action. Called by the Http kernel. */
1846
+ dispatch(request: HttpRequest): Promise<Response>;
1847
+ }
1848
+ declare const Router: Token$2<Router>;
1733
1849
 
1734
1850
  type ErrorKind = 'Http' | 'Server' | 'ModelNotFound' | 'Validation' | 'Authentication' | 'Authorization' | 'TokenMismatch' | 'BindingResolution' | 'CircularDependency' | 'ContainerNotAvailable';
1735
1851
  /** Every error thrown by the framework implements this. The exception handler switches on `kind`. */
@@ -1894,13 +2010,22 @@ declare function Locked(_target: unknown, context: ClassFieldDecoratorContext |
1894
2010
  /** @Computed: a getter cached for the rest of the request, never part of the component's state. */
1895
2011
  declare function Computed<T>(getter: (this: object) => T, context: ClassGetterDecoratorContext): (this: object) => T;
1896
2012
 
2013
+ /**
2014
+ * Runs Live.test()'s mount and each update. The testing package binds one for every test, so they run in a request
2015
+ * scope like the test's HTTP requests (a request, the carried session, actingAs users) and what they change carries
2016
+ * on to the next request. Without one they run in the current scope.
2017
+ */
2018
+ type TestRequestScope = <T>(run: () => Promise<T>) => Promise<T>;
2019
+ declare const TestRequestScope: Token<TestRequestScope>;
1897
2020
  /**
1898
2021
  * Livewire's Livewire::test(): drives one component through the real mount → snapshot → checksum → update pipeline
1899
- * (no HTTP). Actions are async (`await counter.call('increment')`); assertions are sync and return `this`.
2022
+ * (no HTTP), inside the test's request scope. Actions are async (`await counter.call('increment')`); assertions are
2023
+ * sync and return `this`.
1900
2024
  */
1901
2025
  declare class Testable<C extends Component = Component> {
1902
2026
  #private;
1903
2027
  private readonly manager;
2028
+ private readonly scope;
1904
2029
  private constructor();
1905
2030
  /** Mounts `component` with `params`, as `<Live component={…} {...params} />` would. */
1906
2031
  static create<C extends Component>(component: Class<C> | string, params?: Record<string, unknown>): Promise<Testable<C>>;
@@ -1988,8 +2113,14 @@ declare class LiveComponentManager implements LiveManager {
1988
2113
  /** Applies each component's updates and calls, re-renders it and returns its new snapshot and effects. */
1989
2114
  update(request: LiveUpdateRequest): Promise<LiveUpdateResponse>;
1990
2115
  updateComponent(snapshotJson: string, updates: Record<string, unknown>, calls: Call[]): Promise<ComponentResult>;
1991
- /** The route action of POST /oriel/live/update. */
1992
- handle(request: HttpRequest): Promise<LiveUpdateResponse>;
2116
+ /**
2117
+ * The route action of POST /oriel/live/update. Each component's update runs behind the persistent middleware of the
2118
+ * route that rendered its page (Livewire's): `auth`, `verified`, `guest` and `can`, with the page route's parameters
2119
+ * bound again. A signed-out tab gets a 401, a revoked ability a 403 and a deleted model a 404, before the component
2120
+ * hydrates. When a middleware answers instead (a redirect), that is the response. A key first flashed during the
2121
+ * update shows in this response only, unless the update redirects.
2122
+ */
2123
+ handle(request: HttpRequest): Promise<LiveUpdateResponse | Response>;
1993
2124
  /** A full-page component (Route.get('/counter', Counter)): mounted with the route parameters, inside the layout. */
1994
2125
  page(component: Component): Promise<unknown>;
1995
2126
  /** Parses and checks a snapshot: a bad checksum throws before anything is hydrated. */
@@ -2002,8 +2133,14 @@ declare class LiveComponentManager implements LiveManager {
2002
2133
  private applyUpdate;
2003
2134
  /** Runs one call from the browser: a magic action, an event, or a public method. Returns its return value. */
2004
2135
  private call;
2005
- /** Renders the component (rendering/rendered hooks, nested children tracked) and checks for a single root. */
2136
+ /**
2137
+ * Renders the component (rendering/rendered hooks, nested children tracked) and checks for a single root. A
2138
+ * WithPagination component's page and page URL are what paginate() reads while it renders, as in its mount() and in
2139
+ * its update's hooks and actions.
2140
+ */
2006
2141
  private render;
2142
+ /** The absolute URL of the page a memo path belongs to, on the current request's origin ('/' + path without one). */
2143
+ private pageUrl;
2007
2144
  /** Dispatches, redirects: the effects every response carries. */
2008
2145
  private effects;
2009
2146
  /** dehydrate() hook, then the state as snapshot data, the error bag, and the checksum over both. */
@@ -2013,8 +2150,9 @@ declare class LiveComponentManager implements LiveManager {
2013
2150
  /** The URI the client runtime posts updates to. */
2014
2151
  declare const UPDATE_URI = "/oriel/live/update";
2015
2152
  /**
2016
- * Binds the LiveManager, merges the `live` config, registers POST /oriel/live/update (named `live.update`, in the `web`
2017
- * group: sessions and CSRF apply), the make:live command, and the components under app/Live.
2153
+ * Binds the LiveManager and the PaginationState that WithPagination components answer, merges the `live` config,
2154
+ * registers POST /oriel/live/update (named `live.update`, in the `web` group: sessions and CSRF apply), the make:live
2155
+ * command, and the components under app/Live.
2018
2156
  */
2019
2157
  declare class LiveServiceProvider extends ServiceProvider {
2020
2158
  register(): void;
@@ -2065,4 +2203,65 @@ declare class InvalidLiveRequestError extends LiveError {
2065
2203
  readonly status: number;
2066
2204
  }
2067
2205
 
2068
- export { type ResponseContext as $, AnonymousNotifiable as A, BusFake as B, Component as C, DatabaseMigrations as D, EventFake as E, FakeDisk as F, InteractsWithConsole as G, HttpClient as H, InvalidLiveRequestError as I, InteractsWithDatabase as J, type JsonStructure as K, Live as L, MailFake as M, NotificationFake as N, On as O, PendingEvent as P, QueueFake as Q, MailRecord as R, MakesHttpRequests as S, type Target as T, UPDATE_URI as U, PendingCommand as V, type PushedJob as W, RefreshDatabase as X, RefreshDatabaseState as Y, type RequestData as Z, type RequestOptions as _, type ComponentResult as a, type ResponseCookie as a0, type SentNotification as a1, StorageFake as a2, TESTING_ENVIRONMENT as a3, type TableOrModel as a4, TestCase as a5, type TestHooks as a6, TestResponse as a7, type TestTrait as a8, actingAsAuthFactory as a9, addresses as aa, applyEnvironment as ab, cookieHeader as ac, cookiePrefix as ad, decryptCookie as ae, encryptCookie as af, flatten as ag, guessMimeType as ah, inertiaPageOf as ai, install as aj, isExpired as ak, matches as al, nameOf as am, recordingExceptionHandler as an, recordingViewFactory as ao, responseCookies as ap, runCommand as aq, usingInMemoryDatabase as ar, Computed as b, CorruptComponentPayloadError as c, ErrorBag as d, LiveComponentManager as e, LiveComponentNotFoundError as f, LiveError as g, type LiveProps as h, LiveServiceProvider as i, Locked as j, MethodNotCallableError as k, PropertyNotUpdatableError as l, Testable as m, componentName as n, live as o, AssertableInertia as p, AssertableJson as q, type BatchRecord as r, type BootOptions as s, type CountOrFilter as t, type DatabaseTestOptions as u, DatabaseTransactions as v, type DispatchedEvent as w, type ExpectedErrors as x, FakeFile as y, InteractsWithApplication as z };
2206
+ /** The route middleware an update re-applies by default (config live.persistent_middleware), by alias. */
2207
+ declare const PERSISTENT_MIDDLEWARE: string[];
2208
+ /** A route middleware after alias and group expansion: 'auth:web' → { cls: Authenticate, parameters: ['web'] }. */
2209
+ interface PersistentMiddleware {
2210
+ readonly cls: MiddlewareClass;
2211
+ readonly parameters: readonly string[];
2212
+ }
2213
+ /**
2214
+ * Livewire's persistent middleware: the middleware among `persistent` (aliases) that the page route (the component's
2215
+ * memo path and method) ran, in the order an update runs them. A path no route matches has none.
2216
+ */
2217
+ declare function persistentMiddleware(router: Router, persistent: readonly string[], method: string, path: string): PersistentMiddleware[];
2218
+
2219
+ type ComponentConstructor = abstract new (...args: any[]) => Component;
2220
+ /** What WithPagination() adds to a component: its page and the actions that move it. */
2221
+ interface Paginated {
2222
+ /** The current page. The browser may set it; Live reads it as a page number. */
2223
+ page: number;
2224
+ nextPage(): Promise<void>;
2225
+ previousPage(): Promise<void>;
2226
+ gotoPage(page: number | string): Promise<void>;
2227
+ resetPage(): Promise<void>;
2228
+ setPage(page: number | string): Promise<void>;
2229
+ }
2230
+ /**
2231
+ * Livewire's WithPagination: `class Posts extends WithPagination(Component)`. The public `page` (1 to start; there
2232
+ * is no address-bar sync) is what `paginate()` shows in the component (in `render()`, `mount()`, `hydrate()`, the
2233
+ * update hooks and actions, or in a `@Computed` getter any of them reads), and its page links are built on the
2234
+ * page's URL. The actions move it: `o:click="nextPage"`, `previousPage`, `gotoPage(3)`, `setPage(3)`,
2235
+ * `resetPage` (call it from `updatedSearch()` so a new search starts on page 1). `updatingPage(page)` and
2236
+ * `updatedPage(page)` run around every change. One paginator per component: other page names read the request.
2237
+ */
2238
+ declare function WithPagination<TBase extends ComponentConstructor>(Base: TBase): TBase & (abstract new (...args: any[]) => Paginated);
2239
+
2240
+ /**
2241
+ * What <Pagination> reads from a paginator. Structural, since Live can't import Database: paginate()'s
2242
+ * LengthAwarePaginator (with lastPage(), so page buttons) and simplePaginate()'s Paginator (Previous and Next only).
2243
+ */
2244
+ interface PaginationSource {
2245
+ currentPage(): number;
2246
+ lastPage?(): number;
2247
+ hasMorePages(): boolean;
2248
+ onFirstPage(): boolean;
2249
+ /** Page buttons on each side of the current one (the paginator's onEachSide(), 3 by default). */
2250
+ readonly onEachSideCount?: number;
2251
+ /** Not cursorPaginate(): its pages are cursors, which a component's page number can't follow. */
2252
+ readonly nextCursor?: never;
2253
+ }
2254
+ interface PaginationProps {
2255
+ paginator: PaginationSource;
2256
+ /** Classes for the <nav>, such as its layout ("flex gap-2"); in your file, so Tailwind generates them. */
2257
+ class?: string;
2258
+ }
2259
+ /**
2260
+ * Livewire's pagination links for a WithPagination component: `<Pagination paginator={posts} />` in render(). A
2261
+ * <nav aria-label="Pagination"> with « Previous, the page buttons and Next » as Live actions (previousPage,
2262
+ * gotoPage(n), nextPage), the current page marked aria-current="page", the ends disabled, the kits' theme classes
2263
+ * (btn, btn-secondary). Nothing when everything fits on one page. The address bar is left alone.
2264
+ */
2265
+ declare function Pagination({ paginator, class: className }: PaginationProps): Htmlable;
2266
+
2267
+ export { type JsonStructure as $, AnonymousNotifiable as A, BusFake as B, Component as C, type BootOptions as D, EventFake as E, FakeDisk as F, type CountOrFilter as G, DatabaseMigrations as H, InvalidLiveRequestError as I, type DatabaseTestOptions as J, DatabaseTransactions as K, Live as L, MailFake as M, NotificationFake as N, On as O, PERSISTENT_MIDDLEWARE as P, QueueFake as Q, type DispatchedEvent as R, type ExpectedErrors as S, type Target as T, UPDATE_URI as U, FakeFile as V, WithPagination as W, HttpClient as X, InteractsWithApplication as Y, InteractsWithConsole as Z, InteractsWithDatabase as _, type ComponentResult as a, MailRecord as a0, MakesHttpRequests as a1, PendingCommand as a2, type PushedJob as a3, RefreshDatabase as a4, RefreshDatabaseState as a5, type RequestData as a6, type RequestOptions as a7, type ResponseContext as a8, type ResponseCookie as a9, usingInMemoryDatabase as aA, type SentNotification as aa, StorageFake as ab, TESTING_ENVIRONMENT as ac, type TableOrModel as ad, TestCase as ae, type TestHooks as af, TestResponse as ag, type TestTrait as ah, actingAsAuthFactory as ai, addresses as aj, applyEnvironment as ak, cookieHeader as al, cookiePrefix as am, decryptCookie as an, encryptCookie as ao, flatten as ap, guessMimeType as aq, inertiaPageOf as ar, install as as, isExpired as at, matches as au, nameOf as av, recordingExceptionHandler as aw, recordingViewFactory as ax, responseCookies as ay, runCommand as az, Computed as b, CorruptComponentPayloadError as c, ErrorBag as d, LiveComponentManager as e, LiveComponentNotFoundError as f, LiveError as g, type LiveProps as h, LiveServiceProvider as i, Locked as j, MethodNotCallableError as k, type Paginated as l, Pagination as m, type PaginationProps as n, type PaginationSource as o, PendingEvent as p, type PersistentMiddleware as q, PropertyNotUpdatableError as r, TestRequestScope as s, Testable as t, componentName as u, live as v, persistentMiddleware as w, AssertableInertia as x, AssertableJson as y, type BatchRecord as z };
package/dist/testing.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { A as AnonymousNotifiable, p as AssertableInertia, q as AssertableJson, r as BatchRecord, s as BootOptions, B as BusFake, t as CountOrFilter, D as DatabaseMigrations, u as DatabaseTestOptions, v as DatabaseTransactions, w as DispatchedEvent, E as EventFake, x as ExpectedErrors, F as FakeDisk, y as FakeFile, H as HttpClient, z as InteractsWithApplication, G as InteractsWithConsole, J as InteractsWithDatabase, K as JsonStructure, L as Live, M as MailFake, R as MailRecord, S as MakesHttpRequests, N as NotificationFake, V as PendingCommand, W as PushedJob, Q as QueueFake, X as RefreshDatabase, Y as RefreshDatabaseState, Z as RequestData, _ as RequestOptions, $ as ResponseContext, a0 as ResponseCookie, a1 as SentNotification, a2 as StorageFake, a3 as TESTING_ENVIRONMENT, a4 as TableOrModel, T as Target, a5 as TestCase, a6 as TestHooks, a7 as TestResponse, a8 as TestTrait, m as Testable, a9 as actingAsAuthFactory, aa as addresses, ab as applyEnvironment, ac as cookieHeader, ad as cookiePrefix, ae as decryptCookie, af as encryptCookie, ag as flatten, ah as guessMimeType, ai as inertiaPageOf, aj as install, ak as isExpired, al as matches, am as nameOf, an as recordingExceptionHandler, ao as recordingViewFactory, ap as responseCookies, aq as runCommand, ar as usingInMemoryDatabase } from './testing--F6FODc_.js';
1
+ export { A as AnonymousNotifiable, x as AssertableInertia, y as AssertableJson, z as BatchRecord, D as BootOptions, B as BusFake, G as CountOrFilter, H as DatabaseMigrations, J as DatabaseTestOptions, K as DatabaseTransactions, R as DispatchedEvent, E as EventFake, S as ExpectedErrors, F as FakeDisk, V as FakeFile, X as HttpClient, Y as InteractsWithApplication, Z as InteractsWithConsole, _ as InteractsWithDatabase, $ as JsonStructure, L as Live, M as MailFake, a0 as MailRecord, a1 as MakesHttpRequests, N as NotificationFake, a2 as PendingCommand, a3 as PushedJob, Q as QueueFake, a4 as RefreshDatabase, a5 as RefreshDatabaseState, a6 as RequestData, a7 as RequestOptions, a8 as ResponseContext, a9 as ResponseCookie, aa as SentNotification, ab as StorageFake, ac as TESTING_ENVIRONMENT, ad as TableOrModel, T as Target, ae as TestCase, af as TestHooks, ag as TestResponse, ah as TestTrait, t as Testable, ai as actingAsAuthFactory, aj as addresses, ak as applyEnvironment, al as cookieHeader, am as cookiePrefix, an as decryptCookie, ao as encryptCookie, ap as flatten, aq as guessMimeType, ar as inertiaPageOf, as as install, at as isExpired, au as matches, av as nameOf, aw as recordingExceptionHandler, ax as recordingViewFactory, ay as responseCookies, az as runCommand, aA as usingInMemoryDatabase } from './testing-BErengYY.js';
2
2
  import './contracts.js';
3
3
  import './index.d-DOlTeG-8.js';
package/dist/testing.js CHANGED
@@ -45,9 +45,9 @@ import {
45
45
  responseCookies,
46
46
  runCommand,
47
47
  usingInMemoryDatabase
48
- } from "./chunk-I2OMKIQZ.js";
49
- import "./chunk-HU43NADT.js";
50
- import "./chunk-S7YC43IH.js";
48
+ } from "./chunk-WNJP46B7.js";
49
+ import "./chunk-PM5YTG57.js";
50
+ import "./chunk-BSQKOLSK.js";
51
51
  export {
52
52
  AnonymousNotifiable,
53
53
  AssertableInertia,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orieljs/framework",
3
- "version": "0.1.0-alpha.3",
3
+ "version": "0.1.0-alpha.5",
4
4
  "description": "Oriel: a Laravel-style, full-stack TypeScript framework for Node.js and Bun.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -56,35 +56,35 @@
56
56
  "pluralize": "8.0.0"
57
57
  },
58
58
  "devDependencies": {
59
- "@orieljs/auth": "0.1.0-alpha.3",
60
- "@orieljs/bus": "0.1.0-alpha.3",
61
- "@orieljs/collections": "0.1.0-alpha.3",
62
- "@orieljs/cache": "0.1.0-alpha.3",
63
- "@orieljs/config": "0.1.0-alpha.3",
64
- "@orieljs/console": "0.1.0-alpha.3",
65
- "@orieljs/container": "0.1.0-alpha.3",
66
- "@orieljs/cookie": "0.1.0-alpha.3",
67
- "@orieljs/contracts": "0.1.0-alpha.3",
68
- "@orieljs/database": "0.1.0-alpha.3",
69
- "@orieljs/encryption": "0.1.0-alpha.3",
70
- "@orieljs/events": "0.1.0-alpha.3",
71
- "@orieljs/filesystem": "0.1.0-alpha.3",
72
- "@orieljs/hashing": "0.1.0-alpha.3",
73
- "@orieljs/foundation": "0.1.0-alpha.3",
74
- "@orieljs/http": "0.1.0-alpha.3",
75
- "@orieljs/inertia": "0.1.0-alpha.3",
76
- "@orieljs/live": "0.1.0-alpha.3",
77
- "@orieljs/log": "0.1.0-alpha.3",
78
- "@orieljs/mail": "0.1.0-alpha.3",
79
- "@orieljs/pipeline": "0.1.0-alpha.3",
80
- "@orieljs/notifications": "0.1.0-alpha.3",
81
- "@orieljs/routing": "0.1.0-alpha.3",
82
- "@orieljs/queue": "0.1.0-alpha.3",
83
- "@orieljs/session": "0.1.0-alpha.3",
84
- "@orieljs/support": "0.1.0-alpha.3",
85
- "@orieljs/testing": "0.1.0-alpha.3",
86
- "@orieljs/view": "0.1.0-alpha.3",
87
- "@orieljs/validation": "0.1.0-alpha.3"
59
+ "@orieljs/bus": "0.1.0-alpha.5",
60
+ "@orieljs/auth": "0.1.0-alpha.5",
61
+ "@orieljs/cache": "0.1.0-alpha.5",
62
+ "@orieljs/config": "0.1.0-alpha.5",
63
+ "@orieljs/collections": "0.1.0-alpha.5",
64
+ "@orieljs/console": "0.1.0-alpha.5",
65
+ "@orieljs/container": "0.1.0-alpha.5",
66
+ "@orieljs/contracts": "0.1.0-alpha.5",
67
+ "@orieljs/cookie": "0.1.0-alpha.5",
68
+ "@orieljs/encryption": "0.1.0-alpha.5",
69
+ "@orieljs/events": "0.1.0-alpha.5",
70
+ "@orieljs/foundation": "0.1.0-alpha.5",
71
+ "@orieljs/database": "0.1.0-alpha.5",
72
+ "@orieljs/hashing": "0.1.0-alpha.5",
73
+ "@orieljs/filesystem": "0.1.0-alpha.5",
74
+ "@orieljs/http": "0.1.0-alpha.5",
75
+ "@orieljs/inertia": "0.1.0-alpha.5",
76
+ "@orieljs/log": "0.1.0-alpha.5",
77
+ "@orieljs/notifications": "0.1.0-alpha.5",
78
+ "@orieljs/pipeline": "0.1.0-alpha.5",
79
+ "@orieljs/live": "0.1.0-alpha.5",
80
+ "@orieljs/queue": "0.1.0-alpha.5",
81
+ "@orieljs/routing": "0.1.0-alpha.5",
82
+ "@orieljs/session": "0.1.0-alpha.5",
83
+ "@orieljs/mail": "0.1.0-alpha.5",
84
+ "@orieljs/support": "0.1.0-alpha.5",
85
+ "@orieljs/testing": "0.1.0-alpha.5",
86
+ "@orieljs/validation": "0.1.0-alpha.5",
87
+ "@orieljs/view": "0.1.0-alpha.5"
88
88
  },
89
89
  "peerDependencies": {
90
90
  "pg": "^8.23.0",