@rebasepro/server 0.13.1-canary.gcd6689e → 0.13.1-canary.gcef69d4

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 (31) hide show
  1. package/dist/api/errors.d.ts +0 -6
  2. package/dist/api/openapi-generator.d.ts +14 -0
  3. package/dist/api/rest/idempotency.d.ts +41 -4
  4. package/dist/api/rest/write-validation.d.ts +12 -5
  5. package/dist/{auth-ByFdJcuM.js → auth-DU4ShERo.js} +11 -33
  6. package/dist/auth-DU4ShERo.js.map +1 -0
  7. package/dist/{backup-CVggVhR2.js → backup-BJiY_mM-.js} +2 -2
  8. package/dist/{backup-CVggVhR2.js.map → backup-BJiY_mM-.js.map} +1 -1
  9. package/dist/{cron-routes-CrQ0tK-_.js → cron-routes-D5a9v1HY.js} +2 -2
  10. package/dist/{cron-routes-CrQ0tK-_.js.map → cron-routes-D5a9v1HY.js.map} +1 -1
  11. package/dist/{cron-scheduler-B3RFt0HS.js → cron-scheduler-BhFZWR0T.js} +21 -2
  12. package/dist/cron-scheduler-BhFZWR0T.js.map +1 -0
  13. package/dist/{cron-store-BywZsyfZ.js → cron-store-Cu4sOseb.js} +11 -1
  14. package/dist/cron-store-Cu4sOseb.js.map +1 -0
  15. package/dist/{errors-CgkCzoj7.js → errors-BpudWAVU.js} +2 -10
  16. package/dist/errors-BpudWAVU.js.map +1 -0
  17. package/dist/index.es.js +246 -166
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/{openapi-generator-BEwyiaAr.js → openapi-generator-D5xsfVJY.js} +99 -102
  20. package/dist/openapi-generator-D5xsfVJY.js.map +1 -0
  21. package/dist/{schema-editor-routes-COEkzWEa.js → schema-editor-routes-C1DxDnDR.js} +2 -2
  22. package/dist/{schema-editor-routes-COEkzWEa.js.map → schema-editor-routes-C1DxDnDR.js.map} +1 -1
  23. package/dist/{src-Cum9kox5.js → src-CKOZBpeJ.js} +69 -29
  24. package/dist/src-CKOZBpeJ.js.map +1 -0
  25. package/package.json +6 -6
  26. package/dist/auth-ByFdJcuM.js.map +0 -1
  27. package/dist/cron-scheduler-B3RFt0HS.js.map +0 -1
  28. package/dist/cron-store-BywZsyfZ.js.map +0 -1
  29. package/dist/errors-CgkCzoj7.js.map +0 -1
  30. package/dist/openapi-generator-BEwyiaAr.js.map +0 -1
  31. package/dist/src-Cum9kox5.js.map +0 -1
@@ -55,12 +55,6 @@ export interface RebaseApiError extends Error {
55
55
  code?: string;
56
56
  details?: unknown;
57
57
  }
58
- /**
59
- * Type guard for errors that carry optional API metadata (statusCode, code, details).
60
- * Returns true for any Error instance — the optional properties are then
61
- * checked via normal property access.
62
- */
63
- export declare function isRebaseApiError(error: unknown): error is RebaseApiError;
64
58
  /**
65
59
  * Hono error-handling middleware (`app.onError`).
66
60
  * Converts any error into the canonical `{ error: { message, code } }` shape.
@@ -12,5 +12,19 @@ export interface OpenApiGeneratorOptions {
12
12
  basePath?: string;
13
13
  /** Whether auth is enabled on data routes. Defaults to true. */
14
14
  requireAuth?: boolean;
15
+ /**
16
+ * The list-pagination bounds the REST layer applies, so the spec states the
17
+ * ones a request will actually meet.
18
+ *
19
+ * These were hardcoded as `default: 20, maximum: 100` — neither of which
20
+ * the server has ever used. The spec drives the API Explorer and is what a
21
+ * generated client is built from, so an understated ceiling is a request
22
+ * the client refuses to make, and an overstated one is a 400 nobody
23
+ * predicted.
24
+ */
25
+ listLimits?: {
26
+ defaultLimit?: number;
27
+ maxLimit?: number;
28
+ };
15
29
  }
16
30
  export declare function generateOpenApiSpec(collections: CollectionConfig[], options?: OpenApiGeneratorOptions): Record<string, unknown>;
