@rebasepro/server 0.20.1-canary.g4d882ca → 0.21.0

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 (60) hide show
  1. package/dist/api/rest/api-generator.d.ts +28 -0
  2. package/dist/auth/jwt.d.ts +67 -0
  3. package/dist/auth/rls-scope.d.ts +14 -0
  4. package/dist/{auth-DJsLXsCR.js → auth-gzoRjnuh.js} +24 -12
  5. package/dist/auth-gzoRjnuh.js.map +1 -0
  6. package/dist/boot/env.d.ts +8 -2
  7. package/dist/boot/fetch-bundle.d.ts +19 -0
  8. package/dist/boot/role.d.ts +2 -0
  9. package/dist/contract-routes-eLxV0le1.js.map +1 -1
  10. package/dist/{cron-routes-Bfwni8Zg.js → cron-routes-BamgO0Xr.js} +2 -2
  11. package/dist/{cron-routes-Bfwni8Zg.js.map → cron-routes-BamgO0Xr.js.map} +1 -1
  12. package/dist/{cron-store-Bsiw4Q6u.js → cron-store-yXOyIEmn.js} +2 -3
  13. package/dist/{cron-store-Bsiw4Q6u.js.map → cron-store-yXOyIEmn.js.map} +1 -1
  14. package/dist/db/ambient-transaction.d.ts +48 -0
  15. package/dist/ddl-bootstrap-CfNvxMuK.js.map +1 -1
  16. package/dist/deploy/pod-contract.d.ts +1 -1
  17. package/dist/errors-DMImyqyR.js.map +1 -1
  18. package/dist/functions/index.js.map +1 -1
  19. package/dist/{history-recorder-r5_IzSHK.js → history-recorder-hBGuXcZc.js} +2 -2
  20. package/dist/{history-recorder-r5_IzSHK.js.map → history-recorder-hBGuXcZc.js.map} +1 -1
  21. package/dist/{history-store-D4RVK-uZ.js → history-store-C9EtGtoL.js} +5 -6
  22. package/dist/history-store-C9EtGtoL.js.map +1 -0
  23. package/dist/index.d.ts +2 -1
  24. package/dist/index.es.js +2263 -90
  25. package/dist/index.es.js.map +1 -1
  26. package/dist/init/callback-client.d.ts +16 -0
  27. package/dist/init/surfaces.d.ts +37 -7
  28. package/dist/jobs/types.d.ts +5 -0
  29. package/dist/{jobs-CW5lm_Ix.js → jobs-DZ8DLLcU.js} +82 -13
  30. package/dist/jobs-DZ8DLLcU.js.map +1 -0
  31. package/dist/{jwt-DATvkKB_.js → jwt-C4OW-DNq.js} +136 -4
  32. package/dist/jwt-C4OW-DNq.js.map +1 -0
  33. package/dist/logger-DO2PZc4i.js.map +1 -1
  34. package/dist/mcp/consent-page.d.ts +75 -0
  35. package/dist/mcp/mcp-routes.d.ts +52 -0
  36. package/dist/mcp/mcp-tools.d.ts +51 -0
  37. package/dist/mcp/oauth-metadata.d.ts +123 -0
  38. package/dist/mcp/oauth-routes.d.ts +52 -0
  39. package/dist/mcp/oauth-store.d.ts +157 -0
  40. package/dist/metrics/index.d.ts +16 -1
  41. package/dist/{openapi-generator-DGyLbISS.js → openapi-generator-CAFKF36E.js} +2 -8
  42. package/dist/openapi-generator-CAFKF36E.js.map +1 -0
  43. package/dist/{query-parser-BQiPZrM-.js → query-parser-uqzkZ82i.js} +2 -2
  44. package/dist/{query-parser-BQiPZrM-.js.map → query-parser-uqzkZ82i.js.map} +1 -1
  45. package/dist/services/webhook-service.d.ts +11 -8
  46. package/dist/sql-rows-C6GEc2oE.js +45 -0
  47. package/dist/sql-rows-C6GEc2oE.js.map +1 -0
  48. package/dist/src-Br6ARbs6.js.map +1 -1
  49. package/dist/{src-DqZ9YiGA.js → src-DW1cQ_28.js} +261 -17
  50. package/dist/src-DW1cQ_28.js.map +1 -0
  51. package/dist/utils/portable-crypto.d.ts +8 -0
  52. package/package.json +5 -5
  53. package/dist/auth-DJsLXsCR.js.map +0 -1
  54. package/dist/history-store-D4RVK-uZ.js.map +0 -1
  55. package/dist/internal-tables-DYVcFFSv.js +0 -117
  56. package/dist/internal-tables-DYVcFFSv.js.map +0 -1
  57. package/dist/jobs-CW5lm_Ix.js.map +0 -1
  58. package/dist/jwt-DATvkKB_.js.map +0 -1
  59. package/dist/openapi-generator-DGyLbISS.js.map +0 -1
  60. package/dist/src-DqZ9YiGA.js.map +0 -1
