@rebasepro/server 0.15.0 → 0.16.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 (36) hide show
  1. package/dist/auth/api-keys/api-key-middleware.d.ts +1 -1
  2. package/dist/auth/jwt.d.ts +1 -1
  3. package/dist/auth/rls-scope.d.ts +1 -1
  4. package/dist/{auth-DIKS1rsI.js → auth-5Et5mnUA.js} +141 -32
  5. package/dist/auth-5Et5mnUA.js.map +1 -0
  6. package/dist/boot/boot.d.ts +17 -1
  7. package/dist/boot/env.d.ts +1 -0
  8. package/dist/boot/provision.d.ts +1 -1
  9. package/dist/boot/schema-stamp.d.ts +173 -0
  10. package/dist/boot/version-skew.d.ts +27 -3
  11. package/dist/{contract-routes-DDNj4_J1.js → contract-routes-DZ-LBpSL.js} +2 -2
  12. package/dist/contract-routes-DZ-LBpSL.js.map +1 -0
  13. package/dist/cron/define-cron.d.ts +1 -1
  14. package/dist/{cron-store-BBGvOA-9.js → cron-store-DfH_4Cd9.js} +2 -2
  15. package/dist/{cron-store-BBGvOA-9.js.map → cron-store-DfH_4Cd9.js.map} +1 -1
  16. package/dist/ddl-bootstrap-Cywoj8Ta.js.map +1 -1
  17. package/dist/email/index.d.ts +1 -0
  18. package/dist/email/templates.d.ts +21 -5
  19. package/dist/email/types.d.ts +14 -0
  20. package/dist/functions/define-function.d.ts +1 -1
  21. package/dist/index.es.js +386 -35
  22. package/dist/index.es.js.map +1 -1
  23. package/dist/init/surfaces.d.ts +8 -1
  24. package/dist/{jobs-BOEOIGAm.js → jobs-CyOKXXlu.js} +2 -2
  25. package/dist/{jobs-BOEOIGAm.js.map → jobs-CyOKXXlu.js.map} +1 -1
  26. package/dist/jwt-DxH9fLPt.js.map +1 -1
  27. package/dist/{openapi-generator-DLiiGD9X.js → openapi-generator-BCKJRUS4.js} +2 -2
  28. package/dist/{openapi-generator-DLiiGD9X.js.map → openapi-generator-BCKJRUS4.js.map} +1 -1
  29. package/dist/singleton.d.ts +1 -1
  30. package/dist/{src-B-E7RjdN.js → src-BPfYOeN4.js} +3 -3
  31. package/dist/src-BPfYOeN4.js.map +1 -0
  32. package/dist/src-CrCxd8km.js.map +1 -1
  33. package/package.json +5 -5
  34. package/dist/auth-DIKS1rsI.js.map +0 -1
  35. package/dist/contract-routes-DDNj4_J1.js.map +0 -1
  36. package/dist/src-B-E7RjdN.js.map +0 -1
package/dist/index.es.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { createRequire as __createRequire } from "module";
2
2
  import process from "process";
3
3
  __createRequire(import.meta.url);
4
- 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-E7RjdN.js";
4
+ 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-BPfYOeN4.js";
5
5
  import { c as DEFAULT_DATA_SOURCE_KEY, g as toCanonicalOp, i as getCollectionDataPath, m as parseRelationAggregateSort, n as RLS_ROLES_SQL, o as isPostgresCollectionConfig, r as RLS_UID_SQL, t as RLS_JWT_SQL } from "./src-CrCxd8km.js";
6
6
  import { n as ADMIN_PROPERTY_KEYS, t as ADMIN_COLLECTION_KEYS } from "./admin_block-DLILvzle.js";
7
7
  import { a as isDuplicateObjectRace, i as isConcurrentDdlRace, n as createDdlBootstrapper, o as revokeInternalTableSql, s as isSQLAdmin, t as CONCURRENT_DDL_SQLSTATES } from "./ddl-bootstrap-Cywoj8Ta.js";
8
8
  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-DxH9fLPt.js";
9
- import { n as createContractRoutes } from "./contract-routes-DDNj4_J1.js";
10
- import { $ as createAuthMiddleware, A as _coercedNumber, B as validatePasswordStrength, C as providerVerifiedEmail, Ct as resolveListLimitParam, D as _enum, E as ZodNumber, F as createEmailService, G as getPasswordResetTemplate, H as generateSecurePassword, I as assertEmailLinkBases, J as RawHtml, K as getUserInvitationTemplate, L as resolveEmailLinkBase, M as createDataRateLimiter, N as MemoryRateLimitStore, O as object, P as SMTPEmailService, Q as createAdapterAuthMiddleware, R as resolveAuthHooks, S as pkceTokenParams, St as parseQueryOptions, T as createBuiltinAuthAdapter, Tt as isPublicStoragePath, U as getEmailVerificationTemplate, V as verifyPassword, W as getMagicLinkTemplate, X as html, Y as escapeHtml, Z as raw, _ as verifyOidcIdToken, _t as httpMethodToOperation, a as resolveRateLimitStoreKind, at as queryTokenAuth, b as createGoogleProvider, bt as parseAggregateSelect, c as createSlackProvider, ct as createApiKeyPreAuth, d as createDiscordProvider, dt as isApiKeyToken, et as createRequireAuth, f as createTwitterProvider, ft as validateApiKey, g as tryVerifyOidcIdToken, gt as scopeDataDriver, h as createMicrosoftProvider, ht as SERVICE_IDENTITY, i as createApiKeyStore, it as publicObjectAuth, j as DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT, k as string, l as createBitbucketProvider, lt as createFunctionApiKeyGuard, m as createAppleProvider, mt as safeCompare, n as createCustomAuthAdapter, nt as fileTokenAuth, o as createSqlRateLimitStore, ot as requireAdmin, p as createFacebookProvider, pt as extractBearerToken, q as getWelcomeEmailTemplate, r as createApiKeyRoutes, rt as optionalAuth, s as createSpotifyProvider, st as requireAuth, tt as extractUserFromToken, u as createGitLabProvider, ut as createStorageApiKeyGuard, v as createGitHubProvider, vt as isOperationAllowed, w as createJwksRoutes, wt as PUBLIC_STORAGE_PREFIX, x as oauthCodeFlowSchema, xt as parseGroupBy, y as createLinkedinProvider, yt as orderByEntriesToTuples, z as hashPassword } from "./auth-DIKS1rsI.js";
9
+ import { n as createContractRoutes, r as computeSchemaVersion } from "./contract-routes-DZ-LBpSL.js";
10
+ import { $ as createAdapterAuthMiddleware, A as _coercedNumber, B as validatePasswordStrength, C as providerVerifiedEmail, Ct as parseQueryOptions, D as _enum, E as ZodNumber, Et as isPublicStoragePath, F as createEmailService, G as getPasswordResetTemplate, H as generateSecurePassword, I as assertEmailLinkBases, J as resolveEmailBranding, K as getUserInvitationTemplate, L as resolveEmailLinkBase, M as createDataRateLimiter, N as MemoryRateLimitStore, O as object, P as SMTPEmailService, Q as raw, R as resolveAuthHooks, S as pkceTokenParams, St as parseGroupBy, T as createBuiltinAuthAdapter, Tt as PUBLIC_STORAGE_PREFIX, U as getEmailVerificationTemplate, V as verifyPassword, W as getMagicLinkTemplate, X as escapeHtml, Y as RawHtml, Z as html, _ as verifyOidcIdToken, _t as scopeDataDriver, a as resolveRateLimitStoreKind, at as publicObjectAuth, b as createGoogleProvider, bt as orderByEntriesToTuples, c as createSlackProvider, ct as requireAuth, d as createDiscordProvider, dt as createStorageApiKeyGuard, et as createAuthMiddleware, f as createTwitterProvider, ft as isApiKeyToken, g as tryVerifyOidcIdToken, gt as SERVICE_IDENTITY, h as createMicrosoftProvider, ht as safeCompare, i as createApiKeyStore, it as optionalAuth, j as DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT, k as string, l as createBitbucketProvider, lt as createApiKeyPreAuth, m as createAppleProvider, mt as extractBearerToken, n as createCustomAuthAdapter, nt as extractUserFromToken, o as createSqlRateLimitStore, ot as queryTokenAuth, p as createFacebookProvider, pt as validateApiKey, q as getWelcomeEmailTemplate, r as createApiKeyRoutes, rt as fileTokenAuth, s as createSpotifyProvider, st as requireAdmin, tt as createRequireAuth, u as createGitLabProvider, ut as createFunctionApiKeyGuard, v as createGitHubProvider, vt as httpMethodToOperation, w as createJwksRoutes, wt as resolveListLimitParam, x as oauthCodeFlowSchema, xt as parseAggregateSelect, y as createLinkedinProvider, yt as isOperationAllowed, z as hashPassword } from "./auth-5Et5mnUA.js";
11
11
  import { t as logger } from "./logger-DfvF_8r-.js";
