@reventlessdev/reventless-aws 3.0.0-alpha.369 → 3.0.0-alpha.371

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 (38) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/package.json +11 -11
  3. package/scripts/ProvisionAdmin.res +2 -2
  4. package/scripts/ProvisionAdmin.res.mjs +7 -6
  5. package/src/Platform.res +56 -7
  6. package/src/Platform.res.mjs +46 -7
  7. package/src/Platform_ProvidedGroups.res +97 -0
  8. package/src/Platform_ProvidedGroups.res.mjs +103 -0
  9. package/src/Platform_Stack.res +6 -3
  10. package/src/Platform_Stack.res.mjs +3 -3
  11. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res +1 -1
  12. package/src/adapter/Api/Platform_ComponentDefinitions_Lambda.res.mjs +1 -1
  13. package/src/adapter/Auth/Auth_ActiveRoleTrigger_Ops.res +1 -1
  14. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res +1 -1
  15. package/src/adapter/Runtime/PgQueryResolverEntryPoint_Ops.res.mjs +2 -1
  16. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res +1 -0
  17. package/src/adapter/Runtime/RuntimeEnvironment_Lambda.res.mjs +1 -0
  18. package/src/components/Api/AppSync_Adapter.res +4 -3
  19. package/src/components/Api/AppSync_SdlDecorate.res +7 -3
  20. package/src/components/Api/AppSync_SdlDecorate.res.mjs +4 -3
  21. package/src/util/Util_OwnerScopeEnv.res +9 -0
  22. package/src/util/Util_OwnerScopeEnv.res.mjs +14 -1
  23. package/src/util/Util_ShellConfig.res +4 -0
  24. package/src/util/Util_ShellConfig.res.mjs +5 -1
  25. package/tests/AppSync_AdapterTest.res +46 -23
  26. package/tests/AppSync_AdapterTest.res.mjs +35 -27
  27. package/tests/PgPipeline_IntegrationTest.res +2 -1
  28. package/tests/PgQueryDbUnion_IntegrationTest.res +2 -1
  29. package/tests/Platform_ProvidedGroupsTest.res +52 -0
  30. package/tests/Platform_ProvidedGroupsTest.res.mjs +98 -0
  31. package/tests/Util_OwnerScopeEnvTest.res +48 -2
  32. package/tests/Util_OwnerScopeEnvTest.res.mjs +49 -3
  33. package/tests/Util_ShellConfigTest.res +17 -0
  34. package/tests/Util_ShellConfigTest.res.mjs +18 -0
  35. package/tests/integration/AggTestAggregate.res +2 -1
  36. package/tests/integration/EpCompositeSlice.res +2 -1
  37. package/tests/integration/EpTestSlice.res +2 -1
  38. package/tests/integration/QueryDbUnion_DynamoDb_IntegrationTest.res +2 -1
