@rebasepro/server 0.16.1-canary.gef08a6e → 0.17.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 (33) hide show
  1. package/dist/{admin_block-BeypnEfb.js → admin_block-BX6YULvJ.js} +8 -8
  2. package/dist/admin_block-BX6YULvJ.js.map +1 -0
  3. package/dist/api/ast-schema-editor.d.ts +1 -1
  4. package/dist/api/rest/idempotency.d.ts +1 -1
  5. package/dist/{ast-schema-editor-BrarYZCq.js → ast-schema-editor-BLADP9O2.js} +3 -3
  6. package/dist/ast-schema-editor-BLADP9O2.js.map +1 -0
  7. package/dist/auth/crypto-utils.d.ts +4 -0
  8. package/dist/auth/jwt-crypto.d.ts +91 -0
  9. package/dist/auth/jwt.d.ts +10 -9
  10. package/dist/auth/middleware.d.ts +1 -1
  11. package/dist/auth/rate-limiter.d.ts +10 -3
  12. package/dist/{auth-DU-nUjPp.js → auth-BVPx33qB.js} +49 -76
  13. package/dist/auth-BVPx33qB.js.map +1 -0
  14. package/dist/boot/fetch-bundle.d.ts +18 -1
  15. package/dist/collections/validate-config.d.ts +14 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.es.js +248 -66
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/{jwt-DoHkMMWF.js → jwt-5VN4C6ln.js} +230 -38
  20. package/dist/jwt-5VN4C6ln.js.map +1 -0
  21. package/dist/{schema-editor-routes-Bf5h5Emf.js → schema-editor-routes-BWCIqZoT.js} +2 -2
  22. package/dist/{schema-editor-routes-Bf5h5Emf.js.map → schema-editor-routes-BWCIqZoT.js.map} +1 -1
  23. package/dist/src-B-CmIFMr.js.map +1 -1
  24. package/dist/src-Cdsw7DqV.js.map +1 -1
  25. package/dist/storage/keys.d.ts +21 -0
  26. package/dist/utils/ip-address.d.ts +30 -0
  27. package/dist/utils/portable-crypto.d.ts +71 -0
  28. package/dist/utils/request-id.d.ts +20 -0
  29. package/package.json +5 -5
  30. package/dist/admin_block-BeypnEfb.js.map +0 -1
  31. package/dist/ast-schema-editor-BrarYZCq.js.map +0 -1
  32. package/dist/auth-DU-nUjPp.js.map +0 -1
  33. package/dist/jwt-DoHkMMWF.js.map +0 -1
package/dist/index.es.js CHANGED
@@ -4,11 +4,11 @@ globalThis.process ??= __rebaseProcess;
4
4
  __rebaseCreateRequire(import.meta.url);
5
5
  import { A as GeoPoint, M as RebaseApiError, N as RebaseClientError, O as EntityReference, S as toSnakeCase, _ as fieldKeyForColumn, b as buildCompositeId, c as collectAllPages, d as normalizeOrderBy, f as serializeOrderBy, g as getEffectiveSecurityRules, h as resolveDataSource, j as Vector, k as EntityRelation, l as paginateFind, m as createDataSourceRegistry, n as buildSdkData, o as serializeFilter, p as CollectionRegistry, s as serializeLogicalCondition, t as buildRoutedRebaseData, u as resolveFindWindow, v as findRelation, x as resolvePrimaryKeys, y as resolveCollectionRelations } from "./src-B-CmIFMr.js";
6
6
  import { a as RLS_JWT_SQL, b as toCanonicalOp, c as getCollectionDataPath, f as DEFAULT_DATA_SOURCE_KEY, i as buildResourceGraph, n as setTopicRuntime, o as RLS_ROLES_SQL, s as RLS_UID_SQL, t as declaredSubscriptions, u as isPostgresCollectionConfig, v as parseRelationAggregateSort } from "./src-Cdsw7DqV.js";
7
- import { n as ADMIN_PROPERTY_KEYS, t as ADMIN_COLLECTION_KEYS } from "./admin_block-BeypnEfb.js";
7
+ import { n as ADMIN_PROPERTY_KEYS, t as ADMIN_COLLECTION_KEYS } from "./admin_block-BX6YULvJ.js";
8
8
  import { a as isDuplicateObjectRace, i as isConcurrentDdlRace, n as createDdlBootstrapper, o as isSQLAdmin, s as isSchemaEditingAdmin, t as CONCURRENT_DDL_SQLSTATES } from "./ddl-bootstrap-5YZCZ8qk.js";
9
- import { C as canonicalStorageKey, D as findStorageSuffixCollision, E as DEFAULT_STORAGE_SOURCE_KEY, O as normalizeStorageSources, S as canonicalStorageId, b as InvalidStorageKeyError, c as getJwks, d as hasAsymmetricSigningKey, i as generateDownloadToken, k as storageEnvSuffix, n as configureJwt, p as isJwtConfigured, v as normalizePemFromEnv, x as canonicalStorageBucket, y as InvalidStorageBucketError } from "./jwt-DoHkMMWF.js";
9
+ import { A as findStorageSuffixCollision, C as canonicalStorageKey, M as storageEnvSuffix, O as sha256Hex, S as canonicalStorageId, b as InvalidStorageKeyError, c as getJwks, d as hasAsymmetricSigningKey, i as generateDownloadToken, j as normalizeStorageSources, k as DEFAULT_STORAGE_SOURCE_KEY, n as configureJwt, p as isJwtConfigured, v as normalizePemFromEnv, x as canonicalStorageBucket, y as InvalidStorageBucketError } from "./jwt-5VN4C6ln.js";
10
10
  import { n as createContractRoutes, r as computeSchemaVersion } from "./contract-routes-D8TvxPLo.js";
