@alepha/react 0.6.1 → 0.6.3
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 +1 -28
- package/dist/index.browser.cjs +19 -23
- package/dist/index.browser.js +7 -7
- package/dist/index.cjs +235 -512
- package/dist/index.d.ts +240 -678
- package/dist/index.js +220 -492
- package/dist/{useAuth-DOVx2kqa.cjs → useActive-BVqdq757.cjs} +333 -431
- package/dist/{useAuth-i7wbKVrt.js → useActive-dAmCT31a.js} +332 -427
- package/package.json +13 -14
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var core = require('@alepha/core');
|
|
4
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
4
|
var React = require('react');
|
|
6
5
|
var server = require('@alepha/server');
|
|
6
|
+
var core = require('@alepha/core');
|
|
7
7
|
var client = require('react-dom/client');
|
|
8
|
-
var
|
|
8
|
+
var router = require('@alepha/router');
|
|
9
9
|
|
|
10
|
-
const KEY = "
|
|
11
|
-
const $
|
|
10
|
+
const KEY = "PAGE";
|
|
11
|
+
const $page = (options) => {
|
|
12
12
|
core.__descriptor(KEY);
|
|
13
|
+
if (options.children) {
|
|
14
|
+
for (const child of options.children) {
|
|
15
|
+
child.options.parent = {
|
|
16
|
+
options
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (options.parent) {
|
|
21
|
+
options.parent.options.children ??= [];
|
|
22
|
+
options.parent.options.children.push({
|
|
23
|
+
options
|
|
24
|
+
});
|
|
25
|
+
}
|
|
13
26
|
return {
|
|
14
27
|
[core.KIND]: KEY,
|
|
15
|
-
options
|
|
16
|
-
};
|
|
17
|
-
};
|
|
18
|
-
$auth[core.KIND] = KEY;
|
|
19
|
-
|
|
20
|
-
const pageDescriptorKey = "PAGE";
|
|
21
|
-
const $page = (options) => {
|
|
22
|
-
core.__descriptor(pageDescriptorKey);
|
|
23
|
-
return {
|
|
24
|
-
[core.KIND]: pageDescriptorKey,
|
|
25
28
|
options,
|
|
26
29
|
render: () => {
|
|
27
|
-
throw new core.NotImplementedError(
|
|
30
|
+
throw new core.NotImplementedError(KEY);
|
|
28
31
|
},
|
|
29
32
|
go: () => {
|
|
30
|
-
throw new core.NotImplementedError(
|
|
33
|
+
throw new core.NotImplementedError(KEY);
|
|
31
34
|
},
|
|
32
35
|
createAnchorProps: () => {
|
|
33
|
-
throw new core.NotImplementedError(
|
|
36
|
+
throw new core.NotImplementedError(KEY);
|
|
37
|
+
},
|
|
38
|
+
can: () => {
|
|
39
|
+
if (options.can) {
|
|
40
|
+
return options.can();
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
34
43
|
}
|
|
35
44
|
};
|
|
36
45
|
};
|
|
37
|
-
$page[core.KIND] =
|
|
46
|
+
$page[core.KIND] = KEY;
|
|
38
47
|
|
|
39
48
|
const RouterContext = React.createContext(
|
|
40
49
|
void 0
|
|
@@ -51,7 +60,7 @@ const NestedView = (props) => {
|
|
|
51
60
|
);
|
|
52
61
|
React.useEffect(() => {
|
|
53
62
|
if (app?.alepha.isBrowser()) {
|
|
54
|
-
return app?.
|
|
63
|
+
return app?.events.on("end", (state) => {
|
|
55
64
|
setView(state.layers[index]?.element);
|
|
56
65
|
});
|
|
57
66
|
}
|
|
@@ -66,162 +75,37 @@ class RedirectionError extends Error {
|
|
|
66
75
|
}
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
class
|
|
78
|
+
class PageDescriptorProvider {
|
|
70
79
|
log = core.$logger();
|
|
71
80
|
alepha = core.$inject(core.Alepha);
|
|
72
81
|
pages = [];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
* @param name - Page name
|
|
78
|
-
* @return PageRoute
|
|
79
|
-
*/
|
|
82
|
+
getPages() {
|
|
83
|
+
return this.pages;
|
|
84
|
+
}
|
|
80
85
|
page(name) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
for (const page of this.pages) {
|
|
87
|
+
if (page.name === name) {
|
|
88
|
+
return page;
|
|
89
|
+
}
|
|
84
90
|
}
|
|
85
|
-
|
|
91
|
+
throw new Error(`Page ${name} not found`);
|
|
86
92
|
}
|
|
87
|
-
|
|
88
|
-
*
|
|
89
|
-
*/
|
|
90
|
-
root(state, context = {}) {
|
|
93
|
+
root(state, context = {}, events) {
|
|
91
94
|
return React.createElement(
|
|
92
95
|
RouterContext.Provider,
|
|
93
96
|
{
|
|
94
97
|
value: {
|
|
95
|
-
state,
|
|
96
|
-
router: this,
|
|
97
98
|
alepha: this.alepha,
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
99
|
+
state,
|
|
100
|
+
context,
|
|
101
|
+
events: events ?? new core.EventEmitter()
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
|
-
state.layers[0]?.element
|
|
104
|
+
React.createElement(NestedView, {}, state.layers[0]?.element)
|
|
105
105
|
);
|
|
106
106
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
* @param url
|
|
110
|
-
* @param options
|
|
111
|
-
*/
|
|
112
|
-
async render(url, options = {}) {
|
|
113
|
-
const [pathname, search = ""] = url.split("?");
|
|
114
|
-
const state = {
|
|
115
|
-
pathname,
|
|
116
|
-
search,
|
|
117
|
-
layers: [],
|
|
118
|
-
context: {}
|
|
119
|
-
};
|
|
120
|
-
await this.emit("begin", void 0);
|
|
121
|
-
try {
|
|
122
|
-
let layers = await this.match(url, options, state.context);
|
|
123
|
-
if (layers.length === 0) {
|
|
124
|
-
if (this.notFoundPageRoute) {
|
|
125
|
-
layers = await this.createLayers(url, this.notFoundPageRoute);
|
|
126
|
-
} else {
|
|
127
|
-
layers.push({
|
|
128
|
-
name: "not-found",
|
|
129
|
-
element: "Not Found",
|
|
130
|
-
index: 0,
|
|
131
|
-
path: "/"
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
state.layers = layers;
|
|
136
|
-
await this.emit("success", void 0);
|
|
137
|
-
} catch (e) {
|
|
138
|
-
if (e instanceof RedirectionError) {
|
|
139
|
-
return {
|
|
140
|
-
element: null,
|
|
141
|
-
layers: [],
|
|
142
|
-
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
143
|
-
context: state.context
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
this.log.error(e);
|
|
147
|
-
state.layers = [
|
|
148
|
-
{
|
|
149
|
-
name: "error",
|
|
150
|
-
element: this.renderError(e),
|
|
151
|
-
index: 0,
|
|
152
|
-
path: "/"
|
|
153
|
-
}
|
|
154
|
-
];
|
|
155
|
-
await this.emit("error", e);
|
|
156
|
-
}
|
|
157
|
-
if (options.state) {
|
|
158
|
-
options.state.layers = state.layers;
|
|
159
|
-
options.state.pathname = state.pathname;
|
|
160
|
-
options.state.search = state.search;
|
|
161
|
-
options.state.context = state.context;
|
|
162
|
-
await this.emit("end", options.state);
|
|
163
|
-
return {
|
|
164
|
-
element: this.root(options.state, options.args),
|
|
165
|
-
layers: options.state.layers,
|
|
166
|
-
context: state.context
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
await this.emit("end", state);
|
|
170
|
-
return {
|
|
171
|
-
element: this.root(state, options.args),
|
|
172
|
-
layers: state.layers,
|
|
173
|
-
context: state.context
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
*
|
|
178
|
-
* @param url
|
|
179
|
-
* @param options
|
|
180
|
-
* @param context
|
|
181
|
-
* @protected
|
|
182
|
-
*/
|
|
183
|
-
async match(url, options = {}, context = {}) {
|
|
184
|
-
const pages = this.pages;
|
|
185
|
-
const previous = options.previous;
|
|
186
|
-
const [pathname, search] = url.split("?");
|
|
187
|
-
for (const route of pages) {
|
|
188
|
-
if (route.children?.find((it) => !it.path || it.path === "/")) continue;
|
|
189
|
-
if (!route.match) continue;
|
|
190
|
-
const match2 = route.match.exec(pathname);
|
|
191
|
-
if (match2) {
|
|
192
|
-
const params = match2.params ?? {};
|
|
193
|
-
const query = {};
|
|
194
|
-
if (search) {
|
|
195
|
-
for (const [key, value] of new URLSearchParams(search).entries()) {
|
|
196
|
-
query[key] = String(value);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
return await this.createLayers(
|
|
200
|
-
url,
|
|
201
|
-
route,
|
|
202
|
-
params,
|
|
203
|
-
query,
|
|
204
|
-
previous,
|
|
205
|
-
options.args,
|
|
206
|
-
context
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
return [];
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Create layers for the given route.
|
|
214
|
-
*
|
|
215
|
-
* @param url
|
|
216
|
-
* @param route
|
|
217
|
-
* @param params
|
|
218
|
-
* @param query
|
|
219
|
-
* @param previous
|
|
220
|
-
* @param args
|
|
221
|
-
* @param renderContext
|
|
222
|
-
* @protected
|
|
223
|
-
*/
|
|
224
|
-
async createLayers(url, route, params = {}, query = {}, previous = [], args, renderContext) {
|
|
107
|
+
async createLayers(route, request) {
|
|
108
|
+
const { pathname, search } = request.url;
|
|
225
109
|
const layers = [];
|
|
226
110
|
let context = {};
|
|
227
111
|
const stack = [{ route }];
|
|
@@ -236,13 +120,13 @@ class Router extends core.EventEmitter {
|
|
|
236
120
|
const route2 = it.route;
|
|
237
121
|
const config = {};
|
|
238
122
|
try {
|
|
239
|
-
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, query) : query;
|
|
123
|
+
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, request.query) : request.query;
|
|
240
124
|
} catch (e) {
|
|
241
125
|
it.error = e;
|
|
242
126
|
break;
|
|
243
127
|
}
|
|
244
128
|
try {
|
|
245
|
-
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, params) : params;
|
|
129
|
+
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, request.params) : request.params;
|
|
246
130
|
} catch (e) {
|
|
247
131
|
it.error = e;
|
|
248
132
|
break;
|
|
@@ -253,18 +137,20 @@ class Router extends core.EventEmitter {
|
|
|
253
137
|
if (!route2.resolve) {
|
|
254
138
|
continue;
|
|
255
139
|
}
|
|
140
|
+
const previous = request.previous;
|
|
256
141
|
if (previous?.[i] && !forceRefresh && previous[i].name === route2.name) {
|
|
257
|
-
const
|
|
142
|
+
const url = (str) => str ? str.replace(/\/\/+/g, "/") : "/";
|
|
258
143
|
const prev = JSON.stringify({
|
|
259
|
-
part:
|
|
144
|
+
part: url(previous[i].part),
|
|
260
145
|
params: previous[i].config?.params ?? {}
|
|
261
146
|
});
|
|
262
147
|
const curr = JSON.stringify({
|
|
263
|
-
part:
|
|
148
|
+
part: url(route2.path),
|
|
264
149
|
params: config.params ?? {}
|
|
265
150
|
});
|
|
266
151
|
if (prev === curr) {
|
|
267
152
|
it.props = previous[i].props;
|
|
153
|
+
it.error = previous[i].error;
|
|
268
154
|
context = {
|
|
269
155
|
...context,
|
|
270
156
|
...it.props
|
|
@@ -274,15 +160,14 @@ class Router extends core.EventEmitter {
|
|
|
274
160
|
forceRefresh = true;
|
|
275
161
|
}
|
|
276
162
|
try {
|
|
277
|
-
const props = await route2.resolve?.(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
) ?? {};
|
|
163
|
+
const props = await route2.resolve?.({
|
|
164
|
+
...request,
|
|
165
|
+
// request
|
|
166
|
+
...config,
|
|
167
|
+
// params, query
|
|
168
|
+
...context
|
|
169
|
+
// previous props
|
|
170
|
+
}) ?? {};
|
|
286
171
|
it.props = {
|
|
287
172
|
...props
|
|
288
173
|
};
|
|
@@ -292,7 +177,13 @@ class Router extends core.EventEmitter {
|
|
|
292
177
|
};
|
|
293
178
|
} catch (e) {
|
|
294
179
|
if (e instanceof RedirectionError) {
|
|
295
|
-
|
|
180
|
+
return {
|
|
181
|
+
layers: [],
|
|
182
|
+
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
183
|
+
head: request.head,
|
|
184
|
+
pathname,
|
|
185
|
+
search
|
|
186
|
+
};
|
|
296
187
|
}
|
|
297
188
|
this.log.error(e);
|
|
298
189
|
it.error = e;
|
|
@@ -303,28 +194,29 @@ class Router extends core.EventEmitter {
|
|
|
303
194
|
for (let i = 0; i < stack.length; i++) {
|
|
304
195
|
const it = stack[i];
|
|
305
196
|
const props = it.props ?? {};
|
|
306
|
-
const
|
|
307
|
-
for (const key of Object.keys(
|
|
308
|
-
|
|
197
|
+
const params = { ...it.config?.params };
|
|
198
|
+
for (const key of Object.keys(params)) {
|
|
199
|
+
params[key] = String(params[key]);
|
|
309
200
|
}
|
|
310
|
-
if (it.route.
|
|
311
|
-
this.
|
|
201
|
+
if (it.route.head && !it.error) {
|
|
202
|
+
this.fillHead(it.route, request, {
|
|
312
203
|
...props,
|
|
313
204
|
...context
|
|
314
205
|
});
|
|
315
206
|
}
|
|
316
207
|
acc += "/";
|
|
317
|
-
acc += it.route.path ?
|
|
208
|
+
acc += it.route.path ? this.compile(it.route.path, params) : "";
|
|
318
209
|
const path = acc.replace(/\/+/, "/");
|
|
319
210
|
if (it.error) {
|
|
320
211
|
const errorHandler = this.getErrorHandler(it.route);
|
|
321
|
-
const element = errorHandler ? errorHandler({
|
|
212
|
+
const element = await (errorHandler ? errorHandler({
|
|
322
213
|
...it.config,
|
|
323
214
|
error: it.error,
|
|
324
|
-
url
|
|
325
|
-
}) : this.renderError(it.error);
|
|
215
|
+
url: ""
|
|
216
|
+
}) : this.renderError(it.error));
|
|
326
217
|
layers.push({
|
|
327
218
|
props,
|
|
219
|
+
error: it.error,
|
|
328
220
|
name: it.route.name,
|
|
329
221
|
part: it.route.path,
|
|
330
222
|
config: it.config,
|
|
@@ -348,13 +240,8 @@ class Router extends core.EventEmitter {
|
|
|
348
240
|
path
|
|
349
241
|
});
|
|
350
242
|
}
|
|
351
|
-
return layers;
|
|
243
|
+
return { layers, head: request.head, pathname, search };
|
|
352
244
|
}
|
|
353
|
-
/**
|
|
354
|
-
*
|
|
355
|
-
* @param route
|
|
356
|
-
* @protected
|
|
357
|
-
*/
|
|
358
245
|
getErrorHandler(route) {
|
|
359
246
|
if (route.errorHandler) return route.errorHandler;
|
|
360
247
|
let parent = route.parent;
|
|
@@ -363,12 +250,6 @@ class Router extends core.EventEmitter {
|
|
|
363
250
|
parent = parent.parent;
|
|
364
251
|
}
|
|
365
252
|
}
|
|
366
|
-
/**
|
|
367
|
-
*
|
|
368
|
-
* @param page
|
|
369
|
-
* @param props
|
|
370
|
-
* @protected
|
|
371
|
-
*/
|
|
372
253
|
async createElement(page, props) {
|
|
373
254
|
if (page.lazy) {
|
|
374
255
|
const component = await page.lazy();
|
|
@@ -379,48 +260,43 @@ class Router extends core.EventEmitter {
|
|
|
379
260
|
}
|
|
380
261
|
return void 0;
|
|
381
262
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
ctx.helmet ??= {};
|
|
395
|
-
if (ctx.helmet?.title) {
|
|
396
|
-
ctx.helmet.title = `${helmet.title} - ${ctx.helmet.title}`;
|
|
397
|
-
} else {
|
|
398
|
-
ctx.helmet.title = helmet.title;
|
|
399
|
-
}
|
|
263
|
+
fillHead(page, ctx, props) {
|
|
264
|
+
if (!page.head) {
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
ctx.head ??= {};
|
|
268
|
+
const head = typeof page.head === "function" ? page.head(props, ctx.head) : page.head;
|
|
269
|
+
if (head.title) {
|
|
270
|
+
ctx.head ??= {};
|
|
271
|
+
if (ctx.head.titleSeparator) {
|
|
272
|
+
ctx.head.title = `${head.title}${ctx.head.titleSeparator}${ctx.head.title}`;
|
|
273
|
+
} else {
|
|
274
|
+
ctx.head.title = head.title;
|
|
400
275
|
}
|
|
276
|
+
ctx.head.titleSeparator = head.titleSeparator;
|
|
277
|
+
}
|
|
278
|
+
if (head.htmlAttributes) {
|
|
279
|
+
ctx.head.htmlAttributes = {
|
|
280
|
+
...ctx.head.htmlAttributes,
|
|
281
|
+
...head.htmlAttributes
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
if (head.bodyAttributes) {
|
|
285
|
+
ctx.head.bodyAttributes = {
|
|
286
|
+
...ctx.head.bodyAttributes,
|
|
287
|
+
...head.bodyAttributes
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (head.meta) {
|
|
291
|
+
ctx.head.meta = [...ctx.head.meta ?? [], ...head.meta ?? []];
|
|
401
292
|
}
|
|
402
293
|
}
|
|
403
|
-
/**
|
|
404
|
-
*
|
|
405
|
-
* @param e
|
|
406
|
-
* @protected
|
|
407
|
-
*/
|
|
408
294
|
renderError(e) {
|
|
409
295
|
return React.createElement("pre", { style: { overflow: "auto" } }, `${e.stack}`);
|
|
410
296
|
}
|
|
411
|
-
/**
|
|
412
|
-
* Render an empty view.
|
|
413
|
-
*
|
|
414
|
-
* @protected
|
|
415
|
-
*/
|
|
416
297
|
renderEmptyView() {
|
|
417
298
|
return React.createElement(NestedView, {});
|
|
418
299
|
}
|
|
419
|
-
/**
|
|
420
|
-
* Create a valid href for the given page.
|
|
421
|
-
* @param page
|
|
422
|
-
* @param params
|
|
423
|
-
*/
|
|
424
300
|
href(page, params = {}) {
|
|
425
301
|
const found = this.pages.find((it) => it.name === page.options.name);
|
|
426
302
|
if (!found) {
|
|
@@ -432,16 +308,15 @@ class Router extends core.EventEmitter {
|
|
|
432
308
|
url = `${parent.path ?? ""}/${url}`;
|
|
433
309
|
parent = parent.parent;
|
|
434
310
|
}
|
|
435
|
-
url =
|
|
311
|
+
url = this.compile(url, params);
|
|
436
312
|
return url.replace(/\/\/+/g, "/") || "/";
|
|
437
313
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
*/
|
|
314
|
+
compile(path, params = {}) {
|
|
315
|
+
for (const [key, value] of Object.entries(params)) {
|
|
316
|
+
path = path.replace(`:${key}`, value);
|
|
317
|
+
}
|
|
318
|
+
return path;
|
|
319
|
+
}
|
|
445
320
|
renderView(index, path, view = this.renderEmptyView()) {
|
|
446
321
|
return React.createElement(
|
|
447
322
|
RouterLayerContext.Provider,
|
|
@@ -454,23 +329,39 @@ class Router extends core.EventEmitter {
|
|
|
454
329
|
view
|
|
455
330
|
);
|
|
456
331
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
332
|
+
configure = core.$hook({
|
|
333
|
+
name: "configure",
|
|
334
|
+
handler: () => {
|
|
335
|
+
const pages = this.alepha.getDescriptorValues($page);
|
|
336
|
+
for (const { value, key } of pages) {
|
|
337
|
+
value.options.name ??= key;
|
|
338
|
+
if (value.options.parent) {
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
this.add(this.map(pages, value));
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
map(pages, target) {
|
|
346
|
+
const children = target.options.children ?? [];
|
|
347
|
+
for (const it of pages) {
|
|
348
|
+
if (it.value.options.parent === target) {
|
|
349
|
+
children.push(it.value);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
...target.options,
|
|
354
|
+
parent: void 0,
|
|
355
|
+
children: children.map((it) => this.map(pages, it))
|
|
356
|
+
};
|
|
357
|
+
}
|
|
461
358
|
add(entry) {
|
|
462
359
|
if (this.alepha.isReady()) {
|
|
463
360
|
throw new Error("Router is already initialized");
|
|
464
361
|
}
|
|
465
|
-
if (entry.notFoundHandler) {
|
|
466
|
-
this.notFoundPageRoute = {
|
|
467
|
-
name: "not-found",
|
|
468
|
-
component: entry.notFoundHandler
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
362
|
entry.name ??= this.nextId();
|
|
472
363
|
const page = entry;
|
|
473
|
-
page.match = this.
|
|
364
|
+
page.match = this.createMatch(page);
|
|
474
365
|
this.pages.push(page);
|
|
475
366
|
if (page.children) {
|
|
476
367
|
for (const child of page.children) {
|
|
@@ -479,13 +370,7 @@ class Router extends core.EventEmitter {
|
|
|
479
370
|
}
|
|
480
371
|
}
|
|
481
372
|
}
|
|
482
|
-
|
|
483
|
-
* Create a match function for the given page.
|
|
484
|
-
*
|
|
485
|
-
* @param page
|
|
486
|
-
* @protected
|
|
487
|
-
*/
|
|
488
|
-
createMatchFunction(page) {
|
|
373
|
+
createMatch(page) {
|
|
489
374
|
let url = page.path ?? "/";
|
|
490
375
|
let target = page.parent;
|
|
491
376
|
while (target) {
|
|
@@ -493,112 +378,195 @@ class Router extends core.EventEmitter {
|
|
|
493
378
|
target = target.parent;
|
|
494
379
|
}
|
|
495
380
|
let path = url.replace(/\/\/+/g, "/");
|
|
496
|
-
if (path.endsWith("/")) {
|
|
381
|
+
if (path.endsWith("/") && path !== "/") {
|
|
497
382
|
path = path.slice(0, -1);
|
|
498
383
|
}
|
|
499
|
-
|
|
500
|
-
return {
|
|
501
|
-
exec: pathToRegexp.match(path.split("?")[0]),
|
|
502
|
-
path
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
return {
|
|
506
|
-
exec: pathToRegexp.match(path),
|
|
507
|
-
path
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
*
|
|
512
|
-
*/
|
|
513
|
-
empty() {
|
|
514
|
-
return this.pages.length === 0;
|
|
384
|
+
return path;
|
|
515
385
|
}
|
|
516
|
-
/**
|
|
517
|
-
*
|
|
518
|
-
* @protected
|
|
519
|
-
*/
|
|
520
386
|
_next = 0;
|
|
521
|
-
/**
|
|
522
|
-
*
|
|
523
|
-
* @protected
|
|
524
|
-
*/
|
|
525
387
|
nextId() {
|
|
526
388
|
this._next += 1;
|
|
527
389
|
return `P${this._next}`;
|
|
528
390
|
}
|
|
529
391
|
}
|
|
392
|
+
const isPageRoute = (it) => {
|
|
393
|
+
return it && typeof it === "object" && typeof it.path === "string" && typeof it.page === "object";
|
|
394
|
+
};
|
|
530
395
|
|
|
531
|
-
class
|
|
396
|
+
class BrowserHeadProvider {
|
|
397
|
+
renderHead(document, head) {
|
|
398
|
+
if (head.title) {
|
|
399
|
+
document.title = head.title;
|
|
400
|
+
}
|
|
401
|
+
if (head.bodyAttributes) {
|
|
402
|
+
for (const [key, value] of Object.entries(head.bodyAttributes)) {
|
|
403
|
+
if (value) {
|
|
404
|
+
document.body.setAttribute(key, value);
|
|
405
|
+
} else {
|
|
406
|
+
document.body.removeAttribute(key);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (head.htmlAttributes) {
|
|
411
|
+
for (const [key, value] of Object.entries(head.htmlAttributes)) {
|
|
412
|
+
if (value) {
|
|
413
|
+
document.documentElement.setAttribute(key, value);
|
|
414
|
+
} else {
|
|
415
|
+
document.documentElement.removeAttribute(key);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (head.meta) {
|
|
420
|
+
for (const [key, value] of Object.entries(head.meta)) {
|
|
421
|
+
const meta = document.querySelector(`meta[name="${key}"]`);
|
|
422
|
+
if (meta) {
|
|
423
|
+
meta.setAttribute("content", value.content);
|
|
424
|
+
} else {
|
|
425
|
+
const newMeta = document.createElement("meta");
|
|
426
|
+
newMeta.setAttribute("name", key);
|
|
427
|
+
newMeta.setAttribute("content", value.content);
|
|
428
|
+
document.head.appendChild(newMeta);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
class BrowserRouterProvider extends router.RouterProvider {
|
|
436
|
+
log = core.$logger();
|
|
532
437
|
alepha = core.$inject(core.Alepha);
|
|
533
|
-
|
|
438
|
+
pageDescriptorProvider = core.$inject(PageDescriptorProvider);
|
|
439
|
+
events = new core.EventEmitter();
|
|
440
|
+
add(entry) {
|
|
441
|
+
this.pageDescriptorProvider.add(entry);
|
|
442
|
+
}
|
|
534
443
|
configure = core.$hook({
|
|
535
444
|
name: "configure",
|
|
536
|
-
handler: () => {
|
|
537
|
-
const
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
445
|
+
handler: async () => {
|
|
446
|
+
for (const page of this.pageDescriptorProvider.getPages()) {
|
|
447
|
+
if (page.component || page.lazy) {
|
|
448
|
+
this.push({
|
|
449
|
+
path: page.match,
|
|
450
|
+
page
|
|
451
|
+
});
|
|
542
452
|
}
|
|
543
|
-
this.router.add(this.map(pages, value));
|
|
544
453
|
}
|
|
545
454
|
}
|
|
546
455
|
});
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
456
|
+
async transition(url, options = {}) {
|
|
457
|
+
const { pathname, search } = url;
|
|
458
|
+
const state = {
|
|
459
|
+
pathname,
|
|
460
|
+
search,
|
|
461
|
+
layers: [],
|
|
462
|
+
head: {}
|
|
463
|
+
};
|
|
464
|
+
await this.events.emit("begin", void 0);
|
|
465
|
+
try {
|
|
466
|
+
const previous = options.previous;
|
|
467
|
+
const { route, params } = this.match(pathname);
|
|
468
|
+
const query = {};
|
|
469
|
+
if (search) {
|
|
470
|
+
for (const [key, value] of new URLSearchParams(search).entries()) {
|
|
471
|
+
query[key] = String(value);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (isPageRoute(route)) {
|
|
475
|
+
const result = await this.pageDescriptorProvider.createLayers(
|
|
476
|
+
route.page,
|
|
477
|
+
{
|
|
478
|
+
url,
|
|
479
|
+
params: params ?? {},
|
|
480
|
+
query,
|
|
481
|
+
previous,
|
|
482
|
+
...state,
|
|
483
|
+
head: state.head,
|
|
484
|
+
...options.context ?? {}
|
|
485
|
+
}
|
|
486
|
+
);
|
|
487
|
+
if (result.redirect) {
|
|
488
|
+
return {
|
|
489
|
+
element: null,
|
|
490
|
+
layers: [],
|
|
491
|
+
redirect: result.redirect,
|
|
492
|
+
head: state.head
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
state.layers = result.layers;
|
|
496
|
+
state.head = result.head;
|
|
558
497
|
}
|
|
498
|
+
if (state.layers.length === 0) {
|
|
499
|
+
state.layers.push({
|
|
500
|
+
name: "not-found",
|
|
501
|
+
element: "Not Found",
|
|
502
|
+
index: 0,
|
|
503
|
+
path: "/"
|
|
504
|
+
});
|
|
505
|
+
}
|
|
506
|
+
await this.events.emit("success", void 0);
|
|
507
|
+
} catch (e) {
|
|
508
|
+
this.log.error(e);
|
|
509
|
+
state.layers = [
|
|
510
|
+
{
|
|
511
|
+
name: "error",
|
|
512
|
+
element: this.pageDescriptorProvider.renderError(e),
|
|
513
|
+
index: 0,
|
|
514
|
+
path: "/"
|
|
515
|
+
}
|
|
516
|
+
];
|
|
517
|
+
await this.events.emit("error", e);
|
|
559
518
|
}
|
|
519
|
+
if (!options.state) {
|
|
520
|
+
await this.events.emit("end", state);
|
|
521
|
+
return {
|
|
522
|
+
element: this.root(state, options.context),
|
|
523
|
+
layers: state.layers,
|
|
524
|
+
head: state.head
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
options.state.layers = state.layers;
|
|
528
|
+
options.state.pathname = state.pathname;
|
|
529
|
+
options.state.search = state.search;
|
|
530
|
+
options.state.head = state.head;
|
|
531
|
+
await this.events.emit("end", options.state);
|
|
560
532
|
return {
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
533
|
+
element: this.root(state, options.context),
|
|
534
|
+
layers: options.state.layers,
|
|
535
|
+
head: state.head
|
|
564
536
|
};
|
|
565
537
|
}
|
|
538
|
+
root(state, context = {}) {
|
|
539
|
+
return this.pageDescriptorProvider.root(state, context, this.events);
|
|
540
|
+
}
|
|
566
541
|
}
|
|
567
542
|
|
|
543
|
+
const envSchema = core.t.object({
|
|
544
|
+
REACT_ROOT_ID: core.t.string({ default: "root" })
|
|
545
|
+
});
|
|
568
546
|
class ReactBrowserProvider {
|
|
569
547
|
log = core.$logger();
|
|
570
548
|
client = core.$inject(server.HttpClient);
|
|
571
|
-
|
|
549
|
+
alepha = core.$inject(core.Alepha);
|
|
550
|
+
router = core.$inject(BrowserRouterProvider);
|
|
551
|
+
headProvider = core.$inject(BrowserHeadProvider);
|
|
552
|
+
env = core.$inject(envSchema);
|
|
572
553
|
root;
|
|
573
554
|
transitioning;
|
|
574
555
|
state = {
|
|
575
556
|
layers: [],
|
|
576
557
|
pathname: "",
|
|
577
558
|
search: "",
|
|
578
|
-
|
|
559
|
+
head: {}
|
|
579
560
|
};
|
|
580
|
-
/**
|
|
581
|
-
*
|
|
582
|
-
*/
|
|
583
561
|
get document() {
|
|
584
562
|
return window.document;
|
|
585
563
|
}
|
|
586
|
-
/**
|
|
587
|
-
*
|
|
588
|
-
*/
|
|
589
564
|
get history() {
|
|
590
565
|
return window.history;
|
|
591
566
|
}
|
|
592
|
-
/**
|
|
593
|
-
*
|
|
594
|
-
*/
|
|
595
567
|
get url() {
|
|
596
568
|
return window.location.pathname + window.location.search;
|
|
597
569
|
}
|
|
598
|
-
/**
|
|
599
|
-
*
|
|
600
|
-
* @param props
|
|
601
|
-
*/
|
|
602
570
|
async invalidate(props) {
|
|
603
571
|
const previous = [];
|
|
604
572
|
if (props) {
|
|
@@ -639,29 +607,22 @@ class ReactBrowserProvider {
|
|
|
639
607
|
}
|
|
640
608
|
this.history.pushState({}, "", url);
|
|
641
609
|
}
|
|
642
|
-
/**
|
|
643
|
-
*
|
|
644
|
-
* @param options
|
|
645
|
-
* @protected
|
|
646
|
-
*/
|
|
647
610
|
async render(options = {}) {
|
|
648
611
|
const previous = options.previous ?? this.state.layers;
|
|
649
612
|
const url = options.url ?? this.url;
|
|
650
613
|
this.transitioning = { to: url };
|
|
651
|
-
const result = await this.router.
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
614
|
+
const result = await this.router.transition(
|
|
615
|
+
new URL(`http://localhost${url}`),
|
|
616
|
+
{
|
|
617
|
+
previous,
|
|
618
|
+
state: this.state
|
|
619
|
+
}
|
|
620
|
+
);
|
|
655
621
|
if (result.redirect) {
|
|
656
622
|
return await this.render({ url: result.redirect });
|
|
657
623
|
}
|
|
658
624
|
this.transitioning = void 0;
|
|
659
|
-
return { url };
|
|
660
|
-
}
|
|
661
|
-
renderHelmetContext(ctx) {
|
|
662
|
-
if (ctx.title) {
|
|
663
|
-
this.document.title = ctx.title;
|
|
664
|
-
}
|
|
625
|
+
return { url, head: result.head };
|
|
665
626
|
}
|
|
666
627
|
/**
|
|
667
628
|
* Get embedded layers from the server.
|
|
@@ -682,27 +643,15 @@ class ReactBrowserProvider {
|
|
|
682
643
|
* @protected
|
|
683
644
|
*/
|
|
684
645
|
getRootElement() {
|
|
685
|
-
const root = this.document.getElementById(
|
|
646
|
+
const root = this.document.getElementById(this.env.REACT_ROOT_ID);
|
|
686
647
|
if (root) {
|
|
687
648
|
return root;
|
|
688
649
|
}
|
|
689
650
|
const div = this.document.createElement("div");
|
|
690
|
-
div.id =
|
|
691
|
-
this.document.body.
|
|
651
|
+
div.id = this.env.REACT_ROOT_ID;
|
|
652
|
+
this.document.body.prepend(div);
|
|
692
653
|
return div;
|
|
693
654
|
}
|
|
694
|
-
getUserFromCookies() {
|
|
695
|
-
const cookies = this.document.cookie.split("; ");
|
|
696
|
-
const userCookie = cookies.find((cookie) => cookie.startsWith("user="));
|
|
697
|
-
try {
|
|
698
|
-
if (userCookie) {
|
|
699
|
-
return JSON.parse(decodeURIComponent(userCookie.split("=")[1]));
|
|
700
|
-
}
|
|
701
|
-
} catch (error) {
|
|
702
|
-
this.log.warn(error, "Failed to parse user cookie");
|
|
703
|
-
}
|
|
704
|
-
return void 0;
|
|
705
|
-
}
|
|
706
655
|
// -------------------------------------------------------------------------------------------------------------------
|
|
707
656
|
/**
|
|
708
657
|
*
|
|
@@ -713,73 +662,35 @@ class ReactBrowserProvider {
|
|
|
713
662
|
handler: async () => {
|
|
714
663
|
const cache = this.getHydrationState();
|
|
715
664
|
const previous = cache?.layers ?? [];
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
665
|
+
if (cache?.links) {
|
|
666
|
+
this.client.links = cache.links;
|
|
667
|
+
}
|
|
668
|
+
const { head } = await this.render({ previous });
|
|
669
|
+
if (head) {
|
|
670
|
+
this.headProvider.renderHead(this.document, head);
|
|
671
|
+
}
|
|
672
|
+
const context = {};
|
|
673
|
+
await this.alepha.run("react:browser:render", {
|
|
674
|
+
context,
|
|
675
|
+
cache
|
|
719
676
|
});
|
|
677
|
+
const element = this.router.root(this.state, context);
|
|
720
678
|
if (previous.length > 0) {
|
|
721
679
|
this.root = client.hydrateRoot(this.getRootElement(), element);
|
|
722
680
|
this.log.info("Hydrated root element");
|
|
723
681
|
} else {
|
|
724
|
-
this.root
|
|
682
|
+
this.root ??= client.createRoot(this.getRootElement());
|
|
725
683
|
this.root.render(element);
|
|
726
684
|
this.log.info("Created root element");
|
|
727
685
|
}
|
|
728
686
|
window.addEventListener("popstate", () => {
|
|
729
687
|
this.render();
|
|
730
688
|
});
|
|
731
|
-
this.router.on("end", ({
|
|
732
|
-
|
|
733
|
-
this.renderHelmetContext(context.helmet);
|
|
734
|
-
}
|
|
689
|
+
this.router.events.on("end", ({ head: head2 }) => {
|
|
690
|
+
this.headProvider.renderHead(this.document, head2);
|
|
735
691
|
});
|
|
736
692
|
}
|
|
737
693
|
});
|
|
738
|
-
/**
|
|
739
|
-
*
|
|
740
|
-
* @protected
|
|
741
|
-
*/
|
|
742
|
-
stop = core.$hook({
|
|
743
|
-
name: "stop",
|
|
744
|
-
handler: async () => {
|
|
745
|
-
if (this.root) {
|
|
746
|
-
this.root.unmount();
|
|
747
|
-
this.log.info("Unmounted root element");
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
class Auth {
|
|
754
|
-
alepha = core.$inject(core.Alepha);
|
|
755
|
-
log = core.$logger();
|
|
756
|
-
client = core.$inject(server.HttpClient);
|
|
757
|
-
api = "/api/_oauth/login";
|
|
758
|
-
start = core.$hook({
|
|
759
|
-
name: "start",
|
|
760
|
-
handler: async () => {
|
|
761
|
-
this.client.on("onError", (err) => {
|
|
762
|
-
if (err.statusCode === 401) {
|
|
763
|
-
this.login();
|
|
764
|
-
}
|
|
765
|
-
});
|
|
766
|
-
}
|
|
767
|
-
});
|
|
768
|
-
login = (provider) => {
|
|
769
|
-
if (this.alepha.isBrowser()) {
|
|
770
|
-
const browser = this.alepha.get(ReactBrowserProvider);
|
|
771
|
-
const redirect = browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href;
|
|
772
|
-
window.location.href = `${this.api}?redirect=${redirect}`;
|
|
773
|
-
if (browser.transitioning) {
|
|
774
|
-
throw new RedirectionError(browser.state.pathname);
|
|
775
|
-
}
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
throw new RedirectionError(this.api);
|
|
779
|
-
};
|
|
780
|
-
logout = () => {
|
|
781
|
-
window.location.href = `/api/_oauth/logout?redirect=${encodeURIComponent(window.location.origin)}`;
|
|
782
|
-
};
|
|
783
694
|
}
|
|
784
695
|
|
|
785
696
|
class RouterHookApi {
|
|
@@ -902,14 +813,23 @@ const useRouter = () => {
|
|
|
902
813
|
layer,
|
|
903
814
|
ctx.alepha.isBrowser() ? ctx.alepha.get(ReactBrowserProvider) : void 0
|
|
904
815
|
),
|
|
905
|
-
[
|
|
816
|
+
[layer]
|
|
906
817
|
);
|
|
907
818
|
};
|
|
908
819
|
|
|
909
820
|
const Link = (props) => {
|
|
910
821
|
React.useContext(RouterContext);
|
|
822
|
+
const to = typeof props.to === "string" ? props.to : props.to.options.path;
|
|
823
|
+
if (!to) {
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
const can = typeof props.to === "string" ? void 0 : props.to.options.can;
|
|
827
|
+
if (can && !can()) {
|
|
828
|
+
return null;
|
|
829
|
+
}
|
|
830
|
+
const name = typeof props.to === "string" ? void 0 : props.to.options.name;
|
|
911
831
|
const router = useRouter();
|
|
912
|
-
return /* @__PURE__ */ jsxRuntime.jsx("a", { ...router.createAnchorProps(
|
|
832
|
+
return /* @__PURE__ */ jsxRuntime.jsx("a", { ...router.createAnchorProps(to), ...props, children: props.children ?? name });
|
|
913
833
|
};
|
|
914
834
|
|
|
915
835
|
const useInject = (clazz) => {
|
|
@@ -917,7 +837,9 @@ const useInject = (clazz) => {
|
|
|
917
837
|
if (!ctx) {
|
|
918
838
|
throw new Error("useRouter must be used within a <RouterProvider>");
|
|
919
839
|
}
|
|
920
|
-
return ctx.alepha.get(clazz
|
|
840
|
+
return ctx.alepha.get(clazz, {
|
|
841
|
+
skipRegistration: true
|
|
842
|
+
});
|
|
921
843
|
};
|
|
922
844
|
|
|
923
845
|
const useClient = () => {
|
|
@@ -974,13 +896,13 @@ const useRouterEvents = (opts = {}) => {
|
|
|
974
896
|
const onEnd = opts.onEnd;
|
|
975
897
|
const onError = opts.onError;
|
|
976
898
|
if (onBegin) {
|
|
977
|
-
subs.push(ctx.
|
|
899
|
+
subs.push(ctx.events.on("begin", onBegin));
|
|
978
900
|
}
|
|
979
901
|
if (onEnd) {
|
|
980
|
-
subs.push(ctx.
|
|
902
|
+
subs.push(ctx.events.on("end", onEnd));
|
|
981
903
|
}
|
|
982
904
|
if (onError) {
|
|
983
|
-
subs.push(ctx.
|
|
905
|
+
subs.push(ctx.events.on("error", onError));
|
|
984
906
|
}
|
|
985
907
|
return () => {
|
|
986
908
|
for (const sub of subs) {
|
|
@@ -998,7 +920,7 @@ const useRouterState = () => {
|
|
|
998
920
|
}
|
|
999
921
|
const [state, setState] = React.useState(ctx.state);
|
|
1000
922
|
React.useEffect(
|
|
1001
|
-
() => ctx.
|
|
923
|
+
() => ctx.events.on("end", (it) => {
|
|
1002
924
|
setState({ ...it });
|
|
1003
925
|
}),
|
|
1004
926
|
[]
|
|
@@ -1022,7 +944,7 @@ const useActive = (path) => {
|
|
|
1022
944
|
const [isPending, setPending] = React.useState(false);
|
|
1023
945
|
const isActive = current === href;
|
|
1024
946
|
React.useEffect(
|
|
1025
|
-
() => ctx.
|
|
947
|
+
() => ctx.events.on("end", ({ pathname }) => setCurrent(pathname)),
|
|
1026
948
|
[]
|
|
1027
949
|
);
|
|
1028
950
|
return {
|
|
@@ -1045,38 +967,18 @@ const useActive = (path) => {
|
|
|
1045
967
|
};
|
|
1046
968
|
};
|
|
1047
969
|
|
|
1048
|
-
const useAuth = () => {
|
|
1049
|
-
const ctx = React.useContext(RouterContext);
|
|
1050
|
-
if (!ctx) {
|
|
1051
|
-
throw new Error("useAuth must be used within a RouterContext");
|
|
1052
|
-
}
|
|
1053
|
-
const args = ctx.args ?? {};
|
|
1054
|
-
return {
|
|
1055
|
-
user: args.user,
|
|
1056
|
-
logout: () => {
|
|
1057
|
-
ctx.alepha.get(Auth).logout();
|
|
1058
|
-
},
|
|
1059
|
-
login: (provider) => {
|
|
1060
|
-
ctx.alepha.get(Auth).login();
|
|
1061
|
-
}
|
|
1062
|
-
};
|
|
1063
|
-
};
|
|
1064
|
-
|
|
1065
|
-
exports.$auth = $auth;
|
|
1066
970
|
exports.$page = $page;
|
|
1067
|
-
exports.
|
|
971
|
+
exports.BrowserRouterProvider = BrowserRouterProvider;
|
|
1068
972
|
exports.Link = Link;
|
|
1069
973
|
exports.NestedView = NestedView;
|
|
1070
974
|
exports.PageDescriptorProvider = PageDescriptorProvider;
|
|
1071
975
|
exports.ReactBrowserProvider = ReactBrowserProvider;
|
|
1072
976
|
exports.RedirectionError = RedirectionError;
|
|
1073
|
-
exports.Router = Router;
|
|
1074
977
|
exports.RouterContext = RouterContext;
|
|
1075
978
|
exports.RouterHookApi = RouterHookApi;
|
|
1076
979
|
exports.RouterLayerContext = RouterLayerContext;
|
|
1077
|
-
exports.
|
|
980
|
+
exports.isPageRoute = isPageRoute;
|
|
1078
981
|
exports.useActive = useActive;
|
|
1079
|
-
exports.useAuth = useAuth;
|
|
1080
982
|
exports.useClient = useClient;
|
|
1081
983
|
exports.useInject = useInject;
|
|
1082
984
|
exports.useQueryParams = useQueryParams;
|