@@ -1,9 +1,46 @@
1
1
  import { DataDriver } from "@rebasepro/types";
2
+ /**
3
+ * What a caller may do with a key.
4
+ *
5
+ * `claimed` is the only outcome that permits the write. Recalling and then
6
+ * writing was not atomic: two requests carrying one key both missed the recall,
7
+ * both wrote, and `ON CONFLICT DO NOTHING` protected only the second row in
8
+ * *this* table — the duplicate row in the caller's collection, which is the
9
+ * thing the mechanism exists to prevent, was inserted anyway. The offline queue
10
+ * is shared across tabs, so two tabs reconnecting together is the ordinary case
11
+ * rather than an exotic one.
12
+ */
13
+ export type IdempotencyClaim =
14
+ /** This key has already been answered; serve that answer again. */
15
+ {
16
+ status: "replay";
17
+ response: unknown;
18
+ }
19
+ /** Another request holds this key and has not answered yet. */
20
+ | {
21
+ status: "in-flight";
22
+ }
23
+ /** The key is ours; do the write, then `complete` or `release` it. */
24
+ | {
25
+ status: "claimed";
26
+ };
2
27
  export interface IdempotencyStore {
3
- /** What this key answered before, or `undefined` if it is new. */
4
- recall(key: string, uid: string | undefined): Promise<unknown | undefined>;
5
- /** Record what this key answered. Never throws — see {@link createIdempotencyStore}. */
6
- remember(key: string, uid: string | undefined, response: unknown): Promise<void>;
28
+ /**
29
+ * Take the key if it is free, atomically. Never throws — a store that
30
+ * cannot answer reports `claimed`, which degrades to no idempotency rather
31
+ * than to a refused write.
32
+ */
33
+ claim(key: string, uid: string | undefined): Promise<IdempotencyClaim>;
34
+ /** Record what this key answered. Never throws. */
35
+ complete(key: string, uid: string | undefined, response: unknown): Promise<void>;
36
+ /**
37
+ * Give the key back after the write it was claimed for failed.
38
+ *
39
+ * Without this a transient failure strands the key: every retry would be
40
+ * told `in-flight` until the row aged out, turning one failed write into a
41
+ * day of refusals.
42
+ */
43
+ release(key: string, uid: string | undefined): Promise<void>;
7
44
  }
8
45
  /**
9
46
  * Returns `undefined` when the driver cannot run SQL, which disables the whole
@@ -33,11 +33,18 @@ export declare function assertKnownWriteFields(values: Record<string, unknown>,
33
33
  * This shapes the *response*, which is what the parameter says it does; it is
34
34
  * not a column pushdown, so it saves bandwidth rather than database work.
35
35
  *
36
- * `id` always survives. Rows are addressed by it everywhere above this layer —
37
- * the admin table, realtime reconciliation, the offline cache — and a row that
38
- * arrives without one is not a smaller row, it is an unusable one. Asking for
39
- * `fields=title` and being unable to open the record you clicked is a worse
40
- * answer than one extra key.
36
+ * The collection's key always survives. Rows are addressed by it everywhere
37
+ * above this layer — the admin table, realtime reconciliation, the offline
38
+ * cache — and a row that arrives without one is not a smaller row, it is an
39
+ * unusable one. Asking for `fields=title` and being unable to open the record
40
+ * you clicked is a worse answer than one extra key.
41
+ *
42
+ * That is a statement about the key, not about the name `id`: a collection
43
+ * keyed on `slug`, or on `user_id + role_id`, was projected down to the fields
44
+ * asked for and nothing else, which is the very outcome the paragraph above
45
+ * describes. `assertKnownWriteFields` one function up already has a dedicated
46
+ * error for collections with no `id` column, so this layer had no excuse for
47
+ * assuming one.
41
48
  */
