@reventlessdev/reventless-core 3.0.0-alpha.285 → 3.0.0-alpha.286

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 (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/package.json +6 -6
  3. package/src/Roles.res +3 -0
  4. package/src/Roles.res.mjs +2 -0
  5. package/src/admin/Platform_AdminGroup.res +12 -0
  6. package/src/admin/Platform_AdminGroup.res.mjs +23 -0
  7. package/src/admin/Platform_Admin_Structure.res +14 -10
  8. package/src/admin/Platform_Admin_Structure.res.mjs +22 -33
  9. package/src/components/AutomationSlice/AutomationSlice_Builder.res +2 -1
  10. package/src/components/Counter/Counter_Builder.res +4 -2
  11. package/src/components/Dcb/Dcb_Builder.res +9 -6
  12. package/src/components/Dcb/Dcb_Builder.res.mjs +6 -6
  13. package/src/components/InboundTranslationSlice/InboundTranslationSlice_Builder.res +2 -1
  14. package/src/components/OutboundTranslationSlice/OutboundTranslationSlice_Builder.res +2 -1
  15. package/src/components/QueryDb/QueryDb_Builder.res +1 -1
  16. package/src/components/QueryDb/QueryDb_Builder.res.mjs +3 -2
  17. package/src/components/StateViewSlice/StateViewSlice_Builder.res +1 -0
  18. package/src/plugin/api/PluginBaseFragment.res +1 -1
  19. package/src/plugin/api/PluginBaseFragment.res.mjs +2 -1
  20. package/src/plugin/component/Plugin_Builder.res +7 -3
  21. package/src/plugin/component/Plugin_Builder.res.mjs +6 -3
  22. package/src/plugin/component/Plugin_Helpers.res +2 -1
  23. package/src/plugin/component/Plugin_Helpers.res.mjs +2 -1
  24. package/src/plugin/component/Plugin_Structure.res +52 -19
  25. package/src/plugin/component/Plugin_Structure.res.mjs +40 -15
  26. package/src/plugin/lifecycle/PluginsReadModelSpec.res +1 -1
  27. package/src/plugin/lifecycle/PluginsReadModelSpec.res.mjs +1 -1
  28. package/tests/admin/AdminApiSchemaDriftTest.res +9 -3
  29. package/tests/admin/AdminApiSchemaDriftTest.res.mjs +3 -3
  30. package/tests/admin/Platform_Admin_StructureTest.res +17 -14
  31. package/tests/admin/Platform_Admin_StructureTest.res.mjs +31 -19
  32. package/tests/admin/Platform_ComponentDefinitionsApiTest.res.mjs +8 -72
  33. package/tests/admin/Platform_PluginStructuresApiTest.res.mjs +9 -39
  34. package/tests/api/GraphQL_FragmentGeneratorTest.res +1 -1
  35. package/tests/api/GraphQL_FragmentGeneratorTest.res.mjs +1 -1
  36. package/tests/plugin/PluginStructureAccessTest.res +30 -1
  37. package/tests/plugin/PluginStructureAccessTest.res.mjs +28 -1
  38. package/tests/plugin/StateChange/PsGatedCommands.res +9 -1
  39. package/tests/plugin/StateChange/PsGatedCommands.res.mjs +4 -1
  40. package/tests/plugin/StateView/PsGatedView.res +1 -1
  41. package/tests/plugin/StateView/PsGatedView.res.mjs +1 -1
  42. package/tests/plugin/pluginDefinitionRequiredScalars.txt +5 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 3.0.0-alpha.286 (2026-10-01)
7
+
8
+ * feat!: roles a plugin declares, groups a platform provides ([43daace](https://github.com/ReventlessDev/reventless-core/commit/43daace6ca588afe22562d079af1e6f1da81942e))
9
+
10
+ ### BREAKING CHANGES
11
+
12
+ * AllowGroups and AdminGroup are removed — write AllowRoles over
13
+ the plugin's Roles.t, and use Role.admin / Platform.adminGroup(). Spec module
14
+ types declare `type role`, and their rules are Authorization.rule<role>; a spec
15
+ that writes its own rule declares `type role` (Reventless.Role.name for a rule
16
+ over Authorization.permission). Role.name is a private string: make one from a
17
+ string with Role.make.
18
+
19
+
20
+
6
21
  # 3.0.0-alpha.285 (2026-10-01)
7
22
 
8
23
  ### Features
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reventlessdev/reventless-core",
3
- "version": "3.0.0-alpha.285",
3
+ "version": "3.0.0-alpha.286",
4
4
  "description": "Core package for Reventless framework",
5
5
  "license": "Apache-2.0",
6
6
  "jest": {
@@ -28,22 +28,22 @@
28
28
  "dependencies": {
29
29
  "sury": "11.0.0",
30
30
  "uuid": "^13.0.0",
31
+ "@reventlessdev/rescript-effect": "0.1.0-alpha.34",
31
32
  "@reventlessdev/rescript-fast-csv": "2.0.0-alpha.20",
32
33
  "@reventlessdev/rescript-hash-object": "1.2.0-alpha.15",
33
- "@reventlessdev/rescript-effect": "0.1.0-alpha.34",
34
- "@reventlessdev/rescript-node": "2.0.0-alpha.20",
35
34
  "@reventlessdev/rescript-jest": "1.0.0-alpha.11",
35
+ "@reventlessdev/rescript-node": "2.0.0-alpha.20",
36
36
  "@reventlessdev/rescript-pulumi-pulumi": "2.3.0-alpha.22",
37
37
  "@reventlessdev/rescript-ssh2": "2.0.0-alpha.21",
38
38
  "@reventlessdev/rescript-uuid": "2.0.0-alpha.1",
39
- "@reventlessdev/reventless-spec": "3.0.0-alpha.155",
40
39
  "@reventlessdev/reventless-interop": "3.0.0-alpha.38",
41
- "@reventlessdev/reventless-infra": "3.0.0-alpha.183"
40
+ "@reventlessdev/reventless-spec": "3.0.0-alpha.156",
41
+ "@reventlessdev/reventless-infra": "3.0.0-alpha.184"
42
42
  },
43
43
  "devDependencies": {
44
44
  "rescript": "12.3.1",
45
45
  "sury-ppx": "11.0.0",
46
- "@reventlessdev/reventless-ppx": "1.0.0-alpha.95"
46
+ "@reventlessdev/reventless-ppx": "1.0.0-alpha.96"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "rescript": "^12.3.1"
package/src/Roles.res ADDED
@@ -0,0 +1,3 @@
1
+ // The roles the platform's own components require. `Admin` is `Reventless.Role.admin`,
2
+ // joined by name like any plugin's role.
3
+ type t = Admin
@@ -0,0 +1,2 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+ /* This output is empty. Its source's type definitions, externals and/or unused code got optimized away. */
@@ -0,0 +1,12 @@
1
+ // The administrator group as the host shell reads it from `config.json`: the
2
+ // group the platform gates its admin API on, from the same role-to-group
3
+ // resolution as the server, so the two cannot disagree. Written only where the
4
+ // deployment maps the administrator role away from its own name; the shell
5
+ // reads an absent key as `Admin`, so a default deployment's file is unchanged.
6
+
7
+ let configKey = "adminGroup"
8
+
9
+ let configEntry = (): option<(string, JSON.t)> => {
10
+ let group = Reventless.Role.adminGroup()
11
+ group == (Reventless.Role.admin :> string) ? None : Some((configKey, JSON.Encode.string(group)))
12
+ }
@@ -0,0 +1,23 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Role$Reventless from "@reventlessdev/reventless-spec/src/types/Role.res.mjs";
4
+
5
+ let configKey = "adminGroup";
6
+
7
+ function configEntry() {
8
+ let group = Role$Reventless.adminGroup();
9
+ if (group === Role$Reventless.admin) {
10
+ return;
11
+ } else {
12
+ return [
13
+ configKey,
14
+ group
15
+ ];
16
+ }
17
+ }
18
+
19
+ export {
20
+ configKey,
21
+ configEntry,
22
+ }
23
+ /* Role-Reventless Not a pure module */
@@ -37,7 +37,8 @@ let pluginCommands: array<commandDef> = Plugin_Structure.extractCommandDefs(
37
37
  ~isAggregate=true,
38
38
  ~mutationFieldFor=variantName =>
39
39
  Api_Naming.adminField(~name=PluginSpec.name ++ "_" ++ variantName),
40
- ~commandAuthorization=PluginSpec.commandAuthorization->Obj.magic,
40
+ ~commandAuthorization=command =>
41
+ PluginSpec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
41
42
  ~commandTransition=PluginSpec.commandTransition->Obj.magic,
42
43
  commandSchema,
43
44
  )
@@ -57,16 +58,19 @@ let pluginAggregate: writableDef = {
57
58
  chapter: None,
58
59
  }
59
60
 
60
- let pluginReadModel: queryableDef = Plugin_Structure.queryableDefFromSpec(
61
- ~plugin=pluginId,
62
- ~name=PluginsReadModelSpec.name,
63
- ~stateSchema=PluginsReadModelSpec.stateSchema->S.castToUnknown,
64
- ~authorization=PluginsReadModelSpec.authorization,
65
- ~linkedWriteSide=["Plugin"],
66
- )
61
+ // Functions, not values: the view's access keys are the group the platform maps
62
+ // the administrator role to, and this module is evaluated before a root maps it.
63
+ let pluginReadModel = (): queryableDef =>
64
+ Plugin_Structure.queryableDefFromSpec(
65
+ ~plugin=pluginId,
66
+ ~name=PluginsReadModelSpec.name,
67
+ ~stateSchema=PluginsReadModelSpec.stateSchema->S.castToUnknown,
68
+ ~authorization=PluginsReadModelSpec.authorization->Reventless.Authorization.named,
69
+ ~linkedWriteSide=["Plugin"],
70
+ )
67
71
 
68
- let structure: pluginStructure = {
69
- readModels: [pluginReadModel],
72
+ let structure = (): pluginStructure => {
73
+ readModels: [pluginReadModel()],
70
74
  stateViewSlices: [],
71
75
  stateChangeSlices: [],
72
76
  aggregates: [pluginAggregate],
@@ -1,5 +1,6 @@
1
1
  // Generated by ReScript, PLEASE EDIT WITH CARE
2
2
 
3
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
3
4
  import * as Api_Naming$ReventlessCore from "../components/Api/Api_Naming.res.mjs";
4
5
  import * as PluginSpec$ReventlessCore from "../plugin/lifecycle/PluginSpec.res.mjs";
5
6
  import * as Plugin_Structure$ReventlessCore from "../plugin/component/Plugin_Structure.res.mjs";
@@ -7,7 +8,7 @@ import * as PluginsReadModelSpec$ReventlessCore from "../plugin/lifecycle/Plugin
7
8
 
8
9
  let pluginId = "Platform";
9
10
 
10
- let pluginCommands = Plugin_Structure$ReventlessCore.extractCommandDefs(undefined, true, undefined, variantName => Api_Naming$ReventlessCore.adminField(PluginSpec$ReventlessCore.name + "_" + variantName), PluginSpec$ReventlessCore.commandAuthorization, PluginSpec$ReventlessCore.commandTransition, undefined, PluginSpec$ReventlessCore.commandSchema);
11
+ let pluginCommands = Plugin_Structure$ReventlessCore.extractCommandDefs(undefined, true, undefined, variantName => Api_Naming$ReventlessCore.adminField(PluginSpec$ReventlessCore.name + "_" + variantName), command => Authorization$Reventless.named(PluginSpec$ReventlessCore.commandAuthorization(command)), PluginSpec$ReventlessCore.commandTransition, undefined, PluginSpec$ReventlessCore.commandSchema);
11
12
 
12
13
  let pluginAggregate_producedEventTypes = [];
13
14
 
@@ -31,39 +32,27 @@ let pluginAggregate = {
31
32
  chapter: undefined
32
33
  };
33
34
 
34
- let pluginReadModel = Plugin_Structure$ReventlessCore.queryableDefFromSpec(pluginId, PluginsReadModelSpec$ReventlessCore.name, PluginsReadModelSpec$ReventlessCore.stateSchema, PluginsReadModelSpec$ReventlessCore.authorization, undefined, undefined, ["Plugin"], undefined);
35
-
36
- let structure_readModels = [pluginReadModel];
37
-
38
- let structure_stateViewSlices = [];
39
-
40
- let structure_stateChangeSlices = [];
41
-
42
- let structure_aggregates = [pluginAggregate];
43
-
44
- let structure_automationSlices = [];
45
-
46
- let structure_outboundTranslationSlices = [];
47
-
48
- let structure_inboundTranslationSlices = [];
49
-
50
- let structure_extensions = [];
35
+ function pluginReadModel() {
36
+ return Plugin_Structure$ReventlessCore.queryableDefFromSpec(pluginId, PluginsReadModelSpec$ReventlessCore.name, PluginsReadModelSpec$ReventlessCore.stateSchema, Authorization$Reventless.named(PluginsReadModelSpec$ReventlessCore.authorization), undefined, undefined, ["Plugin"], undefined);
37
+ }
51
38
 
52
- let structure = {
53
- readModels: structure_readModels,
54
- stateViewSlices: structure_stateViewSlices,
55
- stateChangeSlices: structure_stateChangeSlices,
56
- aggregates: structure_aggregates,
57
- automationSlices: structure_automationSlices,
58
- outboundTranslationSlices: structure_outboundTranslationSlices,
59
- inboundTranslationSlices: structure_inboundTranslationSlices,
60
- extensions: structure_extensions,
61
- extensionPoints: undefined,
62
- requiredStores: undefined,
63
- requiredStoreDeclarations: undefined,
64
- requiredCapabilities: undefined,
65
- traitDeclarations: undefined
66
- };
39
+ function structure() {
40
+ return {
41
+ readModels: [pluginReadModel()],
42
+ stateViewSlices: [],
43
+ stateChangeSlices: [],
44
+ aggregates: [pluginAggregate],
45
+ automationSlices: [],
46
+ outboundTranslationSlices: [],
47
+ inboundTranslationSlices: [],
48
+ extensions: [],
49
+ extensionPoints: undefined,
50
+ requiredStores: undefined,
51
+ requiredStoreDeclarations: undefined,
52
+ requiredCapabilities: undefined,
53
+ traitDeclarations: undefined
54
+ };
55
+ }
67
56
 
68
57
  let internalPluginDefinition = {
69
58
  id: pluginId + "@INTERNAL",
@@ -54,7 +54,8 @@ module Make = (
54
54
  let stateSchema = AutomationSlice_Callback.todoRowSchema
55
55
  let config = Reventless.ReadModel.config()
56
56
  let subIdConfig: option<Reventless.ReadModel.subIdConfig<state>> = None
57
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
57
+ type role = Reventless.Role.name
58
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
58
59
  let visibility: Reventless.Visibility.t = Public
59
60
  }
60
61
 
@@ -29,7 +29,8 @@ module Make = (
29
29
 
30
30
  let subIdConfig = None
31
31
  let config = Reventless.ReadModel.config()
32
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
32
+ type role = Reventless.Role.name
33
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
33
34
  let visibility: Reventless.Visibility.t = Public
34
35
  }
35
36
 
@@ -48,7 +49,8 @@ module Make = (
48
49
 
49
50
  let subIdConfig = None
50
51
  let config = Reventless.ReadModel.config()
51
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
52
+ type role = Reventless.Role.name
53
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
52
54
  let visibility: Reventless.Visibility.t = Public
53
55
  }
54
56
  module CountsDb = QueryDb_Builder.Make(
@@ -534,7 +534,8 @@ module Make = (
534
534
  ~commandSchema,
535
535
  )->Array.map(((f, _)) => f),
536
536
  ~commandSchema,
537
- ~commandAuthorization=S.Spec.commandAuthorization->Obj.magic,
537
+ ~commandAuthorization=command =>
538
+ S.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
538
539
  )
539
540
  }
540
541
  })
@@ -549,7 +550,8 @@ module Make = (
549
550
  ~commandSchema,
550
551
  )->Array.map(((f, _)) => f),
551
552
  ~commandSchema,
552
- ~commandAuthorization=S.Spec.commandAuthorization->Obj.magic,
553
+ ~commandAuthorization=command =>
554
+ S.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
553
555
  )
554
556
  }
555
557
  })
@@ -1076,8 +1078,8 @@ module Make = (
1076
1078
  )
1077
1079
  // One SDL field per constructor, each with its own constructor's args and
1078
1080
  // its own per-constructor authorization rule.
1079
- let commandAuthorization: unknown => Reventless.Authorization.permission =
1080
- S.Spec.commandAuthorization->Obj.magic
1081
+ let commandAuthorization: unknown => Reventless.Authorization.permission = command =>
1082
+ S.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named
1081
1083
  let fieldPermissions = Dict.make()
1082
1084
  fieldSpecs->Array.forEach(((fieldName, ctor)) => {
1083
1085
  let hasPayload = Reventless.DcbTag.isVariantPayloadBearing(
@@ -1108,7 +1110,8 @@ module Make = (
1108
1110
  let fieldPermissions = Dict.make()
1109
1111
  switch permissionForFirstConstructor(
1110
1112
  ~commandSchema=ITS.Spec.commandSchema->Reventless.DcbTag.toUnknownSchema,
1111
- ~commandAuthorization=ITS.Spec.commandAuthorization->Obj.magic,
1113
+ ~commandAuthorization=command =>
1114
+ ITS.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
1112
1115
  ) {
1113
1116
  | Some(rule) => fieldPermissions->Dict.set(fieldName, rule)
1114
1117
  | None => ()
@@ -1142,7 +1145,7 @@ module Make = (
1142
1145
  returnTypeName: qn.returnTypeName,
1143
1146
  stateSchema: V.Spec.stateSchema->Reventless.DcbTag.toUnknownSchema,
1144
1147
  authorization: None,
1145
- permission: V.Spec.authorization,
1148
+ permission: V.Spec.authorization->Reventless.Authorization.named,
1146
1149
  systemCallable: systemCallableComponents->Array.includes(V.Spec.name),
1147
1150
  includeIdParam: qn.includeIdParam,
1148
1151
  connectionSpec: true,
@@ -13,6 +13,7 @@ import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js
13
13
  import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js";
14
14
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
15
15
  import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
16
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
16
17
  import * as Component$ReventlessCore from "../Component.res.mjs";
17
18
  import * as DcbValidation$Reventless from "@reventlessdev/reventless-spec/src/components/DcbValidation.res.mjs";
18
19
  import * as Api_Naming$ReventlessCore from "../Api/Api_Naming.res.mjs";
@@ -291,13 +292,13 @@ function Make(DcbEventLogStorage) {
291
292
  syncSlices.forEach(S => {
292
293
  let commandSchema = S.Spec.commandSchema;
293
294
  if (!ApiNoApiHelpers$ReventlessCore.isNoApi(commandSchema)) {
294
- return registerResolver("Dcb", Api_Naming$ReventlessCore.sliceMutationFields(apiNamePrefix, S.Spec.name, commandSchema).map(param => param[0]), commandSchema, S.Spec.commandAuthorization);
295
+ return registerResolver("Dcb", Api_Naming$ReventlessCore.sliceMutationFields(apiNamePrefix, S.Spec.name, commandSchema).map(param => param[0]), commandSchema, command => Authorization$Reventless.named(S.Spec.commandAuthorization(command)));
295
296
  }
296
297
  });
297
298
  asyncSlices.forEach(S => {
298
299
  let commandSchema = S.Spec.commandSchema;
299
300
  if (!ApiNoApiHelpers$ReventlessCore.isNoApi(commandSchema)) {
300
- return registerResolver("Dcb", Api_Naming$ReventlessCore.sliceMutationFields(apiNamePrefix, S.Spec.name, commandSchema).map(param => param[0]), commandSchema, S.Spec.commandAuthorization);
301
+ return registerResolver("Dcb", Api_Naming$ReventlessCore.sliceMutationFields(apiNamePrefix, S.Spec.name, commandSchema).map(param => param[0]), commandSchema, command => Authorization$Reventless.named(S.Spec.commandAuthorization(command)));
301
302
  }
302
303
  });
303
304
  }
@@ -562,7 +563,6 @@ function Make(DcbEventLogStorage) {
562
563
  return;
563
564
  }
564
565
  let sliceDef = Stdlib_Option.flatMap(pluginStructure, s => s.stateChangeSlices.find(d => d.name === S.Spec.name));
565
- let commandAuthorization = S.Spec.commandAuthorization;
566
566
  let fieldPermissions = {};
567
567
  fieldSpecs.forEach(param => {
568
568
  let ctor = param[1];
@@ -570,7 +570,7 @@ function Make(DcbEventLogStorage) {
570
570
  let syntheticCmd = hasPayload ? ({
571
571
  TAG: ctor
572
572
  }) : ctor;
573
- fieldPermissions[param[0]] = commandAuthorization(syntheticCmd);
573
+ fieldPermissions[param[0]] = Authorization$Reventless.named(S.Spec.commandAuthorization(syntheticCmd));
574
574
  });
575
575
  return {
576
576
  fieldNames: fieldSpecs.map(param => param[0]),
@@ -585,7 +585,7 @@ function Make(DcbEventLogStorage) {
585
585
  let mutationEntriesFromInboundSlices = inboundTranslationSlices.map(ITS => {
586
586
  let fieldName = Api_Naming$ReventlessCore.sliceMutationField(name, ITS.Spec.name);
587
587
  let fieldPermissions = {};
588
- let rule = permissionForFirstConstructor(ITS.Spec.commandSchema, ITS.Spec.commandAuthorization);
588
+ let rule = permissionForFirstConstructor(ITS.Spec.commandSchema, command => Authorization$Reventless.named(ITS.Spec.commandAuthorization(command)));
589
589
  if (rule !== undefined) {
590
590
  fieldPermissions[fieldName] = rule;
591
591
  }
@@ -609,7 +609,7 @@ function Make(DcbEventLogStorage) {
609
609
  returnTypeName: qn.returnTypeName,
610
610
  stateSchema: V.Spec.stateSchema,
611
611
  authorization: undefined,
612
- permission: V.Spec.authorization,
612
+ permission: Authorization$Reventless.named(V.Spec.authorization),
613
613
  systemCallable: systemCallableComponents.includes(V.Spec.name),
614
614
  includeIdParam: qn.includeIdParam,
615
615
  connectionSpec: true,
@@ -35,7 +35,8 @@ module Make = (
35
35
  let stateSchema = InboundTranslationSlice_Callback.auditRowSchema
36
36
  let config = Reventless.ReadModel.config()
37
37
  let subIdConfig: option<Reventless.ReadModel.subIdConfig<state>> = None
38
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
38
+ type role = Reventless.Role.name
39
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
39
40
  let visibility: Reventless.Visibility.t = Public
40
41
  }
41
42
 
@@ -51,7 +51,8 @@ module Make = (
51
51
  let stateSchema = OutboundTranslationSlice_Callback.todoRowSchema
52
52
  let config = Reventless.ReadModel.config()
53
53
  let subIdConfig: option<Reventless.ReadModel.subIdConfig<state>> = None
54
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
54
+ type role = Reventless.Role.name
55
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
55
56
  let visibility: Reventless.Visibility.t = Public
56
57
  }
57
58
 
@@ -55,7 +55,7 @@ module Make = (
55
55
  ~subIdField,
56
56
  ~idResolverConfigs=Spec.config.idResolvers,
57
57
  ~idsResolverConfigs=Spec.config.idsResolvers,
58
- ~authorization=Spec.authorization,
58
+ ~authorization=Spec.authorization->Reventless.Authorization.named,
59
59
  ~opts,
60
60
  )
61
61
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
4
  import * as QueryDb$ReventlessCore from "./QueryDb.res.mjs";
5
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
5
6
  import * as Component$ReventlessCore from "../Component.res.mjs";
6
7
  import * as ComponentType$ReventlessCore from "../../ComponentType.res.mjs";
7
8
  import * as QueryDb_Operations$ReventlessCore from "./QueryDb_Operations.res.mjs";
@@ -29,7 +30,7 @@ function Make(Spec) {
29
30
  deleteBatch: Operations.deleteBatch
30
31
  };
31
32
  }));
32
- let resolvers = Resolvers.make(none$1, api, apiRole, storage.dataSourceName, Spec.config.indexes, subIdField, Spec.config.idResolvers, Spec.config.idsResolvers, Spec.authorization, opts);
33
+ let resolvers = Resolvers.make(none$1, api, apiRole, storage.dataSourceName, Spec.config.indexes, subIdField, Spec.config.idResolvers, Spec.config.idsResolvers, Authorization$Reventless.named(Spec.authorization), opts);
33
34
  let outputs_resources = storage.resources.concat(resolvers.resources);
34
35
  let outputs_resolversMaker = resolvers.resourcesMaker;
35
36
  let outputs_dataSourceName = storage.dataSourceName;
@@ -50,4 +51,4 @@ function Make(Spec) {
50
51
  export {
51
52
  Make,
52
53
  }
53
- /* Component-ReventlessCore Not a pure module */
54
+ /* Authorization-Reventless Not a pure module */
@@ -33,6 +33,7 @@ module Make = (
33
33
  let stateSchema = Spec.stateSchema
34
34
  let config = Spec.config
35
35
  let subIdConfig = Spec.subIdConfig
36
+ type role = Spec.role
36
37
  let authorization = Spec.authorization
37
38
  let visibility = Spec.visibility
38
39
  }
@@ -38,7 +38,7 @@ let queryEntries: array<querySchemaEntry> = [
38
38
  // read: the entry path uses only the group, and the per-`@index` auth-table
39
39
  // pipeline params come from `indexConfig.authorization`, which is untouched.
40
40
  authorization: None,
41
- permission: PluginsReadModelSpec.authorization,
41
+ permission: PluginsReadModelSpec.authorization->Reventless.Authorization.named,
42
42
  // No `excludeFields`: the three fields this entry used to name are declared
43
43
  // `@internal` on the spec, and `deriveObjectTypeWithNested` reads that off the
44
44
  // schema itself.
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
4
4
  import * as DcbTag$Reventless from "@reventlessdev/reventless-spec/src/components/DcbTag.res.mjs";
5
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
5
6
  import * as Api_Naming$ReventlessCore from "../../components/Api/Api_Naming.res.mjs";
6
7
  import * as PluginSpec$ReventlessCore from "../lifecycle/PluginSpec.res.mjs";
7
8
  import * as ApiNoApiHelpers$ReventlessCore from "../../components/Api/ApiNoApiHelpers.res.mjs";
@@ -20,7 +21,7 @@ let queryEntries = [{
20
21
  stateSchema: PluginsReadModelSpec$ReventlessCore.stateSchema,
21
22
  specName: PluginsReadModelSpec$ReventlessCore.name,
22
23
  authorization: undefined,
23
- permission: PluginsReadModelSpec$ReventlessCore.authorization,
24
+ permission: Authorization$Reventless.named(PluginsReadModelSpec$ReventlessCore.authorization),
24
25
  subIdField: Stdlib_Option.map(undefined, c => c.subIdField),
25
26
  indexQueries: indexQueriesOfConfig(PluginsReadModelSpec$ReventlessCore.config)
26
27
  }];
@@ -214,7 +214,8 @@ module Make = (
214
214
  ~kind=Aggregate,
215
215
  ~fields=fieldNames,
216
216
  ~commandSchema,
217
- ~commandAuthorization=M.Spec.commandAuthorization->Obj.magic,
217
+ ~commandAuthorization=command =>
218
+ M.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
218
219
  )
219
220
  )
220
221
  let aggDef =
@@ -235,7 +236,8 @@ module Make = (
235
236
  cname,
236
237
  )
237
238
  let syntheticCmd: unknown = hasPayload ? {"TAG": cname}->Obj.magic : cname->Obj.magic
238
- let rule = M.Spec.commandAuthorization(syntheticCmd->Obj.magic)
239
+ let rule =
240
+ M.Spec.commandAuthorization(syntheticCmd->Obj.magic)->Reventless.Authorization.named
239
241
  fieldPermissions->Dict.set(fieldName, rule)
240
242
  })
241
243
  [
@@ -272,7 +274,7 @@ module Make = (
272
274
  returnTypeName: qn.returnTypeName,
273
275
  stateSchema: R.Spec.stateSchema->S.castToUnknown,
274
276
  authorization: None,
275
- permission: R.Spec.authorization,
277
+ permission: R.Spec.authorization->Reventless.Authorization.named,
276
278
  connectionSpec: true,
277
279
  ?subIdField,
278
280
  indexQueries: ?(indexes->Array.length > 0 ? Some(indexes) : None),
@@ -1149,6 +1151,8 @@ module Make = (
1149
1151
  ~opts=?,
1150
1152
  ) => {
1151
1153
  PluginRuntimeBuilder.registerPluginName(name)
1154
+ // Here, outside any `Output.apply`, so a preview refuses the plugin too.
1155
+ pluginStructure->Option.forEach(s => Reventless.RoleCoverage.check(s, ~plugin=name))
1152
1156
  let version = Reventless.PackageVersion.fromCaller()
1153
1157
  Component.make(
1154
1158
  ~componentType=Plugin.componentType->ComponentType.toString,
@@ -14,7 +14,9 @@ import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
14
14
  import * as Plugin$ReventlessCore from "./Plugin.res.mjs";
15
15
  import * as StackReference$Pulumi from "@reventlessdev/rescript-pulumi-pulumi/src/StackReference.res.mjs";
16
16
  import * as Adapter$ReventlessCore from "../../adapter/Adapter.res.mjs";
17
+ import * as RoleCoverage$Reventless from "@reventlessdev/reventless-spec/src/types/RoleCoverage.res.mjs";
17
18
  import * as Aggregate$ReventlessCore from "../../components/Aggregate/Aggregate.res.mjs";
19
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
18
20
  import * as Component$ReventlessCore from "../../components/Component.res.mjs";
19
21
  import * as ReadModel$ReventlessCore from "../../components/ReadModel/ReadModel.res.mjs";
20
22
  import * as Api_Naming$ReventlessCore from "../../components/Api/Api_Naming.res.mjs";
@@ -124,6 +126,7 @@ function Make(Spec) {
124
126
  let systemCallableComponents = systemCallableComponentsOpt !== undefined ? systemCallableComponentsOpt : [];
125
127
  let componentRuntime = componentRuntimeOpt !== undefined ? componentRuntimeOpt : ({});
126
128
  PluginRuntimeBuilder.registerPluginName(name);
129
+ Stdlib_Option.forEach(pluginStructure, s => RoleCoverage$Reventless.check(s, name));
127
130
  let version = PackageVersion$Reventless.fromCaller();
128
131
  return Component$ReventlessCore.make(ComponentType$ReventlessCore.toString(Plugin$ReventlessCore.componentType), name, (extra, extra$1) => {
129
132
  let _prevPluginName = Logger$ReventlessCore.currentPluginName.contents;
@@ -173,7 +176,7 @@ function Make(Spec) {
173
176
  if (fieldNames.length === 0) {
174
177
  return [];
175
178
  }
176
- Stdlib_Option.forEach(Spec.hooks.mutationResolverHook, registerResolver => registerResolver("Aggregate", fieldNames, commandSchema, M.Spec.commandAuthorization));
179
+ Stdlib_Option.forEach(Spec.hooks.mutationResolverHook, registerResolver => registerResolver("Aggregate", fieldNames, commandSchema, command => Authorization$Reventless.named(M.Spec.commandAuthorization(command))));
177
180
  let aggDef = Stdlib_Option.flatMap(pluginStructure, s => s.aggregates.find(d => d.name === M.Spec.name));
178
181
  let fieldPermissions = {};
179
182
  filteredConstructorNames.forEach((cname, idx) => {
@@ -182,7 +185,7 @@ function Make(Spec) {
182
185
  let syntheticCmd = hasPayload ? ({
183
186
  TAG: cname
184
187
  }) : cname;
185
- let rule = M.Spec.commandAuthorization(syntheticCmd);
188
+ let rule = Authorization$Reventless.named(M.Spec.commandAuthorization(syntheticCmd));
186
189
  fieldPermissions[fieldName] = rule;
187
190
  });
188
191
  return [{
@@ -205,7 +208,7 @@ function Make(Spec) {
205
208
  returnTypeName: qn.returnTypeName,
206
209
  stateSchema: R.Spec.stateSchema,
207
210
  authorization: undefined,
208
- permission: R.Spec.authorization,
211
+ permission: Authorization$Reventless.named(R.Spec.authorization),
209
212
  connectionSpec: true,
210
213
  subIdField: subIdField,
211
214
  indexQueries: indexes.length !== 0 ? indexes : undefined,
@@ -1150,7 +1150,8 @@ let registerAdminAggregateMutations = (
1150
1150
  ~kind=Aggregate,
1151
1151
  ~fields=fieldNames,
1152
1152
  ~commandSchema,
1153
- ~commandAuthorization=M.Spec.commandAuthorization->Obj.magic,
1153
+ ~commandAuthorization=command =>
1154
+ M.Spec.commandAuthorization(command->Obj.magic)->Reventless.Authorization.named,
1154
1155
  )
1155
1156
  )
1156
1157
  }
@@ -21,6 +21,7 @@ import * as Logger$ReventlessCore from "../../util/Logger.res.mjs";
21
21
  import * as Adapter$ReventlessCore from "../../adapter/Adapter.res.mjs";
22
22
  import * as Task$ReventlessInterop from "@reventlessdev/reventless-interop/src/components/Task.res.mjs";
23
23
  import * as Aggregate$ReventlessCore from "../../components/Aggregate/Aggregate.res.mjs";
24
+ import * as Authorization$Reventless from "@reventlessdev/reventless-spec/src/types/Authorization.res.mjs";
24
25
  import * as Component$ReventlessCore from "../../components/Component.res.mjs";
25
26
  import * as ReadModel$ReventlessCore from "../../components/ReadModel/ReadModel.res.mjs";
26
27
  import * as Api_Naming$ReventlessCore from "../../components/Api/Api_Naming.res.mjs";
@@ -540,7 +541,7 @@ function registerAdminAggregateMutations(aggregates, hooks) {
540
541
  let fieldNames = filteredConstructorNames.map(cname => Api_Naming$ReventlessCore.adminField(M.Spec.name + "_" + cname));
541
542
  aggregateMutationFieldsRegistry[M.Spec.name] = fieldNames;
542
543
  if (fieldNames.length !== 0) {
543
- return Stdlib_Option.forEach(hooks.mutationResolverHook, registerResolver => registerResolver("Aggregate", fieldNames, commandSchema, M.Spec.commandAuthorization));
544
+ return Stdlib_Option.forEach(hooks.mutationResolverHook, registerResolver => registerResolver("Aggregate", fieldNames, commandSchema, command => Authorization$Reventless.named(M.Spec.commandAuthorization(command))));
544
545
  }
545
546
  });
546
547
  }