@@ -141,6 +141,34 @@ export declare class RestApiGenerator {
141
141
  * it here would report a resolution failure as a validation failure.
142
142
  */
143
143
  private resolveNestedWriteCollection;
144
+ /**
145
+ * `PATCH <collection>/<id>/<relation>/<targetId>` with a `_pivot` body: set
146
+ * the columns that one many-to-many link carries.
147
+ *
148
+ * The membership array on the parent (`PATCH posts/1 { tags: [...] }`) sets
149
+ * *which* links exist; this sets what one of them holds. They are separate
150
+ * because the array cannot express a single-link edit without either
151
+ * unlinking everything it omits or re-sending the whole set — and re-sending
152
+ * the set to change one `role` is exactly the lost update that the
153
+ * membership diff exists to avoid.
154
+ *
155
+ * Validated against the junction's own properties, through the same
156
+ * `assertWriteRequestValid` a row's values go through: `required`, `enum`,
157
+ * `min`/`max`/`matches` and per-field `access.write` mean the same thing on
158
+ * a payload column as on a collection's, or the promise that they are
159
+ * "declared exactly like collection properties" is not one.
160
+ */
161
+ private updateRelationPivotFromBody;
162
+ /**
163
+ * The synthetic collection standing in for the junction a nested path's last
164
+ * hop reaches through, or `undefined` when that hop is not a `manyToMany`
165
+ * carrying `through.properties`.
166
+ *
167
+ * Built from the relation rather than by walking every collection: the same
168
+ * `getJunctionConfigForRelation` the schema planner and the driver use, so
169
+ * the shape validated here is the shape the columns were emitted from.
170
+ */
171
+ private resolveJunctionCollection;
144
172
  /**
145
173
  * Get the request-scoped driver. Throws if none is set — never falls
146
174
  * back to the unscoped `this.driver` to avoid bypassing RLS/auth.
@@ -249,3 +249,70 @@ export declare function generateDownloadToken(path: string, expiresInSeconds?: n
249
249
  * for a *named* source is refused and the client re-fetches `/metadata`.
250
250
  */
251
251
  export declare function verifyDownloadToken(token: string): Promise<DownloadTokenPayload | null>;
252
+ /**
253
+ * Sign a short-lived token that carries state across a redirect.
254
+ *
255
+ * The generalisation of the MFA-pending token: a signed blob the server hands
256
+ * out and expects back, where the point is that the holder cannot edit it. The
257
+ * OAuth authorize flow needs one to carry the authorization request across the
258
+ * sign-in hop — without it, the endpoint the consent page posts to would mint a
259
+ * code for whatever `client_id` and `redirect_uri` its caller typed, skipping
260
+ * every check the authorize endpoint performs.
261
+ *
262
+ * The `purpose` is not decoration. {@link verifyAccessToken} refuses any token
263
+ * that has one, so nothing minted here can be replayed as a session, and
264
+ * {@link verifyPurposeToken} refuses a token whose purpose is not the one the
265
+ * caller named — so a token minted for one hop cannot be spent on another.
266
+ */
267
+ export declare function signPurposeToken(purpose: string, claims: Record<string, unknown>, expiresInSeconds: number): Promise<string>;
268
+ /** Verify a token minted by {@link signPurposeToken}, for one named purpose. */
269
+ export declare function verifyPurposeToken<T>(purpose: string, token: string): Promise<T | null>;
270
+ /** The `purpose` that marks a token as belonging to the MCP resource. */
271
+ export declare const MCP_ACCESS_PURPOSE = "mcp-access";
272
+ export interface McpAccessTokenPayload {
273
+ purpose: typeof MCP_ACCESS_PURPOSE;
274
+ /** The person the token acts for. Fed straight to `withAuth()`, so RLS sees them. */
275
+ uid: string;
276
+ roles: string[];
277
+ /** Granted OAuth scope, space-separated. */
278
+ scope: string;
279
+ /** Which registered client holds this token — carried for audit and revocation. */
280
+ clientId: string;
281
+ /** The resource this token is bound to (RFC 8707). */
282
+ aud: string;
283
+ iss: string;
284
+ }
285
+ /**
286
+ * Mint an access token for the MCP endpoint.
287
+ *
288
+ * Deliberately **not** an ordinary session token, and the `purpose` claim is
289
+ * what enforces that: {@link verifyAccessToken} refuses any token carrying one,
290
+ * so a credential issued to a third-party MCP client — Claude, an IDE, anything
291
+ * that completed the OAuth flow — cannot be replayed against `/api/data`,
292
+ * `/api/admin` or the websocket. It buys exactly the one resource it names.
293
+ *
294
+ * That asymmetry matters more than it first looks. These tokens are handed to
295
+ * software the user authorized but the operator never vetted, they live in that
296
+ * software's storage, and they are the only credential in this system minted
297
+ * for a third party. Without the purpose separation, "connect Claude to your
298
+ * data" would silently mean "give Claude a full session".
299
+ *
300
+ * The audience is the canonical resource URI, and {@link verifyMcpAccessToken}
301
+ * requires the caller to say which resource it is checking for. A token minted
302
+ * for another Rebase project — or another path on this one — fails there.
303
+ *
304
+ * HS256 with the shared secret, like the download token: the authorization
305
+ * server and the resource server are the same process, so nothing outside it
306
+ * ever needs to verify one, and an asymmetric key here would be a second key
307
+ * surface bought for nobody.
308
+ */
309
+ export declare function generateMcpAccessToken(payload: Omit<McpAccessTokenPayload, "purpose">, expiresInSeconds: number): Promise<string>;
310
+ /**
311
+ * Verify an MCP access token **for a specific resource**.
312
+ *
313
+ * `expectedAudience` has no default. The MCP specification requires a resource
314
+ * server to validate that a token was issued for it specifically, and a default
315
+ * would be the thing that quietly turns that check off — the caller has to say
316
+ * what it is, every time, so a new call site cannot forget by omission.
317
+ */
318
+ export declare function verifyMcpAccessToken(token: string, expectedAudience: string): Promise<McpAccessTokenPayload | null>;
@@ -37,6 +37,20 @@ export declare const SERVICE_IDENTITY: {
37
37
  uid: string;
38
38
  roles: string[];
39
39
  };
40
+ /**
41
+ * Can this driver run a request as a specific user?
42
+ *
43
+ * The same question `scopeDataDriver` asks internally, exported because one
44
+ * caller must act on the answer BEFORE it has a request to scope.
45
+ *
46
+ * `scopeDataDriver` returns the driver unscoped when the answer is no, which is
47
+ * the right behaviour for `/api/data` — Mongo has no row-level security and
48
+ * never claimed to, and the route's own checks still apply. It is the wrong
49
+ * behaviour for a surface whose entire promise is "this runs as you": there,
50
+ * an unscoped driver silently means "runs as the database owner". So the MCP
51
+ * surface asks this at boot and declines to mount rather than degrade.
52
+ */
53
+ export declare function supportsRlsScoping(driver: DataDriver): boolean;
40
54
  /**
41
55
  * Scope a DataDriver via `withAuth()` for RLS.
42
56
  *
@@ -3,14 +3,14 @@ import __rebaseProcess from "process";
3
3
  globalThis.process ??= __rebaseProcess;
4
4
  __rebaseCreateRequire(import.meta.url);
5
5
  import { i as __toESM, n as __exportAll } from "./rolldown-runtime-dW7B1o5h.js";
6
- import { et as ANONYMOUS_USER_ID, tt as isAnonymousUid } from "./src-DqZ9YiGA.js";
6
+ import { P as revokeInternalTableSql, at as isAnonymousUid, it as ANONYMOUS_USER_ID } from "./src-DW1cQ_28.js";
7
7
  import "./src-Br6ARbs6.js";
8
8
  import { n as createDdlBootstrapper, o as isSQLAdmin } from "./ddl-bootstrap-CfNvxMuK.js";
9
- import { t as revokeInternalTableSql } from "./internal-tables-DYVcFFSv.js";
9
+ import { t as firstSqlRow } from "./sql-rows-C6GEc2oE.js";
10
10
  import { r as logger } from "./logger-DO2PZc4i.js";
11
11
  import { n as errorHandler, t as ApiError } from "./errors-DMImyqyR.js";
12
- import { a as resolveListLimitParam } from "./query-parser-BQiPZrM-.js";
13
- import { S as sha256Hex, _ as verifyMfaPendingToken, a as generateMfaPendingToken, b as constantTimeEqual, c as getJwks, d as hasAsymmetricSigningKey, f as hashRefreshToken, g as verifyDownloadToken, h as verifyAccessToken, i as generateDownloadToken, l as getRefreshTokenExpiry, n as configureJwt, o as generateRefreshToken, p as isJwtConfigured, r as generateAccessToken, s as getAccessTokenExpiry, t as MAX_COOKIE_AGE_MS, u as getRefreshTokenTtlMs, x as randomInt$1, y as require_jsonwebtoken } from "./jwt-DATvkKB_.js";
12
+ import { a as resolveListLimitParam } from "./query-parser-uqzkZ82i.js";
13
+ import { C as require_jsonwebtoken, E as randomInt$1, O as sha256Hex, _ as verifyAccessToken, b as verifyMfaPendingToken, c as getAccessTokenExpiry, d as getRefreshTokenTtlMs, f as hasAsymmetricSigningKey, i as generateDownloadToken, l as getJwks, m as isJwtConfigured, n as configureJwt, o as generateMfaPendingToken, p as hashRefreshToken, r as generateAccessToken, s as generateRefreshToken, t as MAX_COOKIE_AGE_MS, u as getRefreshTokenExpiry, v as verifyDownloadToken, w as constantTimeEqual } from "./jwt-C4OW-DNq.js";
14
14
  import { n as hasAdministrativeRole, r as isAdministrativeRole, t as ADMINISTRATIVE_ROLES } from "./admin-roles-vYdp_Pil.js";
15
15
  import { c as tryCanonicalStorageKey, i as canonicalStorageId } from "./keys-Qfc4XieN.js";
16
16
  import { createHash, randomBytes, randomInt } from "node:crypto";
@@ -241,6 +241,22 @@ function isRLSScopedDriver(driver) {
241
241
  return "withAuth" in driver && typeof driver.withAuth === "function";
242
242
  }
243
243
  /**
244
+ * Can this driver run a request as a specific user?
245
+ *
246
+ * The same question `scopeDataDriver` asks internally, exported because one
247
+ * caller must act on the answer BEFORE it has a request to scope.
248
+ *
249
+ * `scopeDataDriver` returns the driver unscoped when the answer is no, which is
250
+ * the right behaviour for `/api/data` — Mongo has no row-level security and
251
+ * never claimed to, and the route's own checks still apply. It is the wrong
252
+ * behaviour for a surface whose entire promise is "this runs as you": there,
253
+ * an unscoped driver silently means "runs as the database owner". So the MCP
254
+ * surface asks this at boot and declines to mount rather than degrade.
255
+ */
256
+ function supportsRlsScoping(driver) {
257
+ return isRLSScopedDriver(driver);
258
+ }
259
+ /**
244
260
  * Scope a DataDriver via `withAuth()` for RLS.
245
261
  *
246
262
  * SECURITY: If `withAuth()` is available but fails, the error is re-thrown
@@ -3544,7 +3560,7 @@ function mountSessionRoutes(opts) {
3544
3560
  clearRefreshCookie(c, config.cookieAuth);
3545
3561
  const accessToken = extractBearerToken(c.req.header("authorization"));
3546
3562
  if (ops.afterLogout && accessToken !== void 0) {
3547
- const { verifyAccessToken } = await import("./jwt-DATvkKB_.js").then((n) => n.m);
3563
+ const { verifyAccessToken } = await import("./jwt-C4OW-DNq.js").then((n) => n.h);
3548
3564
  const payload = await verifyAccessToken(accessToken);
3549
3565
  if (payload) ops.afterLogout(payload.uid).catch((err) => {
3550
3566
  logger.error("[AuthHooks] afterLogout error", { error: err instanceof Error ? err.message : err });
@@ -6572,11 +6588,7 @@ function createSqlRateLimitStore(driver, options = {}) {
6572
6588
  * being on their first request — a limiter that never limits, with no error
6573
6589
  * anywhere. Tolerating both costs one line.
6574
6590
  */
6575
- function firstRow(result) {
6576
- if (Array.isArray(result)) return result[0];
6577
- const rows = result?.rows;
6578
- return Array.isArray(rows) ? rows[0] : void 0;
6579
- }
6591
+ var firstRow = firstSqlRow;
6580
6592
  //#endregion
6581
6593
  //#region src/auth/resolve-rate-limit-store.ts
6582
6594
  /**
@@ -7093,6 +7105,6 @@ var auth_exports = /* @__PURE__ */ __exportAll({
7093
7105
  verifyPassword: () => verifyPassword
7094
7106
  });
7095
7107
  //#endregion
7096
- export { escapeHtml as $, MemoryRateLimitStore as A, resolveAuthHooks as B, providerVerifiedEmail as C, PUBLIC_STORAGE_PREFIX as Ct, DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT as D, isBootstrapWindowOpen as E, registerDevEmailSink as F, getEmailOtpTemplate as G, validatePasswordStrength as H, SMTPEmailService as I, getPasswordResetTemplate as J, getEmailVerificationTemplate as K, createEmailService as L, clearActiveDevEmailSink as M, createDevEmailSink as N, createDataRateLimiter as O, extractLinks as P, RawHtml as Q, assertEmailLinkBases as R, pkceTokenParams as S, isOperationAllowed as St, createBuiltinAuthAdapter as T, verifyPassword as U, hashPassword as V, generateSecurePassword as W, getWelcomeEmailTemplate as X, getUserInvitationTemplate as Y, resolveEmailBranding as Z, verifyOidcIdToken as _, extractBearerToken as _t, resolveRateLimitStoreKind as a, extractUserFromToken as at, createGoogleProvider as b, scopeDataDriver as bt, createSlackProvider as c, publicObjectAuth as ct, createDiscordProvider as d, requireAuth as dt, html as et, createTwitterProvider as f, createApiKeyPreAuth as ft, tryVerifyOidcIdToken as g, validateApiKey as gt, createMicrosoftProvider as h, isApiKeyToken as ht, createApiKeyStore as i, createRequireAuth as it, activeDevEmailSink as j, defaultAuthLimiter as k, createBitbucketProvider as l, queryTokenAuth as lt, createAppleProvider as m, createStorageApiKeyGuard as mt, createCustomAuthAdapter as n, createAdapterAuthMiddleware as nt, createSqlRateLimitStore as o, fileTokenAuth as ot, createFacebookProvider as p, createFunctionApiKeyGuard as pt, getMagicLinkTemplate as q, createApiKeyRoutes as r, createAuthMiddleware as rt, createSpotifyProvider as s, optionalAuth as st, auth_exports as t, raw as tt, createGitLabProvider as u, requireAdmin as ut, createGitHubProvider as v, safeCompare as vt, createJwksRoutes as w, isPublicStoragePath as wt, oauthCodeFlowSchema as x, httpMethodToOperation as xt, createLinkedinProvider as y, SERVICE_IDENTITY as yt, resolveEmailLinkBase as z };
7108
+ export { RawHtml as $, defaultAuthLimiter as A, resolveEmailLinkBase as B, providerVerifiedEmail as C, httpMethodToOperation as Ct, DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT as D, isBootstrapWindowOpen as E, isPublicStoragePath as Et, extractLinks as F, generateSecurePassword as G, hashPassword as H, registerDevEmailSink as I, getMagicLinkTemplate as J, getEmailOtpTemplate as K, SMTPEmailService as L, activeDevEmailSink as M, clearActiveDevEmailSink as N, createDataRateLimiter as O, createDevEmailSink as P, resolveEmailBranding as Q, createEmailService as R, pkceTokenParams as S, supportsRlsScoping as St, createBuiltinAuthAdapter as T, PUBLIC_STORAGE_PREFIX as Tt, validatePasswordStrength as U, resolveAuthHooks as V, verifyPassword as W, getUserInvitationTemplate as X, getPasswordResetTemplate as Y, getWelcomeEmailTemplate as Z, verifyOidcIdToken as _, validateApiKey as _t, resolveRateLimitStoreKind as a, createRequireAuth as at, createGoogleProvider as b, SERVICE_IDENTITY as bt, createSlackProvider as c, optionalAuth as ct, createDiscordProvider as d, requireAdmin as dt, escapeHtml as et, createTwitterProvider as f, requireAuth as ft, tryVerifyOidcIdToken as g, isApiKeyToken as gt, createMicrosoftProvider as h, createStorageApiKeyGuard as ht, createApiKeyStore as i, createAuthMiddleware as it, MemoryRateLimitStore as j, createRateLimiter as k, createBitbucketProvider as l, publicObjectAuth as lt, createAppleProvider as m, createFunctionApiKeyGuard as mt, createCustomAuthAdapter as n, raw as nt, createSqlRateLimitStore as o, extractUserFromToken as ot, createFacebookProvider as p, createApiKeyPreAuth as pt, getEmailVerificationTemplate as q, createApiKeyRoutes as r, createAdapterAuthMiddleware as rt, createSpotifyProvider as s, fileTokenAuth as st, auth_exports as t, html as tt, createGitLabProvider as u, queryTokenAuth as ut, createGitHubProvider as v, extractBearerToken as vt, createJwksRoutes as w, isOperationAllowed as wt, oauthCodeFlowSchema as x, scopeDataDriver as xt, createLinkedinProvider as y, safeCompare as yt, assertEmailLinkBases as z };
7097
7109
 
7098
- //# sourceMappingURL=auth-DJsLXsCR.js.map
7110
+ //# sourceMappingURL=auth-gzoRjnuh.js.map