11
- import { $ as html, A as activeDevEmailSink, B as hashPassword, C as providerVerifiedEmail, Ct as PUBLIC_STORAGE_PREFIX, D as createDataRateLimiter, E as DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT, F as SMTPEmailService, G as getEmailVerificationTemplate, H as verifyPassword, I as createEmailService, J as getUserInvitationTemplate, K as getMagicLinkTemplate, L as assertEmailLinkBases, M as createDevEmailSink, N as extractLinks, O as defaultAuthLimiter, P as registerDevEmailSink, Q as escapeHtml, R as resolveEmailLinkBase, S as pkceTokenParams, St as isOperationAllowed, T as createBuiltinAuthAdapter, U as generateSecurePassword, V as validatePasswordStrength, W as getEmailOtpTemplate, X as resolveEmailBranding, Y as getWelcomeEmailTemplate, Z as RawHtml, _ as verifyOidcIdToken, _t as safeCompare, a as resolveRateLimitStoreKind, at as fileTokenAuth, b as createGoogleProvider, bt as hasAdministrativeRole, c as createSlackProvider, ct as queryTokenAuth, d as createDiscordProvider, dt as createApiKeyPreAuth, et as raw, f as createTwitterProvider, ft as createFunctionApiKeyGuard, g as tryVerifyOidcIdToken, gt as extractBearerToken, h as createMicrosoftProvider, ht as validateApiKey, i as createApiKeyStore, it as extractUserFromToken, j as clearActiveDevEmailSink, k as MemoryRateLimitStore, l as createBitbucketProvider, lt as requireAdmin, m as createAppleProvider, mt as isApiKeyToken, n as createCustomAuthAdapter, nt as createAuthMiddleware, o as createSqlRateLimitStore, ot as optionalAuth, p as createFacebookProvider, pt as createStorageApiKeyGuard, q as getPasswordResetTemplate, r as createApiKeyRoutes, rt as createRequireAuth, s as createSpotifyProvider, st as publicObjectAuth, tt as createAdapterAuthMiddleware, u as createGitLabProvider, ut as requireAuth, v as createGitHubProvider, vt as SERVICE_IDENTITY, w as createJwksRoutes, wt as isPublicStoragePath, x as oauthCodeFlowSchema, xt as httpMethodToOperation, y as createLinkedinProvider, yt as scopeDataDriver, z as resolveAuthHooks } from "./auth-DU-nUjPp.js";
11
+ import { $ as html, A as activeDevEmailSink, B as hashPassword, C as providerVerifiedEmail, Ct as PUBLIC_STORAGE_PREFIX, D as createDataRateLimiter, E as DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT, F as SMTPEmailService, G as getEmailVerificationTemplate, H as verifyPassword, I as createEmailService, J as getUserInvitationTemplate, K as getMagicLinkTemplate, L as assertEmailLinkBases, M as createDevEmailSink, N as extractLinks, O as defaultAuthLimiter, P as registerDevEmailSink, Q as escapeHtml, R as resolveEmailLinkBase, S as pkceTokenParams, St as isOperationAllowed, T as createBuiltinAuthAdapter, U as generateSecurePassword, V as validatePasswordStrength, W as getEmailOtpTemplate, X as resolveEmailBranding, Y as getWelcomeEmailTemplate, Z as RawHtml, _ as verifyOidcIdToken, _t as safeCompare, a as resolveRateLimitStoreKind, at as fileTokenAuth, b as createGoogleProvider, bt as hasAdministrativeRole, c as createSlackProvider, ct as queryTokenAuth, d as createDiscordProvider, dt as createApiKeyPreAuth, et as raw, f as createTwitterProvider, ft as createFunctionApiKeyGuard, g as tryVerifyOidcIdToken, gt as extractBearerToken, h as createMicrosoftProvider, ht as validateApiKey, i as createApiKeyStore, it as extractUserFromToken, j as clearActiveDevEmailSink, k as MemoryRateLimitStore, l as createBitbucketProvider, lt as requireAdmin, m as createAppleProvider, mt as isApiKeyToken, n as createCustomAuthAdapter, nt as createAuthMiddleware, o as createSqlRateLimitStore, ot as optionalAuth, p as createFacebookProvider, pt as createStorageApiKeyGuard, q as getPasswordResetTemplate, r as createApiKeyRoutes, rt as createRequireAuth, s as createSpotifyProvider, st as publicObjectAuth, tt as createAdapterAuthMiddleware, u as createGitLabProvider, ut as requireAuth, v as createGitHubProvider, vt as SERVICE_IDENTITY, w as createJwksRoutes, wt as isPublicStoragePath, x as oauthCodeFlowSchema, xt as httpMethodToOperation, y as createLinkedinProvider, yt as scopeDataDriver, z as resolveAuthHooks } from "./auth-BVPx33qB.js";
12
12
  import { t as revokeInternalTableSql } from "./internal-tables-DpxfPaEB.js";
13
13
  import { r as hostEnv, t as logger } from "./logger-DS03e908.js";
14
14
  import { n as errorHandler, t as ApiError } from "./errors-DBwpj9N8.js";
@@ -30,7 +30,7 @@ import { t as createCronStore } from "./cron-store-CbFfQhbg.js";
30
30
  import { a as parseBackupTimestamp, i as parseBackupDestination, n as createBackupRoutes, o as readBackupBytes, r as listBackupObjects } from "./backup-CRdZkA6c.js";
31
31
  import { i as createJobStore, n as createJobQueue, r as defaultBackoff } from "./jobs-B2ELModo.js";
32
32
  import { t as METRIC_SERIES } from "./history-store-oiqhb3HU.js";
33
- import { createHash, createSign, randomBytes, randomUUID } from "node:crypto";
33
+ import { createHash, createSign, randomBytes } from "node:crypto";
34
34
  import * as fs$3 from "fs";
35
35
  import fs, { existsSync } from "fs";
36
36
  import * as path$3 from "path";
@@ -39,9 +39,7 @@ import { pathToFileURL } from "url";
39
39
  import { Hono } from "hono";
40
40
  import { promisify } from "util";
41
41
  import * as crypto$1 from "crypto";
42
- import { createHmac, randomUUID as randomUUID$1 } from "crypto";
43
- import * as path$2 from "node:path";
44
- import path$1 from "node:path";
42
+ import { createHmac, randomUUID } from "crypto";
45
43
  import { bodyLimit } from "hono/body-limit";
46
44
  import { csrf } from "hono/csrf";
47
45
  import { compress } from "hono/compress";
@@ -50,12 +48,12 @@ import * as fs$2 from "node:fs/promises";
50
48
  import fsp from "node:fs/promises";
51
49
  import os from "node:os";
52
50
  import { mkdir, open, unlink, writeFile } from "fs/promises";
51
+ import * as path$2 from "node:path";
52
+ import path$1 from "node:path";
53
53
  import { execFile } from "node:child_process";
54
54
  import { promisify as promisify$1 } from "node:util";
55
55
  import { env, getRuntimeKey } from "hono/adapter";
56
56
  import { sql } from "drizzle-orm";
57
- import { lookup } from "node:dns/promises";
58
- import { isIP } from "node:net";
59
57
  import { serveStatic } from "@hono/node-server/serve-static";
60
58
  import { createServer } from "http";
61
59
  import { cors } from "hono/cors";
