@rebasepro/server 0.13.0 → 0.13.1-canary.g18cfeb7

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.
Files changed (53) hide show
  1. package/dist/{admin_block-CcSGdH7M.js → admin_block-CLeUMG8G.js} +3 -1
  2. package/dist/admin_block-CLeUMG8G.js.map +1 -0
  3. package/dist/api/errors.d.ts +0 -6
  4. package/dist/api/openapi-generator.d.ts +14 -0
  5. package/dist/api/rest/idempotency.d.ts +41 -4
  6. package/dist/api/rest/write-validation.d.ts +12 -5
  7. package/dist/auth/index.d.ts +1 -1
  8. package/dist/auth/jwt.d.ts +12 -0
  9. package/dist/{auth-CuC9M2x6.js → auth-CtxXQYV_.js} +20 -39
  10. package/dist/auth-CtxXQYV_.js.map +1 -0
  11. package/dist/{backup-CVggVhR2.js → backup-BJiY_mM-.js} +2 -2
  12. package/dist/{backup-CVggVhR2.js.map → backup-BJiY_mM-.js.map} +1 -1
  13. package/dist/boot/boot.d.ts +19 -0
  14. package/dist/{contract-routes-Dj8i5AiM.js → contract-routes-FSt0Nyfk.js} +2 -2
  15. package/dist/{contract-routes-Dj8i5AiM.js.map → contract-routes-FSt0Nyfk.js.map} +1 -1
  16. package/dist/cron/cron-scheduler.d.ts +8 -3
  17. package/dist/cron/define-cron.d.ts +5 -3
  18. package/dist/{cron-routes-CrQ0tK-_.js → cron-routes-D5a9v1HY.js} +2 -2
  19. package/dist/{cron-routes-CrQ0tK-_.js.map → cron-routes-D5a9v1HY.js.map} +1 -1
  20. package/dist/{cron-scheduler-B3RFt0HS.js → cron-scheduler-CsQtYLMq.js} +28 -3
  21. package/dist/cron-scheduler-CsQtYLMq.js.map +1 -0
  22. package/dist/{cron-store-BywZsyfZ.js → cron-store-CHH7zrif.js} +16 -3
  23. package/dist/cron-store-CHH7zrif.js.map +1 -0
  24. package/dist/{errors-CgkCzoj7.js → errors-BpudWAVU.js} +2 -10
  25. package/dist/errors-BpudWAVU.js.map +1 -0
  26. package/dist/functions/define-function.d.ts +1 -1
  27. package/dist/index.es.js +673 -232
  28. package/dist/index.es.js.map +1 -1
  29. package/dist/internal-tables-57VaN3o1.js +105 -0
  30. package/dist/internal-tables-57VaN3o1.js.map +1 -0
  31. package/dist/{jwt-DD6EtpGj.js → jwt-CzeviDcB.js} +17 -2
  32. package/dist/{jwt-DD6EtpGj.js.map → jwt-CzeviDcB.js.map} +1 -1
  33. package/dist/{openapi-generator-BEwyiaAr.js → openapi-generator-CSlEZh7-.js} +306 -128
  34. package/dist/openapi-generator-CSlEZh7-.js.map +1 -0
  35. package/dist/{schema-editor-routes-CbF20Mf1.js → schema-editor-routes-BqjzvvWU.js} +4 -4
  36. package/dist/{schema-editor-routes-CbF20Mf1.js.map → schema-editor-routes-BqjzvvWU.js.map} +1 -1
  37. package/dist/{src-_qQ3RNCK.js → src-Ca6NhxKs.js} +79 -2
  38. package/dist/src-Ca6NhxKs.js.map +1 -0
  39. package/dist/{src-Cum9kox5.js → src-CvaxLgnM.js} +115 -34
  40. package/dist/src-CvaxLgnM.js.map +1 -0
  41. package/dist/utils/logging.d.ts +0 -4
  42. package/dist/utils/sql.d.ts +11 -6
  43. package/package.json +6 -6
  44. package/dist/admin_block-CcSGdH7M.js.map +0 -1
  45. package/dist/auth-CuC9M2x6.js.map +0 -1
  46. package/dist/backend-CIxN4FVm.js +0 -15
  47. package/dist/backend-CIxN4FVm.js.map +0 -1
  48. package/dist/cron-scheduler-B3RFt0HS.js.map +0 -1
  49. package/dist/cron-store-BywZsyfZ.js.map +0 -1
  50. package/dist/errors-CgkCzoj7.js.map +0 -1
  51. package/dist/openapi-generator-BEwyiaAr.js.map +0 -1
  52. package/dist/src-Cum9kox5.js.map +0 -1
  53. package/dist/src-_qQ3RNCK.js.map +0 -1
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from "module";
2
2
  import "process";
