mirror of
https://gitee.com/dcren/openiddict-documentation.git
synced 2025-04-05 17:38:03 +08:00
Update the documentation pages
This commit is contained in:
parent
8c93e119b3
commit
91e907797e
349
guides/contributing-a-new-web-provider.html
Normal file
349
guides/contributing-a-new-web-provider.html
Normal file
@ -0,0 +1,349 @@
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE]><![endif]-->
|
||||
<html>
|
||||
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Contributing a new Web provider </title>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="title" content="Contributing a new Web provider ">
|
||||
<meta name="generator" content="docfx 2.56.7.0">
|
||||
|
||||
<link rel="shortcut icon" href="../images/favicon.ico">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/night-owl.min.css">
|
||||
<link rel="stylesheet" href="../styles/colors.css">
|
||||
<link rel="stylesheet" href="../styles/discord.css">
|
||||
<link rel="stylesheet" href="../styles/main.css">
|
||||
<meta property="docfx:navrel" content="../toc.html">
|
||||
<meta property="docfx:tocrel" content="toc.html">
|
||||
|
||||
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="top-navbar">
|
||||
|
||||
<a href="javascript:void(0);" class="burger-icon" onclick="toggleMenu()">
|
||||
<svg name="Hamburger" style="vertical-align: middle;" width="24" height="24" viewbox="0 0 24 24"><path fill="currentColor" fill-rule="evenodd" clip-rule="evenodd" d="M20 6H4V9H20V6ZM4 10.999H20V13.999H4V10.999ZM4 15.999H20V18.999H4V15.999Z"></path></svg>
|
||||
</a>
|
||||
|
||||
|
||||
<a class="brand" href="../index.html">
|
||||
<img src="../images/logo.png" alt="OpenIddict" class="logomark">
|
||||
<span class="brand-title">OpenIddict</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
|
||||
<div id="blackout" class="blackout" onclick="toggleMenu()"></div>
|
||||
|
||||
<nav id="sidebar" role="navigation">
|
||||
|
||||
<div class="sidebar">
|
||||
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
<a class="brand" href="../index.html">
|
||||
<img src="../images/logo.png" alt="OpenIddict" class="logomark">
|
||||
<span class="brand-title">OpenIddict</span>
|
||||
</a>
|
||||
<div id="navbar">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="sidebar-item-separator"></div>
|
||||
|
||||
|
||||
<div id="sidetoggle">
|
||||
<div id="sidetoc"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
|
||||
<span>Generated by <strong>DocFX</strong></span>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<main class="main-panel">
|
||||
|
||||
<div role="main" class="hide-when-search">
|
||||
|
||||
|
||||
<div class="subnav navbar navbar-default">
|
||||
<div class="container hide-when-search" id="breadcrumb">
|
||||
<ul class="breadcrumb">
|
||||
<li></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<article class="content wrap" id="_content" data-uid="">
|
||||
<h1 id="contributing-a-new-web-provider">Contributing a new Web provider</h1>
|
||||
|
||||
<p>As part of the OpenIddict 4.0 effort, <a href="https://kevinchalet.com/2022/02/25/introducing-the-openiddict-client/">a new client stack has been added to OpenIddict</a>.
|
||||
To simplify integrating with social and enterprise providers that offer OAuth 2.0 and OpenID Connect services, a companion package
|
||||
(named <code>OpenIddict.Client.WebIntegration</code>) has been added to the client stack. While it shares some similarities with the
|
||||
<a href="https://github.com/aspnet-contrib/AspNet.Security.OAuth.Providers/issues">existing aspnet-contrib OAuth 2.0 providers</a>, <strong>there are actually important technical differences</strong>:</p>
|
||||
<ul>
|
||||
<li><p>Unlike the ASP.NET Core OAuth 2.0 base handler by the aspnet-contrib providers, <strong>the OpenIddict client is a dual-protocol OAuth 2.0 + OpenID Connect stack</strong>,
|
||||
which means it can support both protocols <em>while</em> enforcing all the security checks required by these protocols.</p>
|
||||
</li>
|
||||
<li><p>Unlike the aspnet-contrib providers, <strong>the source code needed to materialize the OpenIddict web providers is created dynamically</strong> using
|
||||
<a href="https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview">Roslyn Source Generators</a> and
|
||||
<a href="https://github.com/openiddict/openiddict-core/blob/dev/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml">a XML file that includes all the supported providers</a>
|
||||
with the configuration needed to properly generate them. By eliminating all the plumbing code, the OpenIddict web providers are much easier to maintain and update.</p>
|
||||
</li>
|
||||
<li><p>To guarantee interoperability and make the best security choices, <strong>the OpenIddict client heavily relies on server configuration metadata</strong>, which differs from
|
||||
the approach used by the ASP.NET Core OAuth 2.0 base handler, that doesn't support the OpenID Connect discovery and OAuth 2.0 authorization server metadata specifications.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Due to these differences, <strong>contributing a new provider to the OpenIddict stack is quite different from adding an aspnet-contrib provider</strong>:</p>
|
||||
<h2 id="add-a-new-provider-node-for-the-new-provider">Add a new <code><Provider></code> node for the new provider</h2>
|
||||
<p>To add a new OpenIddict web provider, <strong>the first step is to add a new <code><Provider></code> node</strong> to the <a href="https://github.com/openiddict/openiddict-core/blob/dev/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationProviders.xml">OpenIddictClientWebIntegrationProviders.xml</a> file. For instance:</p>
|
||||
<pre><code class="lang-xml"><Provider Name="Zendesk" Documentation="https://developer.zendesk.com/documentation/live-chat/getting-started/auth/">
|
||||
</Provider>
|
||||
</code></pre><p>If available, a link to the official documentation MUST be added. If multiple languages are available, the following order SHOULD be used:</p>
|
||||
<ul>
|
||||
<li>English</li>
|
||||
<li>French</li>
|
||||
<li>Spanish</li>
|
||||
<li>Any other language</li>
|
||||
</ul>
|
||||
<div class="WARNING"><h5>Warning</h5><p>The added provider MUST be placed in the XML file such that the alphabetical order is respected.</p>
|
||||
</div>
|
||||
<h2 id="add-an-environment-node-per-supported-environment">Add an <code><Environment></code> node per supported environment</h2>
|
||||
<p><strong>The second step is to determine whether the service offers multiple environments</strong> (e.g Production, Testing or Development).</p>
|
||||
<ul>
|
||||
<li>If the provider supports multiple environments, multiple <code><Environment></code> nodes - one per environment - MUST be added under <code><Provider></code>:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Salesforce">
|
||||
<Environment Name="Production" />
|
||||
|
||||
<Environment Name="Development" />
|
||||
</Provider>
|
||||
</code></pre><div class="WARNING"><h5>Warning</h5><p>When specifying multiple environments, the production environment MUST always appear first.</p>
|
||||
</div>
|
||||
<ul>
|
||||
<li>If the provider doesn't support multiple environment, a single <code><Environment></code> MUST be added (the <code>Name</code> attribute SHOULD be omitted):</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Google">
|
||||
<Environment />
|
||||
</Provider>
|
||||
</code></pre><h2 id="add-the-appropriate-configuration-for-each-environment">Add the appropriate configuration for each environment</h2>
|
||||
<p><strong>The third step is the most complicated one: adding the appropriate configuration for each of the added environments</strong>.</p>
|
||||
<p>For that, you MUST first determine whether the environment supports OpenID Connect discovery or OAuth 2.0 authorization server metadata.
|
||||
In some cases, this information will be mentioned in the official documentation, but it's not always true. By convention, the server metadata
|
||||
is typically served from <code>https://provider/.well-known/openid-configuration</code>: if you get a valid JSON document from this endpoint, the server
|
||||
supports OpenID Connect/OAuth 2.0 server metadata.</p>
|
||||
<ul>
|
||||
<li>If the server supports OpenID Connect/OAuth 2.0 server metadata, add an <code>Issuer</code> attribute to <code><Environment></code> corresponding to the provider address
|
||||
without the <code>/.well-known/openid-configuration</code> part. For instance, Google exposes its discovery document at <code>https://accounts.google.com/.well-known/openid-configuration</code>
|
||||
so the correct issuer to use is <code>https://accounts.google.com/</code>:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Google">
|
||||
<Environment Issuer="https://accounts.google.com/" />
|
||||
</Provider>
|
||||
</code></pre><ul>
|
||||
<li>If the server doesn't support OpenID Connect/OAuth 2.0 server metadata, you MUST add an <code>Issuer</code> attribute (corresponding to either
|
||||
the value given in the documentation or the base address of the server) <strong>and</strong> a <code><Configuration></code> node with the static configuration needed by
|
||||
the OpenIddict client to communicate with the remote authorization server. For instance:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Reddit">
|
||||
<Environment Issuer="https://www.reddit.com/">
|
||||
<Configuration AuthorizationEndpoint="https://www.reddit.com/api/v1/authorize"
|
||||
TokenEndpoint="https://www.reddit.com/api/v1/access_token"
|
||||
UserinfoEndpoint="https://oauth.reddit.com/api/v1/me" />
|
||||
</Environment>
|
||||
</Provider>
|
||||
</code></pre><div class="CAUTION"><h5>Caution</h5><p>If the provider doesn't support server metadata but is known to support Proof Key for Code Exchange (PKCE), a <code><CodeChallengeMethod></code> node MUST
|
||||
be added under <code><Configuration></code> to ensure the OpenIddict client will send appropriate <code>code_challenge</code>/<code>code_challenge_method</code> parameters:</p>
|
||||
<pre><code class="lang-xml"><Provider Name="Fitbit">
|
||||
<Environment Issuer="https://www.fitbit.com/">
|
||||
<Configuration AuthorizationEndpoint="https://www.fitbit.com/oauth2/authorize"
|
||||
TokenEndpoint="https://api.fitbit.com/oauth2/token"
|
||||
UserinfoEndpoint="https://api.fitbit.com/1/user/-/profile.json">
|
||||
<CodeChallengeMethod Value="S256" />
|
||||
</Configuration>
|
||||
</Environment>
|
||||
</Provider>
|
||||
</code></pre></div>
|
||||
<div class="NOTE"><h5>Note</h5><p>Some providers use a multitenant configuration that relies on a subdomain, a custom domain or a virtual path to discriminate tenant instances.
|
||||
If the provider you want to support requires adding a dynamic part in one of its URLs, a <code><Setting></code> node MUST be added under <code><Provider></code> to
|
||||
store the tenant name. Once added, the URLs can include a placeholder of the same name:</p>
|
||||
<pre><code class="lang-xml"><Provider Name="Zendesk">
|
||||
<!--
|
||||
Note: Zendesk is a multitenant provider that relies on subdomains to identify instances.
|
||||
As such, the following URLs all include a {tenant} placeholder that will be dynamically
|
||||
replaced by OpenIddict at runtime by the tenant configured in the Zendesk settings.
|
||||
-->
|
||||
|
||||
<Environment Issuer="https://{tenant}.zendesk.com/">
|
||||
<Configuration AuthorizationEndpoint="https://{tenant}.zendesk.com/oauth/authorizations/new"
|
||||
TokenEndpoint="https://{tenant}.zendesk.com/oauth/tokens"
|
||||
UserinfoEndpoint="https://{tenant}.zendesk.com/api/v2/users/me" />
|
||||
</Environment>
|
||||
|
||||
<Setting Name="Tenant" Type="String" Required="true"
|
||||
Description="Gets or sets the tenant used to identify the Zendesk instance." />
|
||||
</Provider>
|
||||
</code></pre></div>
|
||||
<h2 id="test-the-generated-provider">Test the generated provider</h2>
|
||||
<p>If the targeted service is fully standard-compliant, no additional configuration should be required at this point.
|
||||
To confirm it, build the solution and add the new provider to the <code>OpenIddict.Sandbox.AspNetCore.Client</code> sandbox:</p>
|
||||
<ul>
|
||||
<li>Update <code>Startup.cs</code> to use your new provider:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-csharp">options.SetRedirectionEndpointUris(
|
||||
// ... other providers...
|
||||
"/signin-[provider name]");
|
||||
</code></pre><pre><code class="lang-csharp">// Register the Web providers integrations.
|
||||
options.UseWebProviders()
|
||||
// ... other providers...
|
||||
.Add[provider name](new()
|
||||
{
|
||||
ClientId = "bXgwc0U3N3A3YWNuaWVsdlRmRWE6MTpjaQ",
|
||||
ClientSecret = "VcohOgBp-6yQCurngo4GAyKeZh0D6SUCCSjJgEo1uRzJarjIUS",
|
||||
RedirectUri = new Uri("https://localhost:44381/signin-[provider name]", UriKind.Absolute)
|
||||
});
|
||||
</code></pre><ul>
|
||||
<li>Update <code>AuthenticationController.cs</code> to allow triggering challenges pointing to the new provider:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-csharp">var issuer = provider switch
|
||||
{
|
||||
// ... other providers...
|
||||
"[provider name]" => "https://[provider issuer]/",
|
||||
|
||||
_ => null
|
||||
};
|
||||
</code></pre><ul>
|
||||
<li>Update <code>Index.cshtml</code> under <code>Views\Home</code> to include a login button for the new provider:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-html"><a class="btn btn-lg btn-success" asp-controller="Authentication"
|
||||
asp-action="Login" asp-route-provider="[provider name]">Sign in using [provider name]</a>
|
||||
</code></pre><div class="NOTE"><h5>Note</h5><p>Unless you agree to share your sandbox credentials with the OpenIddict developers, the changes
|
||||
made to the sandbox project don't need to be committed and included in your pull request.</p>
|
||||
</div>
|
||||
<h2 id="if-necessary-add-the-necessary-workarounds-for-the-provider-to-work-correctly">If necessary, add the necessary workarounds for the provider to work correctly</h2>
|
||||
<p>If an error occurs during the authentication process, the provider MAY require one or multiple workarounds for the integration to work correctly:</p>
|
||||
<ul>
|
||||
<li>The provider MAY require sending the client credentials as part of the <code>Authorization</code> header using basic authentication (i.e <code>client_secret_basic</code>).
|
||||
Providers that implement OpenID Connect discovery or OAuth 2.0 authorization server metadata will typically return the client authentication methods they support.
|
||||
If the provider doesn't expose its metadata, the supported methods MUST be added manually to the static configuration using one or multiple <code><TokenEndpointAuthMethod></code>:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Twitter">
|
||||
<Environment Issuer="https://twitter.com/">
|
||||
<Configuration AuthorizationEndpoint="https://twitter.com/i/oauth2/authorize"
|
||||
TokenEndpoint="https://api.twitter.com/2/oauth2/token"
|
||||
UserinfoEndpoint="https://api.twitter.com/2/users/me">
|
||||
<CodeChallengeMethod Value="S256" />
|
||||
|
||||
<TokenEndpointAuthMethod Value="client_secret_basic" />
|
||||
</Configuration>
|
||||
</Environment>
|
||||
</Provider>
|
||||
</code></pre><ul>
|
||||
<li>The provider MAY require sending one or multiple default or required scopes. If so, the default/required scopes MUST be added to the <code><Environment></code> node:</li>
|
||||
</ul>
|
||||
<pre><code class="lang-xml"><Provider Name="Twitter" Documentation="https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code">
|
||||
<Environment Issuer="https://twitter.com/">
|
||||
<Configuration AuthorizationEndpoint="https://twitter.com/i/oauth2/authorize"
|
||||
TokenEndpoint="https://api.twitter.com/2/oauth2/token"
|
||||
UserinfoEndpoint="https://api.twitter.com/2/users/me">
|
||||
<CodeChallengeMethod Value="S256" />
|
||||
|
||||
<TokenEndpointAuthMethod Value="client_secret_basic" />
|
||||
</Configuration>
|
||||
|
||||
<!--
|
||||
Note: Twitter requires requesting the "tweet.read" and "users.read" scopes for the
|
||||
userinfo endpoint to work correctly. As such, these 2 scopes are marked as required
|
||||
so they are always sent even if they were not explicitly added by the user.
|
||||
-->
|
||||
|
||||
<Scope Name="tweet.read" Default="true" Required="true" />
|
||||
<Scope Name="users.read" Default="true" Required="true" />
|
||||
</Environment>
|
||||
</Provider>
|
||||
</code></pre><ul>
|
||||
<li>The provider MAY require sending the scopes using a different separator than the standard one. While the OAuth 2.0 specification requires using a space
|
||||
to separate multiple scopes, some providers require using a different separator (typically, a comma). If the provider you're adding requires such a hack,
|
||||
update the <code>FormatNonStandardScopeParameter</code> event handler present in
|
||||
<a href="https://github.com/openiddict/openiddict-core/blob/dev/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationHandlers.cs">OpenIddictClientWebIntegrationHandlers.cs</a> to use the correct separator required by the provider.</li>
|
||||
</ul>
|
||||
<pre><code class="lang-csharp">/// <summary>
|
||||
/// Contains the logic responsible for overriding the standard "scope"
|
||||
/// parameter for providers that are known to use a non-standard format.
|
||||
/// </summary>
|
||||
public class FormatNonStandardScopeParameter : IOpenIddictClientHandler<ProcessChallengeContext>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the default descriptor definition assigned to this handler.
|
||||
/// </summary>
|
||||
public static OpenIddictClientHandlerDescriptor Descriptor { get; }
|
||||
= OpenIddictClientHandlerDescriptor.CreateBuilder<ProcessChallengeContext>()
|
||||
.AddFilter<RequireInteractiveGrantType>()
|
||||
.UseSingletonHandler<FormatNonStandardScopeParameter>()
|
||||
.SetOrder(AttachChallengeParameters.Descriptor.Order + 500)
|
||||
.SetType(OpenIddictClientHandlerType.BuiltIn)
|
||||
.Build();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ValueTask HandleAsync(ProcessChallengeContext context)
|
||||
{
|
||||
if (context is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
context.Request.Scope = context.Registration.GetProviderName() switch
|
||||
{
|
||||
// The following providers are known to use comma-separated scopes instead of
|
||||
// the standard format (that requires using a space as the scope separator):
|
||||
Providers.Reddit => string.Join(",", context.Scopes),
|
||||
|
||||
_ => context.Request.Scope
|
||||
};
|
||||
|
||||
return default;
|
||||
}
|
||||
}
|
||||
</code></pre><div class="NOTE"><h5>Note</h5><p>If the provider still doesn't work, it's unfortunately very likely more complex workarounds will be required.
|
||||
If you're not familiar with the OpenIddict events model, open a ticket in the
|
||||
<a href="https://github.com/openiddict/openiddict-core/issues"><code>openiddict-core</code></a> repository to get help.</p>
|
||||
</div>
|
||||
<h2 id="send-a-pull-request-against-the-openiddict-core-repository">Send a pull request against the <code>openiddict-core</code> repository</h2>
|
||||
<p>Once you've been able to confirm that your provider works correctly, all you need to do is send a PR so that it can be added to the
|
||||
<a href="https://github.com/openiddict/openiddict-core/issues"><code>openiddict-repo</code></a> and ship with the already supported providers as part of the next update.</p>
|
||||
</article>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js"></script>
|
||||
<script type="text/javascript" src="../styles/jquery.twbsPagination.js"></script>
|
||||
<script type="text/javascript" src="../styles/url.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/anchor-js/anchor.min.js"></script>
|
||||
<script type="text/javascript" src="../styles/docfx.js"></script>
|
||||
<script type="text/javascript" src="../styles/main.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -8,6 +8,10 @@
|
||||
<li>
|
||||
<a href="index.html" class="sidebar-item" name="" title="Introduction">Introduction</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a href="contributing-a-new-web-provider.html" class="sidebar-item" name="" title="Contributing a new Web provider">Contributing a new Web provider</a>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<a href="getting-started.html" class="sidebar-item" name="" title="Getting started">Getting started</a>
|
||||
|
@ -1594,6 +1594,18 @@
|
||||
"is_incremental": false,
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "Conceptual",
|
||||
"source_relative_path": "guides/contributing-a-new-web-provider.md",
|
||||
"output": {
|
||||
".html": {
|
||||
"relative_path": "guides/contributing-a-new-web-provider.html",
|
||||
"hash": "dssOySLr9rHvHRUmI0sn8w=="
|
||||
}
|
||||
},
|
||||
"is_incremental": false,
|
||||
"version": ""
|
||||
},
|
||||
{
|
||||
"type": "Conceptual",
|
||||
"source_relative_path": "guides/getting-started.md",
|
||||
@ -1636,7 +1648,7 @@
|
||||
"output": {
|
||||
".html": {
|
||||
"relative_path": "guides/toc.html",
|
||||
"hash": "Q2Rq3xUOIstDdNnNV/CmBA=="
|
||||
"hash": "graDxHuH3xaTHg5/QHY/zQ=="
|
||||
}
|
||||
},
|
||||
"is_incremental": false,
|
||||
@ -2445,7 +2457,7 @@
|
||||
"ConceptualDocumentProcessor": {
|
||||
"can_incremental": false,
|
||||
"incrementalPhase": "build",
|
||||
"total_file_count": 135,
|
||||
"total_file_count": 136,
|
||||
"skipped_file_count": 0
|
||||
},
|
||||
"ResourceDocumentProcessor": {
|
||||
|
Loading…
Reference in New Issue
Block a user