@@ -136,6 +134,7 @@ var COLLECTION_KEYS = /* @__PURE__ */ new Set([
136
134
  "securityRules",
137
135
  "schema",
138
136
  "search",
137
+ "indexes",
139
138
  "path",
140
139
  "subcollections",
141
140
  "admin"
@@ -325,22 +324,39 @@ var ProblemCollector = class {
325
324
  constructor(unknownKeys) {
326
325
  this.unknownKeys = unknownKeys;
327
326
  }
328
- error(path, message) {
327
+ error(path, message, kind = "incoherent") {
329
328
  this.problems.push({
330
329
  severity: "error",
330
+ kind,
331
+ path,
332
+ message
333
+ });
334
+ }
335
+ /**
336
+ * Config that parses but cannot do what it says.
337
+ *
338
+ * Not gated on `unknownKeys`: that policy is about keys this version has
339
+ * never heard of, where silence is defensible. This is the opposite —
340
+ * every key is recognised, and the combination is known to be wrong.
341
+ */
342
+ warn(path, message) {
343
+ this.problems.push({
344
+ severity: "warning",
345
+ kind: "incoherent",
331
346
  path,
332
347
  message
333
348
  });
334
349
  }
335
350
  /** A key we know moved or died. Always fatal — we know exactly what to do. */
336
351
  migrated(path, key, migration) {
337
- this.error(path, `\`${key}\` is no longer read here. ${migration.fix}.` + (migration.codemod ? ` Run \`${migration.codemod}\` to migrate the whole project.` : ""));
352
+ this.error(path, `\`${key}\` is no longer read here. ${migration.fix}.` + (migration.codemod ? ` Run \`${migration.codemod}\` to migrate the whole project.` : ""), "key");
338
353
  }
339
354
  /** A key nobody recognises. Might be metadata, might be newer than us. */
340
355
  unknown(path, key, context) {
341
356
  if (this.unknownKeys === "off") return;
342
357
  this.problems.push({
343
358
  severity: this.unknownKeys === "error" ? "error" : "warning",
359
+ kind: "key",
344
360
  path,
345
361
  message: `\`${key}\` is not a known ${context} key and is being ignored. If it is deliberate metadata this is safe; if it is a typo or a key from an older version, the feature it configures is silently absent.`
346
362
  });
@@ -433,6 +449,40 @@ function checkProperty(property, path, collect) {
433
449
  function checkProperties(properties, path, collect) {
434
450
  for (const [key, property] of Object.entries(properties)) checkProperty(property, `${path}.${key}`, collect);
435
451
  }
452
+ /**
453
+ * A board's two halves, checked against each other and against `properties`.
454
+ *
455
+ * Every failure here parses cleanly, boots, serves rows and renders a board.
456
+ * The only symptom is that dragging does not stick — which no test, no
457
+ * typecheck and no config review catches, because the config is *valid*, just
458
+ * incoherent. The panel says so in an amber bar, but only to whoever opens the
459
+ * board; this says it to whoever starts the server.
460
+ *
461
+ * The order key is a `fractional-indexing` key in the base36, lower-case
462
+ * alphabet (`"i0"`, `"i1"`, `"i0i"`) — a string, always. Postgres does the
463
+ * sorting and its default collation is not byte ordering, which is why the
464
+ * alphabet is single-case; see `useKanbanDragAndDrop.ts` in the admin.
465
+ */
466
+ function checkBoardConfig(collection, at, collect) {
467
+ const admin = isPlainObject$1(collection.admin) ? collection.admin : void 0;
468
+ if (!admin) return;
469
+ const orderProperty = admin.orderProperty;
470
+ if ((isPlainObject$1(admin.kanban) || Array.isArray(admin.enabledViews) && admin.enabledViews.includes("kanban") || admin.defaultViewMode === "kanban") && orderProperty === void 0) collect.warn(`${at}.admin.orderProperty`, "this collection renders a Kanban board but declares no `orderProperty`, so a card's position within a column has nowhere to be stored and resets on the next read. (Moving a card *between* columns still works — that writes `kanban.columnProperty`.) Add a hidden string property and name it here: `__order: { name: \"Order\", type: \"string\", admin: { disabled: true, hideFromCollection: true } }`.");
471
+ if (orderProperty === void 0) return;
472
+ if (typeof orderProperty !== "string" || !orderProperty) {
473
+ collect.error(`${at}.admin.orderProperty`, "`orderProperty` must be the key of a property in this collection.");
474
+ return;
475
+ }
476
+ if (!isPlainObject$1(collection.properties)) return;
477
+ const target = collection.properties[orderProperty];
478
+ if (target === void 0) {
479
+ collect.error(`${at}.admin.orderProperty`, `\`orderProperty: "${orderProperty}"\` names no property in this collection. Nothing reads or writes it, so the board cannot be reordered at all.`);
480
+ return;
481
+ }
482
+ if (typeof target === "function") return;
483
+ if (!isPlainObject$1(target)) return;
484
+ if (target.type !== "string") collect.error(`${at}.properties.${orderProperty}`, `\`orderProperty\` names a \`${String(target.type)}\` property, and an order key is a string — a \`fractional-indexing\` key such as "i0" or "i0i", not an index. Stored values can never be valid, so the board asks to be initialised forever and the initialisation itself fails writing a string into this column. Change it to \`type: "string"\`.`);
485
+ }
436
486
  function checkCollection(collection, index, collect) {
437
487
  if (!isPlainObject$1(collection)) {
438
488
  collect.error(`collection[${index}]`, "a collection must be an object.");
@@ -455,6 +505,7 @@ function checkCollection(collection, index, collect) {
455
505
  }
456
506
  if (isPlainObject$1(collection.properties)) checkProperties(collection.properties, `${at}.properties`, collect);
457
507
  else if (collection.properties !== void 0) collect.error(`${at}.properties`, "`properties` must be an object keyed by property name.");
508
+ checkBoardConfig(collection, at, collect);
458
509
  if (Array.isArray(collection.relations)) collection.relations.forEach((relation, i) => {
459
510
  const name = isPlainObject$1(relation) && typeof relation.relationName === "string" ? relation.relationName : String(i);
460
511
  checkRelation(relation, `${at}.relations[${name}]`, collect);
@@ -487,11 +538,15 @@ function assertCollectionConfigs(collections, options = {}) {
487
538
  if (problems.length === 0) return;
488
539
  const warnings = problems.filter((p) => p.severity === "warning");
489
540
  const errors = problems.filter((p) => p.severity === "error");
490
- if (warnings.length > 0) logger.warn(`[collections] ${warnings.length} unrecognised key(s) in the collection config, ignored:\n\n` + render(warnings) + "\n\nSet REBASE_STRICT_COLLECTION_CONFIG=error to make these fail the boot.\n");
541
+ const unknownWarnings = warnings.filter((p) => p.kind === "key");
542
+ const incoherentWarnings = warnings.filter((p) => p.kind === "incoherent");
543
+ if (unknownWarnings.length > 0) logger.warn(`[collections] ${unknownWarnings.length} unrecognised key(s) in the collection config, ignored:\n\n` + render(unknownWarnings) + "\n\nSet REBASE_STRICT_COLLECTION_CONFIG=error to make these fail the boot.\n");
544
+ if (incoherentWarnings.length > 0) logger.warn(`[collections] ${incoherentWarnings.length} collection(s) configured for something they cannot do:\n\n` + render(incoherentWarnings) + "\n");
491
545
  if (errors.length === 0) return;
492
- throw new Error(`${errors.length} problem(s) in the collection config.\n\nThese keys are not read by this version. Nothing would have failed at runtime — whatever they configure would simply be absent — so they are fatal at boot instead.
493
-
494
- ` + render(errors) + "\n");
546
+ const deadKeys = errors.filter((p) => p.kind === "key");
547
+ const incoherent = errors.filter((p) => p.kind === "incoherent");
548
+ const sections = [deadKeys.length > 0 ? "These keys are not read by this version. Nothing would have failed at runtime — whatever they configure would simply be absent — so they are fatal at boot instead.\n\n" + render(deadKeys) : void 0, incoherent.length > 0 ? "These parse, and cannot do what they say. Nothing would have failed at runtime — the feature would simply not work — so they are fatal at boot instead.\n\n" + render(incoherent) : void 0].filter(Boolean);
549
+ throw new Error(`${errors.length} problem(s) in the collection config.\n\n` + sections.join("\n\n") + "\n");
495
550
  }
496
551
  //#endregion
497
552
  //#region src/collections/loader.ts
@@ -1670,7 +1725,7 @@ function stableStringify(value) {
1670
1725
  * correction.
1671
1726
  */
1672
1727
  function requestFingerprint(method, path, body) {
1673
- return createHash("sha256").update(`${method.toUpperCase()} ${path}\n${stableStringify(body)}`).digest("hex");
1728
+ return sha256Hex(`${method.toUpperCase()} ${path}\n${stableStringify(body)}`);
1674
1729
  }
1675
1730
  /**
1676
1731
  * Returns `undefined` when the driver cannot run SQL, which disables the whole
@@ -2046,7 +2101,7 @@ var RestApiGenerator = class {
2046
2101
  const idempotencyKey = c.req.header(IDEMPOTENCY_HEADER);
2047
2102
  const uid = c.get("user")?.uid;
2048
2103
  const store = this.idempotency();
2049
- const claimed = idempotencyKey && store ? await store.claim(idempotencyKey, uid, requestFingerprint(c.req.method, c.req.path, body)) : void 0;
2104
+ const claimed = idempotencyKey && store ? await store.claim(idempotencyKey, uid, await requestFingerprint(c.req.method, c.req.path, body)) : void 0;
2050
2105
  if (claimed?.status === "replay") return respond(claimed.response);
2051
2106
  if (claimed?.status === "mismatch") throw idempotencyKeyReused(idempotencyKey);
2052
2107
  if (claimed?.status === "in-flight") throw ApiError.conflict(`A request with Idempotency-Key '${idempotencyKey}' is already in progress. Retry once it has answered; its result will be replayed.`, "IDEMPOTENCY_KEY_IN_PROGRESS");
@@ -2200,7 +2255,7 @@ var RestApiGenerator = class {
2200
2255
  const idempotencyKey = c.req.header(IDEMPOTENCY_HEADER);
2201
2256
  const uid = c.get("user")?.uid;
2202
2257
  const store = this.idempotency();
2203
- const claimed = idempotencyKey && store ? await store.claim(idempotencyKey, uid, requestFingerprint(c.req.method, c.req.path, body)) : void 0;
2258
+ const claimed = idempotencyKey && store ? await store.claim(idempotencyKey, uid, await requestFingerprint(c.req.method, c.req.path, body)) : void 0;
2204
2259
  if (claimed?.status === "replay") return c.json(claimed.response, 201);
2205
2260
  if (claimed?.status === "mismatch") throw idempotencyKeyReused(idempotencyKey);
2206
2261
  if (claimed?.status === "in-flight") throw ApiError.conflict(`A request with Idempotency-Key '${idempotencyKey}' is already in progress. Retry once it has answered; its result will be replayed.`, "IDEMPOTENCY_KEY_IN_PROGRESS");
@@ -2255,14 +2310,33 @@ var RestApiGenerator = class {
2255
2310
  * gateway in front of this API would reject partial updates the server
2256
2311
  * would have accepted.
2257
2312
  *
2258
- * PUT was mounted on the same handler for a while so that published
2259
- * SDKs kept working. It is gone: two verbs for one operation meant the
2260
- * spec had to describe the same route twice, one of them marked
2261
- * deprecated, and a merge served under a verb that means replace is a
2262
- * contract nobody can generate against. `update()` in the SDK sends
2263
- * PATCH.
2313
+ * PUT is mounted on the same handler, and is **not** in the generated
2314
+ * spec: the contract is PATCH, and a client generated from the spec can
2315
+ * only ever send it. The alias exists because dropping it was shipped
2316
+ * ahead of the clients that needed it — every published SDK up to and
2317
+ * including 0.16.0 sends PUT from `collection.update()`, so a control
2318
+ * plane that had already dropped the alias answered `rebase cloud
2319
+ * stop | start | restart` with a 404 naming the caller's own collection.
2320
+ * A verb removal is only safe once the oldest client in the field speaks
2321
+ * the new one.
2322
+ *
2323
+ * Delete it when no released SDK sends PUT any more — i.e. one release
2324
+ * after the first published client whose `update()` sends PATCH, giving
2325
+ * the field a version to move to.
2326
+ *
2327
+ * `Deprecation: true` is RFC 8594's signal, and how a caller finds out
2328
+ * before that happens. No `Sunset` date: the removal is gated on which
2329
+ * SDKs are in the field rather than on a calendar, and inventing a date
2330
+ * we would not honour is worse than saying only what is true. Set inline
2331
+ * rather than through a wrapper — a wrapper has to name the handler's
2332
+ * return type, and Hono's is worth neither widening nor casting for one
2333
+ * header at two call sites.
2264
2334
  */
2265
2335
  this.router.patch(`${basePath}/:id`, updateEntity);
2336
+ this.router.put(`${basePath}/:id`, (c) => {
2337
+ c.header("Deprecation", "true");
2338
+ return updateEntity(c);
2339
+ });
2266
2340
  this.router.delete(`${basePath}/:id`, async (c) => {
2267
2341
  this.enforceApiKeyPermission(c, collection.slug);
2268
2342
  const id = c.req.param("id");
@@ -2432,6 +2506,10 @@ var RestApiGenerator = class {
2432
2506
  return c.json(response);
2433
2507
  };
2434
2508
  this.router.patch("/:parent/:parentId/:rest{.+}", updateNested);
2509
+ this.router.put("/:parent/:parentId/:rest{.+}", (c, next) => {
2510
+ c.header("Deprecation", "true");
2511
+ return updateNested(c, next);
2512
+ });
2435
2513
  this.router.delete("/:parent/:parentId/:rest{.+}", async (c, next) => {
2436
2514
  const rest = c.req.param("rest");
2437
2515
  if (!rest || rest === "undefined") return next();
@@ -2576,32 +2654,12 @@ function responseCompression() {
2576
2654
  }
2577
2655
  //#endregion
2578
2656
  //#region src/utils/request-id.ts
2579
- /**
2580
- * X-Request-ID Middleware for Hono.
2581
- *
2582
- * Generates a unique request identifier (UUID v4) for every inbound
2583
- * request, or propagates an existing `X-Request-ID` header from the
2584
- * caller. The ID is:
2585
- *
2586
- * 1. Stored in the Hono context (`c.get("requestId")`)
2587
- * 2. Echoed back on the response as `X-Request-ID`
2588
- *
2589
- * Downstream middleware and handlers (request logger, error handler,
2590
- * etc.) read the ID from context to include it in log entries and
2591
- * error responses, enabling end-to-end request tracing across services.
2592
- *
2593
- * @example
2594
- * ```ts
2595
- * import { requestId } from "@rebasepro/server";
2596
- * app.use("/*", requestId());
2597
- * ```
2598
- */
2599
2657
  var REQUEST_ID_HEADER = "X-Request-ID";
2600
2658
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2601
2659
  function requestId() {
2602
2660
  return async (c, next) => {
2603
2661
  const incoming = c.req.header(REQUEST_ID_HEADER);
2604
- const id = incoming && UUID_RE.test(incoming) ? incoming : randomUUID();
2662
+ const id = incoming && UUID_RE.test(incoming) ? incoming : crypto.randomUUID();
2605
2663
  c.set("requestId", id);
2606
2664
  await next();
2607
2665
  c.header(REQUEST_ID_HEADER, id);
@@ -3775,7 +3833,7 @@ var TusHandler = class {
3775
3833
  if (Number.isNaN(uploadLength) || uploadLength <= 0) throw ApiError.badRequest("Invalid Upload-Length");
3776
3834
  if (uploadLength > MAX_UPLOAD_SIZE) throw new ApiError(413, "PAYLOAD_TOO_LARGE", `Upload-Length exceeds maximum of ${MAX_UPLOAD_SIZE} bytes`);
3777
3835
  const metadata = this.parseMetadata(c.req.header("Upload-Metadata") || "");
3778
- const id = randomUUID$1();
3836
+ const id = randomUUID();
3779
3837
  const rawKey = metadata.key || metadata.filename || "";
3780
3838
  let key;
3781
3839
  try {
@@ -4567,7 +4625,7 @@ function createStorageRoutes(config) {
4567
4625
  const scopedPath = `${bucket}/${resolvedPath}`;
4568
4626
  if (isPublicStoragePath(scopedPath)) downloadConfig.metadata.public = true;
4569
4627
  else {
4570
- downloadConfig.metadata.token = generateDownloadToken(scopedPath, 300, storageId);
4628
+ downloadConfig.metadata.token = await generateDownloadToken(scopedPath, 300, storageId);
4571
4629
  downloadConfig.metadata.tokenExpiresIn = 300;
4572
4630
  }
4573
4631
  }
@@ -4865,6 +4923,8 @@ function resolveStorageAccessControl(config) {
4865
4923
  }
4866
4924
  //#endregion
4867
4925
  //#region src/init/docs.ts
4926
+ /** Bound once the generator is imported; the route closes over it. */
4927
+ var generateOpenApiSpecFn = null;
4868
4928
  /**
4869
4929
  * Serve the OpenAPI document, and Swagger UI outside production.
4870
4930
  *
@@ -4875,15 +4935,16 @@ function resolveStorageAccessControl(config) {
4875
4935
  * paths that 404, with a Try-It button next to each.
4876
4936
  */
4877
4937
  async function mountOpenApiDocs(app, basePath, enableSwagger, serverCollections, requireAuth) {
4878
- if (enableSwagger === false || serverCollections.length === 0) return;
4938
+ if (serverCollections.length === 0) return;
4939
+ const isPublic = enableSwagger !== false;
4940
+ const spec = (c) => c.json(generateOpenApiSpecFn(serverCollections, {
4941
+ basePath,
4942
+ requireAuth
4943
+ }));
4879
4944
  const { generateOpenApiSpec } = await import("./openapi-generator-FFGT0H6O.js");
4880
- app.get(`${basePath}/docs`, (c) => {
4881
- const spec = generateOpenApiSpec(serverCollections, {
4882
- basePath,
4883
- requireAuth
4884
- });
4885
- return c.json(spec);
4886
- });
4945
+ generateOpenApiSpecFn = generateOpenApiSpec;
4946
+ if (isPublic) app.get(`${basePath}/docs`, (c) => spec(c));
4947
+ else app.get(`${basePath}/docs`, createRequireAuth({}), requireAdmin, (c) => spec(c));
4887
4948
  if (process.env.NODE_ENV !== "production") {
4888
4949
  app.get(`${basePath}/swagger`, (c) => {
4889
4950
  return c.html(`<!DOCTYPE html>
@@ -12977,7 +13038,7 @@ async function _initializeRebaseBackend(config) {
12977
13038
  ]) {
12978
13039
  const providerConfig = safeAuthConfig[key];
12979
13040
  if (providerConfig && requiredFields.every((f) => Boolean(providerConfig[f]))) {
12980
- const createFn = (await import("./auth-DU-nUjPp.js").then((n) => n.t))[factory];
13041
+ const createFn = (await import("./auth-BVPx33qB.js").then((n) => n.t))[factory];
12981
13042
  oauthProviders.push(createFn(providerConfig));
12982
13043
  }
12983
13044
  }
@@ -13079,7 +13140,7 @@ async function _initializeRebaseBackend(config) {
13079
13140
  let schemaEditorOff = schemaEditorUnavailable();
13080
13141
  let schemaEditorRoutes;
13081
13142
  if (!schemaEditorOff && config.collectionsDir) try {
13082
- schemaEditorRoutes = (await import("./schema-editor-routes-Bf5h5Emf.js")).createSchemaEditorRoutes(config.collectionsDir);
13143
+ schemaEditorRoutes = (await import("./schema-editor-routes-BWCIqZoT.js")).createSchemaEditorRoutes(config.collectionsDir);
13083
13144
  } catch (err) {
13084
13145
  if (err?.code === "ERR_MODULE_NOT_FOUND") {
13085
13146
  schemaEditorOff = {
@@ -13145,7 +13206,7 @@ async function _initializeRebaseBackend(config) {
13145
13206
  },
13146
13207
  writeSource: schemaEditorRoutes ? async (change) => {
13147
13208
  const applyEdit = async (dir, collectionId, collection) => {
13148
- const { AstSchemaEditor } = await import("./ast-schema-editor-BrarYZCq.js");
13209
+ const { AstSchemaEditor } = await import("./ast-schema-editor-BLADP9O2.js");
13149
13210
  await new AstSchemaEditor(dir).saveCollection(collectionId, collection, { partial: false });
13150
13211
  };
13151
13212
  if (remoteRepo) {
@@ -14307,6 +14368,55 @@ function loadEnv(options) {
14307
14368
  return env;
14308
14369
  }
14309
14370
  //#endregion
14371
+ //#region src/utils/ip-address.ts
14372
+ /**
14373
+ * `net.isIP`, without `node:net`.
14374
+ *
14375
+ * The SSRF guard in `services/outbound-url-guard.ts` needs to know whether a
14376
+ * host is already a literal address before it decides whether to resolve it.
14377
+ * That is pure string parsing — it opens no socket and asks nothing of the
14378
+ * platform — but importing it from `node:net` pinned the guard to a Node
14379
+ * process anyway. The guard's only other host dependency, the resolver, is
14380
+ * already injectable, so this is what stood between it and running anywhere.
14381
+ *
14382
+ * That matters more here than the line count suggests. On a host with no
14383
+ * `dns.lookup` the guard has to be given a resolver (DNS-over-HTTPS, or the
14384
+ * platform's own), and a module that cannot be *imported* there cannot be
14385
+ * given anything. The alternative — an isolate deployment quietly running
14386
+ * without the guard — is how a webhook destination becomes a way to read the
14387
+ * metadata endpoint.
14388
+ *
14389
+ * The grammar is Node's own, transcribed from `lib/internal/net.js`, and
14390
+ * `test/property/ip-address.property.test.ts` holds it to that by comparing against
14391
+ * `net.isIP` over generated addresses. Transcribing a validator by eye and
14392
+ * declaring it equivalent is not a thing to do to a security boundary; being
14393
+ * able to *check* the claim on every run is what makes it acceptable.
14394
+ *
14395
+ * @module
14396
+ */
14397
+ var IPV4_SEGMENT = "(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])";
14398
+ var IPV4 = `(?:${IPV4_SEGMENT}\\.){3}${IPV4_SEGMENT}`;
14399
+ var IPV4_RE = new RegExp(`^${IPV4}$`);
14400
+ var IPV6_SEGMENT = "(?:[0-9a-fA-F]{1,4})";
14401
+ /**
14402
+ * One alternative per position the `::` elision can occupy, which is why this
14403
+ * is nine branches rather than something shorter and wrong: a compact pattern
14404
+ * that admits two elisions, or a trailing dotted quad in the wrong place,
14405
+ * accepts strings the resolver would reject and the guard would then judge on
14406
+ * bytes it invented.
14407
+ */
14408
+ var IPV6 = `(?:(?:${IPV6_SEGMENT}:){7}(?:${IPV6_SEGMENT}|:)|(?:${IPV6_SEGMENT}:){6}(?:${IPV4}|:${IPV6_SEGMENT}|:)|(?:${IPV6_SEGMENT}:){5}(?::${IPV4}|(?::${IPV6_SEGMENT}){1,2}|:)|(?:${IPV6_SEGMENT}:){4}(?:(?::${IPV6_SEGMENT}){0,1}:${IPV4}|(?::${IPV6_SEGMENT}){1,3}|:)|(?:${IPV6_SEGMENT}:){3}(?:(?::${IPV6_SEGMENT}){0,2}:${IPV4}|(?::${IPV6_SEGMENT}){1,4}|:)|(?:${IPV6_SEGMENT}:){2}(?:(?::${IPV6_SEGMENT}){0,3}:${IPV4}|(?::${IPV6_SEGMENT}){1,5}|:)|(?:${IPV6_SEGMENT}:){1}(?:(?::${IPV6_SEGMENT}){0,4}:${IPV4}|(?::${IPV6_SEGMENT}){1,6}|:)|(?::(?:(?::${IPV6_SEGMENT}){0,5}:${IPV4}|(?::${IPV6_SEGMENT}){1,7}|:)))(?:%[0-9a-zA-Z-.:]{1,})?`;
14409
+ var IPV6_RE = new RegExp(`^${IPV6}$`);
14410
+ /**
14411
+ * `4`, `6`, or `0` for anything that is not an IP address — the same three
14412
+ * answers, for the same inputs, as `net.isIP`.
14413
+ */
14414
+ function ipVersion(address) {
14415
+ if (IPV4_RE.test(address)) return 4;
14416
+ if (IPV6_RE.test(address)) return 6;
14417
+ return 0;
14418
+ }
14419
+ //#endregion
14310
14420
  //#region src/services/outbound-url-guard.ts
14311
14421
  /**
14312
14422
  * Refusal to send a request to a destination the guard does not allow.
@@ -14328,8 +14438,27 @@ var BLOCKED_HOST_SUFFIXES = [
14328
14438
  ".internal",
14329
14439
  ".home.arpa"
14330
14440
  ];
14441
+ /**
14442
+ * The resolver when the caller supplies none: Node's.
14443
+ *
14444
+ * Loaded on use rather than imported at the top, which is what keeps this
14445
+ * module — the check standing between a stored URL and the pod's own metadata
14446
+ * endpoint — loadable on a runtime that has no `node:dns`. There the caller
14447
+ * passes {@link OutboundUrlGuardOptions.lookup} instead, pointing at whatever
14448
+ * the host resolves names with.
14449
+ *
14450
+ * A host with neither fails **closed**, and says which of the two it is
14451
+ * missing: the alternative to resolving a name is not "allow it", it is "do
14452
+ * not send".
14453
+ */
14331
14454
  async function defaultLookup(hostname) {
14332
- return (await lookup(hostname, {
14455
+ let dns;
14456
+ try {
14457
+ dns = await import("node:dns/promises");
14458
+ } catch {
14459
+ throw new BlockedUrlError(`Cannot check where "${hostname}" points: this runtime has no \`node:dns\`, and no \`lookup\` was supplied to the outbound URL guard. Pass one — the guard cannot be skipped, because skipping it is what makes a stored URL a way to reach the internal network.`);
14460
+ }
14461
+ return (await dns.lookup(hostname, {
14333
14462
  all: true,
14334
14463
  verbatim: true
14335
14464
  })).map((e) => e.address);
@@ -14348,7 +14477,7 @@ function parseIpv6(address) {
14348
14477
  const lastColon = text.lastIndexOf(":");
14349
14478
  const maybeV4 = text.slice(lastColon + 1);
14350
14479
  if (maybeV4.includes(".")) {
14351
- if (isIP(maybeV4) !== 4) return null;
14480
+ if (ipVersion(maybeV4) !== 4) return null;
14352
14481
  tail = maybeV4.split(".").map(Number);
14353
14482
  text = text.slice(0, lastColon);
14354
14483
  if (text.endsWith(":")) text += ":";
@@ -14396,7 +14525,7 @@ function blockedIpv4Reason(bytes) {
14396
14525
  * outbound call whose destination comes from data.
14397
14526
  */
14398
14527
  function blockedAddressReason(address) {
14399
- const version = isIP(address);
14528
+ const version = ipVersion(address);
14400
14529
  if (version === 4) return blockedIpv4Reason(address.split(".").map(Number));
14401
14530
  if (version !== 6) return `not an IP address: ${address}`;
14402
14531
  const bytes = parseIpv6(address);
@@ -14447,7 +14576,7 @@ async function assertAllowedOutboundUrl(rawUrl, options = {}) {
14447
14576
  const hostname = url.hostname.startsWith("[") ? url.hostname.slice(1, -1) : url.hostname;
14448
14577
  const lowered = hostname.toLowerCase();
14449
14578
  if (lowered === "localhost" || BLOCKED_HOST_SUFFIXES.some((suffix) => lowered.endsWith(suffix))) throw new BlockedUrlError(`Webhook URL host "${hostname}" is an internal name`);
14450
- const addresses = isIP(hostname) ? [hostname] : await (options.lookup ?? defaultLookup)(hostname);
14579
+ const addresses = ipVersion(hostname) ? [hostname] : await (options.lookup ?? defaultLookup)(hostname);
14451
14580
  if (addresses.length === 0) throw new BlockedUrlError(`Webhook URL host "${hostname}" resolved to no addresses`);
14452
14581
  for (const address of addresses) {
14453
14582
  const reason = blockedAddressReason(address);
@@ -14636,7 +14765,7 @@ var WebhookDispatcher = class {
14636
14765
  "Content-Type": "application/json",
14637
14766
  "X-Webhook-Id": webhook.id,
14638
14767
  "X-Webhook-Event": event,
14639
- "X-Webhook-Delivery": randomUUID$1(),
14768
+ "X-Webhook-Delivery": randomUUID(),
14640
14769
  "X-Webhook-Attempt": String(attemptNumber),
14641
14770
  ...webhook.headers || {}
14642
14771
  };
@@ -16780,6 +16909,29 @@ var BUNDLE_URL_ENV = "REBASE_BUNDLE_URL";
16780
16909
  /** Bearer token for that fetch. Does not expire — see the module note. */
16781
16910
  var BUNDLE_TOKEN_ENV = "REBASE_BUNDLE_TOKEN";
16782
16911
  /**
16912
+ * Records which URL produced the tree sitting in the fetch directory.
16913
+ *
16914
+ * Reusing an already-unpacked bundle is what makes a restart cheap, but "there
16915
+ * is a bundle here" is not the same question as "is it the bundle we were told
16916
+ * to run". Anything that fills the directory behind the runtime's back — an
16917
+ * orphaned `fetch-bundle` init container left on a Deployment, a stale volume —
16918
+ * used to win over the URL, and the pod then served whatever it found while
16919
+ * every deploy reported success. The URL is the instruction; this is how a
16920
+ * restart tells whether the disk already satisfies it.
16921
+ *
16922
+ * `infra/docker/entrypoint.mjs` reads this file by the same name to decide
16923
+ * whether to fetch at all — keep the two in step.
16924
+ */
16925
+ var BUNDLE_SOURCE_FILENAME = ".rebase-bundle-source";
16926
+ /** What the tree in `destination` was fetched from, or null if unknown. */
16927
+ function unpackedBundleSource(destination) {
16928
+ try {
16929
+ return fs$1.readFileSync(path$1.join(destination, BUNDLE_SOURCE_FILENAME), "utf8").trim();
16930
+ } catch {
16931
+ return null;
16932
+ }
16933
+ }
16934
+ /**
16783
16935
  * Whether this process should fetch its bundle rather than read one from disk.
16784
16936
  *
16785
16937
  * An explicit `REBASE_BUNDLE` — a path — always wins. A platform that mounted a
@@ -16789,14 +16941,28 @@ var BUNDLE_TOKEN_ENV = "REBASE_BUNDLE_TOKEN";
16789
16941
  function shouldFetchBundle(env = process.env) {
16790
16942
  return Boolean(env["REBASE_BUNDLE_URL"]) && !env.REBASE_BUNDLE;
16791
16943
  }
16944
+ /**
16945
+ * Whether the system `tar` is GNU tar.
16946
+ *
16947
+ * Asked rather than assumed, because the answer differs between a developer's
16948
+ * machine and the Linux image the same code runs in, and the flags below are
16949
+ * GNU spellings that bsdtar rejects outright. Probed once per process.
16950
+ */
16951
+ var gnuTar;
16952
+ function isGnuTar() {
16953
+ gnuTar ??= run("tar", ["--version"]).then(({ stdout }) => /GNU tar/.test(String(stdout))).catch(() => false);
16954
+ return gnuTar;
16955
+ }
16792
16956
  /** Untar with the system `tar`, which every base image has. */
16793
16957
  async function extractWithTar(tarball, destination) {
16794
- await run("tar", [
16958
+ const args = [
16795
16959
  "-xzmf",
16796
16960
  tarball,
16797
16961
  "-C",
16798
16962
  destination
16799
- ]);
16963
+ ];
16964
+ if (await isGnuTar()) args.push("--no-same-owner", "--no-same-permissions", "--no-overwrite-dir");
16965
+ await run("tar", args);
16800
16966
  }
16801
16967
  /**
16802
16968
  * Download and unpack a bundle, returning the directory it landed in.
@@ -16999,6 +17165,21 @@ async function fetchBundle(options) {
16999
17165
  fs$1.rmSync(tarball, { force: true });
17000
17166
  throw new Error(`Could not download the bundle from ${options.url}: ` + (lastError instanceof Error ? lastError.message : String(lastError)));
17001
17167
  }
17168
+ const previous = unpackedBundleSource(destination);
17169
+ if (previous !== null && previous !== options.url) {
17170
+ logger.info("Discarding a bundle unpacked from a different source", {
17171
+ previous,
17172
+ replacing: options.url
17173
+ });
17174
+ for (const entry of fs$1.readdirSync(destination)) {
17175
+ const victim = path$1.join(destination, entry);
17176
+ if (victim === tarball) continue;
17177
+ fs$1.rmSync(victim, {
17178
+ recursive: true,
17179
+ force: true
17180
+ });
17181
+ }
17182
+ }
17002
17183
  const { size } = fs$1.statSync(tarball);
17003
17184
  try {
17004
17185
  await extract(tarball, destination);
@@ -17009,6 +17190,7 @@ async function fetchBundle(options) {
17009
17190
  }
17010
17191
  const root = bundleRootIn(destination);
17011
17192
  if (!root) throw new Error(`The bundle downloaded from ${options.url} unpacked without a ${MANIFEST_FILENAME}. It is not a Rebase bundle, or it was truncated.`);
17193
+ fs$1.writeFileSync(path$1.join(destination, BUNDLE_SOURCE_FILENAME), options.url);
17012
17194
  if (options.installDependencies ?? true) await (options.installImpl ?? installBundleDependencies)(root);
17013
17195
  return root;
17014
17196
  }
@@ -17578,6 +17760,6 @@ var RUNTIME_STARTUP_BUDGET_SECONDS = 300;
17578
17760
  /** Where a bundle is mounted, and what the runtime is told to read. */
17579
17761
  var RUNTIME_BUNDLE_MOUNT = "/bundle";
17580
17762
  //#endregion
17581
- export { ApiError, BlockedUrlError, BundleError, CONCURRENT_DDL_SQLSTATES, CronScheduler, DEFAULT_DRIVER_ID, DEFAULT_MAX_FILE_SIZE, DEFAULT_STORAGE_ID, DOCUMENT_MIME_TYPES, DefaultDriverRegistry, DefaultStorageRegistry, GCSStorageController, IMAGE_MIME_TYPES, LocalStorageController, MetricsRegistry, RUNTIME_BUNDLE_MOUNT, RUNTIME_HEALTH_PATH, RUNTIME_LIVENESS_PATH, RUNTIME_MIN_TERMINATION_GRACE_SECONDS, RUNTIME_PRESTOP_DRAIN_SECONDS, RUNTIME_PROBE_PATHS, RUNTIME_STARTUP_BUDGET_SECONDS, RawHtml, S3StorageController, SMTPEmailService, StoragePolicyError, TOPOLOGY_ENV_VARS, TransformCache, TusHandler, UnknownStorageSourceError, WEBHOOK_DELIVERY_TASK, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, activeDevEmailSink, applyCollectionDefaults, assertAllowedOutboundUrl, assertCollectionConfigs, assertDistinctSuffixes, assertEmailLinkBases, assertWriteRequestValid, authJwt, authRoles, authUid, blockedAddressReason, bootFromBundle, classifySurface, cleanupDevPortFile, clearActiveDevEmailSink, compileStoragePolicies, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDdlBootstrapper, createDevEmailSink, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createJobQueue, createJobStore, createJwksRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createRlsAudit, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defaultBackoff, defineCron, defineFunction, drainBackgroundWork, envSuffixForKey, errorHandler, escapeHtml, extractLinks, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getApiKey, getDriver, getEmailOtpTemplate, getEmailVerificationTemplate, getEnv, getJwks, getMagicLinkTemplate, getPasswordResetTemplate, getRequestId, getRoles, getUser, getUserId, getUserInvitationTemplate, getWelcomeEmailTemplate, hasAsymmetricSigningKey, hasRole, hashPassword, html, httpMethodToOperation, identityResolved, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isAdmin, isApiKeyToken, isAuthAdapter, isAuthenticated, isConcurrentDdlRace, isDatabaseAdapter, isDuplicateObjectRace, isLocalhostOrigin, isNodeRuntime, isOperationAllowed, isTopologyEnvVar, isTransformableImage, lazyResource, listBackupObjects, listenWithPortRetry, loadBootEnv, loadBundle, loadBundleConfigExports, loadBundleSchema, loadCollectionsFromDirectory, loadCronJobsFromDirectory, loadCronJobsWithDiagnostics, loadDeclaredStorageSources, loadEnv, loadFunctionsFromDirectory, loadFunctionsWithDiagnostics, loadUsersCollection, logger, oauthCodeFlowSchema, optionalAuth, parseBackupDestination, parseBackupTimestamp, parseTransformOptions, pendingBackgroundWork, pkceTokenParams, providerVerifiedEmail, queryTokenAuth, raw, readBackupBytes, readBundleManifest, rebase, registerDevEmailSink, requireAdmin, requireAuth, requireDriver, requireEnv, requireRole, resolveAuthHooks, resolveAuthOptions, resolveCorsOrigin, resolveDataSources, resolveEmailBranding, resolveEmailLinkBase, resolveEmailOptions, resolveRequireAuth, resolveStorageAccessControl, resolveStorageBackend, resolveStorageSources, runFromBundle, runtimeKey, safeCompare, serveSPA, summarize as summarizeRlsScan, transformImage, tryVerifyOidcIdToken, unknownKeyPolicyFromEnv, validateApiKey, validateCronExpression, validatePasswordStrength, verifyOidcIdToken, verifyPassword, waitUntil };
17763
+ export { ApiError, BlockedUrlError, BundleError, CONCURRENT_DDL_SQLSTATES, CronScheduler, DEFAULT_DRIVER_ID, DEFAULT_MAX_FILE_SIZE, DEFAULT_STORAGE_ID, DOCUMENT_MIME_TYPES, DefaultDriverRegistry, DefaultStorageRegistry, GCSStorageController, IMAGE_MIME_TYPES, LocalStorageController, MetricsRegistry, RUNTIME_BUNDLE_MOUNT, RUNTIME_HEALTH_PATH, RUNTIME_LIVENESS_PATH, RUNTIME_MIN_TERMINATION_GRACE_SECONDS, RUNTIME_PRESTOP_DRAIN_SECONDS, RUNTIME_PROBE_PATHS, RUNTIME_STARTUP_BUDGET_SECONDS, RawHtml, S3StorageController, SMTPEmailService, StoragePolicyError, TOPOLOGY_ENV_VARS, TransformCache, TusHandler, UnknownStorageSourceError, WEBHOOK_DELIVERY_TASK, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, activeDevEmailSink, applyCollectionDefaults, assertAllowedOutboundUrl, assertCollectionConfigs, assertDistinctSuffixes, assertEmailLinkBases, assertWriteRequestValid, authJwt, authRoles, authUid, blockedAddressReason, bootFromBundle, classifySurface, cleanupDevPortFile, clearActiveDevEmailSink, compileStoragePolicies, configureJwt, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDdlBootstrapper, createDevEmailSink, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createJobQueue, createJobStore, createJwksRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createRlsAudit, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defaultBackoff, defineCron, defineFunction, drainBackgroundWork, envSuffixForKey, errorHandler, escapeHtml, extractLinks, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getApiKey, getDriver, getEmailOtpTemplate, getEmailVerificationTemplate, getEnv, getJwks, getMagicLinkTemplate, getPasswordResetTemplate, getRequestId, getRoles, getUser, getUserId, getUserInvitationTemplate, getWelcomeEmailTemplate, hasAsymmetricSigningKey, hasRole, hashPassword, html, httpMethodToOperation, identityResolved, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isAdmin, isApiKeyToken, isAuthAdapter, isAuthenticated, isConcurrentDdlRace, isDatabaseAdapter, isDuplicateObjectRace, isLocalhostOrigin, isNodeRuntime, isOperationAllowed, isTopologyEnvVar, isTransformableImage, lazyResource, listBackupObjects, listenWithPortRetry, loadBootEnv, loadBundle, loadBundleConfigExports, loadBundleSchema, loadCollectionsFromDirectory, loadCronJobsFromDirectory, loadCronJobsWithDiagnostics, loadDeclaredStorageSources, loadEnv, loadFunctionsFromDirectory, loadFunctionsWithDiagnostics, loadUsersCollection, logger, oauthCodeFlowSchema, optionalAuth, parseBackupDestination, parseBackupTimestamp, parseTransformOptions, pendingBackgroundWork, pkceTokenParams, providerVerifiedEmail, queryTokenAuth, raw, readBackupBytes, readBundleManifest, rebase, registerDevEmailSink, requireAdmin, requireAuth, requireDriver, requireEnv, requireRole, resolveAuthHooks, resolveAuthOptions, resolveCorsOrigin, resolveDataSources, resolveEmailBranding, resolveEmailLinkBase, resolveEmailOptions, resolveRequireAuth, resolveStorageAccessControl, resolveStorageBackend, resolveStorageSources, runFromBundle, runtimeKey, safeCompare, serveSPA, summarize as summarizeRlsScan, transformImage, tryVerifyOidcIdToken, unknownKeyPolicyFromEnv, validateApiKey, validateCronExpression, validatePasswordStrength, verifyOidcIdToken, verifyPassword, waitUntil };
17582
17764
 
17583
17765
  //# sourceMappingURL=index.es.js.map