@lunora/client 1.0.0-alpha.11 → 1.0.0-alpha.110

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.
Files changed (91) hide show
  1. package/LICENSE.md +6 -0
  2. package/README.md +16 -3
  3. package/dist/auth/index.d.mts +36 -12
  4. package/dist/auth/index.d.ts +36 -12
  5. package/dist/auth/index.mjs +1 -60
  6. package/dist/index.d.mts +884 -273
  7. package/dist/index.d.ts +884 -273
  8. package/dist/index.mjs +1 -15
  9. package/dist/packem_shared/CONFLICT_ERROR_CODE-BOeeP_Wl.mjs +1 -0
  10. package/dist/packem_shared/ClientServiceWorker-DXnBXeWK.mjs +1 -0
  11. package/dist/packem_shared/DEFAULT_MAX_BUFFER-D3QH2iaq.mjs +1 -0
  12. package/dist/packem_shared/LunoraClient-D4FH_fjY.mjs +1 -0
  13. package/dist/packem_shared/OfflineQueue-BuHVa8B0.mjs +1 -0
  14. package/dist/packem_shared/RETIRE_AFTER_DURABLE_SEQ_ADVANCE-DoEHtuR8.mjs +1 -0
  15. package/dist/packem_shared/SKIP-d7LeP-sY.mjs +1 -0
  16. package/dist/packem_shared/SubscriptionRegistry-CS-AFUI9.mjs +1 -0
  17. package/dist/packem_shared/TabCoordinator-CXD7vulJ.mjs +1 -0
  18. package/dist/packem_shared/anyApi-CBOws2ZA.mjs +1 -0
  19. package/dist/packem_shared/applyDelta-DwcQmRsV.mjs +1 -0
  20. package/dist/packem_shared/createAsyncStoragePersistence-CeUW9NTj.mjs +1 -0
  21. package/dist/packem_shared/createAsyncStorageQueryCache-BfZkthAE.mjs +1 -0
  22. package/dist/packem_shared/createCallRunner-Bwcrfh76.mjs +1 -0
  23. package/dist/packem_shared/createClientQuery-B8Nfj-7o.mjs +1 -0
  24. package/dist/packem_shared/createInMemoryBookmarkStorage-BooZhW0n.mjs +1 -0
  25. package/dist/packem_shared/createInMemoryPersistence-Cz2W6XVj.mjs +1 -0
  26. package/dist/packem_shared/createInMemoryQueryCache-D2uNHLfM.mjs +1 -0
  27. package/dist/packem_shared/createLocalStore-BFdXRTFz.mjs +1 -0
  28. package/dist/packem_shared/createMutatorRunner-CuMRJpUx.mjs +1 -0
  29. package/dist/packem_shared/createReconnect-CjTmjJDH.mjs +1 -0
  30. package/dist/packem_shared/createReply-CwFABEJs.mjs +1 -0
  31. package/dist/packem_shared/createServerClient-Chmnq4DL.mjs +1 -0
  32. package/dist/packem_shared/createSnapshotPrecondition-GRVKxPsh.mjs +1 -0
  33. package/dist/packem_shared/delta-merge-vxvH3PvF.mjs +1 -0
  34. package/dist/packem_shared/deserializePreloaded-C6NTQdFa.mjs +1 -0
  35. package/dist/packem_shared/function-reference.d-Br_hsKje.d.mts +45 -0
  36. package/dist/packem_shared/function-reference.d-Br_hsKje.d.ts +45 -0
  37. package/dist/packem_shared/getServerSession-BaOoo1p6.mjs +1 -0
  38. package/dist/packem_shared/httpStream-CPdblK2G.mjs +11 -0
  39. package/dist/packem_shared/idb-utility-C8WS390w.mjs +1 -0
  40. package/dist/packem_shared/local-store-BjenEm3t.mjs +1 -0
  41. package/dist/packem_shared/lunora-client.d-CGR-MObo.d.ts +4007 -0
  42. package/dist/packem_shared/lunora-client.d-qVBwKXE1.d.mts +4007 -0
  43. package/dist/packem_shared/offline-queue-DSCpAxOp.mjs +1 -0
  44. package/dist/packem_shared/preload.d-0j8xgrYf.d.mts +21 -0
  45. package/dist/packem_shared/preload.d-DTpiMCut.d.ts +21 -0
  46. package/dist/packem_shared/preloadQuery-uFy24PCR.mjs +1 -0
  47. package/dist/packem_shared/single-blob-store-DrhzObic.mjs +1 -0
  48. package/dist/packem_shared/wire-codec-Sw1rAu-Z.mjs +1 -0
  49. package/dist/packem_shared/wire-key-HsUDTlQ7.mjs +1 -0
  50. package/dist/pagination/index.d.mts +42 -42
  51. package/dist/pagination/index.d.ts +42 -42
  52. package/dist/pagination/index.mjs +1 -61
  53. package/dist/query/index.d.mts +111 -43
  54. package/dist/query/index.d.ts +111 -43
  55. package/dist/query/index.mjs +1 -1
  56. package/dist/service.d.mts +49 -0
  57. package/dist/service.d.ts +49 -0
  58. package/dist/service.mjs +1 -0
  59. package/dist/ssr/index.d.mts +109 -79
  60. package/dist/ssr/index.d.ts +109 -79
  61. package/dist/ssr/index.mjs +1 -4
  62. package/dist/upload.d.mts +35 -0
  63. package/dist/upload.d.ts +35 -0
  64. package/dist/upload.mjs +1 -0
  65. package/package.json +16 -1
  66. package/dist/packem_shared/CONFLICT_ERROR_CODE-aUdVbEDw.mjs +0 -4
  67. package/dist/packem_shared/DEFAULT_MAX_BUFFER-BDkqO5PW.mjs +0 -107
  68. package/dist/packem_shared/LunoraClient-6J-4BGWK.mjs +0 -2722
  69. package/dist/packem_shared/OfflineQueue-BI0FNNvc.mjs +0 -1
  70. package/dist/packem_shared/SKIP-vItZChkw.mjs +0 -50
  71. package/dist/packem_shared/SubscriptionRegistry-Dn-7k7eo.mjs +0 -1
  72. package/dist/packem_shared/applyDelta-4jFGTPA3.mjs +0 -61
  73. package/dist/packem_shared/createAsyncStoragePersistence-1Z5BZ8RC.mjs +0 -45
  74. package/dist/packem_shared/createInMemoryBookmarkStorage-BoN7a7TH.mjs +0 -11
  75. package/dist/packem_shared/createInMemoryPersistence-DlFjWtOm.mjs +0 -117
  76. package/dist/packem_shared/createInMemoryQueryCache-4AkTV38-.mjs +0 -150
  77. package/dist/packem_shared/createLocalStore-IOur0jHF.mjs +0 -1
  78. package/dist/packem_shared/createMutationRunner-BqsavzvG.mjs +0 -21
  79. package/dist/packem_shared/createMutatorRunner-BETvCd0p.mjs +0 -31
  80. package/dist/packem_shared/createReconnect-Di_-oHH7.mjs +0 -22
  81. package/dist/packem_shared/createServerClient-CtklXrs2.mjs +0 -11
  82. package/dist/packem_shared/deserializePreloaded-C0eJTY_W.mjs +0 -4
  83. package/dist/packem_shared/getServerSession-8jXewqxd.mjs +0 -13
  84. package/dist/packem_shared/local-store-BNgN3Dw3.mjs +0 -111
  85. package/dist/packem_shared/lunora-client.d-Dm1BYq19.d.mts +0 -2206
  86. package/dist/packem_shared/lunora-client.d-Dm1BYq19.d.ts +0 -2206
  87. package/dist/packem_shared/offline-queue-7Wc4onA0.mjs +0 -164
  88. package/dist/packem_shared/preload.d-BfWzGJWV.d.mts +0 -20
  89. package/dist/packem_shared/preload.d-Sp_Ef-_u.d.ts +0 -20
  90. package/dist/packem_shared/preloadQuery-lobFkD2Z.mjs +0 -13
  91. package/dist/packem_shared/subscription-C1Jy7HiF.mjs +0 -55
