Prepared by Northwind Consulting — internal use only.
++ Confidential. This document and its contents are the property of Northwind Consulting. +
diff --git a/extensions/aayushmishraaa/superdocs-dotnet/src/SuperDocs.Client/ISuperDocsClient.cs b/extensions/aayushmishraaa/superdocs-dotnet/src/SuperDocs.Client/ISuperDocsClient.cs new file mode 100644 index 0000000..b181fc3 --- /dev/null +++ b/extensions/aayushmishraaa/superdocs-dotnet/src/SuperDocs.Client/ISuperDocsClient.cs @@ -0,0 +1,168 @@ +namespace SuperDocs.Client; + +///JSON.parse(JSON.parse(event.data).content)
+/// The polling path (
+ /// builder.Services.AddSuperDocs(builder.Configuration);
+ ///
+ ///
+ /// builder.Services.AddSuperDocs(builder.Configuration)
+ /// .AddStandardResilienceHandler();
+ ///
+ ///
+ /// builder.Services.AddSuperDocs(o => o.ApiKey = Environment.GetEnvironmentVariable("SUPERDOCS_API_KEY")!);
+ ///
+ /// net 30
","new_html":"net 45
"}]}"""; + + // As it arrives on the wire: a JSON string literal whose VALUE is JSON. + string wire = System.Text.Json.JsonSerializer.Serialize(encoded); + + IReadOnlyListnet 45
", change.NewHtml); + } + + [Fact] + public void PlainObjectContent_IsAlsoAccepted() + { + // The same payload NOT double-encoded. Must work identically, so a server-side fix + // to emit real objects does not break every consumer of this SDK. + const string plain = + """{"type":"batch","changes":[{"change_id":"c1","operation":"edit","new_html":"x
"}]}"""; + + ProposedChange change = Assert.Single(ProposedChangeBatch.ParseContent(plain)); + Assert.Equal("c1", change.ChangeId); + } + + [Fact] + public void BareArray_IsAccepted() + { + const string array = """[{"change_id":"c1","operation":"delete","old_html":"x
"}]"""; + ProposedChange change = Assert.Single(ProposedChangeBatch.ParseContent(array)); + Assert.Equal(ChangeOperation.Delete, change.Operation); + } + + [Fact] + public void SingleUnwrappedChange_IsAccepted() + { + const string single = """{"change_id":"c9","operation":"create","new_html":"new
"}"""; + ProposedChange change = Assert.Single(ProposedChangeBatch.ParseContent(single)); + Assert.Equal("c9", change.ChangeId); + Assert.Equal(ChangeOperation.Create, change.Operation); + } + + [Theory] + [InlineData(null)] + [InlineData("")] + [InlineData(" ")] + [InlineData("not json at all")] + [InlineData("{\"unexpected\":\"shape\"}")] + public void UnparseableContent_YieldsEmptyRatherThanThrowing(string? content) + { + // A malformed progress frame must not abort a review in flight. The authoritative + // list is always Job.Metadata.PendingChanges. + Assert.Empty(ProposedChangeBatch.ParseContent(content)); + } + + [Fact] + public void PendingChanges_AreNotDoubleParsed() + { + // The bug in the other direction, and the one the documentation actively encourages: + // applying the second parse to the polling path, which returns real objects. + Job job = System.Text.Json.JsonSerializer.DeserializePayment terms are net 45 days from invoice date.
", change.NewHtml); + Assert.Equal(ChangeOperation.Edit, change.Operation); + } + + [Fact] + public void BothPathsAgreeOnTheSameChange() + { + // The property that actually matters to a consumer: it should not be possible to + // tell which path a change arrived on. + Job job = System.Text.Json.JsonSerializer.DeserializePayment terms are net 30 days from invoice date.
", + "new_html": "Payment terms are net 45 days from invoice date.
", + "ai_explanation": "I have updated the payment terms from net 30 to net 45 days." + } + ], + "intermediate_responses": [ + { + "type": "proposed_change_batch", + "sequence": 4, + "content": "{\"type\": \"single_approval\", \"batch_id\": \"97ca364e\", \"batch_total\": 1, \"changes\": [{\"change_id\": \"97ca364e-8ebb-4d19-8cac-ae8812663caf\", \"operation\": \"edit\", \"old_html\": \"Payment terms are net 30 days from invoice date.
\", \"new_html\": \"Payment terms are net 45 days from invoice date.
\"}]}" + } + ] + } + } + """; + + public const string Completed = """ + {"job_id":"j1","session_id":"s1","status":"completed","progress":100,"metadata":{}} + """; + + public const string ApprovalOk = """ + {"status":"ok","message":"Approval processed","batch_complete":true} + """; + + public const string JobCreated = """ + {"job_id":"j1","session_id":"s1","status":"pending","message":"queued"} + """; + + public const string Whoami = """ + {"account_id":"a1","tier":"free","quota":{"monthly_limit":500,"used":12,"remaining":488}} + """; +} diff --git a/extensions/aayushmishraaa/superdocs-dotnet/tests/SuperDocs.Client.Tests/SuperDocs.Client.Tests.csproj b/extensions/aayushmishraaa/superdocs-dotnet/tests/SuperDocs.Client.Tests/SuperDocs.Client.Tests.csproj new file mode 100644 index 0000000..2cb39b5 --- /dev/null +++ b/extensions/aayushmishraaa/superdocs-dotnet/tests/SuperDocs.Client.Tests/SuperDocs.Client.Tests.csproj @@ -0,0 +1,40 @@ +