12
12
  import { n as errorHandler, t as ApiError } from "./errors-EBYiaJ2E.js";
13
13
  import { t as logMiddleware } from "./logs-routes-CWBLQj2l.js";
@@ -19,9 +19,9 @@ import { t as createFunctionRoutes } from "./function-routes-Btcez1T-.js";
19
19
  import { n as loadCronJobsFromDirectory, r as loadCronJobsWithDiagnostics } from "./cron-loader-YhhQeVBM.js";
20
20
  import { r as validateCronExpression, t as CronScheduler } from "./cron-scheduler-DIpYBmZP.js";
21
21
  import { t as createCronRoutes } from "./cron-routes-maM_RlUu.js";
22
- import { t as createCronStore } from "./cron-store-BBGvOA-9.js";
22
+ import { t as createCronStore } from "./cron-store-DfH_4Cd9.js";
23
23
  import { a as parseBackupTimestamp, i as parseBackupDestination, n as createBackupRoutes, o as readBackupBytes, r as listBackupObjects } from "./backup-C6ljYVTp.js";
24
- import { i as createJobStore, n as createJobQueue, r as defaultBackoff } from "./jobs-BOEOIGAm.js";
24
+ import { i as createJobStore, n as createJobQueue, r as defaultBackoff } from "./jobs-CyOKXXlu.js";
25
25
  import { t as FunctionSelectionError } from "./selection-_z6TM1DB.js";
26
26
  import { createHash, randomBytes, randomUUID } from "node:crypto";
27
27
  import * as fs$2 from "fs";
@@ -607,22 +607,56 @@ function compareVersions(a, b) {
607
607
  return left.prerelease < right.prerelease ? -1 : 1;
608
608
  }
609
609
  /**
610
+ * Does `version` lead `against` by at least a minor?
611
+ *
612
+ * Compares the `(major, minor)` pair and ignores the patch, which is the whole
613
+ * point: it separates "pinned one fix ahead", a supported and deliberate thing,
614
+ * from "built against a framework this image predates". Pre-1.0 the minor is the
615
+ * breaking-change axis, so the same tuple comparison is right on both sides of
616
+ * 1.0 without a special case.
617
+ *
618
+ * `undefined` when either version is unparseable, so the caller declines to
619
+ * judge rather than guessing.
620
+ */
621
+ function leadsByMinorOrMore(version, against) {
622
+ const left = parseVersion(version);
623
+ const right = parseVersion(against);
624
+ if (!left || !right) return void 0;
625
+ if (left.parts[0] !== right.parts[0]) return left.parts[0] > right.parts[0];
626
+ return left.parts[1] > right.parts[1];
627
+ }
628
+ /**
610
629
  * Describe how a driver's version relates to the runtime asking it for work.
611
630
  *
612
- * Returns `stale: false` whenever it cannot tell an unknown version, an
613
- * unparseable one, a driver that is newer. Silence beats a confident wrong
614
- * diagnosis, and the caller still prints its own local fact either way.
631
+ * Both directions are reportable, for opposite reasons. A driver **behind** the
632
+ * runtime lacks capabilities the runtime will ask for, and reports their absence
633
+ * in language indistinguishable from a driver that never had them. A driver
634
+ * **ahead** by a minor carries half of a feature whose other half lives in
635
+ * `@rebasepro/server` — and the image supplies that half, so the bundle's code
636
+ * runs against a harness that does not know about it.
637
+ *
638
+ * Returns both flags false whenever it cannot tell: an unknown version, an
639
+ * unparseable one, or a gap too small to mean anything. Silence beats a
640
+ * confident wrong diagnosis, and the caller still prints its own local fact.
615
641
  */
616
642
  function describeDriverSkew(driverVersion, runtimeVersion) {
617
- if (!driverVersion || !runtimeVersion) return { stale: false };
643
+ if (!driverVersion || !runtimeVersion) return {
644
+ stale: false,
645
+ ahead: false
646
+ };
618
647
  const order = compareVersions(driverVersion, runtimeVersion);
619
- if (order === void 0) return { stale: false };
648
+ if (order === void 0) return {
649
+ stale: false,
650
+ ahead: false
651
+ };
620
652
  if (order < 0) return {
621
653
  stale: true,
654
+ ahead: false,
622
655
  detail: `The driver is at ${driverVersion} while this runtime is ${runtimeVersion} — the driver is OLDER, so this is very likely a stale pin rather than a driver that never had the capability.`
623
656
  };
624
657
  return {
625
658
  stale: false,
659
+ ahead: leadsByMinorOrMore(driverVersion, runtimeVersion) === true,
626
660
  detail: `Driver ${driverVersion}, runtime ${runtimeVersion}.`
627
661
  };
628
662
  }
