@rebasepro/server 0.23.0 → 0.24.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 (181) hide show
  1. package/README.md +1 -1
  2. package/bin/rebase-server.js +4 -2
  3. package/dist/{GCSStorageController-CjrA4PMo.js → GCSStorageController-BSiP1c-f.js} +22 -8
  4. package/dist/GCSStorageController-BSiP1c-f.js.map +1 -0
  5. package/dist/{S3StorageController-B6pKDNVj.js → S3StorageController-CAwFRgjV.js} +19 -7
  6. package/dist/S3StorageController-CAwFRgjV.js.map +1 -0
  7. package/dist/api/ast-schema-editor.d.ts +92 -1
  8. package/dist/api/errors.d.ts +9 -0
  9. package/dist/api/live-schema-routes.d.ts +38 -8
  10. package/dist/api/logs-routes.d.ts +39 -1
  11. package/dist/api/openapi-generator.d.ts +17 -0
  12. package/dist/api/rest/api-generator.d.ts +44 -10
  13. package/dist/api/rest/write-validation.d.ts +2 -2
  14. package/dist/api/types.d.ts +17 -1
  15. package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-CWqS_sLJ.js} +309 -11
  16. package/dist/ast-schema-editor-CWqS_sLJ.js.map +1 -0
  17. package/dist/auth/access.d.ts +105 -0
  18. package/dist/auth/adapter-middleware.d.ts +2 -1
  19. package/dist/auth/address-ownership.d.ts +16 -1
  20. package/dist/auth/admin-roles-route.d.ts +4 -2
  21. package/dist/auth/admin-roles.d.ts +17 -20
  22. package/dist/auth/admin-users-route.d.ts +1 -0
  23. package/dist/auth/api-keys/api-key-middleware.d.ts +56 -55
  24. package/dist/auth/api-keys/api-key-routes.d.ts +41 -11
  25. package/dist/auth/api-keys/api-key-store.d.ts +31 -8
  26. package/dist/auth/api-keys/api-key-types.d.ts +14 -16
  27. package/dist/auth/api-keys/http-operation.d.ts +19 -0
  28. package/dist/auth/api-keys/index.d.ts +11 -11
  29. package/dist/auth/api-keys/key-grant.d.ts +41 -0
  30. package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
  31. package/dist/auth/auth-hooks.d.ts +46 -7
  32. package/dist/auth/builtin-auth-adapter.d.ts +8 -0
  33. package/dist/auth/cookie-utils.d.ts +7 -0
  34. package/dist/auth/deliverable-address.d.ts +6 -0
  35. package/dist/auth/email-change-routes.d.ts +41 -0
  36. package/dist/auth/expired-token-sweep.d.ts +67 -0
  37. package/dist/auth/impersonation.d.ts +110 -0
  38. package/dist/auth/index.d.ts +4 -2
  39. package/dist/auth/interfaces.d.ts +110 -59
  40. package/dist/auth/jwt.d.ts +49 -3
  41. package/dist/auth/magic-link-routes.d.ts +2 -6
  42. package/dist/auth/mfa-routes.d.ts +2 -9
  43. package/dist/auth/middleware.d.ts +17 -5
  44. package/dist/auth/otp-routes.d.ts +2 -6
  45. package/dist/auth/passwordless-signup.d.ts +27 -0
  46. package/dist/auth/platform-token.d.ts +122 -0
  47. package/dist/auth/rate-limiter.d.ts +41 -0
  48. package/dist/auth/routes.d.ts +45 -0
  49. package/dist/auth/scope-routes.d.ts +22 -0
  50. package/dist/auth/session-routes.d.ts +11 -6
  51. package/dist/auth/token-revocation.d.ts +50 -1
  52. package/dist/auth/verify-credential.d.ts +28 -0
  53. package/dist/{auth-B-GIMpDG.js → auth-DMLngxn_.js} +2159 -569
  54. package/dist/auth-DMLngxn_.js.map +1 -0
  55. package/dist/backend-DTAOsLQc.js.map +1 -1
  56. package/dist/backup/backup-common.d.ts +10 -0
  57. package/dist/backup/backup-routes.d.ts +24 -4
  58. package/dist/backup/backup-schedule.d.ts +33 -0
  59. package/dist/backup/backup-storage.d.ts +14 -0
  60. package/dist/backup/index.d.ts +2 -0
  61. package/dist/backup-CN0s50D2.js +444 -0
  62. package/dist/backup-CN0s50D2.js.map +1 -0
  63. package/dist/boot/bundle.d.ts +19 -0
  64. package/dist/boot/env.d.ts +49 -4
  65. package/dist/boot/security-headers.d.ts +26 -0
  66. package/dist/boot/static-routing.d.ts +56 -0
  67. package/dist/collection_patch-BRu-BvDv.js +472 -0
  68. package/dist/collection_patch-BRu-BvDv.js.map +1 -0
  69. package/dist/{contract-routes-CbFjuBwa.js → contract-routes-fz8i4pxs.js} +17 -4
  70. package/dist/contract-routes-fz8i4pxs.js.map +1 -0
  71. package/dist/cron/cron-scheduler.d.ts +25 -20
  72. package/dist/cron/cron-store.d.ts +6 -2
  73. package/dist/{cron-loader-DfTj2Hbi.js → cron-loader-CwaANlOG.js} +4 -4
  74. package/dist/cron-loader-CwaANlOG.js.map +1 -0
  75. package/dist/{cron-routes-eE8nif_b.js → cron-routes-Bc-SB0Se.js} +10 -7
  76. package/dist/cron-routes-Bc-SB0Se.js.map +1 -0
  77. package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-CYQgco86.js} +52 -34
  78. package/dist/cron-scheduler-CYQgco86.js.map +1 -0
  79. package/dist/{cron-store-TcoGz-xS.js → cron-store-D2Q9-Aco.js} +10 -15
  80. package/dist/cron-store-D2Q9-Aco.js.map +1 -0
  81. package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BaqMSa4Y.js} +2 -2
  82. package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BaqMSa4Y.js.map} +1 -1
  83. package/dist/email/index.d.ts +2 -2
  84. package/dist/email/templates.d.ts +22 -0
  85. package/dist/email/types.d.ts +26 -0
  86. package/dist/env.d.ts +1 -2
  87. package/dist/{errors-DWsX4yTd.js → errors-D6_y86c5.js} +102 -8
  88. package/dist/errors-D6_y86c5.js.map +1 -0
  89. package/dist/{function-loader-xnbDAPfa.js → function-loader-D7o5Epjj.js} +2 -2
  90. package/dist/{function-loader-xnbDAPfa.js.map → function-loader-D7o5Epjj.js.map} +1 -1
  91. package/dist/{function-routes-Chet4-lB.js → function-routes-CaNG4waN.js} +24 -12
  92. package/dist/function-routes-CaNG4waN.js.map +1 -0
  93. package/dist/functions/context.d.ts +17 -6
  94. package/dist/functions/guards.d.ts +22 -5
  95. package/dist/functions/index.d.ts +2 -2
  96. package/dist/functions/index.js +90 -36
  97. package/dist/functions/index.js.map +1 -1
  98. package/dist/{history-recorder-B4MpJfJK.js → history-recorder-Nr8zLvoU.js} +4 -4
  99. package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-Nr8zLvoU.js.map} +1 -1
  100. package/dist/{history-store-BhxWOuz9.js → history-store-rcAm_xFR.js} +2 -2
  101. package/dist/{history-store-BhxWOuz9.js.map → history-store-rcAm_xFR.js.map} +1 -1
  102. package/dist/index.d.ts +8 -2
  103. package/dist/index.es.js +3084 -753
  104. package/dist/index.es.js.map +1 -1
  105. package/dist/init/health.d.ts +17 -2
  106. package/dist/init/shutdown.d.ts +10 -0
  107. package/dist/init.d.ts +54 -0
  108. package/dist/{jobs-CazMYhyy.js → jobs-DqYNfquG.js} +5 -5
  109. package/dist/{jobs-CazMYhyy.js.map → jobs-DqYNfquG.js.map} +1 -1
  110. package/dist/{jwt-DnQHNFCl.js → jwt-R6bSPMjk.js} +39 -15
  111. package/dist/{jwt-DnQHNFCl.js.map → jwt-R6bSPMjk.js.map} +1 -1
  112. package/dist/{keys-CogCQpxG.js → keys-GAVZqbqx.js} +3 -17
  113. package/dist/{keys-CogCQpxG.js.map → keys-GAVZqbqx.js.map} +1 -1
  114. package/dist/{logger-DO2PZc4i.js → logger-D-S-hO5e.js} +26 -3
  115. package/dist/logger-D-S-hO5e.js.map +1 -0
  116. package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DAdv37GI.js} +48 -8
  117. package/dist/logs-routes-DAdv37GI.js.map +1 -0
  118. package/dist/mcp/consent-page.d.ts +1 -1
  119. package/dist/mcp/mcp-routes.d.ts +7 -0
  120. package/dist/mcp/mcp-tools.d.ts +15 -9
  121. package/dist/mcp/oauth-metadata.d.ts +21 -16
  122. package/dist/mcp/oauth-routes.d.ts +7 -1
  123. package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-DAq_XVDu.js} +104 -13
  124. package/dist/openapi-generator-DAq_XVDu.js.map +1 -0
  125. package/dist/{proxy-Czngl3p9.js → proxy-qRlqeUmO.js} +2 -2
  126. package/dist/{proxy-Czngl3p9.js.map → proxy-qRlqeUmO.js.map} +1 -1
  127. package/dist/{query-parser-DGRVFNM3.js → query-parser-BgiKJKvc.js} +6 -56
  128. package/dist/query-parser-BgiKJKvc.js.map +1 -0
  129. package/dist/{request-timeout-C_4C2BeR.js → request-timeout-DgH7j8qO.js} +3 -3
  130. package/dist/{request-timeout-C_4C2BeR.js.map → request-timeout-DgH7j8qO.js.map} +1 -1
  131. package/dist/schema-edit/apply-schema-change.d.ts +63 -3
  132. package/dist/schema-edit/project-root.d.ts +3 -2
  133. package/dist/schema-edit/remote-source.d.ts +9 -4
  134. package/dist/{schema-editor-routes-C5-lh_jO.js → schema-editor-routes-oIyuWl3L.js} +12 -7
  135. package/dist/schema-editor-routes-oIyuWl3L.js.map +1 -0
  136. package/dist/serve-spa.d.ts +58 -0
  137. package/dist/services/routed-realtime-service.d.ts +11 -0
  138. package/dist/soft-delete-params-BWPilMPF.js +59 -0
  139. package/dist/soft-delete-params-BWPilMPF.js.map +1 -0
  140. package/dist/{src-vkcwKXbT.js → src-CatHFUym.js} +439 -20
  141. package/dist/src-CatHFUym.js.map +1 -0
  142. package/dist/{src-pmvW7BFx.js → src-I3aG1PcY.js} +252 -70
  143. package/dist/src-I3aG1PcY.js.map +1 -0
  144. package/dist/storage/GCSStorageController.d.ts +2 -0
  145. package/dist/storage/LocalStorageController.d.ts +2 -0
  146. package/dist/storage/S3StorageController.d.ts +2 -0
  147. package/dist/storage/index.d.ts +2 -2
  148. package/dist/storage/property-limits.d.ts +41 -6
  149. package/dist/storage/request-keys.d.ts +15 -0
  150. package/dist/storage/requested-object.d.ts +74 -0
  151. package/dist/storage/routes.d.ts +36 -18
  152. package/dist/storage/tus-handler.d.ts +30 -5
  153. package/dist/storage/types.d.ts +19 -0
  154. package/dist/types-BfKcm9do.js.map +1 -1
  155. package/dist/utils/logger.d.ts +12 -0
  156. package/package.json +5 -5
  157. package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
  158. package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
  159. package/dist/admin-roles-vYdp_Pil.js +0 -36
  160. package/dist/admin-roles-vYdp_Pil.js.map +0 -1
  161. package/dist/admin_block-DxKLmdiv.js +0 -206
  162. package/dist/admin_block-DxKLmdiv.js.map +0 -1
  163. package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
  164. package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
  165. package/dist/auth-B-GIMpDG.js.map +0 -1
  166. package/dist/backup-D7YR94N3.js +0 -253
  167. package/dist/backup-D7YR94N3.js.map +0 -1
  168. package/dist/contract-routes-CbFjuBwa.js.map +0 -1
  169. package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
  170. package/dist/cron-routes-eE8nif_b.js.map +0 -1
  171. package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
  172. package/dist/cron-store-TcoGz-xS.js.map +0 -1
  173. package/dist/errors-DWsX4yTd.js.map +0 -1
  174. package/dist/function-routes-Chet4-lB.js.map +0 -1
  175. package/dist/logger-DO2PZc4i.js.map +0 -1
  176. package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
  177. package/dist/openapi-generator-O_O24MAT.js.map +0 -1
  178. package/dist/query-parser-DGRVFNM3.js.map +0 -1
  179. package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
  180. package/dist/src-pmvW7BFx.js.map +0 -1
  181. package/dist/src-vkcwKXbT.js.map +0 -1
