@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 +36 -2
- package/dist/index.es.js.map +1 -1
- package/package.json +4 -4
- package/src/collection.test.ts +50 -10
- package/src/collection.ts +7 -1
- package/src/data-proxy.test.ts +22 -6
- package/src/realtime-optout.test.ts +38 -4
- package/src/transport.ts +43 -0
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
|
},
|