@@ -0,0 +1,98 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Platform_ProvidedGroups$ReventlessAws from "../src/Platform_ProvidedGroups.res.mjs";
4
+
5
+ function group(name) {
6
+ return {
7
+ GroupName: name
8
+ };
9
+ }
10
+
11
+ globalThis.describe("Platform_ProvidedGroups.listAll", () => {
12
+ globalThis.test("follows NextToken until the last page", async () => {
13
+ let seen = [];
14
+ let send = async input => {
15
+ seen.push(input.NextToken);
16
+ let match = input.NextToken;
17
+ if (match !== undefined) {
18
+ return {
19
+ Groups: [{
20
+ GroupName: "Merchandiser"
21
+ }]
22
+ };
23
+ } else {
24
+ return {
25
+ Groups: [
26
+ {
27
+ GroupName: "Admin"
28
+ },
29
+ {
30
+ GroupName: "Shopper"
31
+ }
32
+ ],
33
+ NextToken: "p2"
34
+ };
35
+ }
36
+ };
37
+ let groups = await Platform_ProvidedGroups$ReventlessAws.listAll(send, "p1");
38
+ globalThis.expect([
39
+ groups,
40
+ seen
41
+ ]).toEqual([
42
+ [
43
+ "Admin",
44
+ "Shopper",
45
+ "Merchandiser"
46
+ ],
47
+ [
48
+ undefined,
49
+ "p2"
50
+ ]
51
+ ]);
52
+ });
53
+ });
54
+
55
+ globalThis.describe("Platform_ProvidedGroups.poolFromExports", () => {
56
+ let from = pairs => {
57
+ let $$exports = Object.fromEntries(pairs);
58
+ return Platform_ProvidedGroups$ReventlessAws.poolFromExports(key => $$exports[key]);
59
+ };
60
+ globalThis.test("reads the pool id and region", () => {
61
+ globalThis.expect(from([
62
+ [
63
+ "identityProviderId",
64
+ "p1"
65
+ ],
66
+ [
67
+ "identityProviderRegion",
68
+ "eu-west-1"
69
+ ]
70
+ ])).toEqual({
71
+ id: "p1",
72
+ region: "eu-west-1"
73
+ });
74
+ });
75
+ globalThis.test("reads them nested under default, as an ESM platform exports them", () => {
76
+ globalThis.expect(from([[
77
+ "default",
78
+ Object.fromEntries([[
79
+ "cognitoUserPoolId",
80
+ "p-old"
81
+ ]])
82
+ ]])).toEqual({
83
+ id: "p-old",
84
+ region: undefined
85
+ });
86
+ });
87
+ globalThis.test("no pool id is no pool to list", () => {
88
+ globalThis.expect(from([])).toEqual(undefined);
89
+ });
90
+ });
91
+
92
+ let Cognito;
93
+
94
+ export {
95
+ Cognito,
96
+ group,
97
+ }
98
+ /* Not a pure module */
@@ -68,7 +68,7 @@ describe("Util_OwnerScopeEnv — the elevated-groups carrier", () => {
68
68
  testSync("the platform's administrator default reaches a composed environment", () => {
69
69
  Reventless.OwnerScope.clearElevatedGroups()
70
70
  NodeProcess.env->Dict.delete(Util_OwnerScopeEnv.key)
71
- Reventless.OwnerScope.defaultElevatedGroups([Reventless.AdminGroup.name])
71
+ Reventless.OwnerScope.defaultElevatedRoles([Reventless.Role.admin])
72
72
 
73
73
  let variables = Dict.make()
74
74
  Util_OwnerScopeEnv.applyElevatedGroupsDefault(variables)
@@ -81,7 +81,53 @@ describe("Util_OwnerScopeEnv — the elevated-groups carrier", () => {
81
81
  // Round-tripped, like the first case above: the runtime reads this back with
82
82
  // `parseElevatedGroups`, so the encoding is asserted rather than the spelling.
83
83
  expect(Reventless.OwnerScope.parseElevatedGroups(encoded))->toEqual([
84
- Reventless.AdminGroup.name,
84
+ Reventless.Role.adminGroup(),
85
85
  ])
86
86
  })
87
+
88
+ // Runtimes read groups, never roles, so an elevated role travels as the group
89
+ // the deploy program mapped it to.
90
+ testSync("an elevated role travels as the group it is mapped to", () => {
91
+ Reventless.OwnerScope.clearElevatedGroups()
92
+ Reventless.Role.clearGroups()
93
+ NodeProcess.env->Dict.delete(Util_OwnerScopeEnv.key)
94
+ Reventless.Role.setGroups([(Reventless.Role.make("Fulfilment"), "shop-ops")])
95
+ Reventless.OwnerScope.setElevatedRoles([Reventless.Role.make("Fulfilment")])
96
+ Reventless.OwnerScope.setElevatedGroups(["Admin"])
97
+
98
+ let variables = Dict.make()
99
+ Util_OwnerScopeEnv.applyElevatedGroupsDefault(variables)
100
+ let encoded = switch variables->Dict.get(Util_OwnerScopeEnv.key) {
101
+ | Some(value) => value->Obj.magic
102
+ | None => ""
103
+ }
104
+ Reventless.OwnerScope.clearElevatedGroups()
105
+ Reventless.Role.clearGroups()
106
+
107
+ expect(Reventless.OwnerScope.parseElevatedGroups(encoded))->toEqual(["Admin", "shop-ops"])
108
+ })
109
+ })
110
+
111
+ describe("Util_OwnerScopeEnv.applyRoleGroupsDefault", () => {
112
+ testSync("carries the renamed roles, and only those", () => {
113
+ Reventless.Role.clearGroups()
114
+ Reventless.Role.setGroups([(Reventless.Role.make("Merchandiser"), "shop-merch-team")])
115
+ let variables = Dict.make()
116
+ Util_OwnerScopeEnv.applyRoleGroupsDefault(variables)
117
+ Reventless.Role.clearGroups()
118
+ let encoded = switch variables->Dict.get(Reventless.Role.envKey) {
119
+ | Some(value) => value->Obj.magic
120
+ | None => ""
121
+ }
122
+ expect(Reventless.Role.parseGroups(encoded))->toEqual([
123
+ (Reventless.Role.make("Merchandiser"), "shop-merch-team"),
124
+ ])
125
+ })
126
+
127
+ testSync("adds nothing when no role is renamed", () => {
128
+ Reventless.Role.clearGroups()
129
+ let variables = Dict.make()
130
+ Util_OwnerScopeEnv.applyRoleGroupsDefault(variables)
131
+ expect(variables->Dict.get(Reventless.Role.envKey)->Option.isNone)->toBe(true)
132
+ })
87
133
  })
@@ -2,7 +2,7 @@
2
2
 
3
3
  import * as Stdlib_Dict from "@rescript/runtime/lib/es6/Stdlib_Dict.js";
4
4
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
5
- import * as AdminGroup$Reventless from "@reventlessdev/reventless-spec/src/types/AdminGroup.res.mjs";
5
+ import * as Role$Reventless from "@reventlessdev/reventless-spec/src/types/Role.res.mjs";
6
6
  import * as OwnerScope$Reventless from "@reventlessdev/reventless-spec/src/types/OwnerScope.res.mjs";
7
7
  import * as Util_OwnerScopeEnv$ReventlessAws from "../src/util/Util_OwnerScopeEnv.res.mjs";
8
8
 
@@ -59,13 +59,59 @@ globalThis.describe("Util_OwnerScopeEnv — the elevated-groups carrier", () =>
59
59
  globalThis.test("the platform's administrator default reaches a composed environment", () => {
60
60
  OwnerScope$Reventless.clearElevatedGroups();
61
61
  Stdlib_Dict.$$delete(process.env, Util_OwnerScopeEnv$ReventlessAws.key);
62
- OwnerScope$Reventless.defaultElevatedGroups([AdminGroup$Reventless.name]);
62
+ OwnerScope$Reventless.defaultElevatedRoles([Role$Reventless.admin]);
63
63
  let variables = {};
64
64
  Util_OwnerScopeEnv$ReventlessAws.applyElevatedGroupsDefault(variables);
65
65
  let value = variables[Util_OwnerScopeEnv$ReventlessAws.key];
66
66
  let encoded = value !== undefined ? value : "";
67
67
  OwnerScope$Reventless.clearElevatedGroups();
68
- globalThis.expect(OwnerScope$Reventless.parseElevatedGroups(encoded)).toEqual([AdminGroup$Reventless.name]);
68
+ globalThis.expect(OwnerScope$Reventless.parseElevatedGroups(encoded)).toEqual([Role$Reventless.adminGroup()]);
69
+ });
70
+ globalThis.test("an elevated role travels as the group it is mapped to", () => {
71
+ OwnerScope$Reventless.clearElevatedGroups();
72
+ Role$Reventless.clearGroups();
73
+ Stdlib_Dict.$$delete(process.env, Util_OwnerScopeEnv$ReventlessAws.key);
74
+ Role$Reventless.setGroups([[
75
+ "Fulfilment",
76
+ "shop-ops"
77
+ ]]);
78
+ OwnerScope$Reventless.setElevatedRoles(["Fulfilment"]);
79
+ OwnerScope$Reventless.setElevatedGroups(["Admin"]);
80
+ let variables = {};
81
+ Util_OwnerScopeEnv$ReventlessAws.applyElevatedGroupsDefault(variables);
82
+ let value = variables[Util_OwnerScopeEnv$ReventlessAws.key];
83
+ let encoded = value !== undefined ? value : "";
84
+ OwnerScope$Reventless.clearElevatedGroups();
85
+ Role$Reventless.clearGroups();
86
+ globalThis.expect(OwnerScope$Reventless.parseElevatedGroups(encoded)).toEqual([
87
+ "Admin",
88
+ "shop-ops"
89
+ ]);
90
+ });
91
+ });
92
+
93
+ globalThis.describe("Util_OwnerScopeEnv.applyRoleGroupsDefault", () => {
94
+ globalThis.test("carries the renamed roles, and only those", () => {
95
+ Role$Reventless.clearGroups();
96
+ Role$Reventless.setGroups([[
97
+ "Merchandiser",
98
+ "shop-merch-team"
99
+ ]]);
100
+ let variables = {};
101
+ Util_OwnerScopeEnv$ReventlessAws.applyRoleGroupsDefault(variables);
102
+ Role$Reventless.clearGroups();
103
+ let value = variables[Role$Reventless.envKey];
104
+ let encoded = value !== undefined ? value : "";
105
+ globalThis.expect(Role$Reventless.parseGroups(encoded)).toEqual([[
106
+ "Merchandiser",
107
+ "shop-merch-team"
108
+ ]]);
109
+ });
110
+ globalThis.test("adds nothing when no role is renamed", () => {
111
+ Role$Reventless.clearGroups();
112
+ let variables = {};
113
+ Util_OwnerScopeEnv$ReventlessAws.applyRoleGroupsDefault(variables);
114
+ globalThis.expect(Stdlib_Option.isNone(variables[Role$Reventless.envKey])).toBe(true);
69
115
  });
70
116
  });
71
117
 
@@ -328,3 +328,20 @@ describe("the subscription endpoint", () => {
328
328
  )
329
329
  )
330
330
  })
