Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ dotnet_naming_style.end_in_async.capitalization = pascal_case
generated_code = true
dotnet_analyzer_diagnostic.severity = none

[src/GoAffPro.Client.Generated/Generated/**/*.cs]
generated_code = true
dotnet_analyzer_diagnostic.severity = none
dotnet_diagnostic.CS1591.severity = none
dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA1716.severity = none

[*.json]
indent_size = 2

Expand Down
8 changes: 2 additions & 6 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ packages/
openapi/goaffpro.openapi.json
openapi/goaffpro-user.openapi.json
openapi/goaffpro-public.openapi.json
openapi/swagger-ui-init.js
obj/GoAffPro.Client.Generator.hash

# Generated code (tracked, but can be regenerated)
# Uncomment to gitignore if you prefer not to commit generated code:
# src/GoAffPro.Client/Generated/*.g.cs

# Test results
TestResults/
Expand All @@ -36,8 +30,10 @@ Thumbs.db

# Local development overrides
examples/GoAffPro.Client.Example/appsettings.development.json
tests/GoAffPro.Client.IntegrationTests/appsettings.Test.local.json

# Local LLM/notes docs (not published to GitHub)
AGENTS.md
ARCHITECTURE.md
docs/
.tools/
14 changes: 8 additions & 6 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
<PackageVersion Include="MinVer" Version="6.0.0" />
<PackageVersion Include="Polly" Version="8.4.2" />
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
</ItemGroup>
<ItemGroup Label="Code generation">
<PackageVersion Include="Microsoft.Build.Framework" Version="18.3.3" />
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="18.3.3" />
<PackageVersion Include="NSwag.Core" Version="14.1.0" />
<PackageVersion Include="NSwag.Core.Yaml" Version="14.1.0" />
<PackageVersion Include="NSwag.CodeGeneration.CSharp" Version="14.1.0" />
<ItemGroup Label="Code generation and Kiota runtime">
<PackageVersion Include="Microsoft.Kiota.Abstractions" Version="1.21.2" />
<PackageVersion Include="Microsoft.Kiota.Http.HttpClientLibrary" Version="1.21.2" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Form" Version="1.21.2" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Json" Version="1.21.2" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Multipart" Version="1.21.2" />
<PackageVersion Include="Microsoft.Kiota.Serialization.Text" Version="1.21.2" />
</ItemGroup>
<ItemGroup Label="Testing">
<PackageVersion Include="xunit" Version="2.9.3" />
Expand Down
2 changes: 1 addition & 1 deletion GoAffPro.Client.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
<File Path="NuGet.config" />
</Folder>
<Folder Name="/src/">
<Project Path="src/GoAffPro.Client.Generated/GoAffPro.Client.Generated.csproj" />
<Project Path="src/GoAffPro.Client/GoAffPro.Client.csproj" />
<Project Path="src/GoAffPro.Client.Generator/GoAffPro.Client.Generator.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/GoAffPro.Client.IntegrationTests/GoAffPro.Client.IntegrationTests.csproj" />
Expand Down
63 changes: 20 additions & 43 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# GoAffPro.Client

Async-first .NET client for the GoAffPro API with build-time NSwag generation and polling/event-based change detection.
Async-first .NET client for the GoAffPro API with build-time Kiota generation and polling/event-based change detection.

## Targets

Expand Down Expand Up @@ -30,54 +30,34 @@ await using var loggedInClient = await GoAffProClient.CreateLoggedInAsync(
password: "password123");
```

### Wrapper Methods (DX Layer)
### Wrapper Surface

The wrapper methods are built on top of generated clients:
`GoAffProClient` intentionally keeps a minimal wrapper surface:

```csharp
// Fetch orders with optional time filtering
var orders = await client.GetOrdersAsync(from: DateTimeOffset.UtcNow.AddDays(-1), limit: 50);

// Fetch affiliates with time range
var affiliates = await client.GetAffiliatesAsync(from: startDate, toDate: endDate, limit: 50);

// Fetch payouts and products
var payouts = await client.GetPayoutsAsync(limit: 50);
var products = await client.GetProductsAsync(limit: 50);
```

Wrapper methods return typed models:

- `GoAffProOrder` (includes Subtotal, AffiliateId, Status)
- `GoAffProAffiliate` (includes FirstName, LastName, Phone, Country, GroupId)
- `GoAffProReward` (includes AffiliateId, Type, Metadata, Level, Status) - currently disabled
- `GoAffProPayout`
- `GoAffProProduct`

Each model includes strongly typed fields and `RawPayload` (`JsonElement`) for advanced scenarios.

`GetRewardsAsync` is currently disabled because `/user/feed/rewards` is returning `404` (observed on 2026-02-18). The method is marked `[Obsolete]` and returns an empty collection.
- auth helpers: `LoginAsync`, `SetBearerToken`
- generated client access: `User` and `PublicApi`
- polling detector: `GoAffProEventDetector`

### Access Generated Clients Directly

```csharp
var loginResponse = await client.User.UserLoginAsync(new GoAffPro.Client.Generated.User.Body
var loginResponse = await client.User.User.Login.PostAsync(new GoAffPro.Client.Generated.User.User.Login.LoginPostRequestBody
{
Email = "affiliate@example.com",
Password = "password123",
});

var publicSites = await client.PublicApi.PublicSitesAsync(
site_ids: null,
currency: null,
keyword: null,
limit: 20,
offset: 0);
var publicSites = await client.PublicApi.Public.Sites.GetAsync(config =>
{
config.QueryParameters.Limit = 20;
config.QueryParameters.Offset = 0;
});
```

## Event Detection

`GoAffProEventDetector` supports both async streams and classic `.NET` events. It uses time-based filtering to fetch only new items since the last poll.
Detected payloads are propagated as generated Kiota feed item types.

### Async Streams

Expand Down Expand Up @@ -135,18 +115,15 @@ dotnet run --project examples/GoAffPro.Client.Example

## Build-Time Generation

On build, `GoAffPro.Client.Generator`:
On build, `GoAffPro.Client.Generated`:

1. Fetches `https://api.goaffpro.com/docs/admin/swagger-ui-init.js`
(or uses `openapi/swagger-ui-init.js` only if you provide a local override file)
2. Extracts OpenAPI JSON
3. Filters to `/user/*` and `/public/*`
4. Normalizes schema gaps for generation
5. Generates:
- `src/GoAffPro.Client/Generated/GoAffProUserClient.g.cs`
- `src/GoAffPro.Client/Generated/GoAffProPublicClient.g.cs`
1. Loads the local canonical spec `openapi/goaffpro-canonical.yaml`
2. Runs Kiota generation for `/user/*` and `/public/*`
3. Writes generated files under:
- `src/GoAffPro.Client.Generated/Generated/User`
- `src/GoAffPro.Client.Generated/Generated/Public`

Do not edit `*.g.cs` manually.
Generated output is implementation detail for the wrapper package. Do not manually edit files under `Generated/`.

## Testing

Expand Down
13 changes: 13 additions & 0 deletions dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"microsoft.openapi.kiota": {
"version": "1.30.0",
"commands": [
"kiota"
],
"rollForward": false
}
}
}
16 changes: 0 additions & 16 deletions examples/GoAffPro.Client.Example/ExampleOptions.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
<PackageReference Include="Spectre.Console" />
</ItemGroup>

</Project>
Loading