@lunora/react-native 0.0.0 → 1.0.0-alpha.2

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.
@@ -0,0 +1,35 @@
1
+ export { expoClient, setupExpoFocusManager, setupExpoOnlineManager } from '@better-auth/expo/client';
2
+ /**
3
+ * Read the current better-auth session token from an Expo auth client, for use
4
+ * as a **bearer** credential on the Lunora client — `client.setAuthToken(token)`
5
+ * for HTTP RPC and `client.setWsToken(token ?? undefined)` for the live socket.
6
+ *
7
+ * The Expo plugin persists the session as a cookie in `SecureStore`;
8
+ * `getCookie()` exposes it, and this pulls the `session_token` value out.
9
+ * better-auth's `bearer` plugin accepts that value verbatim in the
10
+ * `Authorization` header — so the native client authenticates WITHOUT sending a
11
+ * `Cookie`, which the runtime's CSRF guard rejects on an `Origin`-less native
12
+ * request (React Native sends no `Origin`). Returns `null` when signed out.
13
+ *
14
+ * Re-run it whenever the session changes and feed the result to the client (see
15
+ * the package README):
16
+ *
17
+ * ```ts
18
+ * const token = expoBearerToken(authClient);
19
+ * client.setAuthToken(token);
20
+ * client.setWsToken(token ?? undefined);
21
+ * ```
22
+ */
23
+ declare const expoBearerToken: (authClient: {
24
+ getCookie: () => string;
25
+ }) => null | string;
26
+ /**
27
+ * The slice of a key/value store the better-auth Expo plugin needs — the shape
28
+ * of `expo-secure-store` (a synchronous `getItem`, plus `setItem`). Pass Expo
29
+ * `SecureStore` straight in.
30
+ */
31
+ interface SecureStorageLike {
32
+ getItem: (key: string) => null | string;
33
+ setItem: (key: string, value: string) => unknown;
34
+ }
35
+ export { SecureStorageLike, expoBearerToken };
package/dist/auth.d.ts ADDED
@@ -0,0 +1,35 @@
1
+ export { expoClient, setupExpoFocusManager, setupExpoOnlineManager } from '@better-auth/expo/client';
2
+ /**
3
+ * Read the current better-auth session token from an Expo auth client, for use
4
+ * as a **bearer** credential on the Lunora client — `client.setAuthToken(token)`
5
+ * for HTTP RPC and `client.setWsToken(token ?? undefined)` for the live socket.
6
+ *
7
+ * The Expo plugin persists the session as a cookie in `SecureStore`;
8
+ * `getCookie()` exposes it, and this pulls the `session_token` value out.
9
+ * better-auth's `bearer` plugin accepts that value verbatim in the
10
+ * `Authorization` header — so the native client authenticates WITHOUT sending a
11
+ * `Cookie`, which the runtime's CSRF guard rejects on an `Origin`-less native
12
+ * request (React Native sends no `Origin`). Returns `null` when signed out.
13
+ *
14
+ * Re-run it whenever the session changes and feed the result to the client (see
15
+ * the package README):
16
+ *
17
+ * ```ts
18
+ * const token = expoBearerToken(authClient);
19
+ * client.setAuthToken(token);
20
+ * client.setWsToken(token ?? undefined);
21
+ * ```
22
+ */
23
+ declare const expoBearerToken: (authClient: {
24
+ getCookie: () => string;
25
+ }) => null | string;
26
+ /**
27
+ * The slice of a key/value store the better-auth Expo plugin needs — the shape
28
+ * of `expo-secure-store` (a synchronous `getItem`, plus `setItem`). Pass Expo
29
+ * `SecureStore` straight in.
30
+ */
31
+ interface SecureStorageLike {
32
+ getItem: (key: string) => null | string;
33
+ setItem: (key: string, value: string) => unknown;
34
+ }
35
+ export { SecureStorageLike, expoBearerToken };
package/dist/auth.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export { default as expoBearerToken } from './packem_shared/expoBearerToken-B0Zorz--.mjs';
2
+ export { expoClient, setupExpoFocusManager, setupExpoOnlineManager } from '@better-auth/expo/client';
@@ -0,0 +1,75 @@
1
+ import { AsyncStorageLike, LunoraClientOptions, LunoraClient } from '@lunora/client';
2
+ export * from '@lunora/react';
3
+ /**
4
+ * A `() => headers` factory the React Native client threads onto every HTTP RPC
5
+ * request *and* the WebSocket upgrade — a generic escape hatch for attaching a
6
+ * **custom** credential header (an API-gateway key, a proxy token, …) that
7
+ * React Native's missing cookie jar can't carry implicitly. Return `undefined`
8
+ * (or an empty object) when there's nothing to attach.
9
+ *
10
+ * For better-auth Expo sessions, prefer a **bearer** token instead: read it with
11
+ * `@lunora/react-native/auth`'s `expoBearerToken` and feed it to
12
+ * `client.setAuthToken` / `setWsToken` (see the package README). A bearer avoids
13
+ * the `Cookie` header the runtime's CSRF guard rejects on `Origin`-less native
14
+ * requests.
15
+ */
16
+ type AuthHeadersFactory = () => Record<string, string> | undefined;
17
+ /**
18
+ * Options for `createLunoraClient` — the React Native / Expo counterpart to
19
+ * constructing a `LunoraClient` directly. It is `LunoraClientOptions` with two
20
+ * React-Native-shaped conveniences layered on. `storage` wires the
21
+ * AsyncStorage-backed offline-queue persistence for you (the browser default
22
+ * auto-probes IndexedDB, which React Native lacks, so without this the queue
23
+ * stays in memory and is lost on reload). `getAuthHeaders` is a generic escape
24
+ * hatch for a custom credential header on both the HTTP RPC path and the
25
+ * WebSocket upgrade; for better-auth sessions prefer a bearer token
26
+ * (`expoBearerToken` + the client's `setAuthToken` / `setWsToken`).
27
+ *
28
+ * The `persistence`, `fetch`, and `WebSocket` fields of `LunoraClientOptions`
29
+ * are still accepted and take precedence when you need full control; the two
30
+ * conveniences are sugar over exactly those seams.
31
+ */
32
+ interface CreateLunoraClientOptions extends LunoraClientOptions {
33
+ /**
34
+ * Attaches a credential to every HTTP RPC request and to the WebSocket
35
+ * upgrade request. See `AuthHeadersFactory`. When omitted, requests go out
36
+ * with only whatever `LunoraClient` already sets (its bearer token from
37
+ * `setAuthToken`, if any).
38
+ *
39
+ * Merged UNDER the client's own headers on the HTTP path (an explicit
40
+ * `setAuthToken` bearer wins over a same-named header here); applied to the
41
+ * WebSocket upgrade via a wrapping `WebSocket`, since the socket has no other
42
+ * way to carry credentials in React Native.
43
+ */
44
+ getAuthHeaders?: AuthHeadersFactory;
45
+ /**
46
+ * React Native `AsyncStorage` (or any async key/value store with the same
47
+ * `getItem`/`setItem`/`removeItem` surface — Expo `SecureStore`, an in-memory
48
+ * map in tests). When supplied, the offline mutation queue is persisted here
49
+ * via `createAsyncStoragePersistence`, so writes made offline survive an app
50
+ * restart. Ignored when an explicit `persistence` is passed.
51
+ */
52
+ storage?: AsyncStorageLike;
53
+ }
54
+ /**
55
+ * Construct a `LunoraClient` tuned for React Native / Expo — a thin wrapper over
56
+ * `new LunoraClient(options)` that fills in the two things a browser gets for
57
+ * free but React Native does not.
58
+ *
59
+ * First, a durable offline queue: pass `storage` (React Native `AsyncStorage`,
60
+ * or any async key/value store) and the offline mutation queue is persisted
61
+ * through `createAsyncStoragePersistence` — the browser default auto-probes
62
+ * IndexedDB, which React Native lacks, so without this the queue lives only in
63
+ * memory and is lost on reload.
64
+ *
65
+ * Second, credentialed requests: pass `getAuthHeaders` and the returned headers
66
+ * ride both the HTTP RPC path and the WebSocket upgrade, since React Native has
67
+ * no cookie jar to attach a session implicitly.
68
+ *
69
+ * Everything on `LunoraClientOptions` is still accepted and passed through; an
70
+ * explicit `persistence`, `fetch`, or `WebSocket` takes precedence over the
71
+ * convenience derived from `storage` / `getAuthHeaders`. See the package README
72
+ * for a full setup example.
73
+ */
74
+ declare const createLunoraClient: (options: CreateLunoraClientOptions) => LunoraClient;
75
+ export { type AuthHeadersFactory, type CreateLunoraClientOptions, createLunoraClient };
@@ -0,0 +1,75 @@
1
+ import { AsyncStorageLike, LunoraClientOptions, LunoraClient } from '@lunora/client';
2
+ export * from '@lunora/react';
3
+ /**
4
+ * A `() => headers` factory the React Native client threads onto every HTTP RPC
5
+ * request *and* the WebSocket upgrade — a generic escape hatch for attaching a
6
+ * **custom** credential header (an API-gateway key, a proxy token, …) that
7
+ * React Native's missing cookie jar can't carry implicitly. Return `undefined`
8
+ * (or an empty object) when there's nothing to attach.
9
+ *
10
+ * For better-auth Expo sessions, prefer a **bearer** token instead: read it with
11
+ * `@lunora/react-native/auth`'s `expoBearerToken` and feed it to
12
+ * `client.setAuthToken` / `setWsToken` (see the package README). A bearer avoids
13
+ * the `Cookie` header the runtime's CSRF guard rejects on `Origin`-less native
14
+ * requests.
15
+ */
16
+ type AuthHeadersFactory = () => Record<string, string> | undefined;
17
+ /**
18
+ * Options for `createLunoraClient` — the React Native / Expo counterpart to
19
+ * constructing a `LunoraClient` directly. It is `LunoraClientOptions` with two
20
+ * React-Native-shaped conveniences layered on. `storage` wires the
21
+ * AsyncStorage-backed offline-queue persistence for you (the browser default
22
+ * auto-probes IndexedDB, which React Native lacks, so without this the queue
23
+ * stays in memory and is lost on reload). `getAuthHeaders` is a generic escape
24
+ * hatch for a custom credential header on both the HTTP RPC path and the
25
+ * WebSocket upgrade; for better-auth sessions prefer a bearer token
26
+ * (`expoBearerToken` + the client's `setAuthToken` / `setWsToken`).
27
+ *
28
+ * The `persistence`, `fetch`, and `WebSocket` fields of `LunoraClientOptions`
29
+ * are still accepted and take precedence when you need full control; the two
30
+ * conveniences are sugar over exactly those seams.
31
+ */
32
+ interface CreateLunoraClientOptions extends LunoraClientOptions {
33
+ /**
34
+ * Attaches a credential to every HTTP RPC request and to the WebSocket
35
+ * upgrade request. See `AuthHeadersFactory`. When omitted, requests go out
36
+ * with only whatever `LunoraClient` already sets (its bearer token from
37
+ * `setAuthToken`, if any).
38
+ *
39
+ * Merged UNDER the client's own headers on the HTTP path (an explicit
40
+ * `setAuthToken` bearer wins over a same-named header here); applied to the
41
+ * WebSocket upgrade via a wrapping `WebSocket`, since the socket has no other
42
+ * way to carry credentials in React Native.
43
+ */
44
+ getAuthHeaders?: AuthHeadersFactory;
45
+ /**
46
+ * React Native `AsyncStorage` (or any async key/value store with the same
47
+ * `getItem`/`setItem`/`removeItem` surface — Expo `SecureStore`, an in-memory
48
+ * map in tests). When supplied, the offline mutation queue is persisted here
49
+ * via `createAsyncStoragePersistence`, so writes made offline survive an app
50
+ * restart. Ignored when an explicit `persistence` is passed.
51
+ */
52
+ storage?: AsyncStorageLike;
53
+ }
54
+ /**
55
+ * Construct a `LunoraClient` tuned for React Native / Expo — a thin wrapper over
56
+ * `new LunoraClient(options)` that fills in the two things a browser gets for
57
+ * free but React Native does not.
58
+ *
59
+ * First, a durable offline queue: pass `storage` (React Native `AsyncStorage`,
60
+ * or any async key/value store) and the offline mutation queue is persisted
61
+ * through `createAsyncStoragePersistence` — the browser default auto-probes
62
+ * IndexedDB, which React Native lacks, so without this the queue lives only in
63
+ * memory and is lost on reload.
64
+ *
65
+ * Second, credentialed requests: pass `getAuthHeaders` and the returned headers
66
+ * ride both the HTTP RPC path and the WebSocket upgrade, since React Native has
67
+ * no cookie jar to attach a session implicitly.
68
+ *
69
+ * Everything on `LunoraClientOptions` is still accepted and passed through; an
70
+ * explicit `persistence`, `fetch`, or `WebSocket` takes precedence over the
71
+ * convenience derived from `storage` / `getAuthHeaders`. See the package README
72
+ * for a full setup example.
73
+ */
74
+ declare const createLunoraClient: (options: CreateLunoraClientOptions) => LunoraClient;
75
+ export { type AuthHeadersFactory, type CreateLunoraClientOptions, createLunoraClient };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export { createLunoraClient } from './packem_shared/createLunoraClient-D9i-IKbc.mjs';
2
+ export * from '@lunora/react';
@@ -0,0 +1,36 @@
1
+ import { LunoraClient, createAsyncStoragePersistence } from '@lunora/client';
2
+
3
+ const withAuthHeaders = (fetchImpl, getAuthHeaders) => (input, init) => {
4
+ const extra = getAuthHeaders();
5
+ if (!extra) {
6
+ return fetchImpl(input, init);
7
+ }
8
+ const merged = new Headers(extra);
9
+ if (init?.headers) {
10
+ new Headers(init.headers).forEach((value, key) => {
11
+ merged.set(key, value);
12
+ });
13
+ }
14
+ return fetchImpl(input, { ...init, headers: merged });
15
+ };
16
+ const withAuthWebSocket = (WebSocketImpl, getAuthHeaders) => class AuthWebSocket extends WebSocketImpl {
17
+ constructor(url, protocols) {
18
+ const headers = getAuthHeaders();
19
+ super(url, protocols, headers ? { headers } : void 0);
20
+ }
21
+ };
22
+ const createLunoraClient = (options) => {
23
+ const { getAuthHeaders, storage, ...rest } = options;
24
+ const authedFetch = getAuthHeaders && rest.fetch === void 0 && typeof fetch === "function" ? withAuthHeaders(fetch.bind(globalThis), getAuthHeaders) : rest.fetch;
25
+ const authedWebSocket = getAuthHeaders && rest.WebSocket === void 0 && typeof WebSocket === "function" ? withAuthWebSocket(WebSocket, getAuthHeaders) : rest.WebSocket;
26
+ return new LunoraClient({
27
+ ...rest,
28
+ // Auto-wire AsyncStorage persistence unless the caller passed an explicit
29
+ // `persistence` (including `false` to opt out).
30
+ persistence: rest.persistence ?? (storage ? createAsyncStoragePersistence({ storage }) : void 0),
31
+ fetch: authedFetch,
32
+ WebSocket: authedWebSocket
33
+ });
34
+ };
35
+
36
+ export { createLunoraClient, withAuthHeaders, withAuthWebSocket };
@@ -0,0 +1,7 @@
1
+ const SESSION_TOKEN_COOKIE = /(?:^|;)[^;=]*session_token=([^;]+)/;
2
+ const expoBearerToken = (authClient) => {
3
+ const match = SESSION_TOKEN_COOKIE.exec(authClient.getCookie());
4
+ return match?.[1] ?? null;
5
+ };
6
+
7
+ export { expoBearerToken as default };
package/package.json CHANGED
@@ -1,10 +1,73 @@
1
1
  {
2
2
  "name": "@lunora/react-native",
3
- "version": "0.0.0",
4
- "description": "OIDC trusted publishing setup package for @lunora/react-native",
3
+ "version": "1.0.0-alpha.2",
4
+ "description": "React Native / Expo integration for Lunora: an AsyncStorage-backed client factory, the useQuery/useMutation/useSubscription hooks, and a one-call better-auth Expo client",
5
5
  "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
10
- }
6
+ "cloudflare",
7
+ "durable-objects",
8
+ "expo",
9
+ "hooks",
10
+ "lunora",
11
+ "react-native",
12
+ "realtime",
13
+ "usequery",
14
+ "workers"
15
+ ],
16
+ "homepage": "https://lunora.sh",
17
+ "bugs": "https://github.com/anolilab/lunora/issues",
18
+ "license": "FSL-1.1-Apache-2.0",
19
+ "author": {
20
+ "name": "Daniel Bannert",
21
+ "email": "d.bannert@anolilab.de"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/anolilab/lunora.git",
26
+ "directory": "packages/react-native"
27
+ },
28
+ "files": [
29
+ "./dist",
30
+ "README.md",
31
+ "LICENSE.md",
32
+ "__assets__"
33
+ ],
34
+ "type": "module",
35
+ "sideEffects": false,
36
+ "module": "./dist/index.mjs",
37
+ "types": "./dist/index.d.ts",
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.mjs"
42
+ },
43
+ "./auth": {
44
+ "types": "./dist/auth.d.ts",
45
+ "import": "./dist/auth.mjs"
46
+ },
47
+ "./package.json": "./package.json"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ },
52
+ "dependencies": {
53
+ "@lunora/client": "1.0.0-alpha.21",
54
+ "@lunora/react": "1.0.0-alpha.25"
55
+ },
56
+ "peerDependencies": {
57
+ "@better-auth/expo": "^1.6.23",
58
+ "@tanstack/react-query": "^5.101.0",
59
+ "better-auth": "^1.6.23",
60
+ "react": "^19.2.7"
61
+ },
62
+ "peerDependenciesMeta": {
63
+ "@better-auth/expo": {
64
+ "optional": true
65
+ },
66
+ "better-auth": {
67
+ "optional": true
68
+ }
69
+ },
70
+ "engines": {
71
+ "node": "^22.15.0 || >=24.11.0"
72
+ }
73
+ }