@alepha/react 0.5.2 → 0.6.1
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/dist/index.browser.cjs +23 -19
- package/dist/index.browser.js +5 -4
- package/dist/index.cjs +416 -339
- package/dist/index.d.ts +591 -420
- package/dist/index.js +395 -320
- package/dist/{useRouterState-BlKHWZwk.cjs → useAuth-DOVx2kqa.cjs} +243 -102
- package/dist/{useRouterState-CvFCmaq7.js → useAuth-i7wbKVrt.js} +214 -77
- package/package.json +20 -18
- package/src/components/NestedView.tsx +0 -36
- package/src/contexts/RouterContext.ts +0 -15
- package/src/contexts/RouterLayerContext.ts +0 -10
- package/src/descriptors/$page.ts +0 -90
- package/src/hooks/RouterHookApi.ts +0 -154
- package/src/hooks/useActive.ts +0 -57
- package/src/hooks/useClient.ts +0 -6
- package/src/hooks/useInject.ts +0 -12
- package/src/hooks/useQueryParams.ts +0 -59
- package/src/hooks/useRouter.ts +0 -28
- package/src/hooks/useRouterEvents.ts +0 -43
- package/src/hooks/useRouterState.ts +0 -23
- package/src/index.browser.ts +0 -19
- package/src/index.shared.ts +0 -17
- package/src/index.ts +0 -29
- package/src/providers/PageDescriptorProvider.ts +0 -52
- package/src/providers/ReactBrowserProvider.ts +0 -228
- package/src/providers/ReactServerProvider.ts +0 -244
- package/src/providers/ReactSessionProvider.ts +0 -363
- package/src/services/Router.ts +0 -742
|
@@ -1,9 +1,20 @@
|
|
|
1
|
-
import { __descriptor,
|
|
2
|
-
import {
|
|
1
|
+
import { __descriptor, KIND, NotImplementedError, EventEmitter, $logger, $inject, Alepha, $hook } from '@alepha/core';
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
3
|
+
import React, { createContext, useContext, useState, useEffect, createElement, useMemo } from 'react';
|
|
3
4
|
import { HttpClient } from '@alepha/server';
|
|
4
5
|
import { hydrateRoot, createRoot } from 'react-dom/client';
|
|
5
6
|
import { compile, match } from 'path-to-regexp';
|
|
6
7
|
|
|
8
|
+
const KEY = "AUTH";
|
|
9
|
+
const $auth = (options) => {
|
|
10
|
+
__descriptor(KEY);
|
|
11
|
+
return {
|
|
12
|
+
[KIND]: KEY,
|
|
13
|
+
options
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
$auth[KIND] = KEY;
|
|
17
|
+
|
|
7
18
|
const pageDescriptorKey = "PAGE";
|
|
8
19
|
const $page = (options) => {
|
|
9
20
|
__descriptor(pageDescriptorKey);
|
|
@@ -38,20 +49,21 @@ const NestedView = (props) => {
|
|
|
38
49
|
);
|
|
39
50
|
useEffect(() => {
|
|
40
51
|
if (app?.alepha.isBrowser()) {
|
|
41
|
-
return app?.router.on("end", (
|
|
42
|
-
setView(layers[index]?.element);
|
|
52
|
+
return app?.router.on("end", (state) => {
|
|
53
|
+
setView(state.layers[index]?.element);
|
|
43
54
|
});
|
|
44
55
|
}
|
|
45
56
|
}, [app]);
|
|
46
57
|
return view ?? props.children ?? null;
|
|
47
58
|
};
|
|
48
59
|
|
|
49
|
-
class
|
|
60
|
+
class RedirectionError extends Error {
|
|
50
61
|
constructor(page) {
|
|
51
62
|
super("Redirection");
|
|
52
63
|
this.page = page;
|
|
53
64
|
}
|
|
54
65
|
}
|
|
66
|
+
|
|
55
67
|
class Router extends EventEmitter {
|
|
56
68
|
log = $logger();
|
|
57
69
|
alepha = $inject(Alepha);
|
|
@@ -73,7 +85,7 @@ class Router extends EventEmitter {
|
|
|
73
85
|
/**
|
|
74
86
|
*
|
|
75
87
|
*/
|
|
76
|
-
root(state,
|
|
88
|
+
root(state, context = {}) {
|
|
77
89
|
return createElement(
|
|
78
90
|
RouterContext.Provider,
|
|
79
91
|
{
|
|
@@ -81,7 +93,10 @@ class Router extends EventEmitter {
|
|
|
81
93
|
state,
|
|
82
94
|
router: this,
|
|
83
95
|
alepha: this.alepha,
|
|
84
|
-
|
|
96
|
+
args: {
|
|
97
|
+
user: context.user,
|
|
98
|
+
cookies: context.cookies
|
|
99
|
+
}
|
|
85
100
|
}
|
|
86
101
|
},
|
|
87
102
|
state.layers[0]?.element
|
|
@@ -97,11 +112,12 @@ class Router extends EventEmitter {
|
|
|
97
112
|
const state = {
|
|
98
113
|
pathname,
|
|
99
114
|
search,
|
|
100
|
-
layers: []
|
|
115
|
+
layers: [],
|
|
116
|
+
context: {}
|
|
101
117
|
};
|
|
102
|
-
this.emit("begin", void 0);
|
|
118
|
+
await this.emit("begin", void 0);
|
|
103
119
|
try {
|
|
104
|
-
let layers = await this.match(url, options);
|
|
120
|
+
let layers = await this.match(url, options, state.context);
|
|
105
121
|
if (layers.length === 0) {
|
|
106
122
|
if (this.notFoundPageRoute) {
|
|
107
123
|
layers = await this.createLayers(url, this.notFoundPageRoute);
|
|
@@ -115,13 +131,14 @@ class Router extends EventEmitter {
|
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
133
|
state.layers = layers;
|
|
118
|
-
this.emit("success", void 0);
|
|
134
|
+
await this.emit("success", void 0);
|
|
119
135
|
} catch (e) {
|
|
120
|
-
if (e instanceof
|
|
136
|
+
if (e instanceof RedirectionError) {
|
|
121
137
|
return {
|
|
122
138
|
element: null,
|
|
123
139
|
layers: [],
|
|
124
|
-
redirect: typeof e.page === "string" ? e.page : this.href(e.page)
|
|
140
|
+
redirect: typeof e.page === "string" ? e.page : this.href(e.page),
|
|
141
|
+
context: state.context
|
|
125
142
|
};
|
|
126
143
|
}
|
|
127
144
|
this.log.error(e);
|
|
@@ -133,31 +150,35 @@ class Router extends EventEmitter {
|
|
|
133
150
|
path: "/"
|
|
134
151
|
}
|
|
135
152
|
];
|
|
136
|
-
this.emit("error", e);
|
|
153
|
+
await this.emit("error", e);
|
|
137
154
|
}
|
|
138
155
|
if (options.state) {
|
|
139
156
|
options.state.layers = state.layers;
|
|
140
157
|
options.state.pathname = state.pathname;
|
|
141
158
|
options.state.search = state.search;
|
|
142
|
-
|
|
159
|
+
options.state.context = state.context;
|
|
160
|
+
await this.emit("end", options.state);
|
|
143
161
|
return {
|
|
144
|
-
element: this.root(options.state, options),
|
|
145
|
-
layers: options.state.layers
|
|
162
|
+
element: this.root(options.state, options.args),
|
|
163
|
+
layers: options.state.layers,
|
|
164
|
+
context: state.context
|
|
146
165
|
};
|
|
147
166
|
}
|
|
148
|
-
this.emit("end", state);
|
|
167
|
+
await this.emit("end", state);
|
|
149
168
|
return {
|
|
150
|
-
element: this.root(state, options),
|
|
151
|
-
layers: state.layers
|
|
169
|
+
element: this.root(state, options.args),
|
|
170
|
+
layers: state.layers,
|
|
171
|
+
context: state.context
|
|
152
172
|
};
|
|
153
173
|
}
|
|
154
174
|
/**
|
|
155
175
|
*
|
|
156
176
|
* @param url
|
|
157
177
|
* @param options
|
|
178
|
+
* @param context
|
|
158
179
|
* @protected
|
|
159
180
|
*/
|
|
160
|
-
async match(url, options = {}) {
|
|
181
|
+
async match(url, options = {}, context = {}) {
|
|
161
182
|
const pages = this.pages;
|
|
162
183
|
const previous = options.previous;
|
|
163
184
|
const [pathname, search] = url.split("?");
|
|
@@ -179,7 +200,8 @@ class Router extends EventEmitter {
|
|
|
179
200
|
params,
|
|
180
201
|
query,
|
|
181
202
|
previous,
|
|
182
|
-
options.
|
|
203
|
+
options.args,
|
|
204
|
+
context
|
|
183
205
|
);
|
|
184
206
|
}
|
|
185
207
|
}
|
|
@@ -188,14 +210,16 @@ class Router extends EventEmitter {
|
|
|
188
210
|
/**
|
|
189
211
|
* Create layers for the given route.
|
|
190
212
|
*
|
|
213
|
+
* @param url
|
|
191
214
|
* @param route
|
|
192
215
|
* @param params
|
|
193
216
|
* @param query
|
|
194
217
|
* @param previous
|
|
195
|
-
* @param
|
|
218
|
+
* @param args
|
|
219
|
+
* @param renderContext
|
|
196
220
|
* @protected
|
|
197
221
|
*/
|
|
198
|
-
async createLayers(url, route, params = {}, query = {}, previous = [],
|
|
222
|
+
async createLayers(url, route, params = {}, query = {}, previous = [], args, renderContext) {
|
|
199
223
|
const layers = [];
|
|
200
224
|
let context = {};
|
|
201
225
|
const stack = [{ route }];
|
|
@@ -210,13 +234,13 @@ class Router extends EventEmitter {
|
|
|
210
234
|
const route2 = it.route;
|
|
211
235
|
const config = {};
|
|
212
236
|
try {
|
|
213
|
-
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, query) :
|
|
237
|
+
config.query = route2.schema?.query ? this.alepha.parse(route2.schema.query, query) : query;
|
|
214
238
|
} catch (e) {
|
|
215
239
|
it.error = e;
|
|
216
240
|
break;
|
|
217
241
|
}
|
|
218
242
|
try {
|
|
219
|
-
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, params) :
|
|
243
|
+
config.params = route2.schema?.params ? this.alepha.parse(route2.schema.params, params) : params;
|
|
220
244
|
} catch (e) {
|
|
221
245
|
it.error = e;
|
|
222
246
|
break;
|
|
@@ -248,12 +272,15 @@ class Router extends EventEmitter {
|
|
|
248
272
|
forceRefresh = true;
|
|
249
273
|
}
|
|
250
274
|
try {
|
|
251
|
-
const props = await route2.resolve?.(
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
275
|
+
const props = await route2.resolve?.(
|
|
276
|
+
{
|
|
277
|
+
...config,
|
|
278
|
+
...context,
|
|
279
|
+
context: args,
|
|
280
|
+
url
|
|
281
|
+
},
|
|
282
|
+
args ?? {}
|
|
283
|
+
) ?? {};
|
|
257
284
|
it.props = {
|
|
258
285
|
...props
|
|
259
286
|
};
|
|
@@ -262,7 +289,7 @@ class Router extends EventEmitter {
|
|
|
262
289
|
...props
|
|
263
290
|
};
|
|
264
291
|
} catch (e) {
|
|
265
|
-
if (e instanceof
|
|
292
|
+
if (e instanceof RedirectionError) {
|
|
266
293
|
throw e;
|
|
267
294
|
}
|
|
268
295
|
this.log.error(e);
|
|
@@ -278,6 +305,12 @@ class Router extends EventEmitter {
|
|
|
278
305
|
for (const key of Object.keys(params2)) {
|
|
279
306
|
params2[key] = String(params2[key]);
|
|
280
307
|
}
|
|
308
|
+
if (it.route.helmet && renderContext) {
|
|
309
|
+
this.mergeRenderContext(it.route, renderContext, {
|
|
310
|
+
...props,
|
|
311
|
+
...context
|
|
312
|
+
});
|
|
313
|
+
}
|
|
281
314
|
acc += "/";
|
|
282
315
|
acc += it.route.path ? compile(it.route.path)(params2) : "";
|
|
283
316
|
const path = acc.replace(/\/+/, "/");
|
|
@@ -344,6 +377,27 @@ class Router extends EventEmitter {
|
|
|
344
377
|
}
|
|
345
378
|
return void 0;
|
|
346
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* Merge the render context with the page context.
|
|
382
|
+
*
|
|
383
|
+
* @param page
|
|
384
|
+
* @param ctx
|
|
385
|
+
* @param props
|
|
386
|
+
* @protected
|
|
387
|
+
*/
|
|
388
|
+
mergeRenderContext(page, ctx, props) {
|
|
389
|
+
if (page.helmet) {
|
|
390
|
+
const helmet = typeof page.helmet === "function" ? page.helmet(props) : page.helmet;
|
|
391
|
+
if (helmet.title) {
|
|
392
|
+
ctx.helmet ??= {};
|
|
393
|
+
if (ctx.helmet?.title) {
|
|
394
|
+
ctx.helmet.title = `${helmet.title} - ${ctx.helmet.title}`;
|
|
395
|
+
} else {
|
|
396
|
+
ctx.helmet.title = helmet.title;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
347
401
|
/**
|
|
348
402
|
*
|
|
349
403
|
* @param e
|
|
@@ -515,7 +569,12 @@ class ReactBrowserProvider {
|
|
|
515
569
|
router = $inject(Router);
|
|
516
570
|
root;
|
|
517
571
|
transitioning;
|
|
518
|
-
state = {
|
|
572
|
+
state = {
|
|
573
|
+
layers: [],
|
|
574
|
+
pathname: "",
|
|
575
|
+
search: "",
|
|
576
|
+
context: {}
|
|
577
|
+
};
|
|
519
578
|
/**
|
|
520
579
|
*
|
|
521
580
|
*/
|
|
@@ -597,12 +656,17 @@ class ReactBrowserProvider {
|
|
|
597
656
|
this.transitioning = void 0;
|
|
598
657
|
return { url };
|
|
599
658
|
}
|
|
659
|
+
renderHelmetContext(ctx) {
|
|
660
|
+
if (ctx.title) {
|
|
661
|
+
this.document.title = ctx.title;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
600
664
|
/**
|
|
601
665
|
* Get embedded layers from the server.
|
|
602
666
|
*
|
|
603
667
|
* @protected
|
|
604
668
|
*/
|
|
605
|
-
|
|
669
|
+
getHydrationState() {
|
|
606
670
|
try {
|
|
607
671
|
if ("__ssr" in window && typeof window.__ssr === "object") {
|
|
608
672
|
return window.__ssr;
|
|
@@ -625,6 +689,18 @@ class ReactBrowserProvider {
|
|
|
625
689
|
this.document.body.appendChild(div);
|
|
626
690
|
return div;
|
|
627
691
|
}
|
|
692
|
+
getUserFromCookies() {
|
|
693
|
+
const cookies = this.document.cookie.split("; ");
|
|
694
|
+
const userCookie = cookies.find((cookie) => cookie.startsWith("user="));
|
|
695
|
+
try {
|
|
696
|
+
if (userCookie) {
|
|
697
|
+
return JSON.parse(decodeURIComponent(userCookie.split("=")[1]));
|
|
698
|
+
}
|
|
699
|
+
} catch (error) {
|
|
700
|
+
this.log.warn(error, "Failed to parse user cookie");
|
|
701
|
+
}
|
|
702
|
+
return void 0;
|
|
703
|
+
}
|
|
628
704
|
// -------------------------------------------------------------------------------------------------------------------
|
|
629
705
|
/**
|
|
630
706
|
*
|
|
@@ -633,11 +709,12 @@ class ReactBrowserProvider {
|
|
|
633
709
|
ready = $hook({
|
|
634
710
|
name: "ready",
|
|
635
711
|
handler: async () => {
|
|
636
|
-
const cache = this.
|
|
712
|
+
const cache = this.getHydrationState();
|
|
637
713
|
const previous = cache?.layers ?? [];
|
|
638
|
-
const session = cache?.session ?? await this.client.of().session();
|
|
639
714
|
await this.render({ previous });
|
|
640
|
-
const element = this.router.root(this.state,
|
|
715
|
+
const element = this.router.root(this.state, {
|
|
716
|
+
user: cache?.user ?? this.getUserFromCookies()
|
|
717
|
+
});
|
|
641
718
|
if (previous.length > 0) {
|
|
642
719
|
this.root = hydrateRoot(this.getRootElement(), element);
|
|
643
720
|
this.log.info("Hydrated root element");
|
|
@@ -649,6 +726,11 @@ class ReactBrowserProvider {
|
|
|
649
726
|
window.addEventListener("popstate", () => {
|
|
650
727
|
this.render();
|
|
651
728
|
});
|
|
729
|
+
this.router.on("end", ({ context }) => {
|
|
730
|
+
if (context.helmet) {
|
|
731
|
+
this.renderHelmetContext(context.helmet);
|
|
732
|
+
}
|
|
733
|
+
});
|
|
652
734
|
}
|
|
653
735
|
});
|
|
654
736
|
/**
|
|
@@ -666,6 +748,38 @@ class ReactBrowserProvider {
|
|
|
666
748
|
});
|
|
667
749
|
}
|
|
668
750
|
|
|
751
|
+
class Auth {
|
|
752
|
+
alepha = $inject(Alepha);
|
|
753
|
+
log = $logger();
|
|
754
|
+
client = $inject(HttpClient);
|
|
755
|
+
api = "/api/_oauth/login";
|
|
756
|
+
start = $hook({
|
|
757
|
+
name: "start",
|
|
758
|
+
handler: async () => {
|
|
759
|
+
this.client.on("onError", (err) => {
|
|
760
|
+
if (err.statusCode === 401) {
|
|
761
|
+
this.login();
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
login = (provider) => {
|
|
767
|
+
if (this.alepha.isBrowser()) {
|
|
768
|
+
const browser = this.alepha.get(ReactBrowserProvider);
|
|
769
|
+
const redirect = browser.transitioning ? window.location.origin + browser.transitioning.to : window.location.href;
|
|
770
|
+
window.location.href = `${this.api}?redirect=${redirect}`;
|
|
771
|
+
if (browser.transitioning) {
|
|
772
|
+
throw new RedirectionError(browser.state.pathname);
|
|
773
|
+
}
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
throw new RedirectionError(this.api);
|
|
777
|
+
};
|
|
778
|
+
logout = () => {
|
|
779
|
+
window.location.href = `/api/_oauth/logout?redirect=${encodeURIComponent(window.location.origin)}`;
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
|
|
669
783
|
class RouterHookApi {
|
|
670
784
|
constructor(state, layer, browser) {
|
|
671
785
|
this.state = state;
|
|
@@ -790,51 +904,18 @@ const useRouter = () => {
|
|
|
790
904
|
);
|
|
791
905
|
};
|
|
792
906
|
|
|
793
|
-
const
|
|
907
|
+
const Link = (props) => {
|
|
908
|
+
React.useContext(RouterContext);
|
|
794
909
|
const router = useRouter();
|
|
795
|
-
|
|
796
|
-
const layer = useContext(RouterLayerContext);
|
|
797
|
-
if (!ctx || !layer) {
|
|
798
|
-
throw new Error("useRouter must be used within a RouterProvider");
|
|
799
|
-
}
|
|
800
|
-
let name;
|
|
801
|
-
if (typeof path === "object" && path.options.name) {
|
|
802
|
-
name = path.options.name;
|
|
803
|
-
}
|
|
804
|
-
const [current, setCurrent] = useState(ctx.state.pathname);
|
|
805
|
-
const href = useMemo(() => router.createHref(path, layer), [path, layer]);
|
|
806
|
-
const [isPending, setPending] = useState(false);
|
|
807
|
-
const isActive = current === href;
|
|
808
|
-
useEffect(
|
|
809
|
-
() => ctx.router.on("end", ({ pathname }) => setCurrent(pathname)),
|
|
810
|
-
[]
|
|
811
|
-
);
|
|
812
|
-
return {
|
|
813
|
-
name,
|
|
814
|
-
isPending,
|
|
815
|
-
isActive,
|
|
816
|
-
anchorProps: {
|
|
817
|
-
href,
|
|
818
|
-
onClick: (ev) => {
|
|
819
|
-
ev.stopPropagation();
|
|
820
|
-
ev.preventDefault();
|
|
821
|
-
if (isActive) return;
|
|
822
|
-
if (isPending) return;
|
|
823
|
-
setPending(true);
|
|
824
|
-
router.go(href).then(() => {
|
|
825
|
-
setPending(false);
|
|
826
|
-
});
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
};
|
|
910
|
+
return /* @__PURE__ */ jsx("a", { ...router.createAnchorProps(props.to), ...props, children: props.children });
|
|
830
911
|
};
|
|
831
912
|
|
|
832
|
-
const useInject = (
|
|
913
|
+
const useInject = (clazz) => {
|
|
833
914
|
const ctx = useContext(RouterContext);
|
|
834
915
|
if (!ctx) {
|
|
835
916
|
throw new Error("useRouter must be used within a <RouterProvider>");
|
|
836
917
|
}
|
|
837
|
-
return ctx.alepha.get(
|
|
918
|
+
return ctx.alepha.get(clazz);
|
|
838
919
|
};
|
|
839
920
|
|
|
840
921
|
const useClient = () => {
|
|
@@ -923,4 +1004,60 @@ const useRouterState = () => {
|
|
|
923
1004
|
return state;
|
|
924
1005
|
};
|
|
925
1006
|
|
|
926
|
-
|
|
1007
|
+
const useActive = (path) => {
|
|
1008
|
+
const router = useRouter();
|
|
1009
|
+
const ctx = useContext(RouterContext);
|
|
1010
|
+
const layer = useContext(RouterLayerContext);
|
|
1011
|
+
if (!ctx || !layer) {
|
|
1012
|
+
throw new Error("useRouter must be used within a RouterProvider");
|
|
1013
|
+
}
|
|
1014
|
+
let name;
|
|
1015
|
+
if (typeof path === "object" && path.options.name) {
|
|
1016
|
+
name = path.options.name;
|
|
1017
|
+
}
|
|
1018
|
+
const [current, setCurrent] = useState(ctx.state.pathname);
|
|
1019
|
+
const href = useMemo(() => router.createHref(path, layer), [path, layer]);
|
|
1020
|
+
const [isPending, setPending] = useState(false);
|
|
1021
|
+
const isActive = current === href;
|
|
1022
|
+
useEffect(
|
|
1023
|
+
() => ctx.router.on("end", ({ pathname }) => setCurrent(pathname)),
|
|
1024
|
+
[]
|
|
1025
|
+
);
|
|
1026
|
+
return {
|
|
1027
|
+
name,
|
|
1028
|
+
isPending,
|
|
1029
|
+
isActive,
|
|
1030
|
+
anchorProps: {
|
|
1031
|
+
href,
|
|
1032
|
+
onClick: (ev) => {
|
|
1033
|
+
ev.stopPropagation();
|
|
1034
|
+
ev.preventDefault();
|
|
1035
|
+
if (isActive) return;
|
|
1036
|
+
if (isPending) return;
|
|
1037
|
+
setPending(true);
|
|
1038
|
+
router.go(href).then(() => {
|
|
1039
|
+
setPending(false);
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
};
|
|
1044
|
+
};
|
|
1045
|
+
|
|
1046
|
+
const useAuth = () => {
|
|
1047
|
+
const ctx = useContext(RouterContext);
|
|
1048
|
+
if (!ctx) {
|
|
1049
|
+
throw new Error("useAuth must be used within a RouterContext");
|
|
1050
|
+
}
|
|
1051
|
+
const args = ctx.args ?? {};
|
|
1052
|
+
return {
|
|
1053
|
+
user: args.user,
|
|
1054
|
+
logout: () => {
|
|
1055
|
+
ctx.alepha.get(Auth).logout();
|
|
1056
|
+
},
|
|
1057
|
+
login: (provider) => {
|
|
1058
|
+
ctx.alepha.get(Auth).login();
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
export { $auth as $, Auth as A, Link as L, NestedView as N, PageDescriptorProvider as P, Router as R, $page as a, RouterContext as b, RouterLayerContext as c, RouterHookApi as d, useClient as e, useQueryParams as f, useRouter as g, useRouterEvents as h, useRouterState as i, useActive as j, useAuth as k, ReactBrowserProvider as l, RedirectionError as m, pageDescriptorKey as p, useInject as u };
|
package/package.json
CHANGED
|
@@ -1,39 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alepha/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"main": "./dist/index.
|
|
7
|
-
"module": "./dist/index.js",
|
|
6
|
+
"main": "./dist/index.js",
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
9
|
-
"browser":
|
|
8
|
+
"browser": {
|
|
9
|
+
"./dist/index.js": "./dist/index.browser.js"
|
|
10
|
+
},
|
|
10
11
|
"dependencies": {
|
|
11
|
-
"@alepha/
|
|
12
|
-
"@alepha/
|
|
13
|
-
"@alepha/
|
|
14
|
-
"
|
|
15
|
-
"openid-client": "^6.4.1",
|
|
12
|
+
"@alepha/core": "0.6.1",
|
|
13
|
+
"@alepha/security": "0.6.1",
|
|
14
|
+
"@alepha/server": "0.6.1",
|
|
15
|
+
"openid-client": "^6.4.2",
|
|
16
16
|
"path-to-regexp": "^8.2.0",
|
|
17
|
-
"react": "^18.3.1",
|
|
18
17
|
"react-dom": "^18.3.1"
|
|
19
18
|
},
|
|
20
19
|
"devDependencies": {
|
|
21
20
|
"@types/react": "^18.3.20",
|
|
22
|
-
"@types/react-dom": "^18.3.
|
|
21
|
+
"@types/react-dom": "^18.3.6",
|
|
23
22
|
"pkgroll": "^2.12.1",
|
|
23
|
+
"react": "^18.3.1",
|
|
24
24
|
"vitest": "^3.1.1"
|
|
25
25
|
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@types/react": "^18",
|
|
28
|
+
"react": "^18"
|
|
29
|
+
},
|
|
26
30
|
"scripts": {
|
|
27
31
|
"build": "pkgroll --clean-dist"
|
|
28
32
|
},
|
|
29
33
|
"exports": {
|
|
30
|
-
"
|
|
31
|
-
"node": {
|
|
32
|
-
"require": "./dist/index.cjs",
|
|
34
|
+
".": {
|
|
33
35
|
"import": "./dist/index.js",
|
|
34
|
-
"
|
|
35
|
-
"types": "./dist/index.d.ts"
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
"require": "./dist/index.cjs",
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"browser": "./dist/index.browser.js"
|
|
39
|
+
}
|
|
38
40
|
}
|
|
39
41
|
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import type { ReactNode } from "react";
|
|
2
|
-
import { useContext, useEffect, useState } from "react";
|
|
3
|
-
import { RouterContext } from "../contexts/RouterContext";
|
|
4
|
-
import { RouterLayerContext } from "../contexts/RouterLayerContext";
|
|
5
|
-
|
|
6
|
-
export interface NestedViewProps {
|
|
7
|
-
children?: ReactNode;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Nested view component
|
|
12
|
-
*
|
|
13
|
-
* @param props
|
|
14
|
-
* @constructor
|
|
15
|
-
*/
|
|
16
|
-
const NestedView = (props: NestedViewProps) => {
|
|
17
|
-
const app = useContext(RouterContext);
|
|
18
|
-
const layer = useContext(RouterLayerContext);
|
|
19
|
-
const index = layer?.index ?? 0;
|
|
20
|
-
|
|
21
|
-
const [view, setView] = useState<ReactNode | undefined>(
|
|
22
|
-
app?.state.layers[index]?.element,
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (app?.alepha.isBrowser()) {
|
|
27
|
-
return app?.router.on("end", ({ layers }) => {
|
|
28
|
-
setView(layers[index]?.element);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
}, [app]);
|
|
32
|
-
|
|
33
|
-
return view ?? props.children ?? null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
export default NestedView;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Alepha } from "@alepha/core";
|
|
2
|
-
import { createContext } from "react";
|
|
3
|
-
import type { Session } from "../providers/ReactSessionProvider";
|
|
4
|
-
import type { Router, RouterState } from "../services/Router";
|
|
5
|
-
|
|
6
|
-
export interface RouterContextValue {
|
|
7
|
-
router: Router;
|
|
8
|
-
alepha: Alepha;
|
|
9
|
-
state: RouterState;
|
|
10
|
-
session?: Session;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const RouterContext = createContext<RouterContextValue | undefined>(
|
|
14
|
-
undefined,
|
|
15
|
-
);
|