@@ -866,6 +900,198 @@ function provisionTargetFor(bootstrappers, adapter, driverResult) {
866
900
  };
867
901
  }
868
902
  //#endregion
903
+ //#region src/boot/schema-stamp.ts
904
+ /**
905
+ * Does the schema in the database match the collections this process was built
906
+ * from?
907
+ *
908
+ * A split deployment can run several processes from one bundle, and — once a
909
+ * deployment can pin them to *different* bundles — from more than one. They all
910
+ * share one database, and only one of them provisions it. So a process can come
911
+ * up perfectly, pass every probe, and query a column the schema owner has not
912
+ * created yet, or rely on a policy it has not applied. Neither fails in a way
913
+ * anybody sees: the first is a SQL error on one route, the second is a 200 with
914
+ * zero rows.
915
+ *
916
+ * The check is a stamp. The process that provisions writes the version of the
917
+ * collections it just applied into the database; every process compares its own
918
+ * against what it finds. Same table, same shape and the same "unstamped is not
919
+ * an error" rule as the auth schema version, which exists for exactly this class
920
+ * of failure one subsystem over.
921
+ *
922
+ * ## Why the database and not the api
923
+ *
924
+ * The obvious design is an HTTP call to the api's `/api/meta/schema-version`.
925
+ * It is worse in three ways. It needs the api's address configured on every
926
+ * other process, so it adds a variable whose absence disables the check
927
+ * silently. It makes booting depend on another process already being up, which
928
+ * turns a rollout ordering problem into a boot failure. And it asks the wrong
929
+ * question: what breaks is the *database* not matching, and two processes can
930
+ * agree with each other while both disagree with it.
931
+ *
932
+ * The database is also the only answer that works for a `worker`, which has no
933
+ * reason to know any URL, and for a single `all` deployment scaled to three,
934
+ * where there is no api to ask.
935
+ *
936
+ * ## Why both sides compute rather than read
937
+ *
938
+ * Both the stamp and the comparison are computed from the collections the
939
+ * process actually loaded, never from the `schemaVersion` a bundle manifest
940
+ * declares. A declared value is not evidence: `/api/meta/schema-version` returns
941
+ * the manifest's own number verbatim when the bundle has one, which is why
942
+ * comparing that endpoint to that manifest is a check that passes on a bundle
943
+ * whose declared version is nonsense — verified, once, on a fixture corrupted to
944
+ * `v1:deadbeefdeadbeef`. Computing on both sides means the comparison is between
945
+ * two things that were derived, so agreeing means something.
946
+ *
947
+ * ## A driver that predates this
948
+ *
949
+ * The image supplies `@rebasepro/server`; the *driver* comes from the bundle,
950
+ * pinned to whatever the project's package.json asked npm for. So a current
951
+ * runtime routinely runs against a driver older than itself, and that driver has
952
+ * neither hook. Absence is treated as "this driver does not record a version" —
953
+ * the same answer as a driver that never will — and the check silently does
954
+ * nothing rather than failing a boot over a capability the deployment cannot
955
+ * supply. It starts working when the project's driver is next updated. See
956
+ * `version-skew.ts` for the general shape of this problem.
957
+ */
958
+ /**
959
+ * Compare, without acting.
960
+ *
961
+ * Separated from {@link enforceSchemaStamp} because the decision is the part
962
+ * worth testing and the part that is wrong in a way nobody sees. Every branch
963
+ * here has a test.
964
+ */
965
+ function decideSchemaStamp(input) {
966
+ if (input.supported === false) return {
967
+ status: "skipped",
968
+ reason: "this driver does not record a collections schema version"
969
+ };
970
+ if (input.introspecting) return {
971
+ status: "skipped",
972
+ reason: "collections are derived from the database, so they cannot disagree with it"
973
+ };
974
+ if (input.databaseVersion === null) return { status: "unstamped" };
975
+ if (input.databaseVersion === input.processVersion) return {
976
+ status: "match",
977
+ version: input.processVersion
978
+ };
979
+ return {
980
+ status: "mismatch",
981
+ database: input.databaseVersion,
982
+ process: input.processVersion
983
+ };
984
+ }
985
+ /**
986
+ * A refusal to serve against a schema this process does not match.
987
+ *
988
+ * Its own class so the boot paths can present it as a configuration problem
989
+ * rather than a crash, matching `RoleConfigurationError`.
990
+ */
991
+ var SchemaVersionMismatchError = class extends Error {
992
+ databaseVersion;
993
+ processVersion;
994
+ constructor(databaseVersion, processVersion, message) {
995
+ super(message);
996
+ this.databaseVersion = databaseVersion;
997
+ this.processVersion = processVersion;
998
+ this.name = "SchemaVersionMismatchError";
999
+ }
1000
+ };
1001
+ /**
1002
+ * Read the policy from the environment.
1003
+ *
1004
+ * Warning is the default because refusing would fail a rollout *mid-flight*: for
1005
+ * the whole window between the schema owner rolling and the last unit following,
1006
+ * the units that have not rolled yet legitimately disagree. That window is
1007
+ * normal, and a deployment that turns it into a crash loop has traded a silent
1008
+ * problem for a loud outage.
1009
+ *
1010
+ * `refuse` is for the deployment that would rather not serve at all than serve
1011
+ * wrong — and for CI, where the window does not exist.
1012
+ */
1013
+ function resolveSchemaMismatchPolicy(env = process.env) {
1014
+ const raw = (env.REBASE_REQUIRE_SCHEMA_MATCH ?? "").trim().toLowerCase();
1015
+ return raw === "true" || raw === "1" ? "refuse" : "warn";
1016
+ }
1017
+ /**
1018
+ * The message a mismatch prints, or throws.
1019
+ *
1020
+ * One function so the warning and the refusal say exactly the same thing — an
1021
+ * operator who raises the policy from `warn` to `refuse` should not have to
1022
+ * learn a second description of the same fact.
1023
+ */
1024
+ function describeMismatch(databaseVersion, processVersion) {
1025
+ return `The database was last provisioned from a different set of collections than this process was built from (database ${databaseVersion}, this process ${processVersion}).\n A process running ahead of the schema queries columns that do not exist yet, and relies on RLS policies that have not been applied —\n the first is a SQL error on one route, the second is an empty result with a 200. A process running behind is normal during a rollout.\n Roll the process that owns the schema first (REBASE_ROLE=api, or the migration Job), then the rest. Set REBASE_REQUIRE_SCHEMA_MATCH=true to refuse the boot instead of warning.`;
1026
+ }
1027
+ /**
1028
+ * Stamp, or compare and report.
1029
+ *
1030
+ * The provisioning process writes; everyone else reads. A process that both
1031
+ * provisions and would compare has nothing to compare against — it is the
1032
+ * authority — so it stamps and returns.
1033
+ *
1034
+ * Every failure to read or write is swallowed with a warning rather than
1035
+ * propagated. This check exists to make a silent problem visible; letting it
1036
+ * take down a boot it was only supposed to describe would be a strictly worse
1037
+ * trade, and a database that refuses one small write is already telling the
1038
+ * operator something through other channels.
1039
+ */
1040
+ async function enforceSchemaStamp(options) {
1041
+ const { collections, read, stamp, provisioned, introspecting } = options;
1042
+ if (introspecting) return {
1043
+ status: "skipped",
1044
+ reason: "collections are derived from the database, so they cannot disagree with it"
1045
+ };
1046
+ if (!read && !stamp) return {
1047
+ status: "skipped",
1048
+ reason: "this driver does not record a collections schema version"
1049
+ };
1050
+ const processVersion = computeSchemaVersion(collections);
1051
+ if (provisioned) {
1052
+ if (!stamp) return {
1053
+ status: "skipped",
1054
+ reason: "this driver cannot record a collections schema version"
1055
+ };
1056
+ try {
1057
+ await stamp(processVersion);
1058
+ logger.debug(`🔖 [schema] Stamped the collections schema version: ${processVersion}`);
1059
+ } catch (error) {
1060
+ logger.warn("⚠️ [schema] Could not record the collections schema version. Other processes cannot check themselves against this database until one boots that can.", { error });
1061
+ }
1062
+ return {
1063
+ status: "match",
1064
+ version: processVersion
1065
+ };
1066
+ }
1067
+ if (!read) return {
1068
+ status: "skipped",
1069
+ reason: "this driver cannot read a collections schema version"
1070
+ };
1071
+ let databaseVersion;
1072
+ try {
1073
+ databaseVersion = await read();
1074
+ } catch (error) {
1075
+ logger.warn("⚠️ [schema] Could not read the collections schema version from the database.", { error });
1076
+ return {
1077
+ status: "skipped",
1078
+ reason: "the stamp could not be read"
1079
+ };
1080
+ }
1081
+ const verdict = decideSchemaStamp({
1082
+ processVersion,
1083
+ databaseVersion,
1084
+ introspecting
1085
+ });
1086
+ if (verdict.status === "unstamped") logger.debug("🔖 [schema] This database carries no collections schema version yet — it will be stamped by the process that provisions it.");
1087
+ else if (verdict.status === "mismatch") {
1088
+ const message = describeMismatch(verdict.database, verdict.process);
1089
+ if ((options.policy ?? "warn") === "refuse") throw new SchemaVersionMismatchError(verdict.database, verdict.process, message);
1090
+ logger.warn(`⚠️ [schema] ${message}`);
1091
+ }
1092
+ return verdict;
1093
+ }
1094
+ //#endregion
869
1095
  //#region src/services/driver-registry.ts