331
+
332
+ // The shell gates its admin discovery on this group; a mirror of the server's
333
+ // own resolution, so a renamed administrator role reaches the browser too.
334
+ describe("Util_ShellConfig.fields — adminGroup", () => {
335
+ testSync("is absent while the administrator role keeps its own name", () => {
336
+ Reventless.Role.clearGroups()
337
+ expect(Util_ShellConfig.fields(~computed)->Dict.get("adminGroup")->Option.isNone)->toBe(true)
338
+ })
339
+
340
+ testSync("carries the group a renamed administrator role maps to", () => {
341
+ Reventless.Role.clearGroups()
342
+ Reventless.Role.setGroups([(Reventless.Role.admin, "shop-admins")])
343
+ let out = Util_ShellConfig.fields(~computed)
344
+ Reventless.Role.clearGroups()
345
+ expect(out->get("adminGroup"))->toEqual(JSON.Encode.string("shop-admins"))
346
+ })
347
+ })
@@ -4,6 +4,7 @@ import * as JestGlobals from "@reventlessdev/rescript-jest/src/JestGlobals.res.m
4
4
  import * as Stdlib_JSON from "@rescript/runtime/lib/es6/Stdlib_JSON.js";
5
5
  import * as Stdlib_Array from "@rescript/runtime/lib/es6/Stdlib_Array.js";
