@rebasepro/client 0.11.0 → 0.11.1-canary.g039ee17

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,42 +1,14 @@
1
1
  import type { Transport } from "./transport";
2
- /** A single permission entry scoping an API key to a collection and its allowed operations. */
3
- export interface ApiKeyPermission {
4
- collection: string;
5
- operations: ("read" | "write" | "delete")[];
6
- }
7
- /** An API key with the secret portion masked (returned by list / get / update). */
8
- export interface ApiKeyMasked {
9
- id: string;
10
- name: string;
11
- key_prefix: string;
12
- permissions: ApiKeyPermission[];
13
- admin: boolean;
14
- rate_limit: number | null;
15
- created_by: string;
16
- created_at: string;
17
- updated_at: string;
18
- last_used_at: string | null;
19
- expires_at: string | null;
20
- revoked_at: string | null;
21
- }
22
- /** An API key including the full secret (returned only on creation). */
23
- export interface ApiKeyWithSecret extends ApiKeyMasked {
24
- key: string;
25
- }
26
- /** Payload for creating a new API key. */
27
- export interface CreateApiKeyRequest {
28
- name: string;
29
- permissions: ApiKeyPermission[];
30
- rate_limit?: number | null;
31
- expires_at?: string | null;
32
- }
33
- /** Payload for updating an existing API key. */
34
- export interface UpdateApiKeyRequest {
35
- name?: string;
36
- permissions?: ApiKeyPermission[];
37
- rate_limit?: number | null;
38
- expires_at?: string | null;
39
- }
2
+ /**
3
+ * These were re-declared here, under a comment saying they lived in the server
4
+ * package rather than in `@rebasepro/types`. That stopped being true, and the
5
+ * copy drifted: it never gained `admin`, the flag that grants a key the `admin`
6
+ * role — admin routes plus the RLS `default_admin` policies — so the SDK could
7
+ * describe every kind of key except a privileged one, and
8
+ * `createKey({ …, admin: true })` was an excess-property error.
9
+ */
10
+ export type { ApiKeyPermission, ApiKeyMasked, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest } from "@rebasepro/types";
11
+ import type { ApiKeyMasked, ApiKeyWithSecret, CreateApiKeyRequest, UpdateApiKeyRequest } from "@rebasepro/types";
40
12
  /** Options for the `createApiKeys` factory. */
