@rebasepro/client 0.0.1-canary.f81da60 → 0.1.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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/client",
3
3
  "type": "module",
4
- "version": "0.0.1-canary.f81da60",
4
+ "version": "0.1.2",
5
5
  "description": "HTTP SDK client for the Rebase custom backend",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -30,8 +30,8 @@
30
30
  "./package.json": "./package.json"
31
31
  },
32
32
  "dependencies": {
33
- "@rebasepro/types": "0.0.1-canary.f81da60",
34
- "@rebasepro/utils": "0.0.1-canary.f81da60"
33
+ "@rebasepro/types": "0.1.2",
34
+ "@rebasepro/utils": "0.1.2"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@jest/globals": "^29.7.0",
package/src/auth.ts CHANGED
@@ -193,19 +193,31 @@ accessToken: session.accessToken,
193
193
  refreshToken: session.refreshToken };
194
194
  }
195
195
 
196
- async function signInWithGoogle(idToken: string) {
196
+ /**
197
+ * Sign in with Google.
198
+ *
199
+ * Supports two invocation styles:
200
+ * - `signInWithGoogle({ idToken })` — ID-token flow (One Tap / Sign In button)
201
+ * - `signInWithGoogle({ accessToken })` — Access-token flow (popup)
202
+ * - `signInWithGoogle({ code, redirectUri })` — Authorization code flow (most secure)
203
+ * - `signInWithGoogle(idToken)` — Legacy shorthand for ID-token flow
204
+ */
205
+ async function signInWithGoogle(
206
+ tokenOrPayload: string | { idToken?: string; accessToken?: string; code?: string; redirectUri?: string }
207
+ ) {
197
208
  const fetchFn = getFetch();
209
+ const body = typeof tokenOrPayload === "string"
210
+ ? { idToken: tokenOrPayload }
211
+ : tokenOrPayload;
198
212
  const res = await fetchFn(authUrl("/google"), {
199
213
  method: "POST",
200
214
  headers: { "Content-Type": "application/json" },
201
- body: JSON.stringify({ idToken })
215
+ body: JSON.stringify(body)
202
216
  });
203
- const body = await res.json().catch(() => ({}));
204
- if (!res.ok) throwApiError(res.status, body, res.statusText);
205
- const session = handleAuthResponse(body, "SIGNED_IN");
206
- return { user: session.user,
207
- accessToken: session.accessToken,
208
- refreshToken: session.refreshToken };
217
+ const responseBody = await res.json().catch(() => ({}));
218
+ if (!res.ok) throwApiError(res.status, responseBody, res.statusText);
219
+ const session = handleAuthResponse(responseBody, "SIGNED_IN");
220
+ return { user: session.user, accessToken: session.accessToken, refreshToken: session.refreshToken };
209
221
  }
210
222
 
211
223
  async function signInWithLinkedin(code: string, redirectUri: string) {
@@ -0,0 +1,80 @@
1
+ import type { Transport } from "./transport";
2
+
3
+ /**
4
+ * Client interface for invoking custom backend functions.
5
+ *
6
+ * Custom functions are Hono route files auto-mounted by the Rebase backend
7
+ * at `/api/functions/{name}`. The `FunctionsClient` wraps the shared
8
+ * transport so callers never need to manually construct URLs or inject
9
+ * auth tokens.
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const result = await client.functions.invoke<{ job: Job }>('extract-job', {
14
+ * url: 'https://example.com/posting',
15
+ * html: htmlContent,
16
+ * });
17
+ * ```
18
+ */
19
+ export interface FunctionsClient {
20
+ /**
21
+ * Invoke a custom backend function by name.
22
+ *
23
+ * @typeParam T - Expected shape of the response payload.
24
+ * @param name - Function name (the filename without extension, e.g. `"extract-job"`).
25
+ * @param payload - Optional JSON-serialisable body sent as `POST`.
26
+ * @param options - Optional overrides (HTTP method, sub-path, extra headers).
27
+ * @returns The parsed JSON response from the function.
28
+ */
29
+ invoke<T = unknown>(
30
+ name: string,
31
+ payload?: unknown,
32
+ options?: FunctionInvokeOptions,
33
+ ): Promise<T>;
34
+ }
35
+
36
+ export interface FunctionInvokeOptions {
37
+ /** HTTP method — defaults to `"POST"`. */
38
+ method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
39
+ /** Sub-path appended after the function name, e.g. `"status/123"`. */
40
+ path?: string;
41
+ /** Extra headers merged into the request (auth is still injected automatically). */
42
+ headers?: Record<string, string>;
43
+ }
44
+
45
+ /**
46
+ * Create a `FunctionsClient` backed by the given transport.
47
+ *
48
+ * The transport already handles:
49
+ * - Base URL resolution
50
+ * - JWT injection via `Authorization: Bearer`
51
+ * - 401 retry / `onUnauthorized` flow
52
+ * - Consistent error throwing via `RebaseApiError`
53
+ *
54
+ * @internal
55
+ */
56
+ export function createFunctionsClient(transport: Transport): FunctionsClient {
57
+ return {
58
+ async invoke<T = unknown>(
59
+ name: string,
60
+ payload?: unknown,
61
+ options?: FunctionInvokeOptions,
62
+ ): Promise<T> {
63
+ const method = options?.method ?? "POST";
64
+ const subPath = options?.path ? `/${options.path.replace(/^\//, "")}` : "";
65
+ const routePath = `/functions/${encodeURIComponent(name)}${subPath}`;
66
+
67
+ const init: RequestInit = { method };
68
+
69
+ if (payload !== undefined && method !== "GET") {
70
+ init.body = JSON.stringify(payload);
71
+ }
72
+
73
+ if (options?.headers) {
74
+ init.headers = options.headers;
75
+ }
76
+
77
+ return transport.request<T>(routePath, init);
78
+ },
79
+ };
80
+ }
package/src/index.ts CHANGED
@@ -3,6 +3,8 @@ import { createAuth, CreateAuthOptions } from "./auth";
3
3
  import { createAdmin, CreateAdminOptions } from "./admin";
4
4
  import { createCron, CreateCronOptions } from "./cron";
5
5
  import { createCollectionClient, CollectionClient } from "./collection";
6
+ import { createFunctionsClient } from "./functions";
7
+ import type { FunctionsClient } from "./functions";
6
8
 
7
9
  export * from "./transport";
8
10
  export * from "./auth";
@@ -12,6 +14,7 @@ export * from "./collection";
12
14
  export * from "./websocket";
13
15
  export * from "./storage";
14
16
  export * from "./reviver";
17
+ export * from "./functions";
15
18
 
16
19
  export interface CreateRebaseClientOptions extends RebaseClientConfig {
17
20
  auth?: CreateAuthOptions;
@@ -31,6 +34,7 @@ export type RebaseClient<DB = Record<string, unknown>> = BaseRebaseClient<DB> &
31
34
  auth: ReturnType<typeof createAuth>;
32
35
  admin: ReturnType<typeof createAdmin>;
33
36
  cron: ReturnType<typeof createCron>;
37
+ functions: FunctionsClient;
34
38
  ws?: RebaseWebSocketClient;
35
39
  storage?: StorageSource;
36
40
  call: <T = unknown>(endpoint: string, payload?: unknown) => Promise<T>;
@@ -72,6 +76,7 @@ export function createRebaseClient<DB = Record<string, unknown>>(options: Create
72
76
  const admin = createAdmin(transport, options.admin);
73
77
  const cron = createCron(transport, options.cron);
74
78
  const storage = createStorage(transport);
79
+ const functions = createFunctionsClient(transport);
75
80
 
76
81
  const resolvedWsUrl = options.websocketUrl ?? deriveWebSocketUrl(options.baseUrl);
77
82
 
@@ -143,6 +148,7 @@ export function createRebaseClient<DB = Record<string, unknown>>(options: Create
143
148
  auth,
144
149
  admin,
145
150
  cron,
151
+ functions,
146
152
  storage,
147
153
  ws,
148
154
  setToken: transport.setToken,
package/src/websocket.ts CHANGED
@@ -195,11 +195,13 @@ export class RebaseWebSocketClient {
195
195
  if (!this.ws) return; // Prevent memory leaks / actions after disconnect
196
196
  if (token) {
197
197
  this.authenticate(token).catch(e => {
198
- if (this.ws) console.warn("WebSocket auto-auth failed:", e);
198
+ if (this.ws) console.debug("WebSocket auto-auth skipped:", e?.message || e);
199
199
  });
200
200
  }
201
201
  }).catch(e => {
202
- if (this.ws) console.warn("WebSocket auto-auth failed:", e);
202
+ // User not logged in or auth still loading — this is expected,
203
+ // the WebSocket will authenticate on-demand when a request is made.
204
+ if (this.ws) console.debug("WebSocket auto-auth skipped:", e?.message || e);
203
205
  });
204
206
  }
205
207
  }
@@ -244,7 +246,9 @@ export class RebaseWebSocketClient {
244
246
  console.debug("WebSocket auto-authenticated");
245
247
  }
246
248
  } catch (error) {
247
- console.warn("WebSocket auto-auth failed, requests may fail:", error);
249
+ // User not logged in or auth still loading this is expected.
250
+ // Authentication will happen on-demand when the user logs in.
251
+ console.debug("WebSocket connected without auth:", (error as Error)?.message || error);
248
252
  }
249
253
  }
250
254