6
6
  import * as Stdlib_Option from "@rescript/runtime/lib/es6/Stdlib_Option.js";
7
+ import * as Role$Reventless from "@reventlessdev/reventless-spec/src/types/Role.res.mjs";
7
8
  import * as Primitive_object from "@rescript/runtime/lib/es6/Primitive_object.js";
8
9
  import * as Primitive_string from "@rescript/runtime/lib/es6/Primitive_string.js";
9
10
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
@@ -341,6 +342,23 @@ globalThis.describe("the subscription endpoint", () => {
341
342
  });
342
343
  });
343
344
 
345
+ globalThis.describe("Util_ShellConfig.fields — adminGroup", () => {
346
+ globalThis.test("is absent while the administrator role keeps its own name", () => {
347
+ Role$Reventless.clearGroups();
348
+ globalThis.expect(Stdlib_Option.isNone(Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined)["adminGroup"])).toBe(true);
349
+ });
350
+ globalThis.test("carries the group a renamed administrator role maps to", () => {
351
+ Role$Reventless.clearGroups();
352
+ Role$Reventless.setGroups([[
353
+ Role$Reventless.admin,
354
+ "shop-admins"
355
+ ]]);
356
+ let out = Util_ShellConfig$ReventlessAws.fields(computed, undefined, undefined, undefined, undefined);
357
+ Role$Reventless.clearGroups();
358
+ globalThis.expect(get(out, "adminGroup")).toEqual("shop-admins");
359
+ });
360
+ });
361
+
344
362
  export {
345
363
  computed,
346
364
  get,
@@ -18,6 +18,7 @@ type error = AlreadyExists
18
18
 
19
19
  let name = "AggTestAggregate"
20
20
  let moduleUrl = "agg-test://AggTestAggregate"
21
- let commandAuthorization = (_: command): Reventless.Authorization.permission => AllowAnonymous
21
+ type role = Reventless.Role.name
22
+ let commandAuthorization = (_: command): Reventless.Authorization.rule<role> => AllowAnonymous
22
23
  type lifecycleState = unit
23
24
  let commandTransition = (_: command): Reventless.Transition.t<lifecycleState> => Unrestricted
@@ -63,7 +63,8 @@ type event =
63
63
 
64
64
  let name = "EpCompositeSlice"
65
65
  let moduleUrl = "ep-test://EpCompositeSlice"
66
- let commandAuthorization = (_: command): Reventless.Authorization.permission => AllowAnonymous
66
+ type role = Reventless.Role.name
67
+ let commandAuthorization = (_: command): Reventless.Authorization.rule<role> => AllowAnonymous
67
68
  type lifecycleState = unit
68
69
  let commandTransition = (_: command): Reventless.Transition.t<lifecycleState> => Unrestricted
69
70
  let readConsistency = Reventless.ReadConsistency.EscalateOnRetry
@@ -21,7 +21,8 @@ type event = WidgetAdded({widgetId: @s.matches(Reventless.DcbTag.partition) stri
21
21
 
22
22
  let name = "EpTestSlice"
23
23
  let moduleUrl = "ep-test://EpTestSlice"
24
- let commandAuthorization = (_: command): Reventless.Authorization.permission => AllowAnonymous
24
+ type role = Reventless.Role.name
25
+ let commandAuthorization = (_: command): Reventless.Authorization.rule<role> => AllowAnonymous
25
26
  type lifecycleState = unit
26
27
  let commandTransition = (_: command): Reventless.Transition.t<lifecycleState> => Unrestricted
27
28
  let readConsistency = Reventless.ReadConsistency.EscalateOnRetry
@@ -32,7 +32,8 @@ module CustomersSpec = {
32
32
 
33
33
  let config = Reventless.ReadModel.config()
34
34
  let subIdConfig = None
35
- let authorization: Reventless.Authorization.permission = AllowAuthenticated
35
+ type role = Reventless.Role.name
36
+ let authorization: Reventless.Authorization.rule<role> = AllowAuthenticated
36
37
  let visibility: Reventless.Visibility.t = Public
37
38
  }
38
39