@shivaedev/react 0.21.0 → 0.22.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.
@@ -1 +1 @@
1
- {"version":3,"file":"mountLive.d.ts","sourceRoot":"","sources":["../../src/client/mountLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,QAAQ,EAAqB,MAAM,QAAQ,CAAC;AAEjE,OAAO,KAAK,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAepE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,cAuC9G"}
1
+ {"version":3,"file":"mountLive.d.ts","sourceRoot":"","sources":["../../src/client/mountLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,QAAQ,EAAqB,MAAM,QAAQ,CAAC;AAEjE,OAAO,KAAK,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAYpE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,EAAE,QAAQ,CAAC,KAAK,cA8B9G"}
@@ -1,23 +1,18 @@
1
1
  import { Cause, Option, Predicate } from "effect";
2
2
  import * as Atom from "effect/reactivity/Atom";
3
3
  import { LiveConnection } from "@shivaedev/contract/automaticLive.ts";
4
+ import { liveBindings } from "#internal/liveBindings.ts";
4
5
  import { recheckUnauthorized } from "#internal/sessionRecheck.ts";
5
- function isLiveBound(value) {
6
- return Predicate.hasProperty(value, LiveConnection);
7
- }
8
6
  function recheckFailure(registry, failure) {
9
7
  const error = Option.flatMap(failure, Cause.findErrorOption);
10
8
  if (Option.isSome(error)) {
11
- void recheckUnauthorized(registry, error.value);
9
+ void recheckUnauthorized(registry, error.value, true);
12
10
  }
13
11
  }
14
12
  export function mountLive(registry, client, coalesceWindow) {
15
13
  const releases = [];
16
14
  const found = new Set();
17
- function mount(value) {
18
- if (!isLiveBound(value)) {
19
- return;
20
- }
15
+ for (const value of liveBindings(client)) {
21
16
  const live = value[LiveConnection];
22
17
  if (Predicate.hasProperty(live, "connection") && Atom.isAtom(live.connection) && !found.has(live.connection)) {
23
18
  if (coalesceWindow !== undefined
@@ -31,12 +26,6 @@ export function mountLive(registry, client, coalesceWindow) {
31
26
  releases.push(registry.mount(live.connection));
32
27
  }
33
28
  }
34
- mount(client);
35
- if (typeof client === "object" && client !== null) {
36
- for (const value of Object.values(client)) {
37
- mount(value);
38
- }
39
- }
40
29
  return () => {
41
30
  for (const release of releases) {
42
31
  release();
@@ -1 +1 @@
1
- {"version":3,"file":"mountLive.js","sourceRoot":"","sources":["../../src/client/mountLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAiB,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,OAAO,EAAkB,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,SAAS,WAAW,CAAC,KAAc;IAClC,OAAO,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,cAAc,CAAC,QAAmC,EAAE,OAA4C;IACxG,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACjD,CAAC;AACF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAmC,EAAE,MAAe,EAAE,cAA+B;IAC9G,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAW,CAAC;IACjC,SAAS,KAAK,CAAC,KAAc;QAC5B,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO;QACR,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;QACnC,IAAI,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9G,IACC,cAAc,KAAK,SAAS;mBACzB,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC;mBAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;mBAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,EACtC,CAAC;gBACF,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YACnD,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3B,QAAQ,CAAC,IAAI,CACZ,QAAQ,CAAC,SAAS,CACjB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EACjD,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAC9C,EAAE,SAAS,EAAE,IAAI,EAAE,CACnB,CACD,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChD,CAAC;IACF,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,CAAC;IACd,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3C,KAAK,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACF,CAAC;IACD,OAAO,GAAG,EAAE;QACX,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"mountLive.js","sourceRoot":"","sources":["../../src/client/mountLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAiB,MAAM,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACjE,OAAO,KAAK,IAAI,MAAM,wBAAwB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,sCAAsC,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE,SAAS,cAAc,CAAC,QAAmC,EAAE,OAA4C;IACxG,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,eAAe,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,KAAK,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACvD,CAAC;AACF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAmC,EAAE,MAAe,EAAE,cAA+B;IAC9G,MAAM,QAAQ,GAAsB,EAAE,CAAC;IACvC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAW,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,cAAc,CAAC,CAAC;QACnC,IAAI,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAC9G,IACC,cAAc,KAAK,SAAS;mBACzB,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC;mBAC7C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC;mBAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,EACtC,CAAC;gBACF,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;YACnD,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC3B,QAAQ,CAAC,IAAI,CACZ,QAAQ,CAAC,SAAS,CACjB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,EACjD,CAAC,OAAO,EAAE,EAAE,CAAC,cAAc,CAAC,QAAQ,EAAE,OAAO,CAAC,EAC9C,EAAE,SAAS,EAAE,IAAI,EAAE,CACnB,CACD,CAAC;YACF,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;QAChD,CAAC;IACF,CAAC;IACD,OAAO,GAAG,EAAE;QACX,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sessionBoundary.d.ts","sourceRoot":"","sources":["../../src/client/sessionBoundary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAA0C,KAAK,SAAS,EAAmC,MAAM,OAAO,CAAC;AAMhH,MAAM,WAAW,oBAAoB,CAAC,QAAQ,EAAE,OAAO;IACtD,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,YAAY,KAAK,OAAO,CAAC;IACtF,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC;IACjD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED,wBAAgB,iBAAiB,IAAI,MAAM,IAAI,CAE9C;AAqED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAClD,OAAO,EACP,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,GACR,EAAE,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,SAAS,CAUrD"}
1
+ {"version":3,"file":"sessionBoundary.d.ts","sourceRoot":"","sources":["../../src/client/sessionBoundary.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAA0C,KAAK,SAAS,EAAmC,MAAM,OAAO,CAAC;AAQhH,MAAM,WAAW,oBAAoB,CAAC,QAAQ,EAAE,OAAO;IACtD,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,CAAC;IAClD,QAAQ,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,YAAY,KAAK,OAAO,CAAC;IACtF,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,KAAK,MAAM,CAAC;IACjD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,SAAS,CAAC;IACzD,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED,wBAAgB,iBAAiB,IAAI,MAAM,IAAI,CAE9C;AAmFD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,EAClD,OAAO,EACP,kBAAkB,EAClB,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,QAAQ,GACR,EAAE,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,GAAG,SAAS,CAUrD"}
@@ -1,7 +1,9 @@
1
1
  import { RegistryContext } from "@effect/atom-react";
2
2
  import * as AtomRegistry from "effect/reactivity/AtomRegistry";
3
3
  import { createContext, createElement, Fragment, useContext, useEffect, useState } from "react";
4
+ import { LiveConnection } from "@shivaedev/contract/automaticLive.ts";
4
5
  import { DraftSessionContext } from "@shivaedev/form/client/react.ts";
6
+ import { liveBindings } from "#internal/liveBindings.ts";
5
7
  import { registerSessionRecheck } from "#internal/sessionRecheck.ts";
6
8
  import { useLatestCallback } from "#internal/useLatestCallback.ts";
7
9
  import { mountLive } from "./mountLive.js";
@@ -10,12 +12,18 @@ const RecheckContext = createContext(() => undefined);
10
12
  export function useSessionRecheck() {
11
13
  return useContext(RecheckContext);
12
14
  }
13
- function owning(connect) {
15
+ function owning(connect, identity) {
14
16
  const registry = AtomRegistry.make({ "defaultIdleTTL": 400 });
15
17
  let client;
16
18
  return {
17
19
  get client() {
18
20
  client ??= { value: connect(registry) };
21
+ for (const binding of liveBindings(client.value)) {
22
+ const session = binding[LiveConnection].identity;
23
+ if (session !== undefined) {
24
+ registry.set(session, identity);
25
+ }
26
+ }
19
27
  return client.value;
20
28
  },
21
29
  mounted: 0,
@@ -23,8 +31,8 @@ function owning(connect) {
23
31
  };
24
32
  }
25
33
  // No cleanup runs when a hidden <Activity> subtree is unmounted, so nodes a hidden render creates must not outlive it.
26
- function hidden(connect) {
27
- const owned = owning(connect);
34
+ function hidden(connect, identity) {
35
+ const owned = owning(connect, identity);
28
36
  let reaping = false;
29
37
  owned.registry.onNodeAdded = () => {
30
38
  if (reaping || owned.mounted > 0) {
@@ -40,10 +48,10 @@ function hidden(connect) {
40
48
  };
41
49
  return owned;
42
50
  }
43
- function Generation({ session, connect, recheck, children, liveCoalesceWindow }) {
51
+ function Generation({ session, connect, recheck, children, identity, liveCoalesceWindow, }) {
44
52
  const recheckLatest = useLatestCallback(recheck);
45
53
  const [open] = useState(() => (registry) => connect(session, registry));
46
- const [owned, own] = useState(() => owning(open));
54
+ const [owned, own] = useState(() => owning(open, identity));
47
55
  useEffect(() => registerSessionRecheck(owned.registry, recheckLatest), [owned, recheckLatest]);
48
56
  useEffect(() => {
49
57
  owned.mounted += 1;
@@ -56,10 +64,10 @@ function Generation({ session, connect, recheck, children, liveCoalesceWindow })
56
64
  return;
57
65
  }
58
66
  owned.registry.dispose();
59
- own((current) => (current === owned ? hidden(open) : current));
67
+ own((current) => (current === owned ? hidden(open, identity) : current));
60
68
  });
61
69
  };
62
- }, [owned, liveCoalesceWindow, open]);
70
+ }, [identity, owned, liveCoalesceWindow, open]);
63
71
  return createElement(RecheckContext.Provider, { value: recheckLatest }, createElement(RegistryContext.Provider, { value: owned.registry }, children(owned.client)));
64
72
  }
65
73
  export function SessionBoundary({ session, liveCoalesceWindow, identify, connect, recheck, signedOut, children, }) {
@@ -67,6 +75,6 @@ export function SessionBoundary({ session, liveCoalesceWindow, identify, connect
67
75
  const current = useDraftOwner(id);
68
76
  return session === undefined
69
77
  ? createElement(Fragment, null, signedOut)
70
- : createElement(DraftSessionContext.Provider, { value: current }, createElement(Generation, { children, connect, key: id, liveCoalesceWindow, recheck, session }));
78
+ : createElement(DraftSessionContext.Provider, { value: current }, createElement(Generation, { children, connect, identity: id, key: id, liveCoalesceWindow, recheck, session }));
71
79
  }
72
80
  //# sourceMappingURL=sessionBoundary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sessionBoundary.js","sourceRoot":"","sources":["../../src/client/sessionBoundary.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sessionBoundary.js","sourceRoot":"","sources":["../../src/client/sessionBoundary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type LiveBound } from "@shivaedev/contract/automaticLive.ts";
2
+ export declare function liveBindings(client: unknown): readonly LiveBound[];
3
+ //# sourceMappingURL=liveBindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveBindings.d.ts","sourceRoot":"","sources":["../../src/internal/liveBindings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,sCAAsC,CAAC;AAMtF,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,SAAS,EAAE,CAGlE"}
@@ -0,0 +1,10 @@
1
+ import { Predicate } from "effect";
2
+ import { LiveConnection } from "@shivaedev/contract/automaticLive.ts";
3
+ function isLiveBound(value) {
4
+ return Predicate.hasProperty(value, LiveConnection);
5
+ }
6
+ export function liveBindings(client) {
7
+ const values = typeof client === "object" && client !== null ? [client, ...Object.values(client)] : [client];
8
+ return values.filter(isLiveBound);
9
+ }
10
+ //# sourceMappingURL=liveBindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"liveBindings.js","sourceRoot":"","sources":["../../src/internal/liveBindings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,OAAO,EAAkB,cAAc,EAAE,MAAM,sCAAsC,CAAC;AAEtF,SAAS,WAAW,CAAC,KAAc;IAClC,OAAO,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAe;IAC3C,MAAM,MAAM,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7G,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACnC,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
2
2
  export declare function registerSessionRecheck(registry: AtomRegistry.AtomRegistry, recheck: () => void): () => void;
3
- export declare function recheckUnauthorized(registry: AtomRegistry.AtomRegistry, error: unknown): Promise<void>;
3
+ export declare function recheckUnauthorized(registry: AtomRegistry.AtomRegistry, error: unknown, connection?: boolean): Promise<void>;
4
4
  //# sourceMappingURL=sessionRecheck.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sessionRecheck.d.ts","sourceRoot":"","sources":["../../src/internal/sessionRecheck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAIpE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK3G;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5G"}
1
+ {"version":3,"file":"sessionRecheck.d.ts","sourceRoot":"","sources":["../../src/internal/sessionRecheck.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,YAAY,MAAM,gCAAgC,CAAC;AAIpE,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAK3G;AAED,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,CAAC,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAIhI"}
@@ -6,8 +6,8 @@ export function registerSessionRecheck(registry, recheck) {
6
6
  rechecks.delete(registry);
7
7
  };
8
8
  }
9
- export async function recheckUnauthorized(registry, error) {
10
- if (Predicate.isTagged(error, "Unauthorized")) {
9
+ export async function recheckUnauthorized(registry, error, connection = false) {
10
+ if (Predicate.isTagged(error, "Unauthorized") || (connection && Predicate.isTagged(error, "RpcClientError"))) {
11
11
  await rechecks.get(registry)?.();
12
12
  }
13
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sessionRecheck.js","sourceRoot":"","sources":["../../src/internal/sessionRecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyC,CAAC;AAEtE,MAAM,UAAU,sBAAsB,CAAC,QAAmC,EAAE,OAAmB;IAC9F,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,GAAG,EAAE;QACX,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAmC,EAAE,KAAc;IAC5F,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,EAAE,CAAC;QAC/C,MAAM,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;IAClC,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"sessionRecheck.js","sourceRoot":"","sources":["../../src/internal/sessionRecheck.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGnC,MAAM,QAAQ,GAAG,IAAI,OAAO,EAAyC,CAAC;AAEtE,MAAM,UAAU,sBAAsB,CAAC,QAAmC,EAAE,OAAmB;IAC9F,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,GAAG,EAAE;QACX,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,QAAmC,EAAE,KAAc,EAAE,UAAU,GAAG,KAAK;IAChH,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QAC9G,MAAM,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;IAClC,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/react",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "React query, action, editor and session hooks for native Effect atoms",
5
5
  "keywords": [
6
6
  "effect"
@@ -47,7 +47,7 @@
47
47
  ],
48
48
  "dependencies": {
49
49
  "@shivaedev/access": "0.1.1",
50
- "@shivaedev/contract": "0.19.0",
50
+ "@shivaedev/contract": "0.20.0",
51
51
  "@shivaedev/errors": "0.1.0",
52
52
  "@shivaedev/form": "0.7.0",
53
53
  "@shivaedev/test": "0.10.0"
@@ -58,15 +58,15 @@
58
58
  "@effect/sql-pg": "4.0.5",
59
59
  "@effect/sql-sqlite-node": "4.0.5",
60
60
  "@shivaedev/changes": "0.5.0",
61
- "@shivaedev/identity": "0.3.0",
61
+ "@shivaedev/identity": "0.3.2",
62
62
  "@shivaedev/jobs": "0.22.0",
63
63
  "@shivaedev/local-postgres": "0.7.0",
64
- "@shivaedev/quality": "0.43.0",
65
- "@shivaedev/server": "0.3.0",
64
+ "@shivaedev/quality": "0.44.1",
65
+ "@shivaedev/server": "0.4.0",
66
66
  "@shivaedev/service": "0.5.0",
67
67
  "@shivaedev/sql": "0.24.0",
68
68
  "@shivaedev/test-sql": "0.10.2",
69
- "@shivaedev/test-story": "0.22.0",
69
+ "@shivaedev/test-story": "0.23.0",
70
70
  "@tanstack/react-router": "1.170.45",
71
71
  "@types/node": "24.19.2",
72
72
  "@types/react": "19.3.0",
@@ -1,27 +1,21 @@
1
1
  import { Cause, type Duration, Option, Predicate } from "effect";
2
2
  import * as Atom from "effect/reactivity/Atom";
3
3
  import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
4
- import { type LiveBound, LiveConnection } from "@shivaedev/contract/automaticLive.ts";
4
+ import { LiveConnection } from "@shivaedev/contract/automaticLive.ts";
5
+ import { liveBindings } from "#internal/liveBindings.ts";
5
6
  import { recheckUnauthorized } from "#internal/sessionRecheck.ts";
6
7
 
7
- function isLiveBound(value: unknown): value is LiveBound {
8
- return Predicate.hasProperty(value, LiveConnection);
9
- }
10
-
11
8
  function recheckFailure(registry: AtomRegistry.AtomRegistry, failure: Option.Option<Cause.Cause<unknown>>) {
12
9
  const error = Option.flatMap(failure, Cause.findErrorOption);
13
10
  if (Option.isSome(error)) {
14
- void recheckUnauthorized(registry, error.value);
11
+ void recheckUnauthorized(registry, error.value, true);
15
12
  }
16
13
  }
17
14
 
18
15
  export function mountLive(registry: AtomRegistry.AtomRegistry, client: unknown, coalesceWindow?: Duration.Input) {
19
16
  const releases: Array<() => void> = [];
20
17
  const found = new Set<unknown>();
21
- function mount(value: unknown) {
22
- if (!isLiveBound(value)) {
23
- return;
24
- }
18
+ for (const value of liveBindings(client)) {
25
19
  const live = value[LiveConnection];
26
20
  if (Predicate.hasProperty(live, "connection") && Atom.isAtom(live.connection) && !found.has(live.connection)) {
27
21
  if (
@@ -43,12 +37,6 @@ export function mountLive(registry: AtomRegistry.AtomRegistry, client: unknown,
43
37
  releases.push(registry.mount(live.connection));
44
38
  }
45
39
  }
46
- mount(client);
47
- if (typeof client === "object" && client !== null) {
48
- for (const value of Object.values(client)) {
49
- mount(value);
50
- }
51
- }
52
40
  return () => {
53
41
  for (const release of releases) {
54
42
  release();
@@ -2,7 +2,9 @@ import { RegistryContext } from "@effect/atom-react";
2
2
  import type { Duration } from "effect";
3
3
  import * as AtomRegistry from "effect/reactivity/AtomRegistry";
4
4
  import { createContext, createElement, Fragment, type ReactNode, useContext, useEffect, useState } from "react";
5
+ import { LiveConnection } from "@shivaedev/contract/automaticLive.ts";
5
6
  import { DraftSessionContext } from "@shivaedev/form/client/react.ts";
7
+ import { liveBindings } from "#internal/liveBindings.ts";
6
8
  import { registerSessionRecheck } from "#internal/sessionRecheck.ts";
7
9
  import { useLatestCallback } from "#internal/useLatestCallback.ts";
8
10
  import { mountLive } from "./mountLive.ts";
@@ -25,12 +27,18 @@ interface Owned<TClient> {
25
27
  mounted: number;
26
28
  readonly registry: AtomRegistry.AtomRegistry;
27
29
  }
28
- function owning<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClient): Owned<TClient> {
30
+ function owning<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClient, identity: string | undefined): Owned<TClient> {
29
31
  const registry = AtomRegistry.make({ "defaultIdleTTL": 400 });
30
32
  let client: { readonly value: TClient } | undefined;
31
33
  return {
32
34
  get client() {
33
35
  client ??= { value: connect(registry) };
36
+ for (const binding of liveBindings(client.value)) {
37
+ const session = binding[LiveConnection].identity;
38
+ if (session !== undefined) {
39
+ registry.set(session, identity);
40
+ }
41
+ }
34
42
  return client.value;
35
43
  },
36
44
  mounted: 0,
@@ -38,8 +46,8 @@ function owning<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClie
38
46
  };
39
47
  }
40
48
  // No cleanup runs when a hidden <Activity> subtree is unmounted, so nodes a hidden render creates must not outlive it.
41
- function hidden<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClient): Owned<TClient> {
42
- const owned = owning(connect);
49
+ function hidden<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClient, identity: string | undefined): Owned<TClient> {
50
+ const owned = owning(connect, identity);
43
51
  let reaping = false;
44
52
  owned.registry.onNodeAdded = () => {
45
53
  if (reaping || owned.mounted > 0) {
@@ -58,14 +66,22 @@ function hidden<TClient>(connect: (registry: AtomRegistry.AtomRegistry) => TClie
58
66
  interface GenerationProps<TSession, TClient> {
59
67
  readonly children: (client: TClient) => ReactNode;
60
68
  readonly connect: (session: TSession, registry: AtomRegistry.AtomRegistry) => TClient;
69
+ readonly identity: string | undefined;
61
70
  readonly liveCoalesceWindow?: Duration.Input | undefined;
62
71
  readonly recheck: () => void;
63
72
  readonly session: TSession;
64
73
  }
65
- function Generation<TSession, TClient>({ session, connect, recheck, children, liveCoalesceWindow }: GenerationProps<TSession, TClient>): ReactNode {
74
+ function Generation<TSession, TClient>({
75
+ session,
76
+ connect,
77
+ recheck,
78
+ children,
79
+ identity,
80
+ liveCoalesceWindow,
81
+ }: GenerationProps<TSession, TClient>): ReactNode {
66
82
  const recheckLatest = useLatestCallback(recheck);
67
83
  const [open] = useState(() => (registry: AtomRegistry.AtomRegistry) => connect(session, registry));
68
- const [owned, own] = useState(() => owning(open));
84
+ const [owned, own] = useState(() => owning(open, identity));
69
85
  useEffect(() => registerSessionRecheck(owned.registry, recheckLatest), [owned, recheckLatest]);
70
86
  useEffect(() => {
71
87
  owned.mounted += 1;
@@ -78,10 +94,10 @@ function Generation<TSession, TClient>({ session, connect, recheck, children, li
78
94
  return;
79
95
  }
80
96
  owned.registry.dispose();
81
- own((current) => (current === owned ? hidden(open) : current));
97
+ own((current) => (current === owned ? hidden(open, identity) : current));
82
98
  });
83
99
  };
84
- }, [owned, liveCoalesceWindow, open]);
100
+ }, [identity, owned, liveCoalesceWindow, open]);
85
101
  return createElement(
86
102
  RecheckContext.Provider,
87
103
  { value: recheckLatest },
@@ -104,6 +120,6 @@ export function SessionBoundary<TSession, TClient>({
104
120
  : createElement(
105
121
  DraftSessionContext.Provider,
106
122
  { value: current },
107
- createElement(Generation<TSession, TClient>, { children, connect, key: id, liveCoalesceWindow, recheck, session }),
123
+ createElement(Generation<TSession, TClient>, { children, connect, identity: id, key: id, liveCoalesceWindow, recheck, session }),
108
124
  );
109
125
  }
@@ -0,0 +1,11 @@
1
+ import { Predicate } from "effect";
2
+ import { type LiveBound, LiveConnection } from "@shivaedev/contract/automaticLive.ts";
3
+
4
+ function isLiveBound(value: unknown): value is LiveBound {
5
+ return Predicate.hasProperty(value, LiveConnection);
6
+ }
7
+
8
+ export function liveBindings(client: unknown): readonly LiveBound[] {
9
+ const values = typeof client === "object" && client !== null ? [client, ...Object.values(client)] : [client];
10
+ return values.filter(isLiveBound);
11
+ }
@@ -10,8 +10,8 @@ export function registerSessionRecheck(registry: AtomRegistry.AtomRegistry, rech
10
10
  };
11
11
  }
12
12
 
13
- export async function recheckUnauthorized(registry: AtomRegistry.AtomRegistry, error: unknown): Promise<void> {
14
- if (Predicate.isTagged(error, "Unauthorized")) {
13
+ export async function recheckUnauthorized(registry: AtomRegistry.AtomRegistry, error: unknown, connection = false): Promise<void> {
14
+ if (Predicate.isTagged(error, "Unauthorized") || (connection && Predicate.isTagged(error, "RpcClientError"))) {
15
15
  await rechecks.get(registry)?.();
16
16
  }
17
17
  }