@@ -268,12 +268,29 @@ var DEFAULT_CAPABILITIES = {
268
268
  supportsDocumentAdmin: true,
269
269
  supportsSchemaAdmin: true
270
270
  };
271
- var CAPABILITIES_REGISTRY = {
272
- postgres: POSTGRES_CAPABILITIES,
273
- firestore: FIREBASE_CAPABILITIES,
274
- mongodb: MONGODB_CAPABILITIES,
275
- "(default)": DEFAULT_CAPABILITIES
276
- };
271
+ var BUILT_IN_CAPABILITIES = /* @__PURE__ */ new Map([
272
+ ["postgres", POSTGRES_CAPABILITIES],
273
+ ["firestore", FIREBASE_CAPABILITIES],
274
+ ["mongodb", MONGODB_CAPABILITIES],
275
+ ["(default)", DEFAULT_CAPABILITIES]
276
+ ]);
277
+ /**
278
+ * Capabilities registered at runtime, on `globalThis` rather than in a module
279
+ * local: a third-party driver inlines its own copy of this package and
280
+ * registers through it, while the app and the server read through theirs. A
281
+ * module local made the registration land in a copy nobody else reads.
282
+ * See `module-state-across-copies.test.ts`.
283
+ */
284
+ var REGISTERED_CAPABILITIES_KEY = Symbol.for("@rebasepro/types.dataSourceCapabilities.v1");
285
+ function registeredCapabilities() {
286
+ const g = globalThis;
287
+ let registered = g[REGISTERED_CAPABILITIES_KEY];
288
+ if (!registered) {
289
+ registered = /* @__PURE__ */ new Map();
290
+ g[REGISTERED_CAPABILITIES_KEY] = registered;
291
+ }
292
+ return registered;
293
+ }
277
294
  /**
278
295
  * Look up capabilities for a given engine key.
279
296
  * If `engine` is undefined or not found, returns `DEFAULT_CAPABILITIES`.
@@ -281,7 +298,7 @@ var CAPABILITIES_REGISTRY = {
281
298
  */
