reflex 0.8.15a1__py3-none-any.whl → 0.8.15a2__py3-none-any.whl
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.
Potentially problematic release.
This version of reflex might be problematic. Click here for more details.
- reflex/.templates/web/utils/state.js +68 -8
- reflex/app.py +5 -5
- reflex/utils/codespaces.py +30 -1
- reflex/utils/types.py +8 -1
- {reflex-0.8.15a1.dist-info → reflex-0.8.15a2.dist-info}/METADATA +1 -1
- {reflex-0.8.15a1.dist-info → reflex-0.8.15a2.dist-info}/RECORD +9 -9
- {reflex-0.8.15a1.dist-info → reflex-0.8.15a2.dist-info}/WHEEL +0 -0
- {reflex-0.8.15a1.dist-info → reflex-0.8.15a2.dist-info}/entry_points.txt +0 -0
- {reflex-0.8.15a1.dist-info → reflex-0.8.15a2.dist-info}/licenses/LICENSE +0 -0
|
@@ -529,6 +529,14 @@ export const connect = async (
|
|
|
529
529
|
navigate,
|
|
530
530
|
params,
|
|
531
531
|
) => {
|
|
532
|
+
// Socket already allocated, just reconnect it if needed.
|
|
533
|
+
if (socket.current) {
|
|
534
|
+
if (!socket.current.connected) {
|
|
535
|
+
socket.current.reconnect();
|
|
536
|
+
}
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
|
|
532
540
|
// Get backend URL object from the endpoint.
|
|
533
541
|
const endpoint = getBackendURL(EVENTURL);
|
|
534
542
|
const on_hydrated_queue = [];
|
|
@@ -540,7 +548,9 @@ export const connect = async (
|
|
|
540
548
|
protocols: [reflexEnvironment.version],
|
|
541
549
|
autoUnref: false,
|
|
542
550
|
query: { token: getToken() },
|
|
551
|
+
reconnection: false, // Reconnection will be handled manually.
|
|
543
552
|
});
|
|
553
|
+
socket.current.wait_connect = !socket.current.connected;
|
|
544
554
|
// Ensure undefined fields in events are sent as null instead of removed
|
|
545
555
|
socket.current.io.encoder.replacer = (k, v) => (v === undefined ? null : v);
|
|
546
556
|
socket.current.io.decoder.tryParse = (str) => {
|
|
@@ -550,6 +560,18 @@ export const connect = async (
|
|
|
550
560
|
return false;
|
|
551
561
|
}
|
|
552
562
|
};
|
|
563
|
+
// Set up a reconnect helper function
|
|
564
|
+
socket.current.reconnect = () => {
|
|
565
|
+
if (
|
|
566
|
+
socket.current &&
|
|
567
|
+
!socket.current.connected &&
|
|
568
|
+
!socket.current.wait_connect
|
|
569
|
+
) {
|
|
570
|
+
socket.current.wait_connect = true;
|
|
571
|
+
socket.current.io.opts.query = { token: getToken() }; // Update token for reconnect.
|
|
572
|
+
socket.current.connect();
|
|
573
|
+
}
|
|
574
|
+
};
|
|
553
575
|
|
|
554
576
|
function checkVisibility() {
|
|
555
577
|
if (document.visibilityState === "visible") {
|
|
@@ -565,7 +587,7 @@ export const connect = async (
|
|
|
565
587
|
);
|
|
566
588
|
} else if (!socket.current.connected) {
|
|
567
589
|
console.log("Socket is disconnected, attempting to reconnect ");
|
|
568
|
-
socket.current.
|
|
590
|
+
socket.current.reconnect();
|
|
569
591
|
} else {
|
|
570
592
|
console.log("Socket is reconnected ");
|
|
571
593
|
}
|
|
@@ -588,6 +610,7 @@ export const connect = async (
|
|
|
588
610
|
|
|
589
611
|
// Once the socket is open, hydrate the page.
|
|
590
612
|
socket.current.on("connect", async () => {
|
|
613
|
+
socket.current.wait_connect = false;
|
|
591
614
|
setConnectErrors([]);
|
|
592
615
|
window.addEventListener("pagehide", pagehideHandler);
|
|
593
616
|
window.addEventListener("beforeunload", disconnectTrigger);
|
|
@@ -599,16 +622,33 @@ export const connect = async (
|
|
|
599
622
|
});
|
|
600
623
|
|
|
601
624
|
socket.current.on("connect_error", (error) => {
|
|
602
|
-
|
|
625
|
+
socket.current.wait_connect = false;
|
|
626
|
+
let n_connect_errors = 0;
|
|
627
|
+
setConnectErrors((connectErrors) => {
|
|
628
|
+
const new_errors = [...connectErrors.slice(-9), error];
|
|
629
|
+
n_connect_errors = new_errors.length;
|
|
630
|
+
return new_errors;
|
|
631
|
+
});
|
|
632
|
+
window.setTimeout(() => {
|
|
633
|
+
if (socket.current && !socket.current.connected) {
|
|
634
|
+
socket.current.reconnect();
|
|
635
|
+
}
|
|
636
|
+
}, 200 * n_connect_errors); // Incremental backoff
|
|
603
637
|
});
|
|
604
638
|
|
|
605
639
|
// When the socket disconnects reset the event_processing flag
|
|
606
|
-
socket.current.on("disconnect", () => {
|
|
607
|
-
socket.current =
|
|
640
|
+
socket.current.on("disconnect", (reason, details) => {
|
|
641
|
+
socket.current.wait_connect = false;
|
|
642
|
+
const try_reconnect =
|
|
643
|
+
reason !== "io server disconnect" && reason !== "io client disconnect";
|
|
608
644
|
event_processing = false;
|
|
609
645
|
window.removeEventListener("unload", disconnectTrigger);
|
|
610
646
|
window.removeEventListener("beforeunload", disconnectTrigger);
|
|
611
647
|
window.removeEventListener("pagehide", pagehideHandler);
|
|
648
|
+
if (try_reconnect) {
|
|
649
|
+
// Attempt to reconnect transient non-intentional disconnects.
|
|
650
|
+
socket.current.reconnect();
|
|
651
|
+
}
|
|
612
652
|
});
|
|
613
653
|
|
|
614
654
|
// On each received message, queue the updates and events.
|
|
@@ -785,6 +825,7 @@ export const useEventLoop = (
|
|
|
785
825
|
const [searchParams] = useSearchParams();
|
|
786
826
|
const [connectErrors, setConnectErrors] = useState([]);
|
|
787
827
|
const params = useRef(paramsR);
|
|
828
|
+
const mounted = useRef(false);
|
|
788
829
|
|
|
789
830
|
useEffect(() => {
|
|
790
831
|
const { "*": splat, ...remainingParams } = paramsR;
|
|
@@ -796,11 +837,16 @@ export const useEventLoop = (
|
|
|
796
837
|
}, [paramsR]);
|
|
797
838
|
|
|
798
839
|
const ensureSocketConnected = useCallback(async () => {
|
|
840
|
+
if (!mounted.current) {
|
|
841
|
+
// During hot reload, some components may still have a reference to
|
|
842
|
+
// addEvents, so avoid reconnecting the socket of an unmounted event loop.
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
799
845
|
// only use websockets if state is present and backend is not disabled (reflex cloud).
|
|
800
846
|
if (
|
|
801
847
|
Object.keys(initialState).length > 1 &&
|
|
802
848
|
!isBackendDisabled() &&
|
|
803
|
-
!socket.current
|
|
849
|
+
!socket.current?.connected
|
|
804
850
|
) {
|
|
805
851
|
// Initialize the websocket connection.
|
|
806
852
|
await connect(
|
|
@@ -813,13 +859,23 @@ export const useEventLoop = (
|
|
|
813
859
|
() => params.current,
|
|
814
860
|
);
|
|
815
861
|
}
|
|
816
|
-
}, [
|
|
862
|
+
}, [
|
|
863
|
+
socket,
|
|
864
|
+
dispatch,
|
|
865
|
+
setConnectErrors,
|
|
866
|
+
client_storage,
|
|
867
|
+
navigate,
|
|
868
|
+
params,
|
|
869
|
+
mounted,
|
|
870
|
+
]);
|
|
817
871
|
|
|
818
872
|
// Function to add new events to the event queue.
|
|
819
873
|
const addEvents = useCallback((events, args, event_actions) => {
|
|
820
874
|
const _events = events.filter((e) => e !== undefined && e !== null);
|
|
821
|
-
|
|
822
|
-
|
|
875
|
+
if (!event_actions?.temporal) {
|
|
876
|
+
// Reconnect socket if needed for non-temporal events.
|
|
877
|
+
ensureSocketConnected();
|
|
878
|
+
}
|
|
823
879
|
|
|
824
880
|
if (!(args instanceof Array)) {
|
|
825
881
|
args = [args];
|
|
@@ -914,12 +970,16 @@ export const useEventLoop = (
|
|
|
914
970
|
// Handle socket connect/disconnect.
|
|
915
971
|
useEffect(() => {
|
|
916
972
|
// Initialize the websocket connection.
|
|
973
|
+
mounted.current = true;
|
|
917
974
|
ensureSocketConnected();
|
|
918
975
|
|
|
919
976
|
// Cleanup function.
|
|
920
977
|
return () => {
|
|
978
|
+
mounted.current = false;
|
|
921
979
|
if (socket.current) {
|
|
922
980
|
socket.current.disconnect();
|
|
981
|
+
socket.current.off();
|
|
982
|
+
socket.current = null;
|
|
923
983
|
}
|
|
924
984
|
};
|
|
925
985
|
}, []);
|
reflex/app.py
CHANGED
|
@@ -1781,16 +1781,16 @@ async def process(
|
|
|
1781
1781
|
name=f"reflex_emit_reload|{event.name}|{time.time()}|{event.token}",
|
|
1782
1782
|
)
|
|
1783
1783
|
return
|
|
1784
|
+
router_data[constants.RouteVar.PATH] = "/" + (
|
|
1785
|
+
app.router(path) or "404"
|
|
1786
|
+
if (path := router_data.get(constants.RouteVar.PATH))
|
|
1787
|
+
else "404"
|
|
1788
|
+
).removeprefix("/")
|
|
1784
1789
|
# re-assign only when the value is different
|
|
1785
1790
|
if state.router_data != router_data:
|
|
1786
1791
|
# assignment will recurse into substates and force recalculation of
|
|
1787
1792
|
# dependent ComputedVar (dynamic route variables)
|
|
1788
1793
|
state.router_data = router_data
|
|
1789
|
-
router_data[constants.RouteVar.PATH] = "/" + (
|
|
1790
|
-
app.router(path) or "404"
|
|
1791
|
-
if (path := router_data.get(constants.RouteVar.PATH))
|
|
1792
|
-
else "404"
|
|
1793
|
-
).removeprefix("/")
|
|
1794
1794
|
state.router = RouterData.from_router_data(router_data)
|
|
1795
1795
|
|
|
1796
1796
|
# Preprocess the event.
|
reflex/utils/codespaces.py
CHANGED
|
@@ -26,11 +26,40 @@ def redirect_script() -> str:
|
|
|
26
26
|
const thisUrl = new URL(window.location.href);
|
|
27
27
|
const params = new URLSearchParams(thisUrl.search)
|
|
28
28
|
|
|
29
|
+
function sameHostnameDifferentPort(one, two) {{
|
|
30
|
+
const hostnameOne = one.hostname;
|
|
31
|
+
const hostnameTwo = two.hostname;
|
|
32
|
+
const partsOne = hostnameOne.split(".");
|
|
33
|
+
const partsTwo = hostnameTwo.split(".");
|
|
34
|
+
if (partsOne.length !== partsTwo.length) {{ return false; }}
|
|
35
|
+
for (let i = 1; i < partsOne.length; i++) {{
|
|
36
|
+
if (partsOne[i] !== partsTwo[i]) {{ return false; }}
|
|
37
|
+
}}
|
|
38
|
+
const uniqueNameOne = partsOne[0];
|
|
39
|
+
const uniqueNameTwo = partsTwo[0];
|
|
40
|
+
const uniqueNamePartsOne = uniqueNameOne.split("-");
|
|
41
|
+
const uniqueNamePartsTwo = uniqueNameTwo.split("-");
|
|
42
|
+
if (uniqueNamePartsOne.length !== uniqueNamePartsTwo.length) {{ return false; }}
|
|
43
|
+
for (let i = 0; i < uniqueNamePartsOne.length - 1; i++) {{
|
|
44
|
+
if (uniqueNamePartsOne[i] !== uniqueNamePartsTwo[i]) {{ return false; }}
|
|
45
|
+
}}
|
|
46
|
+
return true;
|
|
47
|
+
}}
|
|
48
|
+
|
|
29
49
|
function doRedirect(url) {{
|
|
30
50
|
if (!window.sessionStorage.getItem("authenticated_github_codespaces")) {{
|
|
31
51
|
const a = document.createElement("a");
|
|
32
52
|
if (params.has("redirect_to")) {{
|
|
33
|
-
|
|
53
|
+
const redirect_to = new URL(params.get("redirect_to"));
|
|
54
|
+
if (!sameHostnameDifferentPort(thisUrl, redirect_to)) {{
|
|
55
|
+
console.warn("Reflex: Not redirecting to different hostname");
|
|
56
|
+
return;
|
|
57
|
+
}}
|
|
58
|
+
if (!redirect_to.hostname.endsWith(".app.github.dev")) {{
|
|
59
|
+
console.warn("Reflex: Not redirecting to non .app.github.dev hostname");
|
|
60
|
+
return;
|
|
61
|
+
}}
|
|
62
|
+
a.href = redirect_to.href;
|
|
34
63
|
}} else if (!window.location.href.startsWith(url)) {{
|
|
35
64
|
a.href = url + `?redirect_to=${{window.location.href}}`
|
|
36
65
|
}} else {{
|
reflex/utils/types.py
CHANGED
|
@@ -443,6 +443,13 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
443
443
|
|
|
444
444
|
from reflex.model import Model
|
|
445
445
|
|
|
446
|
+
if find_spec("sqlmodel"):
|
|
447
|
+
from sqlmodel import SQLModel
|
|
448
|
+
|
|
449
|
+
sqlmodel_types = (Model, SQLModel)
|
|
450
|
+
else:
|
|
451
|
+
sqlmodel_types = (Model,)
|
|
452
|
+
|
|
446
453
|
if isinstance(cls, type) and issubclass(cls, DeclarativeBase):
|
|
447
454
|
insp = sqlalchemy.inspect(cls)
|
|
448
455
|
if name in insp.columns:
|
|
@@ -486,7 +493,7 @@ def get_attribute_access_type(cls: GenericType, name: str) -> GenericType | None
|
|
|
486
493
|
elif (
|
|
487
494
|
isinstance(cls, type)
|
|
488
495
|
and not is_generic_alias(cls)
|
|
489
|
-
and issubclass(cls,
|
|
496
|
+
and issubclass(cls, sqlmodel_types)
|
|
490
497
|
):
|
|
491
498
|
# Check in the annotations directly (for sqlmodel.Relationship)
|
|
492
499
|
hints = get_type_hints(cls) # pyright: ignore [reportArgumentType]
|
|
@@ -2,7 +2,7 @@ reflex/__init__.py,sha256=7iJASSyU1dxLM-l6q6gFAkw6FniXvawAekgfwN5zKjM,10328
|
|
|
2
2
|
reflex/__init__.pyi,sha256=Yy3exOO_7-O7fCjTKO1VDFbjPyeMM7F12WBnEXWx_tk,10428
|
|
3
3
|
reflex/__main__.py,sha256=6cVrGEyT3j3tEvlEVUatpaYfbB5EF3UVY-6vc_Z7-hw,108
|
|
4
4
|
reflex/admin.py,sha256=Nbc38y-M8iaRBvh1W6DQu_D3kEhO8JFvxrog4q2cB_E,434
|
|
5
|
-
reflex/app.py,sha256=
|
|
5
|
+
reflex/app.py,sha256=RYOqnOFpik1DVi2Yk5b6CdB6OaoPW7pXtVCtIYZGhME,79220
|
|
6
6
|
reflex/assets.py,sha256=l5O_mlrTprC0lF7Rc_McOe3a0OtSLnRdNl_PqCpDCBA,3431
|
|
7
7
|
reflex/base.py,sha256=B3DLpG0oEKIYC-PfWE9rnHPCKYrOB6bi08MyZQDSi1s,2326
|
|
8
8
|
reflex/config.py,sha256=LsHAtdH4nkSn3q_Ie-KNdOGdflLXrFICUQov29oFjVk,21229
|
|
@@ -30,7 +30,7 @@ reflex/.templates/web/components/reflex/radix_themes_color_mode_provider.js,sha2
|
|
|
30
30
|
reflex/.templates/web/components/shiki/code.js,sha256=4Es1pxsr-lX4hTQ5mglrwwC6O_SI-z-O60k03z8VFzQ,1144
|
|
31
31
|
reflex/.templates/web/styles/__reflex_style_reset.css,sha256=qbC6JIT643YEsvSQ0D7xBmWE5vXy94JGrKNihRuEjnA,8913
|
|
32
32
|
reflex/.templates/web/utils/react-theme.js,sha256=Aa-RND3ooGCXW6Zavzitc-v0ciKlcQDTFlDtE4mPkFI,2713
|
|
33
|
-
reflex/.templates/web/utils/state.js,sha256=
|
|
33
|
+
reflex/.templates/web/utils/state.js,sha256=7gRWc8ABMOKY3KMF6SpaVEhNILW03wivd7eENVC7ADg,34858
|
|
34
34
|
reflex/.templates/web/utils/helpers/dataeditor.js,sha256=pG6MgsHuStDR7-qPipzfiK32j9bKDBa-4hZ0JSUo4JM,1623
|
|
35
35
|
reflex/.templates/web/utils/helpers/debounce.js,sha256=xGhtTRtS_xIcaeqnYVvYJNseLgQVk-DW-eFiHJYO9As,528
|
|
36
36
|
reflex/.templates/web/utils/helpers/paste.js,sha256=ef30HsR83jRzzvZnl8yV79yqFP8TC_u8SlN99cCS_OM,1799
|
|
@@ -350,7 +350,7 @@ reflex/plugins/tailwind_v3.py,sha256=jCEZ5UYdr706Mw48L-WSHOUB6O55o1C3uG6AMwXqZoI
|
|
|
350
350
|
reflex/plugins/tailwind_v4.py,sha256=8G7iXj6wYRRJlCWlce_vtCgs1YittFvLucyUP-sPXhc,5230
|
|
351
351
|
reflex/utils/__init__.py,sha256=y-AHKiRQAhk2oAkvn7W8cRVTZVK625ff8tTwvZtO7S4,24
|
|
352
352
|
reflex/utils/build.py,sha256=j-OY90O7gMP_bclVt_6J3Q2GFgOHQH_uFpTfdaWmuqU,9746
|
|
353
|
-
reflex/utils/codespaces.py,sha256=
|
|
353
|
+
reflex/utils/codespaces.py,sha256=mR7jqbr16WAdiQyaaqA9Pf0g2lclSenQdHM6ngvLGBI,4345
|
|
354
354
|
reflex/utils/compat.py,sha256=LlFZg8j5Nyul_OR0pMYTDCcaoCR8aEsg8rFpTIGLtvU,3024
|
|
355
355
|
reflex/utils/console.py,sha256=W41Ogj1Jk8tEOhXXy9dy4KCLYp5rn0NZQwbBqXbkwSI,13668
|
|
356
356
|
reflex/utils/decorator.py,sha256=QUZntENupeW5FA5mNRTx0I1GzGKFQXhMjVg24_IIM5o,3957
|
|
@@ -376,7 +376,7 @@ reflex/utils/serializers.py,sha256=18cnbx5rMftrh6T0bj0L2LqMKHPcFTSiKZ8bx_20Ris,1
|
|
|
376
376
|
reflex/utils/telemetry.py,sha256=E_qV7hHKybnWu9MfMSTbJ7-RJebyA1Csh_x6GaCzI_4,10740
|
|
377
377
|
reflex/utils/templates.py,sha256=uZMK4yilPanRRRKB5VTR2WO88q-d3QjUOOBdF2hu31o,14108
|
|
378
378
|
reflex/utils/token_manager.py,sha256=ZtrYR0X8tTs8FpQHtMb09-H2V1xSoLWwVH8jW8OCrU8,7445
|
|
379
|
-
reflex/utils/types.py,sha256=
|
|
379
|
+
reflex/utils/types.py,sha256=1QqDJuw6v8CvkR8Na-6P4bRjJzQI27ONy19JZl4dVtc,38781
|
|
380
380
|
reflex/vars/__init__.py,sha256=pUzFFkY-brpEoqYHQc41VefaOdPQG6xzjer1RJy9IKo,1264
|
|
381
381
|
reflex/vars/base.py,sha256=kZDZV43kpGE-YmX7W4XQePs4iFEESJBcI3c7uyMacyo,112829
|
|
382
382
|
reflex/vars/color.py,sha256=KxmeEl6wt7Ck7yiyX8gxiRHNgpN3n9LrEqOo0ofOrVw,4898
|
|
@@ -387,8 +387,8 @@ reflex/vars/number.py,sha256=Cejba-47shtQt-j0uD_HRfTGOm1IF1uZ1WwpWSrcLSE,28865
|
|
|
387
387
|
reflex/vars/object.py,sha256=q_MTTgWEHjtpwDdyfR16kNf3pXcDEbxSjWdB1AtMdVY,17913
|
|
388
388
|
reflex/vars/sequence.py,sha256=dHtznvmX4CRxIIOsMQ88iQoQ06BFbMqcGvRYwfg0gCg,52440
|
|
389
389
|
scripts/hatch_build.py,sha256=-4pxcLSFmirmujGpQX9UUxjhIC03tQ_fIQwVbHu9kc0,1861
|
|
390
|
-
reflex-0.8.
|
|
391
|
-
reflex-0.8.
|
|
392
|
-
reflex-0.8.
|
|
393
|
-
reflex-0.8.
|
|
394
|
-
reflex-0.8.
|
|
390
|
+
reflex-0.8.15a2.dist-info/METADATA,sha256=4_TNPjSvQ6D2LzcLBsQiM9GHhRdrGcmYqOfMSjGaRiY,12562
|
|
391
|
+
reflex-0.8.15a2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
392
|
+
reflex-0.8.15a2.dist-info/entry_points.txt,sha256=Rxt4dXc7MLBNt5CSHTehVPuSe9Xqow4HLX55nD9tQQ0,45
|
|
393
|
+
reflex-0.8.15a2.dist-info/licenses/LICENSE,sha256=dw3zLrp9f5ObD7kqS32vWfhcImfO52PMmRqvtxq_YEE,11358
|
|
394
|
+
reflex-0.8.15a2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|