diff --git a/packages/poptart/CHANGELOG.md b/packages/poptart/CHANGELOG.md index 213fa1f9b..0883c747a 100644 --- a/packages/poptart/CHANGELOG.md +++ b/packages/poptart/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Note +## v0.1.2 + +- Require `poptart_xrpc` 0.1.1 for concrete binary request content types. + ## v0.1.1 - Bump `poptart_core` and `poptart_oauth` for opaque OAuth token restore support. diff --git a/packages/poptart/pubspec.yaml b/packages/poptart/pubspec.yaml index 0da1b25d9..ed052ea72 100644 --- a/packages/poptart/pubspec.yaml +++ b/packages/poptart/pubspec.yaml @@ -1,6 +1,6 @@ name: poptart resolution: workspace -version: 0.1.1 +version: 0.1.2 description: Friendly Dart and Flutter SDK entrypoint for AT Protocol sessions, OAuth, XRPC, and core Poptart primitives. homepage: https://poptart.xyz documentation: https://poptart.xyz @@ -14,7 +14,7 @@ dependencies: poptart_core: ^0.1.1 poptart_oauth: ^0.1.1 poptart_primitives: ^0.1.0 - poptart_xrpc: ^0.1.0 + poptart_xrpc: ^0.1.1 topics: - atproto diff --git a/packages/poptart_xrpc/CHANGELOG.md b/packages/poptart_xrpc/CHANGELOG.md index dc98a0e80..88e004a99 100644 --- a/packages/poptart_xrpc/CHANGELOG.md +++ b/packages/poptart_xrpc/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Note +## v0.1.1 + +- Ensure wildcard binary input encodings use a concrete request content type. + ## v0.1.0 - Initial Poptart fork release under the new `poptart_*` package name. diff --git a/packages/poptart_xrpc/lib/src/xrpc/xrpc.dart b/packages/poptart_xrpc/lib/src/xrpc/xrpc.dart index cafa26bc7..4325f85ca 100644 --- a/packages/poptart_xrpc/lib/src/xrpc/xrpc.dart +++ b/packages/poptart_xrpc/lib/src/xrpc/xrpc.dart @@ -486,10 +486,11 @@ Map _appendContentType( final String? contentType, ) { if (body is Uint8List) { - return { - 'Content-type': - contentType ?? lookupMimeType('', headerBytes: body) ?? '*/*', - }..addAll(headers ?? {}); + final resolvedContentType = contentType == null || contentType.contains('*') + ? lookupMimeType('', headerBytes: body) ?? 'application/octet-stream' + : contentType; + + return {'Content-type': resolvedContentType}..addAll(headers ?? {}); } return {'Content-type': contentType ?? 'application/json'} diff --git a/packages/poptart_xrpc/pubspec.yaml b/packages/poptart_xrpc/pubspec.yaml index fe72fec2f..df48c6347 100644 --- a/packages/poptart_xrpc/pubspec.yaml +++ b/packages/poptart_xrpc/pubspec.yaml @@ -1,7 +1,7 @@ name: poptart_xrpc resolution: workspace description: Core library for XRPC communication. This is a wrapped HTTP client for AT Protocol. -version: 0.1.0 +version: 0.1.1 homepage: https://poptart.xyz documentation: https://poptart.xyz repository: https://github.com/sprksocial/poptart diff --git a/packages/poptart_xrpc/test/src/xrpc/xrpc_descriptor_test.dart b/packages/poptart_xrpc/test/src/xrpc/xrpc_descriptor_test.dart index c0cab9bfd..9b33bf729 100644 --- a/packages/poptart_xrpc/test/src/xrpc/xrpc_descriptor_test.dart +++ b/packages/poptart_xrpc/test/src/xrpc/xrpc_descriptor_test.dart @@ -138,6 +138,67 @@ void main() { expect(response.data, const _ExampleObject(name: 'alice')); }); + test( + 'procedure call resolves wildcard input encoding from bytes', + () async { + final descriptor = + XRPCMethodDescriptor( + nsid: NSID.parse('com.example.uploadBlob'), + kind: XRPCMethodKind.procedure, + inputEncoding: '*/*', + outputFromJson: _ExampleObject.fromJson, + ); + final bytes = Uint8List.fromList([0xff, 0xd8, 0xff, 0xe0]); + + final response = await call( + descriptor, + input: bytes, + postClient: (url, {body, encoding, headers}) async { + expect(body, bytes); + expect(headers, containsPair('Content-type', 'image/jpeg')); + + return Response( + r'{"$type":"com.example.lexicon","name":"alice"}', + 200, + request: Request('POST', url), + ); + }, + ); + + expect(response.data, const _ExampleObject(name: 'alice')); + }, + ); + + test('procedure call falls back for unknown wildcard bytes', () async { + final descriptor = XRPCMethodDescriptor( + nsid: NSID.parse('com.example.uploadBlob'), + kind: XRPCMethodKind.procedure, + inputEncoding: '*/*', + outputFromJson: _ExampleObject.fromJson, + ); + final bytes = Uint8List.fromList([1, 2, 3]); + + final response = await call( + descriptor, + input: bytes, + postClient: (url, {body, encoding, headers}) async { + expect(body, bytes); + expect( + headers, + containsPair('Content-type', 'application/octet-stream'), + ); + + return Response( + r'{"$type":"com.example.lexicon","name":"alice"}', + 200, + request: Request('POST', url), + ); + }, + ); + + expect(response.data, const _ExampleObject(name: 'alice')); + }); + test('query call preserves descriptor bytes output', () async { final descriptor = XRPCMethodDescriptor<_ExampleParams, void, Uint8List>( nsid: NSID.parse('com.example.getBlob'),