3
3
  __createRequire(import.meta.url);
4
4
  import { r as __require, t as __commonJSMin } from "./rolldown-runtime-DSJWtz9O.js";
5
- import { c as NULL_OPS, i as isRelationalCollectionConfig, l as REST_TO_CANONICAL, n as getDeclaredSubcollections, o as getDataSourceCapabilities, r as isPostgresCollectionConfig, s as CANONICAL_TO_REST, u as toCanonicalOp } from "./src-_qQ3RNCK.js";
5
+ import { a as getDeclaredSubcollections, d as NULL_OPS, f as REST_TO_CANONICAL, l as getDataSourceCapabilities, o as isPostgresCollectionConfig, p as toCanonicalOp, s as isRelationalCollectionConfig, u as CANONICAL_TO_REST } from "./src-Ca6NhxKs.js";
6
6
  //#region ../types/src/types/entities.ts
7
7
  /**
8
8
  * Class used to create a reference to a entity in a different path.
@@ -129,7 +129,7 @@ var Vector = class {
129
129
  //#endregion
130
130
  //#region ../types/src/types/policy.ts
131
131
  /**
132
- * The id a request without a logged-in user reports as `auth.uid()`.
132
+ * The id a request without a logged-in user reports as `rebase.uid()`.
133
133
  *
134
134
  * A user-context request always sets `app.uid`: blank would read back as
135
135
  * `NULL`, and `NULL` is how the trusted server context is recognised, so an
@@ -137,7 +137,7 @@ var Vector = class {
137
137
  * therefore substitutes this sentinel at the single chokepoint where the GUC
138
138
  * is set.
139
139
  *
140
- * The consequence for policy authors is that **`auth.uid() IS NOT NULL` is a
140
+ * The consequence for policy authors is that **`rebase.uid() IS NOT NULL` is a
141
141
  * tautology on the user path** — it is true for anonymous visitors too. Use
142
142
  * {@link policy.authenticated} to mean "signed in", and
143
143
  * {@link policy.serverContext} to mean "the trusted server context". Do not
@@ -154,7 +154,7 @@ var ANONYMOUS_USER_ID = "anonymous";
154
154
  * JavaScript evaluator and the linter were all built on
155
155
  * {@link ANONYMOUS_USER_ID}, while the request path scoped unauthenticated
156
156
  * callers as `'anon'` — so `policy.authenticated()`, which compiled to
157
- * `auth.uid() <> 'anonymous'`, was *true* for an anonymous visitor. The
157
+ * `rebase.uid() <> 'anonymous'`, was *true* for an anonymous visitor. The
158
158
  * sanctioned way to write "signed in" granted to everyone, and the linter
159
159
  * flagged the spelling that actually worked as a foreign convention.
160
160
  *
@@ -235,6 +235,27 @@ var policy = {
235
235
  authUid: () => ({ kind: "authUid" }),
236
236
  authRoles: () => ({ kind: "authRoles" })
237
237
  };
238
+ /** Hard ceiling clamped onto any client-supplied `limit`, on every surface. */
239
+ var MAX_LIST_LIMIT = 1e3;
240
+ /**
241
+ * Resolve a client-supplied list `limit` into a safe, always-defined value.
242
+ *
243
+ * - A provided limit is coerced to an integer and clamped to `[1, maxLimit]`,
244
+ * so `0`, negatives, and absurd values can never bypass the cap.
245
+ * - An absent / blank / non-numeric limit falls back to the mode default:
246
+ * `vectorDefaultLimit` for a vector search, otherwise `defaultLimit`.
247
+ *
248
+ * The return is never `undefined` — no ingress that routes its client limit
249
+ * through this can produce an unbounded read.
250
+ */
251
+ function resolveClientListLimit(rawLimit, opts = {}) {
252
+ const maxLimit = opts.maxLimit ?? 1e3;
253
+ if (rawLimit != null && String(rawLimit).trim() !== "") {
254
+ const parsed = typeof rawLimit === "number" ? rawLimit : parseInt(String(rawLimit), 10);
255
+ if (Number.isFinite(parsed)) return Math.min(Math.max(1, Math.floor(parsed)), maxLimit);
256
+ }
257
+ return opts.vectorSearch ? opts.vectorDefaultLimit ?? 10 : opts.defaultLimit ?? 50;
258
+ }
238
259
  (/* @__PURE__ */ __commonJSMin(((exports, module) => {
239
260
  (function(e) {
240
261
  var t;
@@ -1382,10 +1403,21 @@ function singularizeForKey(name) {
1382
1403
  * have `id` and `path` fields — these are relation-shaped objects from
1383
1404
  * edge cases in the data pipeline (REST fallback, stale cache, custom data source).
1384
1405
  *
1406
+ * When `targetPath` is given, also accepts a bare id. A relation column is a
1407
+ * foreign key, and the REST layer returns it as the scalar it is; only some
1408
+ * fetch paths hydrate it into an object. Which form a caller sees therefore
1409
+ * depends on how the row was loaded, and a caller that only accepted objects
1410
+ * reported half of its own data as a type error. The declared target is the
1411
+ * missing half: with it, an id is a relation that has not been fetched yet.
1412
+ *
1385
1413
  * Returns null if the value cannot be coerced.
1386
1414
  */
1387
- function normalizeToEntityRelation(value, propertyType) {
1415
+ function normalizeToEntityRelation(value, propertyType, targetPath) {
1388
1416
  if (value instanceof EntityRelation) return value;
1417
+ if (targetPath && (typeof value === "string" || typeof value === "number")) {
1418
+ if (value === "") return null;
1419
+ return new EntityRelation(value, targetPath);
1420
+ }
1389
1421
  if (!value || typeof value !== "object" || Array.isArray(value)) return null;
1390
1422
  const obj = value;
1391
1423
  if (!(obj.__type === "relation" || obj.__type === "reference" || typeof obj.isEntityRelation === "function" && obj.isEntityRelation() || typeof obj.isEntityReference === "function" && obj.isEntityReference() || propertyType === "relation" && typeof obj.id !== "undefined" && typeof obj.path === "string")) return null;
@@ -2941,6 +2973,30 @@ var RebasePaginationError = class RebasePaginationError extends Error {
2941
2973
  Object.setPrototypeOf(this, RebasePaginationError.prototype);
2942
2974
  }
2943
2975
  };
2976
+ /**
2977
+ * Resolve `limit`/`offset`/`page` into the window a read will actually use.
2978
+ *
2979
+ * Lives here, next to the walk, for the reason at the top of this file: every
2980
+ * transport has to mean the same thing by "page two". Four of them did not —
2981
+ * the REST layer strode by {@link DEFAULT_LIST_LIMIT}, the local-first
2982
+ * evaluator by {@link DEFAULT_PAGE_SIZE}, the in-process accessor by 20, and
2983
+ * the published type documented a fourth number. Pages that overlap or skip
2984
+ * rows are the mildest of those outcomes.
2985
+ *
2986
+ * `page` wins over `offset`, as {@link FindParams} documents. `driverOffset`
2987
+ * is the value to hand a driver: it stays `undefined` when the caller named no
2988
+ * offset, because keyset pagination seeks with a `where` clause and must not
2989
+ * look like it is paging by offset.
2990
+ */
2991
+ function resolveFindWindow(params) {
2992
+ const limit = params?.limit ?? 50;
2993
+ const offset = params?.page != null ? Math.max(0, (params.page - 1) * limit) : params?.offset ?? 0;
2994
+ return {
2995
+ limit,
2996
+ offset,
2997
+ driverOffset: params?.page != null ? offset : params?.offset
2998
+ };
2999
+ }
2944
3000
  function normalizePageSize(raw) {
2945
3001
  if (raw === void 0 || !Number.isFinite(raw)) return 200;
2946
3002
  return Math.max(1, Math.floor(raw));
@@ -3251,18 +3307,8 @@ function serializeLogicalCondition(cond) {
3251
3307
  }
3252
3308
  return `${cond.column}.${restOp}.${stringifyValue(cond.value)}`;
3253
3309
  }
3254
- /**
3255
- * Parse a logical condition wire-format string back into a
3256
- * `LogicalCondition` or `FilterCondition`.
3257
- *
3258
- * @example
3259
- * deserializeLogicalCondition("status.eq.active")
3260
- * // → { column: "status", operator: "==", value: "active" }
3261
- *
3262
- * deserializeLogicalCondition("or(status.eq.active,age.gte.18)")
3263
- * // → { type: "or", conditions: [...] }
3264
- */
3265
- function deserializeLogicalCondition(str) {
3310
+ function deserializeLogicalCondition(str, nesting = 0) {
3311
+ if (nesting > 32) throw new Error(`Filter groups nest more than 32 levels deep. Flatten the condition — \`or(a,or(b,c))\` is \`or(a,b,c)\`.`);
3266
3312
  const logicalMatch = str.match(/^(and|or)\((.+)\)$/);
3267
3313
  if (logicalMatch) {
3268
3314
  const type = logicalMatch[1];
@@ -3273,10 +3319,10 @@ function deserializeLogicalCondition(str) {
3273
3319
  for (let i = 0; i < innerStr.length; i++) if (innerStr[i] === "(") depth++;
3274
3320
  else if (innerStr[i] === ")") depth--;
3275
3321
  else if (innerStr[i] === "," && depth === 0) {
3276
- conditions.push(deserializeLogicalCondition(innerStr.slice(start, i)));
3322
+ conditions.push(deserializeLogicalCondition(innerStr.slice(start, i), nesting + 1));
3277
3323
  start = i + 1;
3278
3324
  }
3279
- conditions.push(deserializeLogicalCondition(innerStr.slice(start)));
3325
+ conditions.push(deserializeLogicalCondition(innerStr.slice(start), nesting + 1));
3280
3326
  return {
3281
3327
  type,
3282
3328
  conditions
@@ -3390,21 +3436,22 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3390
3436
  const accessor = {
3391
3437
  async find(params) {
3392
3438
  const filter = params?.where ? deserializeFilter(params.where) : void 0;
3393
- const limit = params?.limit ?? 20;
3394
- const offset = params?.offset ?? 0;
3439
+ const { limit, offset, driverOffset } = resolveFindWindow(params);
3395
3440
  const fetchService = driver.restFetchService;
3396
3441
  const rows = fetchService ? await fetchService.fetchCollectionForRest(slug, {
3397
3442
  filter,
3398
- limit: params?.limit,
3399
- offset: params?.offset,
3443
+ logical: params?.logical,
3444
+ limit,
3445
+ offset: driverOffset,
3400
3446
  orderBy: params?.orderBy?.[0],
3401
3447
  order: params?.orderBy?.[1],
3402
3448
  searchString: params?.searchString
3403
3449
  }, params?.include) : await driver.fetchCollection({
3404
3450
  path: slug,
3405
- limit: params?.limit,
3406
- offset: params?.offset,
3451
+ limit,
3452
+ offset: driverOffset,
3407
3453
  filter,
3454
+ logical: params?.logical,
3408
3455
  orderBy: params?.orderBy?.[0],
3409
3456
  order: params?.orderBy?.[1],
3410
3457
  searchString: params?.searchString
@@ -3414,7 +3461,9 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3414
3461
  if (driver.count) {
3415
3462
  total = await driver.count({
3416
3463
  path: slug,
3417
- filter
3464
+ filter,
3465
+ logical: params?.logical,
3466
+ searchString: params?.searchString
3418
3467
  });
3419
3468
  hasMore = offset + rows.length < total;
3420
3469
  }
@@ -3466,22 +3515,39 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3466
3515
  values: {}
3467
3516
  } });
3468
3517
  },
3518
+ updateMany: driver.updateMany ? async (updates) => {
3519
+ return (await driver.updateMany({
3520
+ path: slug,
3521
+ updates: updates.map((u) => ({
3522
+ id: u.id,
3523
+ values: u.data
3524
+ }))
3525
+ })).map((row) => rowToEntity(row, slug, getPks()));
3526
+ } : void 0,
3527
+ deleteMany: driver.deleteMany ? async (ids) => {
3528
+ await driver.deleteMany({
3529
+ path: slug,
3530
+ ids
3531
+ });
3532
+ } : void 0,
3469
3533
  count: driver.count ? async (params) => {
3470
3534
  const filter = params?.where ? deserializeFilter(params.where) : void 0;
3471
3535
  return driver.count({
3472
3536
  path: slug,
3473
- filter
3537
+ filter,
3538
+ logical: params?.logical,
3539
+ searchString: params?.searchString
3474
3540
  });
3475
3541
  } : void 0,
3476
3542
  listen: driver.listenCollection ? (params, onUpdate, onError) => {
3477
- const limit = params?.limit ?? 20;
3478
- const offset = params?.offset ?? 0;
3543
+ const { limit, offset, driverOffset } = resolveFindWindow(params);
3479
3544
  const normalize = driver.restFetchService ? inlineRelationRefs : (row) => row;
3480
3545
  return driver.listenCollection({
3481
3546
  path: slug,
3482
- limit: params?.limit,
3483
- offset: params?.offset,
3547
+ limit,
3548
+ offset: driverOffset,
3484
3549
  filter: params?.where,
3550
+ logical: params?.logical,
3485
3551
  orderBy: params?.orderBy?.[0],
3486
3552
  order: params?.orderBy?.[1],
3487
3553
  searchString: params?.searchString,
@@ -3489,7 +3555,7 @@ function createDriverAccessor(driver, slug, getPks = () => []) {
3489
3555
  onUpdate({
3490
3556
  data: entities.map((row) => rowToEntity(normalize(row), slug, getPks())),
3491
3557
  meta: {
3492
- total: entities.length,
3558
+ total: offset + entities.length,
3493
3559
  limit,
3494
3560
  offset,
3495
3561
  hasMore: entities.length >= limit
@@ -3666,9 +3732,24 @@ function toSdkCollectionClient(snap, slug = "collection") {
3666
3732
  async update(id, data) {
3667
3733
  return entityToRow(await snap.update(id, data));
3668
3734
  },
3735
+ async updateMany(updates) {
3736
+ if (!Array.isArray(updates)) throw new TypeError("updateMany expects an array of { id, data } entries.");
3737
+ if (updates.length === 0) return [];
3738
+ if (!snap.updateMany) throw new Error("Bulk updates are not supported by this collection's data source. Fall back to update() per record.");
3739
+ return (await snap.updateMany(updates.map((u) => ({
3740
+ id: u.id,
3741
+ data: u.data
3742
+ })))).map(entityToRow);
3743
+ },
3669
3744
  delete(id) {
3670
3745
  return snap.delete(id);
3671
3746
  },
3747
+ async deleteMany(ids) {
3748
+ if (!Array.isArray(ids)) throw new TypeError("deleteMany expects an array of ids.");
3749
+ if (ids.length === 0) return;
3750
+ if (!snap.deleteMany) throw new Error("Bulk deletes are not supported by this collection's data source. Fall back to delete() per record.");
3751
+ await snap.deleteMany(ids);
3752
+ },
3672
3753
  count: snap.count ? (params) => snap.count(params) : void 0,
3673
3754
  listen: snap.listen ? (params, onUpdate, onError) => snap.listen(params, (res) => onUpdate({
3674
3755
  data: res.data.map(entityToRow),
@@ -3772,6 +3853,6 @@ function buildRoutedRebaseData({ defaultData, sources, resolveKey }) {
3772
3853
  } });
3773
3854
  }
3774
3855
  //#endregion
3775
- export { Vector as S, ANONYMOUS_USER_ID as _, serializeFilter as a, EntityRelation as b, paginateFind as c, resolveDataSource as d, getEffectiveSecurityRules as f, toSnakeCase as g, buildCompositeId as h, deserializeLogicalCondition as i, CollectionRegistry as l, resolveCollectionRelations as m, buildSdkData as n, serializeLogicalCondition as o, findRelation as p, deserializeFilter as r, collectAllPages as s, buildRoutedRebaseData as t, createDataSourceRegistry as u, isAnonymousUid as v, GeoPoint as x, EntityReference as y };
3856
+ export { EntityReference as C, Vector as E, isAnonymousUid as S, GeoPoint as T, resolvePrimaryKeys as _, serializeFilter as a, resolveClientListLimit as b, paginateFind as c, createDataSourceRegistry as d, resolveDataSource as f, buildCompositeId as g, resolveCollectionRelations as h, deserializeLogicalCondition as i, resolveFindWindow as l, findRelation as m, buildSdkData as n, serializeLogicalCondition as o, getEffectiveSecurityRules as p, deserializeFilter as r, collectAllPages as s, buildRoutedRebaseData as t, CollectionRegistry as u, toSnakeCase as v, EntityRelation as w, ANONYMOUS_USER_ID as x, MAX_LIST_LIMIT as y };
3776
3857
 
3777
- //# sourceMappingURL=src-Cum9kox5.js.map
3858
+ //# sourceMappingURL=src-CvaxLgnM.js.map