@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/dist/auth.d.ts +6 -1
- package/dist/functions.d.ts +49 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.es.js +30 -13
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +30 -13
- package/dist/index.umd.js.map +1 -1
- package/package.json +3 -3
- package/src/auth.ts +20 -8
- package/src/functions.ts +80 -0
- package/src/index.ts +6 -0
- package/src/websocket.ts +7 -3
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/client",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
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.
|
|
34
|
-
"@rebasepro/utils": "0.
|
|
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
|
-
|
|
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(
|
|
215
|
+
body: JSON.stringify(body)
|
|
202
216
|
});
|
|
203
|
-
const
|
|
204
|
-
if (!res.ok) throwApiError(res.status,
|
|
205
|
-
const session = handleAuthResponse(
|
|
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) {
|
package/src/functions.ts
ADDED
|
@@ -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.
|
|
198
|
+
if (this.ws) console.debug("WebSocket auto-auth skipped:", e?.message || e);
|
|
199
199
|
});
|
|
200
200
|
}
|
|
201
201
|
}).catch(e => {
|
|
202
|
-
|
|
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
|
-
|
|
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
|
|