@rebasepro/client 0.1.2 → 0.2.3

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,53 +1 @@
1
- import { FindResponse } from "@rebasepro/types";
2
- import { CollectionClient } from "./collection";
3
- export type FilterOperator = "eq" | "neq" | "gt" | "gte" | "lt" | "lte" | "in" | "nin" | "cs" | "csa" | "==" | "!=" | ">" | ">=" | "<" | "<=" | "array-contains" | "array-contains-any" | "not-in";
4
- export declare class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> {
5
- private collection;
6
- private params;
7
- constructor(collection: CollectionClient<M>);
8
- /**
9
- * Add a filter condition to your query.
10
- * @example
11
- * client.collection('users').where('age', '>=', 18).find()
12
- */
13
- where(column: keyof M & string, operator: FilterOperator, value: unknown): this;
14
- /**
15
- * Order the results by a specific column.
16
- * @example
17
- * client.collection('users').orderBy('createdAt', 'desc').find()
18
- */
19
- orderBy(column: keyof M & string, ascending?: "asc" | "desc"): this;
20
- /**
21
- * Limit the number of results returned.
22
- */
23
- limit(count: number): this;
24
- /**
25
- * Skip the first N results.
26
- */
27
- offset(count: number): this;
28
- /**
29
- * Set a free-text search string if supported by the backend.
30
- */
31
- search(searchString: string): this;
32
- /**
33
- * Include related entities in the response.
34
- * Relations will be populated with full entity data instead of just IDs.
35
- *
36
- * @param relations - Relation names to include, or "*" for all.
37
- * @example
38
- * // Include specific relations
39
- * client.data.posts.include("tags", "author").find()
40
- *
41
- * // Include all relations
42
- * client.data.posts.include("*").find()
43
- */
44
- include(...relations: string[]): this;
45
- /**
46
- * Execute the find query and return the results.
47
- */
48
- find(): Promise<FindResponse<M>>;
49
- /**
50
- * Listen to realtime updates matching this query.
51
- */
52
- listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void;
53
- }
1
+ export { QueryBuilder } from "@rebasepro/common";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@rebasepro/client",
3
3
  "type": "module",
4
- "version": "0.1.2",
4
+ "version": "0.2.3",
5
5
  "description": "HTTP SDK client for the Rebase custom backend",
6
6
  "funding": {
7
7
  "url": "https://github.com/sponsors/rebaseco"
@@ -23,27 +23,27 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./dist/index.d.ts",
26
- "development": "./src/index.ts",
26
+ "development": "./dist/index.es.js",
27
27
  "import": "./dist/index.es.js",
28
28
  "require": "./dist/index.umd.cjs"
29
29
  },
30
30
  "./package.json": "./package.json"
31
31
  },
32
32
  "dependencies": {
33
- "@rebasepro/types": "0.1.2",
34
- "@rebasepro/utils": "0.1.2"
33
+ "@rebasepro/common": "0.2.3",
34
+ "@rebasepro/utils": "0.2.3",
35
+ "@rebasepro/types": "0.2.3"
35
36
  },
36
37
  "devDependencies": {
37
38
  "@jest/globals": "^29.7.0",
38
39
  "@types/jest": "^29.5.14",
39
- "@types/node": "^20.17.14",
40
+ "@types/node": "^20.19.41",
40
41
  "cross-env": "^7.0.3",
41
42
  "jest": "^29.7.0",
42
- "npm-run-all": "^4.1.5",
43
- "ts-jest": "^29.3.1",
43
+ "ts-jest": "^29.4.10",
44
44
  "tsd": "^0.31.2",
45
- "typescript": "^5.8.3",
46
- "vite": "^5.4.17"
45
+ "typescript": "^5.9.3",
46
+ "vite": "^5.4.21"
47
47
  },