package/LICENSE.md CHANGED
@@ -103,3 +103,9 @@ Unless required by applicable law or agreed to in writing, software distributed
103
103
  under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
104
  CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
105
  specific language governing permissions and limitations under the License.
106
+
107
+ <!-- DEPENDENCIES -->
108
+ <!-- /DEPENDENCIES -->
109
+
110
+ <!-- TYPE_DEPENDENCIES -->
111
+ <!-- /TYPE_DEPENDENCIES -->
package/README.md CHANGED
@@ -34,7 +34,7 @@
34
34
 
35
35
  ---
36
36
 
37
- The framework-agnostic browser/edge SDK for Lunora. It runs RPC over HTTP and real-time deltas over a single multiplexed WebSocket, with optimistic updates, an offline mutation queue, and decorrelated-jitter reconnect built in. It is the lowest-level user-facing entry point that every framework adapter (React, Vue, Svelte, Solid) layers on top of.
37
+ The framework-agnostic browser/edge SDK for Lunora. It runs RPC over HTTP and real-time deltas over a single multiplexed WebSocket, with optimistic updates, an offline mutation queue, and exponential-backoff-with-jitter reconnect built in. It is the lowest-level user-facing entry point that every framework adapter (React, Vue, Svelte, Solid) layers on top of.
38
38
 
