@rebasepro/client 0.12.1-canary.g389e9b2 → 0.12.1-canary.g4e7bcbf

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/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, PUBLIC_STORAGE_PREFIX, RebaseApiError, RebaseApiError as RebaseApiError$1, RebaseClientError, Vector, isPublicStoragePath, toCanonicalOp } from "@rebasepro/types";
1
+ import { DEFAULT_STORAGE_SOURCE_KEY, EntityReference, EntityRelation, GeoPoint, PUBLIC_STORAGE_PREFIX, RebaseApiError, RebaseApiError as RebaseApiError$1, RebaseClientError, RebaseClientError as RebaseClientError$1, Vector, isPublicStoragePath, toCanonicalOp } from "@rebasepro/types";
2
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
@@ -49,6 +49,38 @@ function isServerLikeEnvironment() {
49
49
  * greppable — this is the string a user will paste into a search.
50
50
  */
51
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.";
52
+ /**
53
+ * Refuse a filter whose *value* is missing.
54
+ *
55
+ * `where: { status: ["==", undefined] }` used to serialize to the literal
56
+ * string, so `status=eq.undefined` went out on the wire and the server dutifully
57
+ * looked for rows whose status is the four-letter word "undefined". The caller
58
+ * saw an empty page, not an error — the classic shape of a variable that was
59
+ * never set.
60
+ *
61
+ * Dropping the condition instead would be worse than sending it: the query
62
+ * would come back *unfiltered*, which for an ownership or tenant filter means
63
+ * returning rows the caller never asked to see. So this is a hard error, and
64
+ * both correct spellings are named in the message: omit the key to skip the
65
+ * filter, or use `["is-null", null]` to match SQL NULL (which still
66
+ * serializes — `null` is a value, `undefined` is the absence of one).
67
+ */
68
+ function assertNoUndefinedFilterValues(where) {
69
+ const reject = (field, op) => {
70
+ throw new RebaseClientError$1(`Filter on "${field}" has an undefined value (["${String(op)}", undefined]). Omit "${field}" from \`where\` to skip the filter, or use ["is-null", null] to match SQL NULL.`);
71
+ };
72
+ for (const [field, condition] of Object.entries(where)) {
73
+ if (condition === void 0) continue;
74
+ if (!Array.isArray(condition)) continue;
75
+ const tuples = Array.isArray(condition[0]) ? condition : [condition];
76
+ for (const tuple of tuples) {
77
+ if (!Array.isArray(tuple) || tuple.length !== 2) continue;
78
+ const [op, value] = tuple;
79
+ if (value === void 0) reject(field, op);
80
+ if (Array.isArray(value) && value.some((v) => v === void 0)) reject(field, op);
81
+ }
82
+ }
83
+ }
52
84
  function buildQueryString(params) {
53
85
  if (!params) return "";
54
86
  const parts = [];
@@ -67,6 +99,7 @@ function buildQueryString(params) {
67
99
  parts.push(`${root.type}=${encodeURIComponent(`(${serialized})`)}`);
68
100
  }
69
101
  if (params.where) {
102
+ assertNoUndefinedFilterValues(params.where);
70
103
  const serialized = serializeFilter(params.where);
71
104
  for (const [field, value] of Object.entries(serialized)) if (Array.isArray(value)) for (const v of value) parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(v)}`);
72
105
  else parts.push(`${encodeURIComponent(field)}=${encodeURIComponent(value)}`);
@@ -1297,7 +1330,8 @@ function createCollectionClient(transport, slug, ws) {
1297
1330
  const qs = buildQueryString({
1298
1331
  ...params,
1299
1332
  limit: void 0,
1300
- offset: void 0
1333
+ offset: void 0,
1334
+ include: void 0
1301
1335
  });
1302
1336
  return (await transport.request(basePath + "/count" + qs, { method: "GET" })).count ?? 0;
1303
1337
  },