870
1096
  /**
871
1097
  * The default driver identifier used when:
@@ -3947,7 +4173,7 @@ function assertStorageAccessControlConfigured(state, isProduction) {
3947
4173
  */
3948
4174
  async function mountOpenApiDocs(app, basePath, enableSwagger, serverCollections, requireAuth) {
3949
4175
  if (enableSwagger === false || serverCollections.length === 0) return;
3950
- const { generateOpenApiSpec } = await import("./openapi-generator-DLiiGD9X.js");
4176
+ const { generateOpenApiSpec } = await import("./openapi-generator-BCKJRUS4.js");
3951
4177
  app.get(`${basePath}/docs`, (c) => {
3952
4178
  const spec = generateOpenApiSpec(serverCollections, {
3953
4179
  basePath,
@@ -4137,7 +4363,8 @@ var ALL_RUNTIME_SURFACES = [
4137
4363
  "admin",
4138
4364
  "functions",
4139
4365
  "cron",
4140
- "meta"
4366
+ "meta",
4367
+ "realtime"
4141
4368
  ];
4142
4369
  /**
4143
4370
  * Resolve a partial surface set against the default, which is everything on.
@@ -10207,7 +10434,7 @@ function _resetRebaseMock() {
10207
10434
  * It clears the default policies through their `rolesOverlap(['admin'])` arm —
10208
10435
  * which is why the difference rarely shows. It shows when you write your own:
10209
10436
  *
10210
- * - `policy.serverContext()` compiles to `auth.uid() IS NULL` and is therefore
10437
+ * - `policy.serverContext()` compiles to `rebase.uid() IS NULL` and is therefore
10211
10438
  * **false** for this accessor. A collection with `disableDefaultPolicies:
10212
10439
  * true` whose rule is `serverContext()` denies these writes (`42501`) and
10213
10440
  * returns zero rows — HTTP 200, empty — for these reads.
@@ -10342,6 +10569,8 @@ function wrapDatabaseAdapter(dbAdapter) {
10342
10569
  initializeWebsockets: dbAdapter.initializeWebsockets,
10343
10570
  ensureCollectionSchema: dbAdapter.ensureCollectionSchema ? (collections, driverResult, log) => dbAdapter.ensureCollectionSchema(collections, driverResult, log) : void 0,
10344
10571
  ensureCollectionPolicies: dbAdapter.ensureCollectionPolicies ? (collections, driverResult, log) => dbAdapter.ensureCollectionPolicies(collections, driverResult, log) : void 0,
10572
+ readCollectionsSchemaVersion: dbAdapter.readCollectionsSchemaVersion ? (driverResult) => dbAdapter.readCollectionsSchemaVersion(driverResult) : void 0,
10573
+ stampCollectionsSchemaVersion: dbAdapter.stampCollectionsSchemaVersion ? (version, driverResult) => dbAdapter.stampCollectionsSchemaVersion(version, driverResult) : void 0,
10345
10574
  getAdmin: dbAdapter.getAdmin,
10346
10575
  mountRoutes: dbAdapter.mountRoutes
10347
10576
  };
@@ -10413,6 +10642,10 @@ async function _initializeRebaseBackend(config) {
10413
10642
  schemaProvisioning: {
10414
10643
  attempted: schemaOutcome.status === "applied",
10415
10644
  reason: schemaOutcome.status === "skipped" ? schemaOutcome.reason : void 0
10645
+ },
10646
+ realtime: {
10647
+ subscribe: surfaces.realtime,
10648
+ provision: config.provisionSchema ?? true
10416
10649
  }
10417
10650
  });
10418
10651
  delegates[b.id || bootstrapper.type] = driverResult.driver;
@@ -10503,10 +10736,18 @@ async function _initializeRebaseBackend(config) {
10503
10736
  logger.info("Authentication initialized");
10504
10737
  } else logger.warn("Auth requested but default bootstrapper does not support initializeAuth");
10505
10738
  }
10506
- await provisionCollectionPolicies(provisionable, provisionTarget, {
10739
+ const policyOutcome = await provisionCollectionPolicies(provisionable, provisionTarget, {
10507
10740
  introspecting: introspectCollections,
10508
10741
  provision: config.provisionSchema ?? true
10509
10742
  });
10743
+ await enforceSchemaStamp({
10744
+ collections: provisionable,
10745
+ provisioned: schemaOutcome.status === "applied" && policyOutcome.status === "applied",
10746
+ introspecting: introspectCollections,
10747
+ policy: resolveSchemaMismatchPolicy(),
10748
+ read: provisionTarget.bootstrapper.readCollectionsSchemaVersion ? () => provisionTarget.bootstrapper.readCollectionsSchemaVersion(provisionTarget.driverResult) : void 0,
10749
+ stamp: provisionTarget.bootstrapper.stampCollectionsSchemaVersion ? (version) => provisionTarget.bootstrapper.stampCollectionsSchemaVersion(version, provisionTarget.driverResult) : void 0
10750
+ });
10510
10751
  let historyConfigResult = void 0;
10511
10752
  if (config.history) if (defaultBootstrapper.initializeHistory) {
10512
10753
  logger.debug("Bootstrapping entity history via driver protocol");
@@ -10624,7 +10865,7 @@ async function _initializeRebaseBackend(config) {
10624
10865
  ]) {
10625
10866
  const providerConfig = safeAuthConfig[key];
10626
10867
  if (providerConfig && requiredFields.every((f) => Boolean(providerConfig[f]))) {
10627
- const createFn = (await import("./auth-DIKS1rsI.js").then((n) => n.t))[factory];
10868
+ const createFn = (await import("./auth-5Et5mnUA.js").then((n) => n.t))[factory];
10628
10869
  oauthProviders.push(createFn(providerConfig));
10629
10870
  }
10630
10871
  }
@@ -10964,7 +11205,7 @@ async function _initializeRebaseBackend(config) {
10964
11205
  const { loadCronJobsWithDiagnostics } = await import("./cron-loader-YhhQeVBM.js").then((n) => n.t);
10965
11206
  const { CronScheduler } = await import("./cron-scheduler-DIpYBmZP.js").then((n) => n.n);
10966
11207
  const { createCronRoutes } = await import("./cron-routes-maM_RlUu.js").then((n) => n.n);
10967
- const { createCronStore } = await import("./cron-store-BBGvOA-9.js").then((n) => n.n);
11208
+ const { createCronStore } = await import("./cron-store-DfH_4Cd9.js").then((n) => n.n);
10968
11209
  const { jobs: loadedCronJobs, problems: cronProblems } = await loadCronJobsWithDiagnostics(config.cronsDir);
10969
11210
  cronScheduler = new CronScheduler();
10970
11211
  cronScheduler.setClient(serverSingleton);
@@ -10994,7 +11235,7 @@ async function _initializeRebaseBackend(config) {
10994
11235
  }
10995
11236
  let jobQueue;
10996
11237
  if (config.jobs?.enabled) {
10997
- const { createJobStore, createJobQueue } = await import("./jobs-BOEOIGAm.js").then((n) => n.t);
11238
+ const { createJobStore, createJobQueue } = await import("./jobs-CyOKXXlu.js").then((n) => n.t);
10998
11239
  const store = createJobStore(defaultDriver);
10999
11240
  if (store) {
11000
11241
  await store.ensureTable();
@@ -11028,7 +11269,7 @@ async function _initializeRebaseBackend(config) {
11028
11269
  logger.debug("Logs routes mounted", { path: `${basePath}/logs` });
11029
11270
  }
11030
11271
  if (surfaces.meta) {
11031
- const { createContractRoutes } = await import("./contract-routes-DDNj4_J1.js").then((n) => n.t);
11272
+ const { createContractRoutes } = await import("./contract-routes-DZ-LBpSL.js").then((n) => n.t);
11032
11273
  const contractRouter = new Hono();
11033
11274
  if (adminSurfacesGated) {
11034
11275
  if (apiKeyPreAuth) contractRouter.use("/contract", apiKeyPreAuth);
@@ -11053,7 +11294,7 @@ async function _initializeRebaseBackend(config) {
11053
11294
  defaultKey: defaultDriverId,
11054
11295
  resolveKey: keyForCollectionPath
11055
11296
  }) : defaultRealtimeService;
11056
- if (defaultBootstrapper.initializeWebsockets && effectiveRealtimeService) await defaultBootstrapper.initializeWebsockets(config.server, effectiveRealtimeService, defaultDriver, config.auth, authAdapter);
11297
+ if (surfaces.realtime && defaultBootstrapper.initializeWebsockets && effectiveRealtimeService) await defaultBootstrapper.initializeWebsockets(config.server, effectiveRealtimeService, defaultDriver, config.auth, authAdapter);
11057
11298
  logger.debug("Rebase Backend Initialized");
11058
11299
  const authSchemaCheck = authConfigResult?.schemaHealthCheck;
11059
11300
  const healthCheck = createHealthCheck(defaultDriver, authSchemaCheck ? () => authSchemaCheck.call(authConfigResult) : void 0);
@@ -11159,7 +11400,7 @@ function defineFunction(definition) {
11159
11400
  * against that identity, not skipped. See that constant's docblock. It clears
11160
11401
  * the default policies through their `rolesOverlap(['admin'])` arm, which is why
11161
11402
  * the distinction rarely shows; it shows against hand-written rules, where
11162
- * `policy.serverContext()` (`auth.uid() IS NULL`) is **false** for it. Use
11403
+ * `policy.serverContext()` (`rebase.uid() IS NULL`) is **false** for it. Use
11163
11404
  * `rebase.sql()` when you need the genuine bypass — owner connection, no
11164
11405
  * policies.
11165
11406
  *
@@ -12040,6 +12281,49 @@ function isAssetRequest(requestPath, destination) {
12040
12281
  return ASSET_EXTENSIONS.has(lastSegment.slice(dot + 1).toLowerCase());
12041
12282
  }
12042
12283
  /**
12284
+ * Does this filename carry a content hash, and may it therefore be cached forever?
12285
+ *
12286
+ * The two answers a build needs are opposites, and picking wrong in either
12287
+ * direction is a real bug. A hashed chunk (`index-vgugiqRO.js`) can be
12288
+ * `immutable` for a year because a new build gives it a new URL. `index.html`
12289
+ * cannot be cached at all: it is the document naming those hashed chunks, so a
12290
+ * cached copy pins a tab to the previous deploy's filenames, which the new build
12291
+ * no longer contains — the page dies on a 404 for a chunk, and the user has no
12292
+ * way to know a reload is what they need.
12293
+ *
12294
+ * Erring toward "not hashed" is therefore the safe direction: the cost is a
12295
+ * revalidation that usually answers 304, against serving a year-stale file with
12296
+ * no way to recall it. So this demands positive evidence of a hash rather than
12297
+ * assuming one — a segment of 8+ characters after the last `-` that is not
12298
+ * ordinary lowercase prose. Vite and Rollup emit base64url digests, which
12299
+ * essentially always carry a digit or a capital; a hand-written
12300
+ * `vendor-analytics.js` does not, and gets revalidated.
12301
+ *
12302
+ * Deliberately not "everything under /assets/": that is a Vite convention, not a
12303
+ * guarantee, and a build that drops an unhashed file there would have it pinned
12304
+ * in every visitor's cache for a year with no way to correct it.
12305
+ */
12306
+ function isContentHashed(requestPath) {
12307
+ const lastSegment = requestPath.slice(requestPath.lastIndexOf("/") + 1);
12308
+ const dot = lastSegment.lastIndexOf(".");
12309
+ if (dot <= 0) return false;
12310
+ const stem = lastSegment.slice(0, dot);
12311
+ const dash = stem.lastIndexOf("-");
12312
+ if (dash < 0) return false;
12313
+ const suffix = stem.slice(dash + 1);
12314
+ if (suffix.length < 8) return false;
12315
+ if (!/^[A-Za-z0-9_-]+$/.test(suffix)) return false;
12316
+ return /[0-9A-Z]/.test(suffix);
12317
+ }
12318
+ /** A year, and never revalidated: the URL changes when the bytes do. */
12319
+ var IMMUTABLE_CACHE = "public, max-age=31536000, immutable";
12320
+ /**
12321
+ * Store it, but check before using it. Not `no-store`: revalidation answers 304
12322
+ * on an unchanged document, which is cheaper than re-sending it, and correctness
12323
+ * here needs freshness rather than absence.
12324
+ */
12325
+ var REVALIDATE_CACHE = "no-cache";
12326
+ /**
12043
12327
  * Serve a Single Page Application from an Hono app.
12044
12328
  *
12045
12329
  * @internal Not part of the stable public API. Exported only because the
@@ -12060,6 +12344,12 @@ function serveSPA(app, config) {
12060
12344
  return;
12061
12345
  }
12062
12346
  const scope = isRoot ? "/*" : `${basePath}/*`;
12347
+ app.use(scope, async (c, next) => {
12348
+ await next();
12349
+ if (c.res.headers.has("cache-control")) return;
12350
+ if (c.res.status !== 200) return;
12351
+ c.header("Cache-Control", isContentHashed(c.req.path) ? IMMUTABLE_CACHE : REVALIDATE_CACHE);
12352
+ });
12063
12353
  app.use(scope, responseCompression());
12064
12354
  app.use(scope, serveStatic({
12065
12355
  root: path$2.relative(process.cwd(), frontendPath),
@@ -12386,6 +12676,19 @@ var bootEnvExtension = object({
12386
12676
  SMTP_NAME: string().optional(),
12387
12677
  APP_NAME: string().default("Rebase"),
12388
12678
  /**
12679
+ * Logo shown above the card in the default email templates, at 48x48.
12680
+ *
12681
+ * Must be a PNG or JPG on an absolute `http(s)` URL: mail clients do not
12682
+ * render SVG and block `data:` URIs, and the image is fetched by the
12683
+ * recipient's client rather than by this process. Anything else renders no
12684
+ * logo rather than a broken image — see `resolveEmailBranding`.
12685
+ *
12686
+ * Left unset, an app that still answers to the default `APP_NAME` gets the
12687
+ * Rebase mark and one that has renamed itself gets nothing. This is the only
12688
+ * way a managed tenant, which ships no code of its own, can set its own.
12689
+ */
12690
+ EMAIL_LOGO_URL: string().optional(),
12691
+ /**
12389
12692
  * Serve the bundle's static/admin assets from this process.
12390
12693
  *
12391
12694
  * Default on, because a self-hosted single-container deployment is the case
@@ -12400,13 +12703,24 @@ var bootEnvExtension = object({
12400
12703
  /**
12401
12704
  * What the runtime may do to the database schema at boot.
12402
12705
  *
12403
- * - `none` (default in production) — touch nothing. Schema changes are a
12404
- * deliberate, reviewable step, not a side effect of a restart.
12405
- * - `ensure` create the auth/system tables if missing, never touch
12406
- * collection tables. The default outside production.
12407
- * - `push` reconcile collection tables with the bundle's schema. Convenient
12408
- * for a local compose stack; in production it means a container restart can
12409
- * rewrite the schema, so it must be asked for explicitly.
12706
+ * - `none` — touch nothing. The schema is provisioned by something else: a
12707
+ * migration step, or another process in a split deployment.
12708
+ * - anything else, **including unset** run the additive provisioning pass
12709
+ * in `boot/provision.ts`: create missing tables, columns and enum types,
12710
+ * never drop or rewrite one.
12711
+ *
12712
+ * The default is `ensure` everywhere, production included see
12713
+ * `provisioningDisabled`, which is the single place the value is read and
12714
+ * which only asks whether it is `none`.
12715
+ *
12716
+ * `push` is in the enum and is **not** distinguished from `ensure` anywhere
12717
+ * in the boot path; nothing implements "reconcile destructively" here. The
12718
+ * published image goes further and refuses to start on it
12719
+ * (`docker/entrypoint.mjs`), because a full push computes a diff and will
12720
+ * happily `DROP COLUMN` — and a container restart must never be able to
12721
+ * destroy a production column as a side effect of rescheduling. Reshaping
12722
+ * and destructive changes stay a deliberate `rebase db generate` + `rebase
12723
+ * db migrate`, or a reviewed `rebase db push` from a checkout.
12410
12724
  */
12411
12725
  REBASE_MIGRATE_ON_BOOT: _enum([
12412
12726
  "none",
@@ -12477,8 +12791,13 @@ var bootEnvExtension = object({
12477
12791
  *
12478
12792
  * Deliberately tri-state, and resolved against NODE_ENV by
12479
12793
  * {@link resolveEnableSwagger} rather than defaulted here. Unset means "on
12480
- * in development, off in production" — an explicit `true` or `false` always
12481
- * wins in both.
12794
+ * in development, off in production"; `false` turns both off anywhere.
12795
+ *
12796
+ * `true` in production is only half a switch, and the asymmetry is in
12797
+ * `init/docs.ts` rather than here: the *spec* at `/api/docs` is served
12798
+ * whenever this is not `false`, but the Swagger *UI* at `/api/swagger` is
12799
+ * gated on `NODE_ENV !== "production"` independently and this variable
12800
+ * cannot open it.
12482
12801
  *
12483
12802
  * It used to default to `"false"` outright, which reads as a safe default
12484
12803
  * and was not one: the runtime is how every scaffolded project boots, so
@@ -12673,6 +12992,13 @@ var RoleConfigurationError = class extends Error {
12673
12992
  * and sets `REBASE_CRON_SCHEDULER=false` on the api. `functions` runs no timers
12674
12993
  * at all — a function process is scaled by request load and replaced at will, so
12675
12994
  * giving it scheduled work would make its replica count mean something.
12995
+ *
12996
+ * `realtime` is off for the same two, and it is the surface whose cost is paid
12997
+ * whether or not anyone calls it: a process that consumes change events holds a
12998
+ * dedicated `LISTEN` connection outside the pool for as long as it runs, and
12999
+ * only a process serving websockets has anybody to deliver to. Writes made *by*
13000
+ * these processes are still heard — capture is database triggers, so a change is
13001
+ * published by the database rather than by whichever pod made it.
12676
13002
  */
12677
13003
  var ROLES = {
12678
13004
  all: {
@@ -12692,7 +13018,8 @@ var ROLES = {
12692
13018
  storage: false,
12693
13019
  admin: false,
12694
13020
  cron: false,
12695
- meta: false
13021
+ meta: false,
13022
+ realtime: false
12696
13023
  },
12697
13024
  ownership: {
12698
13025
  cronScheduler: false,
@@ -12708,7 +13035,8 @@ var ROLES = {
12708
13035
  admin: false,
12709
13036
  functions: false,
12710
13037
  cron: false,
12711
- meta: false
13038
+ meta: false,
13039
+ realtime: false
12712
13040
  },
12713
13041
  ownership: {},
12714
13042
  provisionSchema: false
@@ -13116,6 +13444,8 @@ function adapterToBootstrapper(adapter, id, isDefault) {
13116
13444
  initializeWebsockets: adapter.initializeWebsockets,
13117
13445
  ensureCollectionSchema: adapter.ensureCollectionSchema ? (collections, driverResult, log) => adapter.ensureCollectionSchema(collections, driverResult, log) : void 0,
13118
13446
  ensureCollectionPolicies: adapter.ensureCollectionPolicies ? (collections, driverResult, log) => adapter.ensureCollectionPolicies(collections, driverResult, log) : void 0,
13447
+ readCollectionsSchemaVersion: adapter.readCollectionsSchemaVersion ? (driverResult) => adapter.readCollectionsSchemaVersion(driverResult) : void 0,
13448
+ stampCollectionsSchemaVersion: adapter.stampCollectionsSchemaVersion ? (version, driverResult) => adapter.stampCollectionsSchemaVersion(version, driverResult) : void 0,
13119
13449
  getAdmin: adapter.getAdmin,
13120
13450
  mountRoutes: adapter.mountRoutes
13121
13451
  };
@@ -13194,6 +13524,7 @@ function resolveEmailOptions(env) {
13194
13524
  name: env.SMTP_NAME
13195
13525
  },
13196
13526
  appName: env.APP_NAME,
13527
+ logoUrl: env.EMAIL_LOGO_URL,
13197
13528
  resetPasswordUrl: env.FRONTEND_URL
13198
13529
  };
13199
13530
  }
@@ -13938,17 +14269,37 @@ async function runFromBundle(options = {}) {
13938
14269
  * driver. Nothing detected that before this: the halves simply disagreed in
13939
14270
  * silence until some capability turned out to be missing three layers down.
13940
14271
  *
13941
- * A warning rather than a refusal. Old drivers are usually fine — the pairing is
14272
+ * A warning rather than a refusal. Either pairing can be fine — both are
13942
14273
  * supported, and a boot that dies on version arithmetic would be a far worse
13943
14274
  * failure than the drift it is guarding against. This only has to make the skew
13944
14275
  * *visible*, so that the next person reading the log starts from the right
13945
14276
  * question.
14277
+ *
14278
+ * ## Both directions, because only one of them was ever reported
14279
+ *
14280
+ * A driver *behind* the runtime was the original case: the platform ships a fix,
14281
+ * every tenant rolls onto the new image, and none of them run the fixed driver.
14282
+ *
14283
+ * A driver *ahead* by a minor is the mirror image and was silent until it cost
14284
+ * another day. It is not the deliberate pin this check used to assume — that is
14285
+ * a patch bump, and still says nothing. It is what a floating runtime range
14286
+ * produces when the image lags: a bundle built against a framework the image
14287
+ * predates, so a feature split across `@rebasepro/server` and the driver has
14288
+ * only its driver half present. Nothing errors. The half that landed reads
14289
+ * config the older harness never sets, defaults it, and a subsystem — realtime
14290
+ * channels, in the case that prompted this — is inert in a process that passes
14291
+ * every probe. The fix is the opposite of the stale case, which is exactly why
14292
+ * the two need separate sentences: bump the *image*, not the package.json.
13946
14293
  */
13947
14294
  function warnOnDriverSkew(dataSources, runtimeVersion) {
13948
14295
  if (!runtimeVersion) return;
13949
14296
  for (const source of dataSources) {
13950
- if (!describeDriverSkew(source.driverVersion, runtimeVersion).stale) continue;
13951
- logger.warn(`Driver version skew on data source "${source.key}": "${source.driverPackage}" is at ${source.driverVersion}, this runtime is ${runtimeVersion}. A driver is installed from your bundle's dependencies, NOT supplied by the platform image, so a newer runtime does not update it. Capabilities added after ${source.driverVersion} are unavailable to this deployment — bump "${source.driverPackage}" in your project's package.json and redeploy.`);
14297
+ const skew = describeDriverSkew(source.driverVersion, runtimeVersion);
14298
+ if (skew.stale) {
14299
+ logger.warn(`Driver version skew on data source "${source.key}": "${source.driverPackage}" is at ${source.driverVersion}, this runtime is ${runtimeVersion}. A driver is installed from your bundle's dependencies, NOT supplied by the platform image, so a newer runtime does not update it. Capabilities added after ${source.driverVersion} are unavailable to this deployment — bump "${source.driverPackage}" in your project's package.json and redeploy.`);
14300
+ continue;
14301
+ }
14302
+ if (skew.ahead) logger.warn(`Driver version skew on data source "${source.key}": "${source.driverPackage}" is at ${source.driverVersion}, this runtime is ${runtimeVersion}. The driver is AHEAD of the platform image by a minor or more. Your bundle supplies the driver while the image supplies \`@rebasepro/server\`, so a feature spanning both packages has only its driver half running here — the other half is missing, and the usual symptom is a subsystem that is silently inert rather than one that errors. Deploy a newer platform image (or pin the runtime version), or pin "${source.driverPackage}" back to ${runtimeVersion} in your project's package.json.`);
13952
14303
  }
13953
14304
  }
13954
14305
  /**
@@ -13971,6 +14322,6 @@ function warnOnUnusableBundleShape(bundle) {
13971
14322
  logger.warn(`This bundle declares a config package at "${bundle.manifest.entry.config}", but no collections directory resolved inside it, so no collections were loaded and no tables will be created. Rebuild with \`rebase build\` and check the manifest's \`entry.collections\`.`);
13972
14323
  }
13973
14324
  //#endregion
13974
- 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, RawHtml, S3StorageController, SMTPEmailService, TransformCache, TusHandler, UnknownStorageSourceError, WEBHOOK_DELIVERY_TASK, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, applyCollectionDefaults, assertAllowedOutboundUrl, assertCollectionConfigs, assertDistinctSuffixes, assertEmailLinkBases, assertWriteRequestValid, authJwt, authRoles, authUid, blockedAddressReason, bootFromBundle, classifySurface, cleanupDevPortFile, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDdlBootstrapper, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createJobQueue, createJobStore, createJwksRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defaultBackoff, defineCron, defineFunction, envSuffixForKey, errorHandler, escapeHtml, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getEmailVerificationTemplate, getJwks, getMagicLinkTemplate, getPasswordResetTemplate, getUserInvitationTemplate, getWelcomeEmailTemplate, hasAsymmetricSigningKey, hashPassword, html, httpMethodToOperation, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isApiKeyToken, isAuthAdapter, isConcurrentDdlRace, isDatabaseAdapter, isDuplicateObjectRace, isLocalhostOrigin, isOperationAllowed, isTransformableImage, listBackupObjects, listenWithPortRetry, loadBootEnv, loadBundle, loadBundleConfigExports, loadBundleSchema, loadCollectionsFromDirectory, loadCronJobsFromDirectory, loadCronJobsWithDiagnostics, loadDeclaredStorageSources, loadEnv, loadFunctionsFromDirectory, loadUsersCollection, logger, oauthCodeFlowSchema, optionalAuth, parseBackupDestination, parseBackupTimestamp, parseTransformOptions, pkceTokenParams, providerVerifiedEmail, queryTokenAuth, raw, readBackupBytes, readBundleManifest, rebase, requireAdmin, requireAuth, resolveAuthHooks, resolveAuthOptions, resolveCorsOrigin, resolveDataSources, resolveEmailLinkBase, resolveEmailOptions, resolveRequireAuth, resolveStorageBackend, resolveStorageSources, runFromBundle, safeCompare, serveSPA, transformImage, tryVerifyOidcIdToken, unknownKeyPolicyFromEnv, validateApiKey, validateCronExpression, validatePasswordStrength, verifyOidcIdToken, verifyPassword };
14325
+ 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, RawHtml, S3StorageController, SMTPEmailService, TransformCache, TusHandler, UnknownStorageSourceError, WEBHOOK_DELIVERY_TASK, WebhookDispatcher, _resetRebaseMock, _setRebaseMock, applyCollectionDefaults, assertAllowedOutboundUrl, assertCollectionConfigs, assertDistinctSuffixes, assertEmailLinkBases, assertWriteRequestValid, authJwt, authRoles, authUid, blockedAddressReason, bootFromBundle, classifySurface, cleanupDevPortFile, createAppleProvider, createBackupRoutes, createBitbucketProvider, createBuiltinAuthAdapter, createContractRoutes, createCronRoutes, createCronStore, createCustomAuthAdapter, createDdlBootstrapper, createDiscordProvider, createEmailService, createFacebookProvider, createFunctionRoutes, createGitHubProvider, createGitLabProvider, createGoogleProvider, createHistoryRoutes, createJobQueue, createJobStore, createJwksRoutes, createLinkedinProvider, createMetricsMiddleware, createMetricsRoutes, createMicrosoftProvider, createSlackProvider, createSourceBundle, createSpotifyProvider, createStorageController, createStorageRoutes, createTwitterProvider, defaultBackoff, defineCron, defineFunction, envSuffixForKey, errorHandler, escapeHtml, extractUserFromToken, fileTokenAuth, findCollectionConfigProblems, generateSecurePassword, getEmailVerificationTemplate, getJwks, getMagicLinkTemplate, getPasswordResetTemplate, getUserInvitationTemplate, getWelcomeEmailTemplate, hasAsymmetricSigningKey, hashPassword, html, httpMethodToOperation, initializeDataSource, initializeDataSources, initializeRebaseBackend, installShutdownHandlers, isApiKeyToken, isAuthAdapter, isConcurrentDdlRace, isDatabaseAdapter, isDuplicateObjectRace, isLocalhostOrigin, isOperationAllowed, isTransformableImage, listBackupObjects, listenWithPortRetry, loadBootEnv, loadBundle, loadBundleConfigExports, loadBundleSchema, loadCollectionsFromDirectory, loadCronJobsFromDirectory, loadCronJobsWithDiagnostics, loadDeclaredStorageSources, loadEnv, loadFunctionsFromDirectory, loadUsersCollection, logger, oauthCodeFlowSchema, optionalAuth, parseBackupDestination, parseBackupTimestamp, parseTransformOptions, pkceTokenParams, providerVerifiedEmail, queryTokenAuth, raw, readBackupBytes, readBundleManifest, rebase, requireAdmin, requireAuth, resolveAuthHooks, resolveAuthOptions, resolveCorsOrigin, resolveDataSources, resolveEmailBranding, resolveEmailLinkBase, resolveEmailOptions, resolveRequireAuth, resolveStorageBackend, resolveStorageSources, runFromBundle, safeCompare, serveSPA, transformImage, tryVerifyOidcIdToken, unknownKeyPolicyFromEnv, validateApiKey, validateCronExpression, validatePasswordStrength, verifyOidcIdToken, verifyPassword };
13975
14326
 
13976
14327
  //# sourceMappingURL=index.es.js.map