39
39
  Part of the [Lunora](https://github.com/anolilab/lunora) framework — a type-safe, real-time backend on Cloudflare Workers + Durable Objects with a Vite-first DX.
40
40
 
@@ -63,8 +63,21 @@ const client = new LunoraClient({ url: "https://app.acme.test" });
63
63
  // One-shot query (HTTP, carries the D1 bookmark for read-your-writes).
64
64
  const messages = await client.query(api.messages.list, { room: "general" });
65
65
 
66
- // Mutation with an optimistic update applied to matching subscribers.
67
- await client.mutation(api.messages.send, { body: "hi" }, { optimistic: (current = []) => [...current, { body: "hi", pending: true }] });
66
+ // Mutation with an optimistic update. `optimisticUpdate` names the query it
67
+ // patches a write and the queries it affects are different functions, and only
68
+ // you know which. (The per-call `optimistic` shortcut patches the subscription
69
+ // registered under the mutation's OWN reference and args, nothing else.)
70
+ await client.mutation(
71
+ api.messages.send,
72
+ { room: "general", body: "hi" },
73
+ {
74
+ optimisticUpdate: (store, args) => {
75
+ const current = store.getQuery(api.messages.list, { room: args.room }) ?? [];
76
+
77
+ store.setQuery(api.messages.list, { room: args.room }, [...current, { body: args.body, pending: true }]);
78
+ },
79
+ },
80
+ );
68
81
 
69
82
  // Live subscription over WS — returns an unsubscribe function.
70
83
  const unsubscribe = client.subscribe(api.messages.list, { room: "general" }, (next) => {
@@ -1,20 +1,44 @@
1
- import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-Dm1BYq19.mjs";
1
+ import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-qVBwKXE1.mjs";
2
+ import '@lunora/errors';
3
+ import "../packem_shared/function-reference.d-Br_hsKje.mjs";
2
4
  import '@lunora/runtime';
5
+ /**
6
+ * Resolved authentication state. See the contract table in this module's header
7
+ * — the states are not interchangeable, and `unreachable` is the one that exists
8
+ * only so "the server said no session" and "we could not ask" stop colliding.
9
+ */
10
+ type AuthStatus = "authenticated" | "loading" | "unauthenticated" | "unreachable";
11
+ /**
12
+ * Whether a gate should render its authenticated branch.
13
+ *
14
+ * Both `authenticated` and `unreachable` qualify: the credential is held in
15
+ * either case, and only the identity round-trip differs.
16
+ */
17
+ declare const isAuthenticatedStatus: (status: AuthStatus) => boolean;
18
+ /** Whether a gate should render its loading branch — the first resolve only. */
19
+ declare const isLoadingStatus: (status: AuthStatus) => boolean;
3
20
  interface IdentityStore {
4
- /** Read the current resolved user, or `null` when signed out / not yet resolved. */
21
+ /** The current {@link AuthStatus} what a gate branches on. */
22
+ getStatus: () => AuthStatus;
23
+ /**
24
+ * The last resolved user, or `null`. `null` does NOT mean signed out on its
25
+ * own: read `getStatus` for that. A user resolved before the endpoint
26
+ * went unreachable is retained, so the UI keeps rendering the identity it
27
+ * last knew instead of blanking.
28
+ */
5
29
  getUser: () => User | null;
6
30
  /**
7
- * Subscribe to identity changes. `onChange` is called whenever the user or
8
- * token changes. Returns an unsubscribe handle.
9
- */
31
+ * Subscribe to identity changes. `onChange` is called whenever the user or
32
+ * the status changes. Returns an unsubscribe handle.
33
+ */
10
34
  subscribe: (onChange: () => void) => () => void;
11
35
  }
12
36
  /**
13
- * Return the per-client identity store, creating it on first access.
14
- *
15
- * The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
16
- * and creation is idempotent — calling this multiple times with the same client
17
- * returns the same store, keeping the single-fetch / fan-out invariant.
18
- */
37
+ * Return the per-client identity store, creating it on first access.
38
+ *
39
+ * The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
40
+ * and creation is idempotent — calling this multiple times with the same client
41
+ * returns the same store, keeping the single-fetch / fan-out invariant.
42
+ */
19
43
  declare const getIdentityStore: (client: LunoraClient) => IdentityStore;
20
- export { type IdentityStore, getIdentityStore };
44
+ export { type AuthStatus, type IdentityStore, getIdentityStore, isAuthenticatedStatus, isLoadingStatus };
@@ -1,20 +1,44 @@
1
- import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-Dm1BYq19.js";
1
+ import { U as User, L as LunoraClient } from "../packem_shared/lunora-client.d-CGR-MObo.js";
2
+ import '@lunora/errors';
3
+ import "../packem_shared/function-reference.d-Br_hsKje.js";
2
4
  import '@lunora/runtime';
5
+ /**
6
+ * Resolved authentication state. See the contract table in this module's header
7
+ * — the states are not interchangeable, and `unreachable` is the one that exists
8
+ * only so "the server said no session" and "we could not ask" stop colliding.
9
+ */
10
+ type AuthStatus = "authenticated" | "loading" | "unauthenticated" | "unreachable";
11
+ /**
12
+ * Whether a gate should render its authenticated branch.
13
+ *
14
+ * Both `authenticated` and `unreachable` qualify: the credential is held in
15
+ * either case, and only the identity round-trip differs.
16
+ */
17
+ declare const isAuthenticatedStatus: (status: AuthStatus) => boolean;
18
+ /** Whether a gate should render its loading branch — the first resolve only. */
19
+ declare const isLoadingStatus: (status: AuthStatus) => boolean;
3
20
  interface IdentityStore {
4
- /** Read the current resolved user, or `null` when signed out / not yet resolved. */
21
+ /** The current {@link AuthStatus} what a gate branches on. */
22
+ getStatus: () => AuthStatus;
23
+ /**
24
+ * The last resolved user, or `null`. `null` does NOT mean signed out on its
25
+ * own: read `getStatus` for that. A user resolved before the endpoint
26
+ * went unreachable is retained, so the UI keeps rendering the identity it
27
+ * last knew instead of blanking.
28
+ */
5
29
  getUser: () => User | null;
6
30
  /**
7
- * Subscribe to identity changes. `onChange` is called whenever the user or
8
- * token changes. Returns an unsubscribe handle.
9
- */
31
+ * Subscribe to identity changes. `onChange` is called whenever the user or
32
+ * the status changes. Returns an unsubscribe handle.
33
+ */
10
34
  subscribe: (onChange: () => void) => () => void;
11
35
  }
12
36
  /**
13
- * Return the per-client identity store, creating it on first access.
14
- *
15
- * The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
16
- * and creation is idempotent — calling this multiple times with the same client
17
- * returns the same store, keeping the single-fetch / fan-out invariant.
18
- */
37
+ * Return the per-client identity store, creating it on first access.
38
+ *
39
+ * The store is cached via a `WeakMap` so it is GC'd when the client is dropped,
40
+ * and creation is idempotent — calling this multiple times with the same client
41
+ * returns the same store, keeping the single-fetch / fan-out invariant.
42
+ */
19
43
  declare const getIdentityStore: (client: LunoraClient) => IdentityStore;
20
- export { type IdentityStore, getIdentityStore };
44
+ export { type AuthStatus, type IdentityStore, getIdentityStore, isAuthenticatedStatus, isLoadingStatus };
@@ -1,60 +1 @@
1
- const stores = /* @__PURE__ */ new WeakMap();
2
- const createIdentityStore = (client) => {
3
- const listeners = /* @__PURE__ */ new Set();
4
- let user = null;
5
- let started = false;
6
- const notify = () => {
7
- for (const listener of listeners) {
8
- listener();
9
- }
10
- };
11
- let generation = 0;
12
- const setUser = (next) => {
13
- if (user !== next) {
14
- user = next;
15
- notify();
16
- }
17
- };
18
- const refresh = () => {
19
- generation += 1;
20
- const current = generation;
21
- if (client.getAuthToken() === null) {
22
- setUser(null);
23
- return;
24
- }
25
- client.getCurrentUser().then((next) => {
26
- if (current === generation) {
27
- setUser(next);
28
- }
29
- return void 0;
30
- }).catch(() => {
31
- if (current === generation) {
32
- setUser(null);
33
- }
34
- });
35
- };
36
- client.onAuthTokenChange(refresh);
37
- return {
38
- getUser: () => user,
39
- subscribe: (onChange) => {
40
- listeners.add(onChange);
41
- if (!started) {
42
- started = true;
43
- refresh();
44
- }
45
- return () => {
46
- listeners.delete(onChange);
47
- };
48
- }
49
- };
50
- };
51
- const getIdentityStore = (client) => {
52
- let store = stores.get(client);
53
- if (!store) {
54
- store = createIdentityStore(client);
55
- stores.set(client, store);
56
- }
57
- return store;
58
- };
59
-
60
- export { getIdentityStore };
1
+ const f=t=>t==="authenticated"||t==="unreachable",g=t=>t==="loading",l=new WeakMap,h=t=>{const n=new Set;let a=null,r=t.getAuthToken()===null?"unauthenticated":"loading",i=!1;const d=()=>{for(const e of n)e()};let o=0;const s=(e,u)=>{(r!==e||a!==u)&&(r=e,a=u,d())},c=()=>{o+=1;const e=o;if(t.getAuthToken()===null){s("unauthenticated",null);return}s(a===null?"loading":"authenticated",a),t.getCurrentUser().then(u=>{e===o&&s(u===null?"unauthenticated":"authenticated",u)}).catch(()=>{e===o&&s("unreachable",a)})};return t.onAuthTokenChange(c),t.onConnectionStatus(e=>{e==="connected"&&r==="unreachable"&&c()}),{getStatus:()=>r,getUser:()=>a,subscribe:e=>(n.add(e),i||(i=!0,c()),()=>{n.delete(e)})}},S=t=>{let n=l.get(t);return n||(n=h(t),l.set(t,n)),n};export{S as getIdentityStore,f as isAuthenticatedStatus,g as isLoadingStatus};