48
48
  "files": [
49
49
  "dist",
package/src/auth.ts CHANGED
@@ -29,8 +29,8 @@ export type AuthChangeEvent = "SIGNED_IN" | "SIGNED_OUT" | "TOKEN_REFRESHED" | "
29
29
  export interface AuthConfig {
30
30
  needsSetup: boolean;
31
31
  registrationEnabled: boolean;
32
- googleEnabled: boolean;
33
32
  emailServiceEnabled: boolean;
33
+ enabledProviders: string[];
34
34
  }
35
35
 
36
36
  export interface AuthStorage {
@@ -196,23 +196,19 @@ refreshToken: session.refreshToken };
196
196
  /**
197
197
  * Sign in with Google.
198
198
  *
199
- * Supports two invocation styles:
199
+ * Supports three invocation styles:
200
200
  * - `signInWithGoogle({ idToken })` — ID-token flow (One Tap / Sign In button)
201
201
  * - `signInWithGoogle({ accessToken })` — Access-token flow (popup)
202
202
  * - `signInWithGoogle({ code, redirectUri })` — Authorization code flow (most secure)
203
- * - `signInWithGoogle(idToken)` — Legacy shorthand for ID-token flow
204
203
  */
205
204
  async function signInWithGoogle(
206
- tokenOrPayload: string | { idToken?: string; accessToken?: string; code?: string; redirectUri?: string }
205
+ payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }
207
206
  ) {
208
207
  const fetchFn = getFetch();
209
- const body = typeof tokenOrPayload === "string"
210
- ? { idToken: tokenOrPayload }
211
- : tokenOrPayload;
212
208
  const res = await fetchFn(authUrl("/google"), {
213
209
  method: "POST",
214
210
  headers: { "Content-Type": "application/json" },
215
- body: JSON.stringify(body)
211
+ body: JSON.stringify(payload)
216
212
  });
217
213
  const responseBody = await res.json().catch(() => ({}));
218
214
  if (!res.ok) throwApiError(res.status, responseBody, res.statusText);
package/src/collection.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Transport, FindParams, buildQueryString } from "./transport";
2
2
  import { RebaseWebSocketClient } from "./websocket";
3
- import { Entity, FilterValues, WhereFilterOp, CollectionAccessor, WhereFieldValue, FindResponse } from "@rebasepro/types";
3
+ import { Entity, FilterValues, WhereFilterOp, CollectionAccessor, WhereFieldValue, FindResponse, FilterOperator } from "@rebasepro/types";
4
4
 
5
- import { FilterOperator, QueryBuilder } from "./query_builder";
5
+ import { QueryBuilder } from "./query_builder";
6
6
 
7
7
  function parseWhereFilter(where?: Record<string, WhereFieldValue>): FilterValues<string> | undefined {
8
8
  if (!where) return undefined;
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ export * from "./auth";
11
11
  export * from "./admin";
12
12
  export * from "./cron";
13
13
  export * from "./collection";
14
+ export * from "./query_builder";
14
15
  export * from "./websocket";
15
16
  export * from "./storage";
16
17
  export * from "./reviver";
@@ -163,7 +164,7 @@ export function createRebaseClient<DB = Record<string, unknown>>(options: Create
163
164
  method: "POST",
164
165
  body: payload ? JSON.stringify(payload) : undefined
165
166
  });
166
- return res.data ?? (res as unknown as T);
167
+ return res.data ?? (res as T);
167
168
  },
168
169
  data: dataProxy,
169
170
  email: undefined