41
13
  export interface CreateApiKeysOptions {
42
14
  apiKeysPath?: string;
@@ -27,14 +27,8 @@ export interface FunctionsClient {
27
27
  */
28
28
  invoke<T = unknown>(name: string, payload?: unknown, options?: FunctionInvokeOptions): Promise<T>;
29
29
  }
30
- export interface FunctionInvokeOptions {
31
- /** HTTP method defaults to `"POST"`. */
32
- method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
33
- /** Sub-path appended after the function name, e.g. `"status/123"`. */
34
- path?: string;
35
- /** Extra headers merged into the request (auth is still injected automatically). */
36
- headers?: Record<string, string>;
37
- }
30
+ export type { FunctionInvokeOptions } from "@rebasepro/types";
31
+ import type { FunctionInvokeOptions } from "@rebasepro/types";
38
32
  /**
39
33
  * Create a `FunctionsClient` backed by the given transport.
40
34
  *
package/dist/index.d.ts CHANGED
@@ -15,6 +15,9 @@ export { RebaseClientError } from "./errors";
15
15
  export type { RebaseClientConfig, FindParams, FindResponse } from "./transport";
16
16
  export type { CollectionClient } from "./collection";
17
17
  export type { FindResult, SDKCollectionClient, SDKQueryBuilderInterface, PaginationMeta } from "@rebasepro/types";
18
+ export type { IterateParams, FindAllParams, PageWalkOptions, CursorSpec } from "@rebasepro/types";
19
+ export { RebasePaginationError } from "@rebasepro/common";
20
+ export type { PaginationErrorCode } from "@rebasepro/common";
18
21
  export { QueryBuilder, or, and, cond } from "@rebasepro/common";
19
22
  export { createCookieStorage, createMemoryStorage } from "./auth";
20
23
  export type { AuthConfig, AuthStorage, CookieStorageOptions, CreateAuthOptions } from "./auth";
package/dist/index.es.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, PUBLIC_STORAGE_PREFIX, RebaseApiError, RebaseApiError as RebaseApiError$1, RebaseClientError, Vector, isPublicStoragePath, toCanonicalOp } from "@rebasepro/types";
2
- import { COMPOSITE_ID_SEPARATOR, QueryBuilder, and, buildCompositeId, cond, or, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
2
+ import { COMPOSITE_ID_SEPARATOR, QueryBuilder, RebasePaginationError, and, buildCompositeId, collectAllPages, cond, or, paginateFind, serializeFilter, serializeLogicalCondition, serializeOrderBy } from "@rebasepro/common";
3
3
  import { toSnakeCase } from "@rebasepro/utils";
4
4
  //#region src/reviver.ts
5
5
  function rebaseReviver(_key, value) {
@@ -30,6 +30,25 @@ function rebaseReviver(_key, value) {
30
30
  }
31
31
  //#endregion
32
32
  //#region src/transport.ts
33
+ /**
34
+ * True when there is no browser to have signed a user in — a Node script, a
35
+ * cron job, an edge worker.
36
+ *
37
+ * Anonymous is an ordinary, correct state in a browser: before sign-in, on a
38
+ * marketing page, for public reads. Warning there would be noise that teaches
39
+ * people to ignore warnings, so the guard is off entirely. This uses the same
40
+ * `typeof window` test as {@link resolveBaseUrl}, and additionally treats a
41
+ * defined `document` as a browser so an SSR shim or test harness that installs
42
+ * only one of the two is still excluded.
43
+ */
44
+ function isServerLikeEnvironment() {
45
+ return typeof window === "undefined" && typeof document === "undefined";
46
+ }
47
+ /**
48
+ * Emitted once per client. Kept as a constant so the wording is testable and
49
+ * greppable — this is the string a user will paste into a search.
50
+ */
51
+ var ANONYMOUS_SERVER_CLIENT_WARNING = "[rebase] This client was created outside a browser with no credential — no `token`, no auth token getter, and no cookie auth flow — so every request runs as an anonymous caller. Row-level security will return only publicly readable rows, which is usually nothing and occasionally the wrong thing. Inside a cron or function handler, use the `client` you were handed instead of building a new one: its data plane is already admin-scoped. In a standalone script or job, pass the service key as `token`. If you really do want anonymous access, pass `anonymous: true` to silence this.";
33
52
  function buildQueryString(params) {
34
53
  if (!params) return "";
35
54
  const parts = [];
@@ -76,12 +95,31 @@ function resolveBaseUrl(configured) {
76
95
  if (typeof window !== "undefined" && window.location?.origin) return window.location.origin;
77
96
  return "";
78
97
  }
79
- function createTransport(config) {
98
+ function createTransport(config, environment) {
80
99
  const fetchFn = config.fetch || globalThis.fetch;
81
100
  const apiPath = config.apiPath || "/api";
82
101
  let token = config.token;
83
102
  let tokenGetter;
84
103
  let onUnauthorizedHandler = config.onUnauthorized;
104
+ /** Once per client, never per request — log spam is its own bug. */
105
+ let anonymousWarningIssued = false;
106
+ /**
107
+ * Warn a server-side caller that it built a client that can only ever be
108
+ * anonymous. Deliberately checked at the *first request* rather than at
109
+ * construction: `setToken()` / `setAuthTokenGetter()` and a server-side
110
+ * `auth.signIn…()` (which calls `transport.setToken`) all land after the
111
+ * constructor, and warning at construction would fire on every one of them.
112
+ */
113
+ function warnIfAnonymousServerClient(activeToken) {
114
+ if (anonymousWarningIssued) return;
115
+ if (activeToken) return;
116
+ if (tokenGetter) return;
117
+ if (config.anonymous) return;
118
+ if (environment?.credentialOutOfBand) return;
119
+ if (!isServerLikeEnvironment()) return;
120
+ anonymousWarningIssued = true;
121
+ console.warn(ANONYMOUS_SERVER_CLIENT_WARNING);
122
+ }
85
123
  function getHeaders(activeToken, init) {
86
124
  return {
87
125
  "Content-Type": "application/json",
@@ -96,6 +134,7 @@ function createTransport(config) {
96
134
  const fetched = await tokenGetter();
97
135
  if (fetched !== null && fetched !== void 0) activeToken = fetched;
98
136
  } catch (e) {}
137
+ warnIfAnonymousServerClient(activeToken);
99
138
  const headers = getHeaders(activeToken, init);
100
139
  if (init?.body instanceof FormData) delete headers["Content-Type"];
101
140
  const res = await fetchFn(url, {
@@ -1184,6 +1223,12 @@ function createCollectionClient(transport, slug, ws) {
1184
1223
  meta: raw.meta
1185
1224
  };
1186
1225
  },
1226
+ iterate(params) {
1227
+ return paginateFind((p) => client.find(p), params, slug);
1228
+ },
1229
+ findAll(params) {
1230
+ return collectAllPages((p) => client.find(p), params, slug);
1231
+ },
1187
1232
  async findById(id) {
1188
1233
  try {
1189
1234
  const raw = await transport.request(`${basePath}/${encodeURIComponent(String(id))}`, { method: "GET" });
@@ -4008,6 +4053,8 @@ var OfflineManager = class {
4008
4053
  meta: answer.meta
4009
4054
  };
4010
4055
  },
4056
+ iterate: (params) => paginateFind((p) => wrapped.find(p), params, slug),
4057
+ findAll: (params) => collectAllPages((p) => wrapped.find(p), params, slug),
4011
4058
  findById: async (id) => {
4012
4059
  await this.ensureCollection(slug);
4013
4060
  if (this.connectivity.shouldAttempt()) try {
@@ -5077,7 +5124,7 @@ function deriveWebSocketUrl(baseUrl) {
5077
5124
  return baseUrl.replace(/^https?:\/\//i, (match) => match.toLowerCase() === "https://" ? "wss://" : "ws://").replace(/\/$/, "");
5078
5125
  }
5079
5126
  function createRebaseClient(options) {
5080
- const transport = createTransport(options);
5127
+ const transport = createTransport(options, { credentialOutOfBand: options.auth?.authFlowMode === "cookie" });
5081
5128
  const auth = createAuth(transport, options.auth);
5082
5129
  const admin = createAdmin(transport, options.admin);
5083
5130
  const cron = createCron(transport, options.cron);
@@ -5262,6 +5309,6 @@ channel: (name, options) => {
5262
5309
  };
5263
5310
  }
5264
5311
  //#endregion
5265
- export { MemoryOfflineStore, QueryBuilder, RebaseApiError, RebaseClientError, RebaseRealtimeChannel, RebaseWebSocketClient, and, cond, createBackups, createCookieStorage, createMemoryStorage, createRebaseClient, isOfflineError, or };
5312
+ export { MemoryOfflineStore, QueryBuilder, RebaseApiError, RebaseClientError, RebasePaginationError, RebaseRealtimeChannel, RebaseWebSocketClient, and, cond, createBackups, createCookieStorage, createMemoryStorage, createRebaseClient, isOfflineError, or };
5266
5313
 
5267
5314
  //# sourceMappingURL=index.es.js.map