42
49
  export declare function projectResponseFields<T extends Record<string, unknown>>(rows: T[], fields: readonly string[] | undefined, collection: CollectionConfig, options?: {
43
50
  include?: readonly string[];
@@ -2,38 +2,16 @@ import { createRequire as __createRequire } from "module";
2
2
  import process from "process";
3
3
  __createRequire(import.meta.url);
4
4
  import { i as __toESM, n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
5
- import { _ as ANONYMOUS_USER_ID, v as isAnonymousUid } from "./src-Cum9kox5.js";
5
+ import { S as isAnonymousUid, b as resolveClientListLimit, x as ANONYMOUS_USER_ID } from "./src-CKOZBpeJ.js";
6
6
  import "./src-_qQ3RNCK.js";
7
7
  import { t as isSQLAdmin } from "./backend-CIxN4FVm.js";
8
8
  import { t as logger } from "./logger-BYU66ENZ.js";
9
- import { n as errorHandler, t as ApiError } from "./errors-CgkCzoj7.js";
9
+ import { n as errorHandler, t as ApiError } from "./errors-BpudWAVU.js";
10
10
  import { a as generateRefreshToken, c as getRefreshTokenTtlMs, f as verifyAccessToken, i as generateDownloadToken, l as hashRefreshToken, m as require_jsonwebtoken, n as configureJwt, o as getAccessTokenExpiry, p as verifyDownloadToken, r as generateAccessToken, s as getRefreshTokenExpiry, t as MAX_COOKIE_AGE_MS, u as isJwtConfigured } from "./jwt-CzeviDcB.js";
11
11
  import { createHash, randomBytes, randomInt } from "node:crypto";
12
12
  import { Hono } from "hono";
13
13
  import { promisify } from "util";
14
14
  import { createCipheriv, createDecipheriv, createHash as createHash$1, createHmac, randomBytes as randomBytes$1, randomUUID as randomUUID$1, scrypt, timingSafeEqual } from "crypto";
15
- /** Hard ceiling clamped onto any client-supplied `limit`, on every surface. */
16
- var MAX_LIST_LIMIT = 1e3;
17
- /**
18
- * Resolve a client-supplied list `limit` into a safe, always-defined value.
19
- *
20
- * - A provided limit is coerced to an integer and clamped to `[1, maxLimit]`,
21
- * so `0`, negatives, and absurd values can never bypass the cap.
22
- * - An absent / blank / non-numeric limit falls back to the mode default:
23
- * `vectorDefaultLimit` for a vector search, otherwise `defaultLimit`.
24
- *
25
- * The return is never `undefined` — no ingress that routes its client limit
26
- * through this can produce an unbounded read.
27
- */
28
- function resolveClientListLimit(rawLimit, opts = {}) {
29
- const maxLimit = opts.maxLimit ?? 1e3;
30
- if (rawLimit != null && String(rawLimit).trim() !== "") {
31
- const parsed = typeof rawLimit === "number" ? rawLimit : parseInt(String(rawLimit), 10);
32
- if (Number.isFinite(parsed)) return Math.min(Math.max(1, Math.floor(parsed)), maxLimit);
33
- }
34
- return opts.vectorSearch ? opts.vectorDefaultLimit ?? 10 : opts.defaultLimit ?? 50;
35
- }
36
- //#endregion
37
15
  //#region ../types/src/controllers/storage.ts
38
16
  /**
39
17
  * Path prefix that marks an object as **public**. Files stored under this
@@ -1492,6 +1470,11 @@ async function finalizeAdminUserCreation(entity, clearPassword, ctx) {
1492
1470
  var scryptAsync = promisify(scrypt);
1493
1471
  var SALT_LENGTH = 32;
1494
1472
  var KEY_LENGTH = 64;
1473
+ var SCRYPT_PARAMS = {
1474
+ N: 16384,
1475
+ r: 8,
1476
+ p: 1
1477
+ };
1495
1478
  /**
1496
1479
  * Password requirements:
1497
1480
  * - Minimum 8 characters
@@ -1516,7 +1499,7 @@ function validatePasswordStrength(password) {
1516
1499
  */
1517
1500
  async function hashPassword(password) {
1518
1501
  const salt = randomBytes$1(SALT_LENGTH);
1519
- const derivedKey = await scryptAsync(password, salt, KEY_LENGTH);
1502
+ const derivedKey = await scryptAsync(password, salt, KEY_LENGTH, SCRYPT_PARAMS);
1520
1503
  return `${salt.toString("hex")}:${derivedKey.toString("hex")}`;
1521
1504
  }
1522
1505
  /**
@@ -1528,7 +1511,7 @@ async function verifyPassword(password, storedHash) {
1528
1511
  if (!saltHex || !hashHex) return false;
1529
1512
  const salt = Buffer.from(saltHex, "hex");
1530
1513
  const storedKey = Buffer.from(hashHex, "hex");
1531
- return timingSafeEqual(await scryptAsync(password, salt, KEY_LENGTH), storedKey);
1514
+ return timingSafeEqual(await scryptAsync(password, salt, KEY_LENGTH, SCRYPT_PARAMS), storedKey);
1532
1515
  }
1533
1516
  //#endregion
1534
1517
  //#region src/auth/auth-hooks.ts
@@ -6550,11 +6533,6 @@ function createAuthRoutes(config) {
6550
6533
  newPassword: string().min(1, "New password is required").max(128)
6551
6534
  });
6552
6535
  const refreshSchema = object({ refreshToken: string().min(1).optional() });
6553
- object({ refreshToken: string().optional() });
6554
- object({
6555
- displayName: string().max(255).optional(),
6556
- photoURL: string().url().max(2048).optional()
6557
- });
6558
6536
  /** Parse a Zod schema against the request body, throwing ApiError on failure */
6559
6537
  function parseBody(schema, body) {
6560
6538
  const result = schema.safeParse(body);
@@ -8958,6 +8936,6 @@ var auth_exports = /* @__PURE__ */ __exportAll({
8958
8936
  verifyPassword: () => verifyPassword
8959
8937
  });
8960
8938
  //#endregion
8961
- export { httpMethodToOperation as $, getEmailVerificationTemplate as A, optionalAuth as B, createDataRateLimiter as C, validatePasswordStrength as D, hashPassword as E, createAdapterAuthMiddleware as F, createApiKeyPreAuth as G, queryTokenAuth as H, createAuthMiddleware as I, isApiKeyToken as J, createFunctionApiKeyGuard as K, createRequireAuth as L, getPasswordResetTemplate as M, getUserInvitationTemplate as N, verifyPassword as O, getWelcomeEmailTemplate as P, scopeDataDriver as Q, extractUserFromToken as R, _coercedNumber as S, resolveAuthHooks as T, requireAdmin as U, publicObjectAuth as V, requireAuth as W, extractBearerToken as X, validateApiKey as Y, safeCompare as Z, createBuiltinAuthAdapter as _, createSpotifyProvider as a, object as b, createGitLabProvider as c, createFacebookProvider as d, isOperationAllowed as et, createAppleProvider as f, createGoogleProvider as g, createLinkedinProvider as h, createApiKeyStore as i, resolveClientListLimit as it, getMagicLinkTemplate as j, generateSecurePassword as k, createDiscordProvider as l, createGitHubProvider as m, createCustomAuthAdapter as n, isPublicStoragePath as nt, createSlackProvider as o, createMicrosoftProvider as p, createStorageApiKeyGuard as q, createApiKeyRoutes as r, MAX_LIST_LIMIT as rt, createBitbucketProvider as s, auth_exports as t, PUBLIC_STORAGE_PREFIX as tt, createTwitterProvider as u, ZodNumber as v, MemoryRateLimitStore as w, string as x, _enum as y, fileTokenAuth as z };
8939
+ export { httpMethodToOperation as $, getEmailVerificationTemplate as A, optionalAuth as B, createDataRateLimiter as C, validatePasswordStrength as D, hashPassword as E, createAdapterAuthMiddleware as F, createApiKeyPreAuth as G, queryTokenAuth as H, createAuthMiddleware as I, isApiKeyToken as J, createFunctionApiKeyGuard as K, createRequireAuth as L, getPasswordResetTemplate as M, getUserInvitationTemplate as N, verifyPassword as O, getWelcomeEmailTemplate as P, scopeDataDriver as Q, extractUserFromToken as R, _coercedNumber as S, resolveAuthHooks as T, requireAdmin as U, publicObjectAuth as V, requireAuth as W, extractBearerToken as X, validateApiKey as Y, safeCompare as Z, createBuiltinAuthAdapter as _, createSpotifyProvider as a, object as b, createGitLabProvider as c, createFacebookProvider as d, isOperationAllowed as et, createAppleProvider as f, createGoogleProvider as g, createLinkedinProvider as h, createApiKeyStore as i, getMagicLinkTemplate as j, generateSecurePassword as k, createDiscordProvider as l, createGitHubProvider as m, createCustomAuthAdapter as n, isPublicStoragePath as nt, createSlackProvider as o, createMicrosoftProvider as p, createStorageApiKeyGuard as q, createApiKeyRoutes as r, createBitbucketProvider as s, auth_exports as t, PUBLIC_STORAGE_PREFIX as tt, createTwitterProvider as u, ZodNumber as v, MemoryRateLimitStore as w, string as x, _enum as y, fileTokenAuth as z };
8962
8940
 
8963
- //# sourceMappingURL=auth-ByFdJcuM.js.map
8941
+ //# sourceMappingURL=auth-DU4ShERo.js.map