@@ -1,125 +1 @@
1
- import { FindParams, Entity, FindResponse } from "@rebasepro/types";
2
- import { CollectionClient } from "./collection";
3
-
4
- export type FilterOperator =
5
- | "eq" | "neq" | "gt" | "gte" | "lt" | "lte"
6
- | "in" | "nin" | "cs" | "csa"
7
- | "==" | "!=" | ">" | ">=" | "<" | "<="
8
- | "array-contains" | "array-contains-any"
9
- | "not-in";
10
-
11
- /**
12
- * Maps standard operators to Rebase backend's string-based operators
13
- */
14
- function mapOperator(op: FilterOperator): string {
15
- switch (op) {
16
- case "==": return "eq";
17
- case "!=": return "neq";
18
- case ">": return "gt";
19
- case ">=": return "gte";
20
- case "<": return "lt";
21
- case "<=": return "lte";
22
- case "array-contains": return "cs";
23
- case "array-contains-any": return "csa";
24
- case "not-in": return "nin";
25
- default: return op;
26
- }
27
- }
28
-
29
- export class QueryBuilder<M extends Record<string, unknown> = Record<string, unknown>> {
30
- private params: FindParams = { where: {} };
31
-
32
- constructor(private collection: CollectionClient<M>) {}
33
-
34
- /**
35
- * Add a filter condition to your query.
36
- * @example
37
- * client.collection('users').where('age', '>=', 18).find()
38
- */
39
- where(column: keyof M & string, operator: FilterOperator, value: unknown): this {
40
- if (!this.params.where) {
41
- this.params.where = {};
42
- }
43
-
44
- const mappedOp = mapOperator(operator);
45
- let formattedValue = value;
46
-
47
- // Handle arrays for in, nin, cs, csa
48
- if (Array.isArray(value) && ["in", "nin", "cs", "csa"].includes(mappedOp)) {
49
- formattedValue = `(${value.join(",")})`;
50
- } else if (value === null) {
51
- formattedValue = "null";
52
- }
53
-
54
- this.params.where[column] = mappedOp === "eq" ? String(formattedValue) : `${mappedOp}.${formattedValue}`;
55
- return this;
56
- }
57
-
58
- /**
59
- * Order the results by a specific column.
60
- * @example
61
- * client.collection('users').orderBy('createdAt', 'desc').find()
62
- */
63
- orderBy(column: keyof M & string, ascending: "asc" | "desc" = "asc"): this {
64
- this.params.orderBy = `${column}:${ascending}`;
65
- return this;
66
- }
67
-
68
- /**
69
- * Limit the number of results returned.
70
- */
71
- limit(count: number): this {
72
- this.params.limit = count;
73
- return this;
74
- }
75
-
76
- /**
77
- * Skip the first N results.
78
- */
79
- offset(count: number): this {
80
- this.params.offset = count;
81
- return this;
82
- }
83
-
84
- /**
85
- * Set a free-text search string if supported by the backend.
86
- */
87
- search(searchString: string): this {
88
- this.params.searchString = searchString;
89
- return this;
90
- }
91
-
92
- /**
93
- * Include related entities in the response.
94
- * Relations will be populated with full entity data instead of just IDs.
95
- *
96
- * @param relations - Relation names to include, or "*" for all.
97
- * @example
98
- * // Include specific relations
99
- * client.data.posts.include("tags", "author").find()
100
- *
101
- * // Include all relations
102
- * client.data.posts.include("*").find()
103
- */
104
- include(...relations: string[]): this {
105
- this.params.include = relations;
106
- return this;
107
- }
108
-
109
- /**
110
- * Execute the find query and return the results.
111
- */
112
- async find(): Promise<FindResponse<M>> {
113
- return this.collection.find(this.params) as Promise<FindResponse<M>>;
114
- }
115
-
116
- /**
117
- * Listen to realtime updates matching this query.
118
- */
119
- listen(onUpdate: (data: FindResponse<M>) => void, onError?: (error: Error) => void): () => void {
120
- if (!this.collection.listen) {
121
- throw new Error("Listen is only available when RebaseClient is configured with a websocketUrl.");
122
- }
123
- return this.collection.listen(this.params, onUpdate, onError);
124
- }
125
- }
1
+ export { QueryBuilder } from "@rebasepro/common";
package/src/transport.ts CHANGED
@@ -166,7 +166,7 @@ export function createTransport(config: RebaseClientConfig): Transport {
166
166
  const res = await fetchFn(url, { ...init,
167
167
  headers });
168
168
 
169
- if (res.status === 204) return undefined as unknown as T;
169
+ if (res.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body
170
170
 
171
171
  const text = await res.text().catch(() => "");
172
172
  let body: any = {};
@@ -193,7 +193,7 @@ headers });
193
193
  const retryHeaders = getHeaders(retryToken, init) as Record<string, string>;
194
194
  const retryRes = await fetchFn(url, { ...init,
195
195
  headers: retryHeaders });
196
- if (retryRes.status === 204) return undefined as unknown as T;
196
+ if (retryRes.status === 204) return undefined as T; // SAFETY: HTTP 204 No Content has no body
197
197
  const retryText = await retryRes.text().catch(() => "");
198
198
  let retryBody: any = {};
199
199
  if (retryText) {