public async Task GetJSAppBundle()

in src/governance/client/Controllers/WorkspacesController.cs [288:404]


    public async Task<IActionResult> GetJSAppBundle()
    {
        // There is not direct API to retrieve the original bundle that was submitted via set_jsapp.
        var ccfClient = await this.CcfClientManager.GetGovClient();
        JsonObject modules, endpoints;

        using (HttpResponseMessage response = await ccfClient.GetAsync(
            $"gov/service/javascript-modules?" +
            $"api-version={this.CcfClientManager.GetGovApiVersion()}"))
        {
            await response.ValidateStatusCodeAsync(this.Logger);
            modules = (await response.Content.ReadFromJsonAsync<JsonObject>())!;
        }

        using (HttpResponseMessage response = await ccfClient.GetAsync(
            $"gov/service/javascript-app?" +
            $"api-version={this.CcfClientManager.GetGovApiVersion()}&case=original"))
        {
            await response.ValidateStatusCodeAsync(this.Logger);
            endpoints = (await response.Content.ReadFromJsonAsync<JsonObject>())!;
        }

        List<string> moduleNames = new();
        List<Task<string>> fetchModuleTasks = new();
        foreach (var item in modules["value"]!.AsArray().AsEnumerable())
        {
            var moduleName = item!.AsObject()["moduleName"]!.ToString();
            moduleNames.Add(moduleName);
        }

        // Sort the module names in alphabetical order so that we return the response ordered by
        // name.
        moduleNames = moduleNames.OrderBy(x => x, StringComparer.Ordinal).ToList();
        foreach (var moduleName in moduleNames)
        {
            var escapedString = Uri.EscapeDataString(moduleName);
            Task<string> fetchModuleTask = ccfClient.GetStringAsync(
            $"gov/service/javascript-modules/{escapedString}?" +
            $"api-version={this.CcfClientManager.GetGovApiVersion()}");
            fetchModuleTasks.Add(fetchModuleTask);
        }

        var endpointsInProposalFormat = new JsonObject();
        foreach (KeyValuePair<string, JsonNode?> apiSpec in
            endpoints["endpoints"]!.AsObject().AsEnumerable())
        {
            // Need to transform the endpoints output to the format that the proposal expects.
            // "/contracts": {
            //   "GET": {
            //     "authnPolicies": [
            //       "member_cert",
            //       "user_cert"
            //     ],
            //     "forwardingRequired": "sometimes",
            //     "jsModule": "/endpoints/contracts.js",
            // =>
            // "/contracts": {
            //   "get": {
            //     "authn_policies": [
            //       "member_cert",
            //       "user_cert"
            //     ],
            //     "forwarding_required": "sometimes",
            //     "js_module": "endpoints/contracts.js",=>
            string api = apiSpec.Key;
            if (endpointsInProposalFormat[api] == null)
            {
                endpointsInProposalFormat[api] = new JsonObject();
            }

            foreach (KeyValuePair<string, JsonNode?> verbSpec in
                apiSpec.Value!.AsObject().AsEnumerable())
            {
                string verb = verbSpec.Key!.ToLower();
                var value = new JsonObject();
                foreach (var item3 in verbSpec.Value!.AsObject().AsEnumerable())
                {
                    value[item3.Key] = item3.Value?.DeepClone();
                }

                // Remove leading / ie "js_module": "/foo/bar" => "js_module": "foo/bar"
                value["js_module"] = value["js_module"]!.ToString().TrimStart('/');

                // The /javascript-app API is not returning mode value for PUT/POST. Need to fill it
                // or else proposal submission fails.
                if ((verb == "put" || verb == "post") && value["mode"] == null)
                {
                    value["mode"] = "readwrite";
                }

                endpointsInProposalFormat[api]!.AsObject()[verb] = value;
            }
        }

        await Task.WhenAll(fetchModuleTasks);
        var modulesArray = new JsonArray();
        for (int i = 0; i < moduleNames.Count; i++)
        {
#pragma warning disable VSTHRD003 // Avoid awaiting foreign Tasks
            string content = (await fetchModuleTasks[i])!;
#pragma warning restore VSTHRD003 // Avoid awaiting foreign Tasks
            modulesArray.Add(new JsonObject
            {
                ["name"] = moduleNames[i].TrimStart('/'),
                ["module"] = content
            });
        }

        return this.Ok(new JsonObject
        {
            ["metadata"] = new JsonObject
            {
                ["endpoints"] = endpointsInProposalFormat
            },
            ["modules"] = modulesArray
        });
    }