282
299
  function getDataSourceCapabilities(engine) {
283
300
  if (!engine) return POSTGRES_CAPABILITIES;
284
- return CAPABILITIES_REGISTRY[engine] ?? DEFAULT_CAPABILITIES;
301
+ return registeredCapabilities().get(engine) ?? BUILT_IN_CAPABILITIES.get(engine) ?? DEFAULT_CAPABILITIES;
285
302
  }
286
303
  //#endregion
287
304
  //#region ../types/src/types/collections.ts
@@ -860,10 +877,15 @@ amendResourceKind("bucket", {
860
877
  "S3_FORCE_PATH_STYLE",
861
878
  "GCS_BUCKET",
862
879
  "GCS_PROJECT_ID",
863
- "GCS_KEY_FILENAME"
880
+ "GCS_KEY_FILENAME",
881
+ "STORAGE_MAX_FILE_SIZE"
864
882
  ],
865
883
  envBasesByEngine: {
866
- local: ["STORAGE_TYPE", "STORAGE_PATH"],
884
+ local: [
885
+ "STORAGE_TYPE",
886
+ "STORAGE_PATH",
887
+ "STORAGE_MAX_FILE_SIZE"
888
+ ],
867
889
  s3: [
868
890
  "STORAGE_TYPE",
869
891
  "S3_BUCKET",
@@ -871,13 +893,15 @@ amendResourceKind("bucket", {
871
893
  "S3_ACCESS_KEY_ID",
872
894
  "S3_SECRET_ACCESS_KEY",
873
895
  "S3_ENDPOINT",
874
- "S3_FORCE_PATH_STYLE"
896
+ "S3_FORCE_PATH_STYLE",
897
+ "STORAGE_MAX_FILE_SIZE"
875
898
  ],
876
899
  gcs: [
877
900
  "STORAGE_TYPE",
878
901
  "GCS_BUCKET",
879
902
  "GCS_PROJECT_ID",
880
- "GCS_KEY_FILENAME"
903
+ "GCS_KEY_FILENAME",
904
+ "STORAGE_MAX_FILE_SIZE"
881
905
  ],
882
906
  azure: [],
883
907
  firebase: []
@@ -892,14 +916,48 @@ registerResourceKind({
892
916
  implicitDefault: false
893
917
  });
894
918
  amendResourceKind("topic", { envBases: [] });
895
- var runtimeHolder = { current: null };
919
+ /**
920
+ * Declared handlers and installed runtimes, for topics and queues — on
921
+ * `globalThis` under a shared symbol, never in module locals.
922
+ *
923
+ * A module local is one per COPY of this package, and two copies in one
924
+ * process is the normal layout rather than an accident: `@rebasepro/server`
925
+ * inlines this package into its own dist, while `config/resources.ts` imports
926
+ * it from `node_modules`. With locals, a project's `.handler()` and
927
+ * `.subscription()` went into the project's copy and the worker read the
928
+ * server's empty one (`Job queue started {"tasks":0}`), and the runtime the
929
+ * server installed was invisible to the project's `enqueue`/`publish` — so
930
+ * every queue and topic threw "no runtime is installed" inside a running
931
+ * backend. The CLI deriving the graph had the same split. Same mechanism and
932
+ * reasoning as `registry()` in resources.ts; `module-state-across-copies.test.ts`
933
+ * loads two copies to hold it, and scans for any other module-level state that
934
+ * would split the same way.
935
+ *
936
+ * The version is in the symbol: a change to this object's SHAPE takes a new
937
+ * suffix, so no copy ever reads a shape it does not know.
938
+ */
939
+ var WORK_KEY = Symbol.for("@rebasepro/types.workRegistry.v1");
940
+ function work() {
941
+ const g = globalThis;
942
+ let shared = g[WORK_KEY];
943
+ if (!shared) {
944
+ shared = {
945
+ topicRuntime: null,
946
+ subscriptions: [],
947
+ queueRuntime: null,
948
+ queueConsumers: /* @__PURE__ */ new Map()
949
+ };
950
+ g[WORK_KEY] = shared;
951
+ }
952
+ return shared;
953
+ }
896
954
  /** Install the transport topics publish through. Called by the server at boot. */
897
955
  function setTopicRuntime(runtime) {
898
- runtimeHolder.current = runtime;
956
+ work().topicRuntime = runtime;
899
957
  }
900
- var subscriptions = [];
901
958
  /** Every declared subscription, for the worker to wire and the graph to record. */
902
959
  function declaredSubscriptions(topic) {
960
+ const { subscriptions } = work();
903
961
  return topic ? subscriptions.filter((s) => s.topic === topic) : subscriptions.slice();
904
962
  }
905
963
  registerResourceKind({
@@ -950,15 +1008,13 @@ registerResourceKind({
950
1008
  optionKeys: ["maxAttempts"],
951
1009
  implicitDefault: false
952
1010
  });
953
- var queueRuntimeHolder = { current: null };
954
1011
  /** Install the transport queues enqueue through. Called by the server at boot. */
955
1012
  function setQueueRuntime(runtime) {
956
- queueRuntimeHolder.current = runtime;
1013
+ work().queueRuntime = runtime;
957
1014
  }
958
- var queueConsumers = /* @__PURE__ */ new Map();
959
1015
  /** Every declared queue handler, for the worker to wire. */
960
1016
  function declaredQueueConsumers() {
961
- return [...queueConsumers.values()];
1017
+ return [...work().queueConsumers.values()];
962
1018
  }
963
1019
  /**
964
1020
  * One declaration, as the data layer's definition.
@@ -996,6 +1052,369 @@ function resourceToStorageSource(declaration) {
996
1052
  };
997
1053
  }
998
1054
  //#endregion
999
- export { NULL_OPS as A, isPostgresCollectionConfig as C, ALL_WHERE_FILTER_OPS as D, getDataSourceCapabilities as E, toCanonicalOp as F, isRelationAggregateSort as M, parseRelationAggregateSort as N, CANONICAL_TO_REST as O, sortKeyToString as P, getDeclaredSubcollections as S, DEFAULT_DATA_SOURCE_KEY as T, RLS_JWT_SQL as _, resourceToStorageSource as a, rewriteLegacyRlsFunctions as b, DEFAULT_STORAGE_SOURCE_KEY as c, buildResourceGraph as d, resolveResourceRefs as f, resourceKinds as g, resourceKind as h, resourceToDataSource as i, REST_TO_CANONICAL as j, LIST_OPS as k, storageEnvSuffix as l, resourceKeyOf as m, declaredQueueConsumers as n, setQueueRuntime as o, resourceEnvSuffix as p, declaredSubscriptions as r, setTopicRuntime as s, declareCron as t, DEFAULT_RESOURCE_KEY as u, RLS_ROLES_SQL as v, isRelationalCollectionConfig as w, getCollectionDataPath as x, RLS_UID_SQL as y };
1055
+ //#region ../types/src/types/scopes.ts
1056
+ /**
1057
+ * Scopes — what a credential may do, named `resource:action`.
1058
+ *
1059
+ * One vocabulary for every way of reaching a Rebase backend: a person's
1060
+ * session, a service key, a personal key and an OAuth token for `/mcp` all
1061
+ * answer "may this caller do X?" with the same strings, so a grant reads the
1062
+ * same on a key, on a role and on a consent screen.
1063
+ *
1064
+ * A scope may carry a target — `data:read:posts` is `data:read` on the `posts`
1065
+ * collection only. The unqualified scope covers every target. Only the data
1066
+ * plane and app scopes take targets; see {@link SCOPE_TARGETS}.
1067
+ *
1068
+ * Two planes, held differently:
1069
+ *
1070
+ * - **The data plane** (`data:*`, `storage:*`, `functions:invoke`). Every
1071
+ * signed-in person holds all of it, because what a person may do with data
1072
+ * is decided row by row by the collection's `securityRules` and by storage
1073
+ * policies, never by a scope. On a key or a token these scopes narrow: a key
1074
+ * holding `data:read:posts` reaches nothing else, whatever RLS would allow.
1075
+ * - **The admin plane** (everything else). Nobody holds it implicitly. The
1076
+ * `admin` role holds all of it; any other role holds what the app declares
1077
+ * for it under `auth.roles` on the users collection.
1078
+ *
1079
+ * Apps declare their own scopes too (`auth.scopes`), named the same way —
1080
+ * `project:deploy`. Every signed-in person holds every app scope: like the data
1081
+ * plane, the function behind it decides whether the person may act, and the
1082
+ * scope exists so a key can be narrowed to that one action.
1083
+ *
1084
+ * @module
1085
+ */
1086
+ /** @group Auth */
1087
+ var DATA_PLANE_SCOPES = [
1088
+ "data:read",
1089
+ "data:write",
1090
+ "data:delete",
1091
+ "storage:read",
1092
+ "storage:write",
1093
+ "storage:delete",
1094
+ "functions:invoke"
1095
+ ];
1096
+ /** @group Auth */
1097
+ var ADMIN_SCOPES = [
1098
+ "users:read",
1099
+ "users:write",
1100
+ "schema:read",
1101
+ "schema:write",
1102
+ "database:read",
1103
+ "database:write",
1104
+ "backups:read",
1105
+ "cron:read",
1106
+ "cron:write",
1107
+ "logs:read",
1108
+ "keys:read",
1109
+ "keys:write"
1110
+ ];
1111
+ /** Every scope Rebase itself defines, in display order. @group Auth */
1112
+ var BUILT_IN_SCOPES = [...DATA_PLANE_SCOPES, ...ADMIN_SCOPES];
1113
+ /**
1114
+ * Scopes no key may hold.
1115
+ *
1116
+ * A key that could manage keys could mint its own successor, widen itself, or
1117
+ * revoke the keys other integrations run on — and revoking it would undo none
1118
+ * of that. Managing keys is for a person (or the service key).
1119
+ *
1120
+ * @group Auth
1121
+ */
1122
+ var KEY_MANAGEMENT_SCOPES = ["keys:read", "keys:write"];
1123
+ /** The one built-in role. It holds every scope and is the RLS `admin` role. @group Auth */
1124
+ var ADMIN_ROLE = "admin";
1125
+ /**
1126
+ * The built-in scopes that accept a target, and what the target names.
1127
+ *
1128
+ * - `data:*` — a collection slug
1129
+ * - `storage:*` — a storage source id (`(default)` for the default source)
1130
+ * - `functions:invoke` — a custom function's name
1131
+ *
1132
+ * @group Auth
1133
+ */
1134
+ var SCOPE_TARGETS = {
1135
+ "data:read": "collection",
1136
+ "data:write": "collection",
1137
+ "data:delete": "collection",
1138
+ "storage:read": "bucket",
1139
+ "storage:write": "bucket",
1140
+ "storage:delete": "bucket",
1141
+ "functions:invoke": "function"
1142
+ };
1143
+ /** @group Auth */
1144
+ var BUILT_IN_SCOPE_DESCRIPTIONS = {
1145
+ "data:read": {
1146
+ label: "Read data",
1147
+ description: "Read rows from collections, through the caller's row-level security."
1148
+ },
1149
+ "data:write": {
1150
+ label: "Create and update data",
1151
+ description: "Create and update rows in collections, through the caller's row-level security."
1152
+ },
1153
+ "data:delete": {
1154
+ label: "Delete data",
1155
+ description: "Delete rows from collections, through the caller's row-level security."
1156
+ },
1157
+ "storage:read": {
1158
+ label: "Read files",
1159
+ description: "List and download stored files."
1160
+ },
1161
+ "storage:write": {
1162
+ label: "Upload files",
1163
+ description: "Upload files and create folders."
1164
+ },
1165
+ "storage:delete": {
1166
+ label: "Delete files",
1167
+ description: "Delete stored files."
1168
+ },
1169
+ "functions:invoke": {
1170
+ label: "Call functions",
1171
+ description: "Call the backend's custom functions. A function can do anything its code does."
1172
+ },
1173
+ "users:read": {
1174
+ label: "See users",
1175
+ description: "List user accounts and their roles."
1176
+ },
1177
+ "users:write": {
1178
+ label: "Manage users",
1179
+ description: "Create, edit and delete accounts, reset passwords and second factors, and assign roles up to the holder's own."
1180
+ },
1181
+ "schema:read": {
1182
+ label: "See the schema",
1183
+ description: "Read the collection schema, plan schema changes and run the RLS audit."
1184
+ },
1185
+ "schema:write": {
1186
+ label: "Change the schema",
1187
+ description: "Apply schema changes: edits collection files and alters the database."
1188
+ },
1189
+ "database:read": {
1190
+ label: "Inspect the database",
1191
+ description: "List databases, tables, Postgres roles and branches."
1192
+ },
1193
+ "database:write": {
1194
+ label: "Run SQL",
1195
+ description: "Run SQL as the database owner, outside row-level security, and create or delete branches."
1196
+ },
1197
+ "backups:read": {
1198
+ label: "Download backups",
1199
+ description: "List and download database backups — every row, outside row-level security."
1200
+ },
1201
+ "cron:read": {
1202
+ label: "See cron jobs",
1203
+ description: "List cron jobs and read their run history."
1204
+ },
1205
+ "cron:write": {
1206
+ label: "Run cron jobs",
1207
+ description: "Trigger cron jobs and switch them on or off."
1208
+ },
1209
+ "logs:read": {
1210
+ label: "Read server logs",
1211
+ description: "Read the server's request and application logs."
1212
+ },
1213
+ "keys:read": {
1214
+ label: "See service keys",
1215
+ description: "List the project's service keys. Never grantable to a key."
1216
+ },
1217
+ "keys:write": {
1218
+ label: "Manage service keys",
1219
+ description: "Create, change and revoke the project's service keys. Never grantable to a key."
1220
+ }
1221
+ };
1222
+ /** The access model of an app that declares nothing: built-ins only. @group Auth */
1223
+ var EMPTY_ACCESS_MODEL = {
1224
+ roles: {},
1225
+ scopes: {}
1226
+ };
1227
+ var SCOPE_PART = /^[a-z][a-z0-9-]*$/;
1228
+ /**
1229
+ * Split `resource:action[:target]`. Returns null for anything else.
1230
+ *
1231
+ * The target is everything after the second colon, so a target may itself
1232
+ * contain colons. Resource and action are lower-case words.
1233
+ *
1234
+ * @group Auth
1235
+ */
1236
+ function parseScope(value) {
1237
+ if (typeof value !== "string") return null;
1238
+ const first = value.indexOf(":");
1239
+ if (first < 0) return null;
1240
+ const second = value.indexOf(":", first + 1);
1241
+ const resource = value.slice(0, first);
1242
+ const action = second < 0 ? value.slice(first + 1) : value.slice(first + 1, second);
1243
+ if (!SCOPE_PART.test(resource) || !SCOPE_PART.test(action)) return null;
1244
+ if (second < 0) return { scope: `${resource}:${action}` };
1245
+ const target = value.slice(second + 1);
1246
+ if (target.length === 0 || /\s/.test(target)) return null;
1247
+ return {
1248
+ scope: `${resource}:${action}`,
1249
+ target
1250
+ };
1251
+ }
1252
+ /** @group Auth */
1253
+ function isBuiltInScope(scope) {
1254
+ return BUILT_IN_SCOPES.includes(scope);
1255
+ }
1256
+ /** @group Auth */
1257
+ function isDataPlaneScope(scope) {
1258
+ return DATA_PLANE_SCOPES.includes(scope);
1259
+ }
1260
+ /** @group Auth */
1261
+ function isAdminScope(scope) {
1262
+ return ADMIN_SCOPES.includes(scope);
1263
+ }
1264
+ /** Does this list of roles include the built-in `admin` role? @group Auth */
1265
+ function hasAdminRole(roles) {
1266
+ return !!roles?.includes(ADMIN_ROLE);
1267
+ }
1268
+ /**
1269
+ * Does a set of held scopes grant `scope`, optionally on one `target`?
1270
+ *
1271
+ * The unqualified grant covers every target. A qualified grant covers its own
1272
+ * target only, and never answers an unqualified question: a key holding
1273
+ * `data:read:posts` is not asked "may you read data?" and told yes.
1274
+ *
1275
+ * @group Auth
1276
+ */
1277
+ function scopeGrants(held, scope, target) {
1278
+ for (const entry of held) {
1279
+ if (entry === scope) return true;
1280
+ if (target !== void 0 && entry === `${scope}:${target}`) return true;
1281
+ }
1282
+ return false;
1283
+ }
1284
+ /**
1285
+ * Does a set of held scopes grant `scope` on at least one target?
1286
+ *
1287
+ * For a surface that lists what is reachable — the collections an MCP client
1288
+ * may query — and filters per item afterwards.
1289
+ *
1290
+ * @group Auth
1291
+ */
1292
+ function scopeGrantsAny(held, scope) {
1293
+ const prefix = `${scope}:`;
1294
+ return held.some((entry) => entry === scope || entry.startsWith(prefix));
1295
+ }
1296
+ /**
1297
+ * Every scope a person holding `roles` has.
1298
+ *
1299
+ * The data plane and every app scope always; the whole admin plane with the
1300
+ * `admin` role; otherwise each declared role's scopes. A role nobody declared
1301
+ * adds nothing — it may still mean something to an RLS policy.
1302
+ *
1303
+ * @group Auth
1304
+ */
1305
+ function scopesForRoles(roles, model = EMPTY_ACCESS_MODEL) {
1306
+ const held = /* @__PURE__ */ new Set([...DATA_PLANE_SCOPES, ...Object.keys(model.scopes)]);
1307
+ if (hasAdminRole(roles)) {
1308
+ for (const scope of ADMIN_SCOPES) held.add(scope);
1309
+ return [...held];
1310
+ }
1311
+ for (const role of roles ?? []) {
1312
+ const definition = Object.prototype.hasOwnProperty.call(model.roles, role) ? model.roles[role] : void 0;
1313
+ for (const scope of definition?.scopes ?? []) held.add(scope);
1314
+ }
1315
+ return [...held];
1316
+ }
1317
+ /**
1318
+ * Every scope this access model knows, unqualified: the built-ins, then the
1319
+ * app's own.
1320
+ *
1321
+ * @group Auth
1322
+ */
1323
+ function knownScopes(model = EMPTY_ACCESS_MODEL) {
1324
+ return [...BUILT_IN_SCOPES, ...Object.keys(model.scopes)];
1325
+ }
1326
+ /** Does this scope accept a target? @group Auth */
1327
+ function scopeAcceptsTarget(scope, model = EMPTY_ACCESS_MODEL) {
1328
+ if (isBuiltInScope(scope)) return SCOPE_TARGETS[scope] !== void 0;
1329
+ return (Object.prototype.hasOwnProperty.call(model.scopes, scope) ? model.scopes[scope] : void 0)?.target !== void 0;
1330
+ }
1331
+ /**
1332
+ * Check a list of scope strings against an access model. Returns the
1333
+ * problems, empty when every entry is a known scope with an acceptable target.
1334
+ *
1335
+ * @group Auth
1336
+ */
1337
+ function validateScopes(values, model = EMPTY_ACCESS_MODEL) {
1338
+ const known = new Set(knownScopes(model));
1339
+ const problems = [];
1340
+ for (const value of values) {
1341
+ const text = typeof value === "string" ? value : String(value);
1342
+ const parsed = typeof value === "string" ? parseScope(value) : null;
1343
+ if (!parsed) problems.push({
1344
+ scope: text,
1345
+ reason: "malformed"
1346
+ });
1347
+ else if (!known.has(parsed.scope)) problems.push({
1348
+ scope: text,
1349
+ reason: "unknown"
1350
+ });
1351
+ else if (parsed.target !== void 0 && !scopeAcceptsTarget(parsed.scope, model)) problems.push({
1352
+ scope: text,
1353
+ reason: "target-not-accepted"
1354
+ });
1355
+ }
1356
+ return problems;
1357
+ }
1358
+ /**
1359
+ * The entries of `requested` that `held` does not cover — what a credential
1360
+ * would hold beyond its minter. Empty means the request is within reach.
1361
+ *
1362
+ * `data:read:posts` is covered by `data:read`; `data:read` is not covered by
1363
+ * `data:read:posts`.
1364
+ *
1365
+ * @group Auth
1366
+ */
1367
+ function scopesBeyond(requested, held) {
1368
+ return requested.filter((entry) => {
1369
+ const parsed = parseScope(entry);
1370
+ if (!parsed) return true;
1371
+ return !scopeGrants(held, parsed.scope, parsed.target);
1372
+ });
1373
+ }
1374
+ /**
1375
+ * Narrow `requested` to what `held` covers, entry by entry. What a personal
1376
+ * key holds today when its owner has lost a role since it was minted.
1377
+ *
1378
+ * @group Auth
1379
+ */
1380
+ function intersectScopes(requested, held) {
1381
+ const beyond = new Set(scopesBeyond(requested, held));
1382
+ return requested.filter((entry) => !beyond.has(entry));
1383
+ }
1384
+ /** The roles of an access model, `admin` first. @group Auth */
1385
+ function summarizeRoles(model = EMPTY_ACCESS_MODEL) {
1386
+ return [{
1387
+ id: ADMIN_ROLE,
1388
+ name: "Admin",
1389
+ description: "Holds every scope. Row-level security does not limit it: it reads, changes and deletes every row.",
1390
+ scopes: [...ADMIN_SCOPES],
1391
+ builtIn: true
1392
+ }, ...Object.entries(model.roles).map(([id, definition]) => ({
1393
+ id,
1394
+ name: definition.name ?? id,
1395
+ ...definition.description ? { description: definition.description } : {},
1396
+ scopes: [...definition.scopes],
1397
+ builtIn: false
1398
+ }))];
1399
+ }
1400
+ /** Every scope of an access model, described, in display order. @group Auth */
1401
+ function summarizeScopes(model = EMPTY_ACCESS_MODEL) {
1402
+ const builtIn = BUILT_IN_SCOPES.map((scope) => ({
1403
+ scope,
1404
+ ...BUILT_IN_SCOPE_DESCRIPTIONS[scope],
1405
+ ...SCOPE_TARGETS[scope] ? { target: SCOPE_TARGETS[scope] } : {},
1406
+ plane: isDataPlaneScope(scope) ? "data" : "admin"
1407
+ }));
1408
+ const app = Object.entries(model.scopes).map(([scope, definition]) => ({
1409
+ scope,
1410
+ label: definition.label,
1411
+ description: definition.description ?? "",
1412
+ ...definition.target ? { target: definition.target } : {},
1413
+ plane: "app"
1414
+ }));
1415
+ return [...builtIn, ...app];
1416
+ }
1417
+ //#endregion
1418
+ export { parseRelationAggregateSort as $, DEFAULT_RESOURCE_KEY as A, rewriteLegacyRlsFunctions as B, declaredSubscriptions as C, setTopicRuntime as D, setQueueRuntime as E, resourceKind as F, DEFAULT_DATA_SOURCE_KEY as G, getDeclaredSubcollections as H, resourceKinds as I, CANONICAL_TO_REST as J, getDataSourceCapabilities as K, RLS_JWT_SQL as L, resolveResourceRefs as M, resourceEnvSuffix as N, DEFAULT_STORAGE_SOURCE_KEY as O, resourceKeyOf as P, isRelationAggregateSort as Q, RLS_ROLES_SQL as R, declaredQueueConsumers as S, resourceToStorageSource as T, isPostgresCollectionConfig as U, getCollectionDataPath as V, isRelationalCollectionConfig as W, NULL_OPS as X, LIST_OPS as Y, REST_TO_CANONICAL as Z, scopesForRoles as _, KEY_MANAGEMENT_SCOPES as a, validateScopes as b, intersectScopes as c, isDataPlaneScope as d, sortKeyToString as et, knownScopes as f, scopesBeyond as g, scopeGrantsAny as h, EMPTY_ACCESS_MODEL as i, buildResourceGraph as j, storageEnvSuffix as k, isAdminScope as l, scopeGrants as m, ADMIN_SCOPES as n, SCOPE_TARGETS as o, parseScope as p, ALL_WHERE_FILTER_OPS as q, BUILT_IN_SCOPES as r, hasAdminRole as s, ADMIN_ROLE as t, toCanonicalOp as tt, isBuiltInScope as u, summarizeRoles as v, resourceToDataSource as w, declareCron as x, summarizeScopes as y, RLS_UID_SQL as z };
1000
1419
 
1001
- //# sourceMappingURL=src-vkcwKXbT.js.map
1420
+ //# sourceMappingURL=src-CatHFUym.js.map