@xmachines/play-router 2.0.0-alpha.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -89
- package/dist/base-route-map.d.ts +63 -57
- package/dist/base-route-map.d.ts.map +1 -1
- package/dist/base-route-map.js +65 -59
- package/dist/base-route-map.js.map +1 -1
- package/dist/build-tree.d.ts +13 -12
- package/dist/build-tree.d.ts.map +1 -1
- package/dist/build-tree.js +30 -28
- package/dist/build-tree.js.map +1 -1
- package/dist/create-route-map-from-tree.d.ts +15 -15
- package/dist/create-route-map-from-tree.js +15 -15
- package/dist/create-route-map.d.ts +18 -16
- package/dist/create-route-map.d.ts.map +1 -1
- package/dist/create-route-map.js +10 -9
- package/dist/create-route-map.js.map +1 -1
- package/dist/errors.d.ts +40 -38
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +40 -38
- package/dist/errors.js.map +1 -1
- package/dist/extract-routes.d.ts +8 -7
- package/dist/extract-routes.d.ts.map +1 -1
- package/dist/extract-routes.js +31 -27
- package/dist/extract-routes.js.map +1 -1
- package/dist/find-route.d.ts +18 -15
- package/dist/find-route.d.ts.map +1 -1
- package/dist/find-route.js +42 -38
- package/dist/find-route.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -10
- package/dist/index.js.map +1 -1
- package/dist/machine-to-graph.d.ts +3 -2
- package/dist/machine-to-graph.d.ts.map +1 -1
- package/dist/machine-to-graph.js +21 -30
- package/dist/machine-to-graph.js.map +1 -1
- package/dist/query.d.ts +39 -37
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +62 -57
- package/dist/query.js.map +1 -1
- package/dist/router-bridge-base.d.ts +208 -190
- package/dist/router-bridge-base.d.ts.map +1 -1
- package/dist/router-bridge-base.js +235 -211
- package/dist/router-bridge-base.js.map +1 -1
- package/dist/router-sync.d.ts +41 -35
- package/dist/router-sync.d.ts.map +1 -1
- package/dist/router-sync.js +53 -45
- package/dist/router-sync.js.map +1 -1
- package/dist/types.d.ts +163 -164
- package/dist/types.d.ts.map +1 -1
- package/dist/url-pattern-utils.d.ts +53 -47
- package/dist/url-pattern-utils.d.ts.map +1 -1
- package/dist/url-pattern-utils.js +61 -55
- package/dist/url-pattern-utils.js.map +1 -1
- package/dist/validate-routes.d.ts +32 -31
- package/dist/validate-routes.d.ts.map +1 -1
- package/dist/validate-routes.js +30 -29
- package/dist/validate-routes.js.map +1 -1
- package/package.json +23 -21
package/dist/types.d.ts
CHANGED
|
@@ -2,146 +2,133 @@ import type { Graph } from "@statelyai/graph";
|
|
|
2
2
|
import type { Signal } from "@xmachines/play-signals";
|
|
3
3
|
import type { PlaySpec } from "@xmachines/play-actor";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* The data on each node of the graph that represents the machine.
|
|
6
|
+
* It holds the state metadata that the route extraction and the queries need.
|
|
7
7
|
*/
|
|
8
8
|
export interface MachineNodeData {
|
|
9
|
-
/** XState state ID
|
|
9
|
+
/** The XState state ID, for example "test.dashboard.overview" */
|
|
10
10
|
stateId: string;
|
|
11
|
-
/**
|
|
11
|
+
/** The state type of XState */
|
|
12
12
|
type: "atomic" | "compound" | "parallel" | "final" | "history";
|
|
13
|
-
/**
|
|
13
|
+
/** The original meta object of the state */
|
|
14
14
|
meta?: Record<string, unknown>;
|
|
15
|
-
/**
|
|
15
|
+
/** The route path of meta.route, in its string form */
|
|
16
16
|
route?: string;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
19
|
+
* The data on each edge of the graph that represents the machine.
|
|
20
|
+
* It holds the event of the transition and the information of its guard.
|
|
21
21
|
*/
|
|
22
22
|
export interface MachineEdgeData {
|
|
23
|
-
/** The event type that
|
|
23
|
+
/** The event type that starts this transition */
|
|
24
24
|
eventType: string;
|
|
25
25
|
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* {@link MachineEdgeData.guarded} instead.
|
|
26
|
+
* The guard as a string, when a guard is present
|
|
27
|
+
*
|
|
28
|
+
* @deprecated Will be removed in the next major.
|
|
30
29
|
*/
|
|
31
30
|
guardType?: string;
|
|
32
|
-
/**
|
|
33
|
-
* True when a guard function gates this transition. XState v6 compiles all
|
|
34
|
-
* guards to functions (authored predicates, JSON-layer names, and the
|
|
35
|
-
* route-matching guard synthesized on native route transitions), so only
|
|
36
|
-
* the presence of a guard — not its identity — is statically knowable.
|
|
37
|
-
*/
|
|
38
|
-
guarded?: boolean;
|
|
39
|
-
/**
|
|
40
|
-
* True when the transition is an XState v6 function transition: the function
|
|
41
|
-
* acts as its own guard/resolver, so its target and conditionality are
|
|
42
|
-
* dynamic and unknowable statically (the edge's target falls back to the
|
|
43
|
-
* source state).
|
|
44
|
-
*/
|
|
45
|
-
dynamic?: boolean;
|
|
46
31
|
}
|
|
47
32
|
/**
|
|
48
|
-
*
|
|
33
|
+
* The type definitions of the routing protocol of @xmachines/play-router
|
|
49
34
|
*
|
|
50
|
-
* PlayRouteEvent, RouterBridge, RouteMetadata, and RouteObject
|
|
51
|
-
*
|
|
35
|
+
* PlayRouteEvent, RouterBridge, RouteMetadata, and RouteObject are here. The routing
|
|
36
|
+
* therefore stays separate from the base event protocol of @xmachines/play.
|
|
52
37
|
*/
|
|
53
38
|
/**
|
|
54
|
-
*
|
|
39
|
+
* A route object, with more metadata.
|
|
55
40
|
*/
|
|
56
41
|
export interface RouteObject {
|
|
57
|
-
/**
|
|
42
|
+
/** The template of the route path, for example '/user/:id' */
|
|
58
43
|
path: string;
|
|
59
|
-
/**
|
|
44
|
+
/** The additional metadata of the route: a title, a breadcrumb, and so on */
|
|
60
45
|
[key: string]: unknown;
|
|
61
46
|
}
|
|
62
47
|
/**
|
|
63
|
-
*
|
|
48
|
+
* The route metadata of the `meta.route` field of a state machine.
|
|
64
49
|
*/
|
|
65
50
|
export type RouteMetadata = string | RouteObject;
|
|
66
51
|
/**
|
|
67
|
-
*
|
|
52
|
+
* The route information of a state node
|
|
68
53
|
*/
|
|
69
54
|
export interface RouteInfo {
|
|
70
|
-
/**
|
|
55
|
+
/** The identifier of the state: node.id, or path.join('.') */
|
|
71
56
|
stateId: string;
|
|
72
|
-
/**
|
|
57
|
+
/** The segments of the state path, from the root */
|
|
73
58
|
statePath: string[];
|
|
74
|
-
/**
|
|
59
|
+
/** The route path of meta.route */
|
|
75
60
|
routePath: string;
|
|
76
|
-
/**
|
|
61
|
+
/** The route pattern with its parameters, for example /profile/:userId, when routePath holds a parameter */
|
|
77
62
|
pattern?: string;
|
|
78
|
-
/**
|
|
63
|
+
/** It tells you if the route path is absolute, which means that it starts with / */
|
|
79
64
|
isAbsolute: boolean;
|
|
80
65
|
/**
|
|
81
|
-
*
|
|
82
|
-
* true = has meta.route, can receive play.route
|
|
66
|
+
* It tells you if this state has a route, which means that it has a meta.route field.
|
|
67
|
+
* true = it has a meta.route field, and it can receive a play.route event
|
|
83
68
|
*/
|
|
84
69
|
routable: boolean;
|
|
85
|
-
/**
|
|
70
|
+
/** The original route metadata */
|
|
86
71
|
metadata: RouteMetadata;
|
|
87
72
|
}
|
|
88
73
|
/**
|
|
89
|
-
*
|
|
74
|
+
* A node of the route tree. It represents one route
|
|
90
75
|
*/
|
|
91
76
|
export interface RouteNode {
|
|
92
|
-
/**
|
|
77
|
+
/** The unique identifier, which is the state ID */
|
|
93
78
|
id: string;
|
|
94
79
|
/**
|
|
95
|
-
* The raw route path
|
|
96
|
-
* or absolute
|
|
80
|
+
* The raw segment of the route path, as `meta.route` declares it. It is relative,
|
|
81
|
+
* for example `"overview"`, or absolute, for example `"/dashboard"`. Never use it for
|
|
82
|
+
* a match of a URL: use `fullPath` for that.
|
|
97
83
|
*/
|
|
98
84
|
path: string;
|
|
99
85
|
/**
|
|
100
|
-
* The
|
|
101
|
-
* Always use `fullPath` for browser URL
|
|
102
|
-
* `createRouteMapFromTree` and `createRouteMap` both use this field.
|
|
86
|
+
* The complete absolute path from the root, for example `"/dashboard/overview"`.
|
|
87
|
+
* Always use `fullPath` for a match of a browser URL and for the construction of a
|
|
88
|
+
* route map. `createRouteMapFromTree` and `createRouteMap` both use this field.
|
|
103
89
|
*/
|
|
104
90
|
fullPath: string;
|
|
105
|
-
/**
|
|
91
|
+
/** The route pattern with its parameters, for example /profile/:userId, when path holds a parameter */
|
|
106
92
|
pattern?: string;
|
|
107
|
-
/** XState state ID this route
|
|
93
|
+
/** The XState state ID of this route */
|
|
108
94
|
stateId: string;
|
|
109
95
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
96
|
+
* It tells you if this state has a route, which means that it has a meta.route field.
|
|
97
|
+
* A state with a meta.route field can receive a play.route event
|
|
112
98
|
*/
|
|
113
99
|
routable: boolean;
|
|
114
|
-
/**
|
|
100
|
+
/** The child routes */
|
|
115
101
|
children: RouteNode[];
|
|
116
|
-
/**
|
|
102
|
+
/** The parent route. It is null for the root */
|
|
117
103
|
parent: RouteNode | null;
|
|
118
|
-
/**
|
|
104
|
+
/** The original meta.route metadata */
|
|
119
105
|
metadata: RouteMetadata;
|
|
120
106
|
}
|
|
121
107
|
/**
|
|
122
|
-
*
|
|
108
|
+
* The complete route tree, with its lookup maps
|
|
123
109
|
*
|
|
124
|
-
*
|
|
125
|
-
* - byStateId:
|
|
126
|
-
* - byPath:
|
|
110
|
+
* It gives you the map between a state ID and a URL path, in both directions:
|
|
111
|
+
* - byStateId: it maps each state ID to its route node, for the target of a play.route event
|
|
112
|
+
* - byPath: it maps each URL path to its route node, for the browser navigation
|
|
127
113
|
*/
|
|
128
114
|
export interface RouteTree {
|
|
129
|
-
/**
|
|
115
|
+
/** The root node of the routes */
|
|
130
116
|
root: RouteNode;
|
|
131
117
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
118
|
+
* The map from a state ID to its route node.
|
|
119
|
+
* It gives you the URL path of a state ID, for the update of the browser URL
|
|
134
120
|
*/
|
|
135
121
|
byStateId: Map<string, RouteNode>;
|
|
136
122
|
/**
|
|
137
|
-
*
|
|
138
|
-
*
|
|
123
|
+
* The map from a complete path to its route node.
|
|
124
|
+
* It gives you the state ID of a URL path, for the target of a play.route event
|
|
139
125
|
*/
|
|
140
126
|
byPath: Map<string, RouteNode>;
|
|
141
127
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
* and
|
|
128
|
+
* The graph of the state machine, for an advanced query.
|
|
129
|
+
* extractMachineRoutes() fills it. Use it for a query of the hierarchy, for a test of
|
|
130
|
+
* the reachability, and for a navigation that knows the transitions, through the
|
|
131
|
+
* algorithms of @statelyai/graph.
|
|
145
132
|
*
|
|
146
133
|
* @example
|
|
147
134
|
* ```typescript
|
|
@@ -152,31 +139,36 @@ export interface RouteTree {
|
|
|
152
139
|
graph?: Graph<MachineNodeData, MachineEdgeData>;
|
|
153
140
|
}
|
|
154
141
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* navigation
|
|
159
|
-
*
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
* @param
|
|
173
|
-
* @param
|
|
174
|
-
* @param
|
|
175
|
-
*
|
|
176
|
-
*
|
|
142
|
+
* The routing event, with its parameters and its query
|
|
143
|
+
*
|
|
144
|
+
* This is the one routing event of the complete Play architecture. It supports a
|
|
145
|
+
* navigation that knows the parameters, for example `/profile/:userId`, for a dynamic
|
|
146
|
+
* route segment.
|
|
147
|
+
*
|
|
148
|
+
* **Architectural context:** the event implements **Passive Infrastructure
|
|
149
|
+
* (INV-04)**, because it holds the navigation intent of the user, and the Actor then
|
|
150
|
+
* evaluates that intent with its guards. The infrastructure makes a request with a
|
|
151
|
+
* `play.route` event, and the Actor decides with a transition of its state machine.
|
|
152
|
+
*
|
|
153
|
+
* **The flow of a browser navigation:**
|
|
154
|
+
* 1. The browser fires `popstate`
|
|
155
|
+
* 2. The router adapter resolves the URL to a route target
|
|
156
|
+
* 3. The adapter sends a `PlayRouteEvent` to the Actor
|
|
157
|
+
* 4. The Actor checks the transition with the guards of its state machine
|
|
158
|
+
*
|
|
159
|
+
* @param type - The discriminator of the event. It is always "play.route"
|
|
160
|
+
* @param to - The target state ID, with a # prefix, for example '#home' or '#profile'
|
|
161
|
+
* @param params - The route parameters of the path only, from the URL path, for
|
|
162
|
+
* example `{ userId: '123' }` of `/profile/123`. The `query` field holds the query
|
|
163
|
+
* parameters separately.
|
|
164
|
+
* @param query - The query parameters only. They stay separate from the params of the path
|
|
165
|
+
* @param match - The complete match result of URLPattern, for the debug work and for
|
|
166
|
+
* the observability. It is optional
|
|
167
|
+
*
|
|
168
|
+
* @returns Nothing. This interface defines the shape of the event only
|
|
177
169
|
*
|
|
178
170
|
* @example
|
|
179
|
-
*
|
|
171
|
+
* The base event and the routing event together
|
|
180
172
|
* ```typescript
|
|
181
173
|
* import type { PlayEvent } from "@xmachines/play";
|
|
182
174
|
* import type { PlayRouteEvent } from "@xmachines/play-router";
|
|
@@ -185,7 +177,7 @@ export interface RouteTree {
|
|
|
185
177
|
* ```
|
|
186
178
|
*
|
|
187
179
|
* @example
|
|
188
|
-
*
|
|
180
|
+
* A basic navigation to a route
|
|
189
181
|
* ```typescript
|
|
190
182
|
* import type { PlayRouteEvent } from "@xmachines/play-router";
|
|
191
183
|
*
|
|
@@ -197,7 +189,7 @@ export interface RouteTree {
|
|
|
197
189
|
* ```
|
|
198
190
|
*
|
|
199
191
|
* @example
|
|
200
|
-
*
|
|
192
|
+
* A navigation with route parameters
|
|
201
193
|
* ```typescript
|
|
202
194
|
* import type { PlayRouteEvent } from "@xmachines/play-router";
|
|
203
195
|
*
|
|
@@ -207,30 +199,31 @@ export interface RouteTree {
|
|
|
207
199
|
* params: { userId: '123' }
|
|
208
200
|
* };
|
|
209
201
|
* actor.send(event);
|
|
210
|
-
* //
|
|
202
|
+
* // It resolves to the route /profile/123
|
|
211
203
|
* ```
|
|
212
204
|
*
|
|
213
205
|
* @example
|
|
214
|
-
*
|
|
206
|
+
* A navigation with query parameters
|
|
215
207
|
* ```typescript
|
|
216
208
|
* import type { PlayRouteEvent } from "@xmachines/play-router";
|
|
217
209
|
*
|
|
218
210
|
* const event: PlayRouteEvent = {
|
|
219
211
|
* type: 'play.route',
|
|
220
212
|
* to: '#settings',
|
|
221
|
-
* params: { section: 'profile' }, //
|
|
222
|
-
* query: { tab: 'security' } //
|
|
213
|
+
* params: { section: 'profile' }, // a route parameter of the path only
|
|
214
|
+
* query: { tab: 'security' } // the query only
|
|
223
215
|
* };
|
|
224
216
|
* actor.send(event);
|
|
225
|
-
* //
|
|
217
|
+
* // It resolves to the route /settings/profile?tab=security
|
|
226
218
|
* ```
|
|
227
219
|
*
|
|
228
220
|
* @see [Play RFC](../../docs/rfc/play.md)
|
|
229
221
|
*
|
|
230
222
|
* @remarks
|
|
231
|
-
* Use `play.route` when you need
|
|
232
|
-
* config pattern on your state machine
|
|
233
|
-
* URLPatternResult for advanced use
|
|
223
|
+
* Use `play.route` when you need a navigation that knows the parameters, with the
|
|
224
|
+
* `route: {}` config pattern on the nodes of your state machine. The `match` field
|
|
225
|
+
* gives you the complete URLPatternResult, for an advanced use such as a debug or an
|
|
226
|
+
* analysis of the pattern.
|
|
234
227
|
*/
|
|
235
228
|
export interface PlayRouteEvent {
|
|
236
229
|
readonly type: "play.route";
|
|
@@ -241,18 +234,19 @@ export interface PlayRouteEvent {
|
|
|
241
234
|
[key: string]: unknown;
|
|
242
235
|
}
|
|
243
236
|
/**
|
|
244
|
-
*
|
|
245
|
-
*
|
|
237
|
+
* The minimal actor interface that `RouterBridgeBase` and every framework router
|
|
238
|
+
* adapter require.
|
|
246
239
|
*
|
|
247
|
-
*
|
|
248
|
-
* `RouterBridgeBase.actor.send`
|
|
249
|
-
*
|
|
250
|
-
*
|
|
240
|
+
* This interface, and not `AbstractActor<AnyActorLogic> & Routable`, gives
|
|
241
|
+
* `RouterBridgeBase.actor.send` the type that accepts a `PlayRouteEvent` directly.
|
|
242
|
+
* It therefore removes the unsafe cast `(actor.send as (e: PlayRouteEvent) => void)`,
|
|
243
|
+
* which the weaker `EventObject` constraint of the actor type needed before.
|
|
251
244
|
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
255
|
-
*
|
|
245
|
+
* Every `AbstractActor` subclass satisfies this interface structurally, for two
|
|
246
|
+
* reasons:
|
|
247
|
+
* - `AbstractActor` implements `send(event: TEvent): void`, and `TEvent` accepts each
|
|
248
|
+
* `EventObject`. Therefore it always accepts a `PlayRouteEvent`, which is a subtype.
|
|
249
|
+
* - `Routable` gives `currentRoute` and `initialRoute`.
|
|
256
250
|
*
|
|
257
251
|
* @example
|
|
258
252
|
* ```typescript
|
|
@@ -266,59 +260,63 @@ export interface PlayRouteEvent {
|
|
|
266
260
|
* ```
|
|
267
261
|
*/
|
|
268
262
|
export interface RoutableActor {
|
|
269
|
-
/** TC39 Signal
|
|
263
|
+
/** The TC39 Signal of the current URL path of the actor, or of its state ID. */
|
|
270
264
|
readonly currentRoute: Signal.Computed<string | null>;
|
|
271
265
|
/**
|
|
272
|
-
* The route
|
|
273
|
-
*
|
|
274
|
-
*
|
|
266
|
+
* The route of the initial state of the machine. The constructor fixes it.
|
|
267
|
+
* A router bridge compares it with the browser URL. It therefore separates a deep
|
|
268
|
+
* link, where the router wins, from a restore of a session, where the actor wins.
|
|
275
269
|
*/
|
|
276
270
|
readonly initialRoute: string | null;
|
|
277
|
-
/**
|
|
271
|
+
/** Sends a route navigation event to the actor. */
|
|
278
272
|
send(event: PlayRouteEvent): void;
|
|
279
273
|
}
|
|
280
274
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
283
|
-
*
|
|
275
|
+
* The complete actor shape of the `PlayRouterProvider` component of each framework
|
|
276
|
+
* adapter: `play-solid-router`, `play-vue-router`, `play-react-router`, and each
|
|
277
|
+
* adapter on the shared framework router bridge bases.
|
|
284
278
|
*
|
|
285
|
-
*
|
|
286
|
-
* view spec
|
|
279
|
+
* The shape extends `RoutableActor` with `currentView`, because the provider renders
|
|
280
|
+
* the current view spec and also keeps the routes in step. It therefore needs both
|
|
281
|
+
* capabilities.
|
|
287
282
|
*
|
|
288
|
-
* - Use `RoutableActor` when
|
|
289
|
-
* `connectRouter
|
|
290
|
-
* - Use `PlayActor` when the component also renders the current view spec
|
|
291
|
-
*
|
|
283
|
+
* - Use `RoutableActor` when you need the routing alone, for example in a
|
|
284
|
+
* `RouterBridgeBase` subclass, or in `connectRouter`.
|
|
285
|
+
* - Use `PlayActor` when the component also renders the current view spec, for
|
|
286
|
+
* example for the renderer callback parameter of `PlayRouterProvider`, and in
|
|
287
|
+
* `PlayRenderer`.
|
|
292
288
|
*
|
|
293
|
-
*
|
|
294
|
-
*
|
|
289
|
+
* Every `AbstractActor` subclass that implements both `Routable` and `Viewable`
|
|
290
|
+
* satisfies this interface structurally.
|
|
295
291
|
*
|
|
296
292
|
* @example
|
|
297
293
|
* ```typescript
|
|
298
294
|
* import type { PlayActor } from "@xmachines/play-router";
|
|
299
295
|
*
|
|
300
296
|
* function MyRouterProvider({ actor }: { actor: PlayActor }) {
|
|
301
|
-
* //
|
|
297
|
+
* // it reads actor.currentRoute for the routing, and actor.currentView for the render
|
|
302
298
|
* }
|
|
303
299
|
* ```
|
|
304
300
|
*/
|
|
305
301
|
export interface PlayActor extends RoutableActor {
|
|
306
|
-
/** TC39 Signal
|
|
302
|
+
/** The TC39 Signal of the current view spec of the actor, or `null` when no view is active. */
|
|
307
303
|
readonly currentView: Signal.State<PlaySpec | null>;
|
|
308
304
|
}
|
|
309
305
|
/**
|
|
310
|
-
* RouterBridge interface
|
|
306
|
+
* The RouterBridge interface of a runtime infrastructure adapter
|
|
311
307
|
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
314
|
-
*
|
|
308
|
+
* The interface defines the connection of the lifecycle between the infrastructure,
|
|
309
|
+
* for example a framework router, and the Actor. The infrastructure builds a "bridge"
|
|
310
|
+
* to the Actor: it observes the signals of the Actor, and it manages its own
|
|
311
|
+
* lifecycle accordingly.
|
|
315
312
|
*
|
|
316
|
-
* **Architectural
|
|
317
|
-
*
|
|
318
|
-
*
|
|
313
|
+
* **Architectural context:** the interface implements **Passive Infrastructure
|
|
314
|
+
* (INV-04)**, because it gives an observation in one direction. The infrastructure
|
|
315
|
+
* connects to observe the signals of the Actor (currentRoute, currentView, and
|
|
316
|
+
* state), and it reflects each change. It makes no decision about the state.
|
|
319
317
|
*
|
|
320
318
|
* @example
|
|
321
|
-
*
|
|
319
|
+
* The implementation of a framework router bridge
|
|
322
320
|
* ```typescript
|
|
323
321
|
* import type { RouterBridge } from "@xmachines/play-router";
|
|
324
322
|
* import { Signal } from "@xmachines/play-signals";
|
|
@@ -327,7 +325,7 @@ export interface PlayActor extends RoutableActor {
|
|
|
327
325
|
* private watcher: Signal.Watcher | null = null;
|
|
328
326
|
*
|
|
329
327
|
* async connect(): Promise<void> {
|
|
330
|
-
* // Start
|
|
328
|
+
* // Start the observation of the actor.currentRoute signal
|
|
331
329
|
* this.watcher = new Signal.subtle.Watcher(() => {
|
|
332
330
|
* const route = actor.currentRoute.get();
|
|
333
331
|
* if (route) router.navigate(route);
|
|
@@ -336,62 +334,63 @@ export interface PlayActor extends RoutableActor {
|
|
|
336
334
|
* }
|
|
337
335
|
*
|
|
338
336
|
* async disconnect(): Promise<void> {
|
|
339
|
-
* // Stop
|
|
337
|
+
* // Stop the observation, and clean the watchers up
|
|
340
338
|
* this.watcher?.unwatch(actor.currentRoute);
|
|
341
339
|
* this.watcher = null;
|
|
342
340
|
* }
|
|
343
341
|
* }
|
|
344
342
|
* ```
|
|
345
343
|
*
|
|
346
|
-
* @see [Play RFC](../../docs/rfc/play.md) -
|
|
344
|
+
* @see [Play RFC](../../docs/rfc/play.md) - invariant INV-04
|
|
347
345
|
*/
|
|
348
346
|
export interface RouterBridge {
|
|
349
347
|
/**
|
|
350
|
-
*
|
|
348
|
+
* Connects the router bridge to the Actor
|
|
351
349
|
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
350
|
+
* The infrastructure calls it when it must start the observation of the Actor
|
|
351
|
+
* signals, and when it must bring its own state, for example the browser URL, in line
|
|
352
|
+
* with the Actor state.
|
|
354
353
|
*
|
|
355
|
-
* @returns
|
|
354
|
+
* @returns The promise that resolves after the connection, or void for a synchronous connection
|
|
356
355
|
*
|
|
357
356
|
* @example
|
|
358
357
|
* ```typescript
|
|
359
358
|
* const bridge: RouterBridge = createBridge(actor, router);
|
|
360
359
|
* await bridge.connect();
|
|
361
|
-
* //
|
|
360
|
+
* // The bridge observes the actor.currentRoute signal now
|
|
362
361
|
* ```
|
|
363
362
|
*/
|
|
364
363
|
connect(): void | Promise<void>;
|
|
365
364
|
/**
|
|
366
|
-
*
|
|
365
|
+
* Disconnects the router bridge from the Actor
|
|
367
366
|
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
367
|
+
* The infrastructure calls it when it must stop the observation and free its
|
|
368
|
+
* resources, for example a signal watcher and an event listener.
|
|
370
369
|
*
|
|
371
|
-
* @returns
|
|
370
|
+
* @returns The promise that resolves after the disconnection, or void for a synchronous disconnection
|
|
372
371
|
*
|
|
373
372
|
* @example
|
|
374
373
|
* ```typescript
|
|
375
374
|
* await bridge.disconnect();
|
|
376
|
-
* //
|
|
375
|
+
* // The bridge stopped its observation, and it freed its resources
|
|
377
376
|
* ```
|
|
378
377
|
*/
|
|
379
378
|
disconnect(): void | Promise<void>;
|
|
380
379
|
}
|
|
381
380
|
/**
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* the global `window` when
|
|
381
|
+
* The minimal window interface of an adapter that subscribes to a DOM event, for
|
|
382
|
+
* example to `hashchange`. You can inject it for SSR and for a test: give a mock in
|
|
383
|
+
* place of the global `window` when no DOM is available.
|
|
385
384
|
*
|
|
386
|
-
*
|
|
387
|
-
* the DOM lib.
|
|
385
|
+
* The definition is structural, and it holds no reference to `Window`. This package
|
|
386
|
+
* therefore compiles without the DOM lib.
|
|
388
387
|
*
|
|
389
388
|
* @example
|
|
390
389
|
* ```typescript
|
|
391
|
-
* //
|
|
390
|
+
* // The normal use — the global window, which is the default
|
|
392
391
|
* connectRouter({ actor, routeMap });
|
|
393
392
|
*
|
|
394
|
-
* // SSR
|
|
393
|
+
* // SSR or a test — an injected mock
|
|
395
394
|
* const mockWin: WindowLike = { addEventListener: vi.fn(), removeEventListener: vi.fn() };
|
|
396
395
|
* connectRouter({ actor, routeMap, window: mockWin });
|
|
397
396
|
* ```
|
|
@@ -401,16 +400,16 @@ export interface WindowLike {
|
|
|
401
400
|
removeEventListener(type: string, listener: (event: Event) => void): void;
|
|
402
401
|
}
|
|
403
402
|
/**
|
|
404
|
-
*
|
|
405
|
-
* `connect()
|
|
406
|
-
* global `location` when
|
|
403
|
+
* The minimal location interface of an adapter that reads the current URL at the
|
|
404
|
+
* moment of `connect()`. You can inject it for SSR and for a test: give a mock in
|
|
405
|
+
* place of the global `location` when no DOM is available.
|
|
407
406
|
*
|
|
408
|
-
*
|
|
409
|
-
* the DOM lib.
|
|
407
|
+
* The definition is structural, and it holds no reference to `Location`. This package
|
|
408
|
+
* therefore compiles without the DOM lib.
|
|
410
409
|
*
|
|
411
410
|
* @example
|
|
412
411
|
* ```typescript
|
|
413
|
-
* // SSR
|
|
412
|
+
* // SSR or a test — an injected mock
|
|
414
413
|
* const mockLoc: LocationLike = { pathname: "/dashboard", search: "?tab=posts" };
|
|
415
414
|
* connectRouter({ actor, routeMap, location: mockLoc });
|
|
416
415
|
* ```
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,IAAI,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;IAC/D,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC/B,iDAAiD;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AAEH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,CAAC;AAEjD;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,4GAA4G;IAC5G,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,UAAU,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,kCAAkC;IAClC,QAAQ,EAAE,aAAa,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACzB,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,uBAAuB;IACvB,QAAQ,EAAE,SAAS,EAAE,CAAC;IACtB,gDAAgD;IAChD,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IACzB,uCAAuC;IACvC,QAAQ,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,SAAS;IACzB,kCAAkC;IAClC,IAAI,EAAE,SAAS,CAAC;IAChB;;;OAGG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC;;;OAGG;IACH,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC/B;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,EAAE,KAAK,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;CAChD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsFG;AACH,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,MAAM,WAAW,aAAa;IAC7B,gFAAgF;IAChF,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACtD;;;;OAIG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,mDAAmD;IACnD,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa;IAC/C,+FAA+F;IAC/F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,WAAW,YAAY;IAC5B;;;;;;;;;;;;;;;OAeG;IACH,OAAO,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEhC;;;;;;;;;;;;;OAaG;IACH,UAAU,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IAC1B,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IACvE,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;CAC1E;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB"}
|