@arrirpc/codegen-kotlin 0.60.3 → 0.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ export default defineConfig({
24
24
  | --------------------- | ------------------------------------------------------------- |
25
25
  | clientName | The name of the generated client class (Defaults to "Client") |
26
26
  | outputFile (required) | Path to the file that will be created by the generator |
27
- | modelPrefix | Add a prefix to the generated class names |
27
+ | typePrefix | Add a prefix to the generated class names |
28
28
 
29
29
  ### 2) Install dependencies
30
30
 
@@ -72,6 +72,77 @@ val service = MyClientUsersService(
72
72
  )
73
73
  ```
74
74
 
75
+ ### Calling Procedures
76
+
77
+ #### Standard HTTP Procedures
78
+
79
+ ```kotlin
80
+ runBlocking {
81
+ // procedure with no parameters
82
+ val getUsersResponse = myClient.users.getUsers()
83
+
84
+ // procedure with parameters
85
+ val getUserResponse = myClient.users.getUser(GetUserParams(userId = "12345"))
86
+ }
87
+ ```
88
+
89
+ #### Event Stream Procedures
90
+
91
+ ##### Basic Usage
92
+
93
+ ```kotlin
94
+ runBlocking {
95
+ myClient.users.watchUserChanges(
96
+ onData { message ->
97
+ println("New message: ${message}")
98
+ },
99
+ onOpen {
100
+ println("Connection established")
101
+ }
102
+ onRequestError { err ->
103
+ println("Error connecting to server: ${err}")
104
+ },
105
+ onResponseError { err ->
106
+ println("Server returned an error: ${err.code} ${err.message}")
107
+ },
108
+ onClose {
109
+ println("Connection closed")
110
+ }
111
+ )
112
+ }
113
+ ```
114
+
115
+ ##### Cancelling Requests
116
+
117
+ Event stream procedures can be cancelled from inside one of the hooks by throwing a `CancellationException`
118
+
119
+ ```kotlin
120
+ runBlocking {
121
+ myClient.users.watchUserChanges(
122
+ onResponseError { err ->
123
+ println("Server returned an error: ${err.code} ${err.message}")
124
+ throw CancellationException()
125
+ }
126
+ )
127
+ }
128
+ ```
129
+
130
+ You can also spawn a job and cancel that job in order to cancel the Event stream procedure from the outside
131
+
132
+ ```kotlin
133
+ val job = someCoroutineScope.launch {
134
+ myClient.users.watchUserChanges()
135
+ }
136
+ job.cancel()
137
+ ```
138
+
139
+ ##### Other Options
140
+
141
+ | Option | Type | Description |
142
+ | -------------- | ----- | ------------------------------------------------------------------------------------------------------- |
143
+ | bufferCapacity | Int | Max buffer size that can be allocated towards reading messages received. Default is 1024 \* 1024 (1MB). |
144
+ | maxBackoffTime | Long? | Max wait time between retries in milliseconds. Default is 30000ms |
145
+
75
146
  ### Using Arri Models
76
147
 
77
148
  All generated models will be data classes. They will have access to the following features:
package/dist/index.cjs CHANGED
@@ -65,7 +65,7 @@ function getClassName(schema, context) {
65
65
  normalize: true
66
66
  })
67
67
  );
68
- return `${context.modelPrefix}${className2}`;
68
+ return `${context.typePrefix}${className2}`;
69
69
  }
70
70
  const depth = instanceDepth(context);
71
71
  if (depth === 1 && !context.discriminatorKey) {
@@ -74,7 +74,7 @@ function getClassName(schema, context) {
74
74
  normalize: true
75
75
  })
76
76
  );
77
- return `${context.modelPrefix}${className2}`;
77
+ return `${context.typePrefix}${className2}`;
78
78
  }
79
79
  if (context.discriminatorParentId && context.discriminatorKey && context.discriminatorValue) {
80
80
  const className2 = kotlinClassName(
@@ -83,7 +83,7 @@ function getClassName(schema, context) {
83
83
  { normalize: true }
84
84
  )
85
85
  );
86
- return `${context.modelPrefix}${className2}`;
86
+ return `${context.typePrefix}${className2}`;
87
87
  }
88
88
  const className = kotlinClassName(
89
89
  codegenUtils.pascalCase(
@@ -93,7 +93,7 @@ function getClassName(schema, context) {
93
93
  }
94
94
  )
95
95
  );
96
- return `${context.modelPrefix}${className}`;
96
+ return `${context.typePrefix}${className}`;
97
97
  }
98
98
  function instanceDepth(context) {
99
99
  const parts = context.instancePath.split("/");
@@ -172,7 +172,7 @@ function kotlinArrayFromSchema(schema, context) {
172
172
  const nullable = isNullable(schema, context);
173
173
  const defaultValue = nullable ? "null" : "mutableListOf()";
174
174
  const subType = kotlinTypeFromSchema(schema.elements, {
175
- modelPrefix: context.modelPrefix,
175
+ typePrefix: context.typePrefix,
176
176
  clientName: context.clientName,
177
177
  clientVersion: context.clientVersion,
178
178
  instancePath: `${context.instancePath}/[Element]`,
@@ -313,7 +313,7 @@ function kotlinObjectFromSchema(schema, context) {
313
313
  kotlinKeys.push(kotlinKey);
314
314
  const prop = schema.properties[key];
315
315
  const type = kotlinTypeFromSchema(prop, {
316
- modelPrefix: context.modelPrefix,
316
+ typePrefix: context.typePrefix,
317
317
  clientName: context.clientName,
318
318
  clientVersion: context.clientVersion,
319
319
  instancePath: `/${className}/${key}`,
@@ -347,7 +347,7 @@ function kotlinObjectFromSchema(schema, context) {
347
347
  const kotlinKey = kotlinIdentifier(key);
348
348
  kotlinKeys.push(kotlinKey);
349
349
  const type = kotlinTypeFromSchema(schema.optionalProperties[key], {
350
- modelPrefix: context.modelPrefix,
350
+ typePrefix: context.typePrefix,
351
351
  clientName: context.clientName,
352
352
  clientVersion: context.clientVersion,
353
353
  instancePath: `/${className}/${key}`,
@@ -446,7 +446,7 @@ function kotlinDiscriminatorFromSchema(schema, context) {
446
446
  for (const key of Object.keys(schema.mapping)) {
447
447
  const subSchema = schema.mapping[key];
448
448
  const subType = kotlinObjectFromSchema(subSchema, {
449
- modelPrefix: context.modelPrefix,
449
+ typePrefix: context.typePrefix,
450
450
  clientName: context.clientName,
451
451
  clientVersion: context.clientVersion,
452
452
  instancePath: context.instancePath,
@@ -634,7 +634,7 @@ function kotlinEnumFromSchema(schema, context) {
634
634
  function kotlinMapFromSchema(schema, context) {
635
635
  const nullable = isNullable(schema, context);
636
636
  const subType = kotlinTypeFromSchema(schema.values, {
637
- modelPrefix: context.modelPrefix,
637
+ typePrefix: context.typePrefix,
638
638
  clientName: context.clientName,
639
639
  clientVersion: context.clientVersion,
640
640
  instancePath: `${context.instancePath}/[value]`,
@@ -1129,8 +1129,8 @@ function kotlinProcedureFromSchema(schema, context) {
1129
1129
  }
1130
1130
  function kotlinHttpRpcFromSchema(schema, context) {
1131
1131
  const name = getProcedureName(context);
1132
- const params = schema.params ? kotlinClassName(`${context.modelPrefix}_${schema.params}`) : void 0;
1133
- const response = schema.response ? kotlinClassName(`${context.modelPrefix}_${schema.response}`) : void 0;
1132
+ const params = schema.params ? kotlinClassName(`${context.typePrefix}_${schema.params}`) : void 0;
1133
+ const response = schema.response ? kotlinClassName(`${context.typePrefix}_${schema.response}`) : void 0;
1134
1134
  const codeComment = getCodeComment(
1135
1135
  {
1136
1136
  description: schema.description,
@@ -1140,40 +1140,36 @@ function kotlinHttpRpcFromSchema(schema, context) {
1140
1140
  "method"
1141
1141
  );
1142
1142
  if (schema.isEventStream) {
1143
- return `${codeComment}fun ${name}(
1144
- scope: CoroutineScope,
1143
+ return `${codeComment}suspend fun ${name}(
1145
1144
  ${params ? `params: ${params},` : ""}
1146
1145
  lastEventId: String? = null,
1147
- bufferCapacity: Int = 1024,
1146
+ bufferCapacity: Int = 1024 * 1024,
1148
1147
  onOpen: ((response: HttpResponse) -> Unit) = {},
1149
1148
  onClose: (() -> Unit) = {},
1150
- onError: ((error: ${context.clientName}Error) -> Unit) = {},
1151
- onConnectionError: ((error: ${context.clientName}Error) -> Unit) = {},
1149
+ onRequestError: ((error: Exception) -> Unit) = {},
1150
+ onResponseError: ((error: ${context.clientName}Error) -> Unit) = {},
1152
1151
  onData: ((${response ? `data: ${response}` : ""}) -> Unit) = {},
1153
- ): Job {
1154
- val job = scope.launch {
1155
- __handleSseRequest(
1156
- scope = scope,
1157
- httpClient = httpClient,
1158
- url = "$baseUrl${schema.path}",
1159
- method = HttpMethod.${codegenUtils.pascalCase(schema.method, { normalize: true })},
1160
- params = ${params ? "params" : "null"},
1161
- headers = headers,
1162
- backoffTime = 0,
1163
- maxBackoffTime = 30000L,
1164
- lastEventId = lastEventId,
1165
- bufferCapacity = bufferCapacity,
1166
- onOpen = onOpen,
1167
- onClose = onClose,
1168
- onError = onError,
1169
- onConnectionError = onConnectionError,
1170
- onData = { str ->
1171
- ${response ? `val data = ${response}.fromJson(str)` : ""}
1172
- onData(${response ? "data" : ""})
1173
- }
1174
- )
1175
- }
1176
- return job
1152
+ maxBackoffTime: Long? = null,
1153
+ ): Unit {
1154
+ __handleSseRequest(
1155
+ httpClient = httpClient,
1156
+ url = "$baseUrl${schema.path}",
1157
+ method = HttpMethod.${codegenUtils.pascalCase(schema.method, { normalize: true })},
1158
+ params = ${params ? "params" : "null"},
1159
+ headers = headers,
1160
+ backoffTime = 0,
1161
+ maxBackoffTime = maxBackoffTime ?: 30000L,
1162
+ lastEventId = lastEventId,
1163
+ bufferCapacity = bufferCapacity,
1164
+ onOpen = onOpen,
1165
+ onClose = onClose,
1166
+ onRequestError = onRequestError,
1167
+ onResponseError = onResponseError,
1168
+ onData = { str ->
1169
+ ${response ? `val data = ${response}.fromJson(str)` : ""}
1170
+ onData(${response ? "data" : ""})
1171
+ }
1172
+ )
1177
1173
  }`;
1178
1174
  }
1179
1175
  const headingCheck = `if (response.headers["Content-Type"] != "application/json") {
@@ -1301,7 +1297,7 @@ const kotlinClientGenerator = codegenUtils.defineGeneratorPlugin(
1301
1297
  function kotlinClientFromAppDefinition(def, options) {
1302
1298
  const clientName = kotlinClassName(options.clientName ?? "Client");
1303
1299
  const context = {
1304
- modelPrefix: options.modelPrefix ?? "",
1300
+ typePrefix: options.typePrefix ?? "",
1305
1301
  clientName,
1306
1302
  clientVersion: def.info?.version ?? "",
1307
1303
  instancePath: "",
@@ -1312,7 +1308,7 @@ function kotlinClientFromAppDefinition(def, options) {
1312
1308
  for (const key of Object.keys(def.definitions)) {
1313
1309
  const subSchema = def.definitions[key];
1314
1310
  const model = kotlinTypeFromSchema(subSchema, {
1315
- modelPrefix: context.modelPrefix,
1311
+ typePrefix: context.typePrefix,
1316
1312
  clientName: context.clientName,
1317
1313
  clientVersion: context.clientVersion,
1318
1314
  instancePath: `/${key}`,
@@ -1644,62 +1640,89 @@ private suspend fun __prepareRequest(
1644
1640
  return client.prepareRequest(builder)
1645
1641
  }
1646
1642
 
1647
- private fun __parseSseEvent(input: String): __SseEvent {
1648
- val lines = input.split("\\n")
1649
- var id: String? = null
1650
- var event: String? = null
1651
- var data: String = ""
1652
- for (line in lines) {
1653
- if (line.startsWith("id: ")) {
1654
- id = line.substring(3).trim()
1655
- continue
1656
- }
1657
- if (line.startsWith("event: ")) {
1658
- event = line.substring(6).trim()
1659
- continue
1660
- }
1661
- if (line.startsWith("data: ")) {
1662
- data = line.substring(5).trim()
1663
- continue
1664
- }
1643
+ // SSE_FN_START
1644
+ private enum class SseEventLineType {
1645
+ Id,
1646
+ Event,
1647
+ Data,
1648
+ Retry,
1649
+ None,
1650
+ }
1651
+
1652
+ private fun __parseSseEventLine(line: String): Pair<SseEventLineType, String> {
1653
+ if (line.startsWith("id:")) {
1654
+ return Pair(SseEventLineType.Id, line.substring(3).trim())
1655
+ }
1656
+ if (line.startsWith("event:")) {
1657
+ return Pair(SseEventLineType.Event, line.substring(6).trim())
1658
+ }
1659
+ if (line.startsWith("data:")) {
1660
+ return Pair(SseEventLineType.Data, line.substring(5).trim())
1661
+ }
1662
+ if (line.startsWith("retry:")) {
1663
+ return Pair(SseEventLineType.Retry, line.substring(6).trim())
1665
1664
  }
1666
- return __SseEvent(id, event, data)
1665
+ return Pair(SseEventLineType.None, "")
1667
1666
  }
1668
1667
 
1669
- private class __SseEvent(val id: String? = null, val event: String? = null, val data: String)
1668
+ private data class __SseEvent(
1669
+ val id: String? = null,
1670
+ val event: String,
1671
+ val data: String,
1672
+ val retry: Int? = null
1673
+ )
1670
1674
 
1671
1675
  private class __SseEventParsingResult(val events: List<__SseEvent>, val leftover: String)
1672
1676
 
1673
1677
  private fun __parseSseEvents(input: String): __SseEventParsingResult {
1674
- val inputs = input.split("\\n\\n").toMutableList()
1675
- if (inputs.isEmpty()) {
1676
- return __SseEventParsingResult(
1677
- events = listOf(),
1678
- leftover = "",
1679
- )
1680
- }
1681
- if (inputs.size == 1) {
1682
- return __SseEventParsingResult(
1683
- events = listOf(),
1684
- leftover = inputs.last(),
1685
- )
1686
- }
1687
- val leftover = inputs.last()
1688
- inputs.removeLast()
1689
1678
  val events = mutableListOf<__SseEvent>()
1690
- for (item in inputs) {
1691
- if (item.contains("data: ")) {
1692
- events.add(__parseSseEvent(item))
1679
+ val lines = input.lines()
1680
+ if (lines.isEmpty()) {
1681
+ return __SseEventParsingResult(events = listOf(), leftover = "")
1682
+ }
1683
+ var id: String? = null
1684
+ var event: String? = null
1685
+ var data: String? = null
1686
+ var retry: Int? = null
1687
+ var lastIndex: Int? = 0
1688
+ lines.forEachIndexed { index, line ->
1689
+ if (line.isNotEmpty()) {
1690
+ val (type, value) = __parseSseEventLine(line)
1691
+ when (type) {
1692
+ SseEventLineType.Id -> id = value
1693
+ SseEventLineType.Event -> event = value
1694
+ SseEventLineType.Data -> data = value
1695
+ SseEventLineType.Retry -> retry = value.toInt()
1696
+ SseEventLineType.None -> {}
1697
+ }
1698
+ }
1699
+ val isEnd = line == ""
1700
+ if (isEnd) {
1701
+ if (data != null) {
1702
+ events.add(
1703
+ __SseEvent(
1704
+ id = id,
1705
+ event = event ?: "message",
1706
+ data = data!!,
1707
+ retry = retry,
1708
+ )
1709
+ )
1710
+ }
1711
+ id = null
1712
+ event = null
1713
+ data = null
1714
+ retry = null
1715
+ lastIndex = if (index + 1 < lines.size) index + 1 else null
1693
1716
  }
1694
1717
  }
1695
1718
  return __SseEventParsingResult(
1696
1719
  events = events,
1697
- leftover = leftover,
1720
+ leftover = if (lastIndex != null) lines.subList(lastIndex!!, lines.size).joinToString(separator = "\\n") else ""
1698
1721
  )
1699
1722
  }
1723
+ // SSE_FN_END
1700
1724
 
1701
1725
  private suspend fun __handleSseRequest(
1702
- scope: CoroutineScope,
1703
1726
  httpClient: HttpClient,
1704
1727
  url: String,
1705
1728
  method: HttpMethod,
@@ -1710,16 +1733,16 @@ private suspend fun __handleSseRequest(
1710
1733
  lastEventId: String?,
1711
1734
  onOpen: ((response: HttpResponse) -> Unit) = {},
1712
1735
  onClose: (() -> Unit) = {},
1713
- onError: ((error: ${clientName}Error) -> Unit) = {},
1714
1736
  onData: ((data: String) -> Unit) = {},
1715
- onConnectionError: ((error: ${clientName}Error) -> Unit) = {},
1737
+ onRequestError: ((error: Exception) -> Unit) = {},
1738
+ onResponseError: ((error: ${clientName}Error) -> Unit) = {},
1716
1739
  bufferCapacity: Int,
1717
1740
  ) {
1718
1741
  val finalHeaders = headers?.invoke() ?: mutableMapOf()
1719
1742
  var lastId = lastEventId
1720
1743
  // exponential backoff maxing out at 32 seconds
1721
1744
  if (backoffTime > 0) {
1722
- withContext(scope.coroutineContext) {
1745
+ withContext(currentCoroutineContext()) {
1723
1746
  Thread.sleep(backoffTime)
1724
1747
  }
1725
1748
  }
@@ -1741,16 +1764,17 @@ private suspend fun __handleSseRequest(
1741
1764
  onOpen(httpResponse)
1742
1765
  } catch (e: CancellationException) {
1743
1766
  onClose()
1767
+ httpResponse.cancel()
1744
1768
  return@execute
1745
1769
  }
1746
1770
  if (httpResponse.status.value !in 200..299) {
1747
1771
  try {
1748
1772
  if (httpResponse.headers["Content-Type"] == "application/json") {
1749
- onConnectionError(
1773
+ onResponseError(
1750
1774
  ${clientName}Error.fromJson(httpResponse.bodyAsText())
1751
1775
  )
1752
1776
  } else {
1753
- onConnectionError(
1777
+ onResponseError(
1754
1778
  ${clientName}Error(
1755
1779
  code = httpResponse.status.value,
1756
1780
  errorMessage = httpResponse.status.description,
@@ -1761,10 +1785,10 @@ private suspend fun __handleSseRequest(
1761
1785
  }
1762
1786
  } catch (e: CancellationException) {
1763
1787
  onClose()
1788
+ httpResponse.cancel()
1764
1789
  return@execute
1765
1790
  }
1766
- __handleSseRequest(
1767
- scope = scope,
1791
+ return@execute __handleSseRequest(
1768
1792
  httpClient = httpClient,
1769
1793
  url = url,
1770
1794
  method = method,
@@ -1776,15 +1800,13 @@ private suspend fun __handleSseRequest(
1776
1800
  bufferCapacity = bufferCapacity,
1777
1801
  onOpen = onOpen,
1778
1802
  onClose = onClose,
1779
- onError = onError,
1780
1803
  onData = onData,
1781
- onConnectionError = onConnectionError,
1804
+ onResponseError = onResponseError,
1782
1805
  )
1783
- return@execute
1784
1806
  }
1785
1807
  if (httpResponse.headers["Content-Type"] != "text/event-stream") {
1786
1808
  try {
1787
- onConnectionError(
1809
+ onResponseError(
1788
1810
  ${clientName}Error(
1789
1811
  code = 0,
1790
1812
  errorMessage = "Expected server to return Content-Type \\"text/event-stream\\". Got \\"\${httpResponse.headers["Content-Type"]}\\"",
@@ -1793,10 +1815,10 @@ private suspend fun __handleSseRequest(
1793
1815
  )
1794
1816
  )
1795
1817
  } catch (e: CancellationException) {
1818
+ httpResponse.cancel()
1796
1819
  return@execute
1797
1820
  }
1798
- __handleSseRequest(
1799
- scope = scope,
1821
+ return@execute __handleSseRequest(
1800
1822
  httpClient = httpClient,
1801
1823
  url = url,
1802
1824
  method = method,
@@ -1808,14 +1830,12 @@ private suspend fun __handleSseRequest(
1808
1830
  bufferCapacity = bufferCapacity,
1809
1831
  onOpen = onOpen,
1810
1832
  onClose = onClose,
1811
- onError = onError,
1812
1833
  onData = onData,
1813
- onConnectionError = onConnectionError,
1834
+ onResponseError = onResponseError,
1814
1835
  )
1815
- return@execute
1816
1836
  }
1817
1837
  newBackoffTime = 0
1818
- val channel: ByteReadChannel = httpResponse.bodyAsChannel()
1838
+ val channel: ByteReadChannel = httpResponse.body()
1819
1839
  var pendingData = ""
1820
1840
  while (!channel.isClosedForRead) {
1821
1841
  val buffer = ByteBuffer.allocateDirect(bufferCapacity)
@@ -1835,6 +1855,7 @@ private suspend fun __handleSseRequest(
1835
1855
  onData(event.data)
1836
1856
  } catch (e: CancellationException) {
1837
1857
  onClose()
1858
+ httpResponse.cancel()
1838
1859
  return@execute
1839
1860
  }
1840
1861
  }
@@ -1844,22 +1865,11 @@ private suspend fun __handleSseRequest(
1844
1865
  return@execute
1845
1866
  }
1846
1867
 
1847
- "error" -> {
1848
- val error = ${clientName}Error.fromJson(event.data)
1849
- try {
1850
- onError(error)
1851
- } catch (e: CancellationException) {
1852
- onClose()
1853
- return@execute
1854
- }
1855
- }
1856
-
1857
1868
  else -> {}
1858
1869
  }
1859
1870
  }
1860
1871
  }
1861
- __handleSseRequest(
1862
- scope = scope,
1872
+ return@execute __handleSseRequest(
1863
1873
  httpClient = httpClient,
1864
1874
  url = url,
1865
1875
  method = method,
@@ -1871,22 +1881,13 @@ private suspend fun __handleSseRequest(
1871
1881
  bufferCapacity = bufferCapacity,
1872
1882
  onOpen = onOpen,
1873
1883
  onClose = onClose,
1874
- onError = onError,
1875
1884
  onData = onData,
1876
- onConnectionError = onConnectionError,
1885
+ onResponseError = onResponseError,
1877
1886
  )
1878
1887
  }
1879
1888
  } catch (e: java.net.ConnectException) {
1880
- onConnectionError(
1881
- ${clientName}Error(
1882
- code = 503,
1883
- errorMessage = if (e.message != null) e.message!! else "Error connecting to $url",
1884
- data = JsonPrimitive(e.toString()),
1885
- stack = e.stackTraceToString().split("\\n"),
1886
- )
1887
- )
1888
- __handleSseRequest(
1889
- scope = scope,
1889
+ onRequestError(e)
1890
+ return __handleSseRequest(
1890
1891
  httpClient = httpClient,
1891
1892
  url = url,
1892
1893
  method = method,
@@ -1898,14 +1899,12 @@ private suspend fun __handleSseRequest(
1898
1899
  bufferCapacity = bufferCapacity,
1899
1900
  onOpen = onOpen,
1900
1901
  onClose = onClose,
1901
- onError = onError,
1902
1902
  onData = onData,
1903
- onConnectionError = onConnectionError,
1903
+ onResponseError = onResponseError,
1904
1904
  )
1905
- return
1906
1905
  } catch (e: Exception) {
1907
- __handleSseRequest(
1908
- scope = scope,
1906
+ onRequestError(e)
1907
+ return __handleSseRequest(
1909
1908
  httpClient = httpClient,
1910
1909
  url = url,
1911
1910
  method = method,
@@ -1917,9 +1916,8 @@ private suspend fun __handleSseRequest(
1917
1916
  bufferCapacity = bufferCapacity,
1918
1917
  onOpen = onOpen,
1919
1918
  onClose = onClose,
1920
- onError = onError,
1921
1919
  onData = onData,
1922
- onConnectionError = onConnectionError,
1920
+ onResponseError = onResponseError,
1923
1921
  )
1924
1922
  }
1925
1923
  }`;
@@ -1932,14 +1930,14 @@ function getHeader(options) {
1932
1930
  )
1933
1931
 
1934
1932
  import io.ktor.client.*
1933
+ import io.ktor.client.call.*
1935
1934
  import io.ktor.client.plugins.*
1936
1935
  import io.ktor.client.request.*
1937
1936
  import io.ktor.client.statement.*
1938
1937
  import io.ktor.http.*
1939
1938
  import io.ktor.utils.io.*
1940
- import kotlinx.coroutines.CoroutineScope
1941
- import kotlinx.coroutines.Job
1942
- import kotlinx.coroutines.launch
1939
+ import kotlinx.coroutines.cancel
1940
+ import kotlinx.coroutines.currentCoroutineContext
1943
1941
  import kotlinx.coroutines.withContext
1944
1942
  import kotlinx.serialization.encodeToString
1945
1943
  import kotlinx.serialization.json.*
package/dist/index.d.cts CHANGED
@@ -2,7 +2,7 @@ import * as _arrirpc_codegen_utils from '@arrirpc/codegen-utils';
2
2
  import { AppDefinition, Schema } from '@arrirpc/codegen-utils';
3
3
 
4
4
  interface CodegenContext {
5
- modelPrefix: string;
5
+ typePrefix: string;
6
6
  clientName: string;
7
7
  clientVersion: string;
8
8
  instancePath: string;
@@ -25,12 +25,12 @@ interface KotlinProperty {
25
25
 
26
26
  interface ServiceContext {
27
27
  clientName: string;
28
- modelPrefix?: string;
28
+ typePrefix?: string;
29
29
  modelJsonInstances: Record<string, string>;
30
30
  }
31
31
  interface KotlinClientOptions {
32
32
  clientName?: string;
33
- modelPrefix?: string;
33
+ typePrefix?: string;
34
34
  outputFile: string;
35
35
  }
36
36
  declare const kotlinClientGenerator: _arrirpc_codegen_utils.GeneratorPlugin<KotlinClientOptions>;
package/dist/index.d.mts CHANGED
@@ -2,7 +2,7 @@ import * as _arrirpc_codegen_utils from '@arrirpc/codegen-utils';
2
2
  import { AppDefinition, Schema } from '@arrirpc/codegen-utils';
3
3
 
4
4
  interface CodegenContext {
5
- modelPrefix: string;
5
+ typePrefix: string;
6
6
  clientName: string;
7
7
  clientVersion: string;
8
8
  instancePath: string;
@@ -25,12 +25,12 @@ interface KotlinProperty {
25
25
 
26
26
  interface ServiceContext {
27
27
  clientName: string;
28
- modelPrefix?: string;
28
+ typePrefix?: string;
29
29
  modelJsonInstances: Record<string, string>;
30
30
  }
31
31
  interface KotlinClientOptions {
32
32
  clientName?: string;
33
- modelPrefix?: string;
33
+ typePrefix?: string;
34
34
  outputFile: string;
35
35
  }
36
36
  declare const kotlinClientGenerator: _arrirpc_codegen_utils.GeneratorPlugin<KotlinClientOptions>;
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ import * as _arrirpc_codegen_utils from '@arrirpc/codegen-utils';
2
2
  import { AppDefinition, Schema } from '@arrirpc/codegen-utils';
3
3
 
4
4
  interface CodegenContext {
5
- modelPrefix: string;
5
+ typePrefix: string;
6
6
  clientName: string;
7
7
  clientVersion: string;
8
8
  instancePath: string;
@@ -25,12 +25,12 @@ interface KotlinProperty {
25
25
 
26
26
  interface ServiceContext {
27
27
  clientName: string;
28
- modelPrefix?: string;
28
+ typePrefix?: string;
29
29
  modelJsonInstances: Record<string, string>;
30
30
  }
31
31
  interface KotlinClientOptions {
32
32
  clientName?: string;
33
- modelPrefix?: string;
33
+ typePrefix?: string;
34
34
  outputFile: string;
35
35
  }
36
36
  declare const kotlinClientGenerator: _arrirpc_codegen_utils.GeneratorPlugin<KotlinClientOptions>;
package/dist/index.mjs CHANGED
@@ -59,7 +59,7 @@ function getClassName(schema, context) {
59
59
  normalize: true
60
60
  })
61
61
  );
62
- return `${context.modelPrefix}${className2}`;
62
+ return `${context.typePrefix}${className2}`;
63
63
  }
64
64
  const depth = instanceDepth(context);
65
65
  if (depth === 1 && !context.discriminatorKey) {
@@ -68,7 +68,7 @@ function getClassName(schema, context) {
68
68
  normalize: true
69
69
  })
70
70
  );
71
- return `${context.modelPrefix}${className2}`;
71
+ return `${context.typePrefix}${className2}`;
72
72
  }
73
73
  if (context.discriminatorParentId && context.discriminatorKey && context.discriminatorValue) {
74
74
  const className2 = kotlinClassName(
@@ -77,7 +77,7 @@ function getClassName(schema, context) {
77
77
  { normalize: true }
78
78
  )
79
79
  );
80
- return `${context.modelPrefix}${className2}`;
80
+ return `${context.typePrefix}${className2}`;
81
81
  }
82
82
  const className = kotlinClassName(
83
83
  pascalCase(
@@ -87,7 +87,7 @@ function getClassName(schema, context) {
87
87
  }
88
88
  )
89
89
  );
90
- return `${context.modelPrefix}${className}`;
90
+ return `${context.typePrefix}${className}`;
91
91
  }
92
92
  function instanceDepth(context) {
93
93
  const parts = context.instancePath.split("/");
@@ -166,7 +166,7 @@ function kotlinArrayFromSchema(schema, context) {
166
166
  const nullable = isNullable(schema, context);
167
167
  const defaultValue = nullable ? "null" : "mutableListOf()";
168
168
  const subType = kotlinTypeFromSchema(schema.elements, {
169
- modelPrefix: context.modelPrefix,
169
+ typePrefix: context.typePrefix,
170
170
  clientName: context.clientName,
171
171
  clientVersion: context.clientVersion,
172
172
  instancePath: `${context.instancePath}/[Element]`,
@@ -307,7 +307,7 @@ function kotlinObjectFromSchema(schema, context) {
307
307
  kotlinKeys.push(kotlinKey);
308
308
  const prop = schema.properties[key];
309
309
  const type = kotlinTypeFromSchema(prop, {
310
- modelPrefix: context.modelPrefix,
310
+ typePrefix: context.typePrefix,
311
311
  clientName: context.clientName,
312
312
  clientVersion: context.clientVersion,
313
313
  instancePath: `/${className}/${key}`,
@@ -341,7 +341,7 @@ function kotlinObjectFromSchema(schema, context) {
341
341
  const kotlinKey = kotlinIdentifier(key);
342
342
  kotlinKeys.push(kotlinKey);
343
343
  const type = kotlinTypeFromSchema(schema.optionalProperties[key], {
344
- modelPrefix: context.modelPrefix,
344
+ typePrefix: context.typePrefix,
345
345
  clientName: context.clientName,
346
346
  clientVersion: context.clientVersion,
347
347
  instancePath: `/${className}/${key}`,
@@ -440,7 +440,7 @@ function kotlinDiscriminatorFromSchema(schema, context) {
440
440
  for (const key of Object.keys(schema.mapping)) {
441
441
  const subSchema = schema.mapping[key];
442
442
  const subType = kotlinObjectFromSchema(subSchema, {
443
- modelPrefix: context.modelPrefix,
443
+ typePrefix: context.typePrefix,
444
444
  clientName: context.clientName,
445
445
  clientVersion: context.clientVersion,
446
446
  instancePath: context.instancePath,
@@ -628,7 +628,7 @@ function kotlinEnumFromSchema(schema, context) {
628
628
  function kotlinMapFromSchema(schema, context) {
629
629
  const nullable = isNullable(schema, context);
630
630
  const subType = kotlinTypeFromSchema(schema.values, {
631
- modelPrefix: context.modelPrefix,
631
+ typePrefix: context.typePrefix,
632
632
  clientName: context.clientName,
633
633
  clientVersion: context.clientVersion,
634
634
  instancePath: `${context.instancePath}/[value]`,
@@ -1123,8 +1123,8 @@ function kotlinProcedureFromSchema(schema, context) {
1123
1123
  }
1124
1124
  function kotlinHttpRpcFromSchema(schema, context) {
1125
1125
  const name = getProcedureName(context);
1126
- const params = schema.params ? kotlinClassName(`${context.modelPrefix}_${schema.params}`) : void 0;
1127
- const response = schema.response ? kotlinClassName(`${context.modelPrefix}_${schema.response}`) : void 0;
1126
+ const params = schema.params ? kotlinClassName(`${context.typePrefix}_${schema.params}`) : void 0;
1127
+ const response = schema.response ? kotlinClassName(`${context.typePrefix}_${schema.response}`) : void 0;
1128
1128
  const codeComment = getCodeComment(
1129
1129
  {
1130
1130
  description: schema.description,
@@ -1134,40 +1134,36 @@ function kotlinHttpRpcFromSchema(schema, context) {
1134
1134
  "method"
1135
1135
  );
1136
1136
  if (schema.isEventStream) {
1137
- return `${codeComment}fun ${name}(
1138
- scope: CoroutineScope,
1137
+ return `${codeComment}suspend fun ${name}(
1139
1138
  ${params ? `params: ${params},` : ""}
1140
1139
  lastEventId: String? = null,
1141
- bufferCapacity: Int = 1024,
1140
+ bufferCapacity: Int = 1024 * 1024,
1142
1141
  onOpen: ((response: HttpResponse) -> Unit) = {},
1143
1142
  onClose: (() -> Unit) = {},
1144
- onError: ((error: ${context.clientName}Error) -> Unit) = {},
1145
- onConnectionError: ((error: ${context.clientName}Error) -> Unit) = {},
1143
+ onRequestError: ((error: Exception) -> Unit) = {},
1144
+ onResponseError: ((error: ${context.clientName}Error) -> Unit) = {},
1146
1145
  onData: ((${response ? `data: ${response}` : ""}) -> Unit) = {},
1147
- ): Job {
1148
- val job = scope.launch {
1149
- __handleSseRequest(
1150
- scope = scope,
1151
- httpClient = httpClient,
1152
- url = "$baseUrl${schema.path}",
1153
- method = HttpMethod.${pascalCase(schema.method, { normalize: true })},
1154
- params = ${params ? "params" : "null"},
1155
- headers = headers,
1156
- backoffTime = 0,
1157
- maxBackoffTime = 30000L,
1158
- lastEventId = lastEventId,
1159
- bufferCapacity = bufferCapacity,
1160
- onOpen = onOpen,
1161
- onClose = onClose,
1162
- onError = onError,
1163
- onConnectionError = onConnectionError,
1164
- onData = { str ->
1165
- ${response ? `val data = ${response}.fromJson(str)` : ""}
1166
- onData(${response ? "data" : ""})
1167
- }
1168
- )
1169
- }
1170
- return job
1146
+ maxBackoffTime: Long? = null,
1147
+ ): Unit {
1148
+ __handleSseRequest(
1149
+ httpClient = httpClient,
1150
+ url = "$baseUrl${schema.path}",
1151
+ method = HttpMethod.${pascalCase(schema.method, { normalize: true })},
1152
+ params = ${params ? "params" : "null"},
1153
+ headers = headers,
1154
+ backoffTime = 0,
1155
+ maxBackoffTime = maxBackoffTime ?: 30000L,
1156
+ lastEventId = lastEventId,
1157
+ bufferCapacity = bufferCapacity,
1158
+ onOpen = onOpen,
1159
+ onClose = onClose,
1160
+ onRequestError = onRequestError,
1161
+ onResponseError = onResponseError,
1162
+ onData = { str ->
1163
+ ${response ? `val data = ${response}.fromJson(str)` : ""}
1164
+ onData(${response ? "data" : ""})
1165
+ }
1166
+ )
1171
1167
  }`;
1172
1168
  }
1173
1169
  const headingCheck = `if (response.headers["Content-Type"] != "application/json") {
@@ -1295,7 +1291,7 @@ const kotlinClientGenerator = defineGeneratorPlugin(
1295
1291
  function kotlinClientFromAppDefinition(def, options) {
1296
1292
  const clientName = kotlinClassName(options.clientName ?? "Client");
1297
1293
  const context = {
1298
- modelPrefix: options.modelPrefix ?? "",
1294
+ typePrefix: options.typePrefix ?? "",
1299
1295
  clientName,
1300
1296
  clientVersion: def.info?.version ?? "",
1301
1297
  instancePath: "",
@@ -1306,7 +1302,7 @@ function kotlinClientFromAppDefinition(def, options) {
1306
1302
  for (const key of Object.keys(def.definitions)) {
1307
1303
  const subSchema = def.definitions[key];
1308
1304
  const model = kotlinTypeFromSchema(subSchema, {
1309
- modelPrefix: context.modelPrefix,
1305
+ typePrefix: context.typePrefix,
1310
1306
  clientName: context.clientName,
1311
1307
  clientVersion: context.clientVersion,
1312
1308
  instancePath: `/${key}`,
@@ -1638,62 +1634,89 @@ private suspend fun __prepareRequest(
1638
1634
  return client.prepareRequest(builder)
1639
1635
  }
1640
1636
 
1641
- private fun __parseSseEvent(input: String): __SseEvent {
1642
- val lines = input.split("\\n")
1643
- var id: String? = null
1644
- var event: String? = null
1645
- var data: String = ""
1646
- for (line in lines) {
1647
- if (line.startsWith("id: ")) {
1648
- id = line.substring(3).trim()
1649
- continue
1650
- }
1651
- if (line.startsWith("event: ")) {
1652
- event = line.substring(6).trim()
1653
- continue
1654
- }
1655
- if (line.startsWith("data: ")) {
1656
- data = line.substring(5).trim()
1657
- continue
1658
- }
1637
+ // SSE_FN_START
1638
+ private enum class SseEventLineType {
1639
+ Id,
1640
+ Event,
1641
+ Data,
1642
+ Retry,
1643
+ None,
1644
+ }
1645
+
1646
+ private fun __parseSseEventLine(line: String): Pair<SseEventLineType, String> {
1647
+ if (line.startsWith("id:")) {
1648
+ return Pair(SseEventLineType.Id, line.substring(3).trim())
1649
+ }
1650
+ if (line.startsWith("event:")) {
1651
+ return Pair(SseEventLineType.Event, line.substring(6).trim())
1652
+ }
1653
+ if (line.startsWith("data:")) {
1654
+ return Pair(SseEventLineType.Data, line.substring(5).trim())
1655
+ }
1656
+ if (line.startsWith("retry:")) {
1657
+ return Pair(SseEventLineType.Retry, line.substring(6).trim())
1659
1658
  }
1660
- return __SseEvent(id, event, data)
1659
+ return Pair(SseEventLineType.None, "")
1661
1660
  }
1662
1661
 
1663
- private class __SseEvent(val id: String? = null, val event: String? = null, val data: String)
1662
+ private data class __SseEvent(
1663
+ val id: String? = null,
1664
+ val event: String,
1665
+ val data: String,
1666
+ val retry: Int? = null
1667
+ )
1664
1668
 
1665
1669
  private class __SseEventParsingResult(val events: List<__SseEvent>, val leftover: String)
1666
1670
 
1667
1671
  private fun __parseSseEvents(input: String): __SseEventParsingResult {
1668
- val inputs = input.split("\\n\\n").toMutableList()
1669
- if (inputs.isEmpty()) {
1670
- return __SseEventParsingResult(
1671
- events = listOf(),
1672
- leftover = "",
1673
- )
1674
- }
1675
- if (inputs.size == 1) {
1676
- return __SseEventParsingResult(
1677
- events = listOf(),
1678
- leftover = inputs.last(),
1679
- )
1680
- }
1681
- val leftover = inputs.last()
1682
- inputs.removeLast()
1683
1672
  val events = mutableListOf<__SseEvent>()
1684
- for (item in inputs) {
1685
- if (item.contains("data: ")) {
1686
- events.add(__parseSseEvent(item))
1673
+ val lines = input.lines()
1674
+ if (lines.isEmpty()) {
1675
+ return __SseEventParsingResult(events = listOf(), leftover = "")
1676
+ }
1677
+ var id: String? = null
1678
+ var event: String? = null
1679
+ var data: String? = null
1680
+ var retry: Int? = null
1681
+ var lastIndex: Int? = 0
1682
+ lines.forEachIndexed { index, line ->
1683
+ if (line.isNotEmpty()) {
1684
+ val (type, value) = __parseSseEventLine(line)
1685
+ when (type) {
1686
+ SseEventLineType.Id -> id = value
1687
+ SseEventLineType.Event -> event = value
1688
+ SseEventLineType.Data -> data = value
1689
+ SseEventLineType.Retry -> retry = value.toInt()
1690
+ SseEventLineType.None -> {}
1691
+ }
1692
+ }
1693
+ val isEnd = line == ""
1694
+ if (isEnd) {
1695
+ if (data != null) {
1696
+ events.add(
1697
+ __SseEvent(
1698
+ id = id,
1699
+ event = event ?: "message",
1700
+ data = data!!,
1701
+ retry = retry,
1702
+ )
1703
+ )
1704
+ }
1705
+ id = null
1706
+ event = null
1707
+ data = null
1708
+ retry = null
1709
+ lastIndex = if (index + 1 < lines.size) index + 1 else null
1687
1710
  }
1688
1711
  }
1689
1712
  return __SseEventParsingResult(
1690
1713
  events = events,
1691
- leftover = leftover,
1714
+ leftover = if (lastIndex != null) lines.subList(lastIndex!!, lines.size).joinToString(separator = "\\n") else ""
1692
1715
  )
1693
1716
  }
1717
+ // SSE_FN_END
1694
1718
 
1695
1719
  private suspend fun __handleSseRequest(
1696
- scope: CoroutineScope,
1697
1720
  httpClient: HttpClient,
1698
1721
  url: String,
1699
1722
  method: HttpMethod,
@@ -1704,16 +1727,16 @@ private suspend fun __handleSseRequest(
1704
1727
  lastEventId: String?,
1705
1728
  onOpen: ((response: HttpResponse) -> Unit) = {},
1706
1729
  onClose: (() -> Unit) = {},
1707
- onError: ((error: ${clientName}Error) -> Unit) = {},
1708
1730
  onData: ((data: String) -> Unit) = {},
1709
- onConnectionError: ((error: ${clientName}Error) -> Unit) = {},
1731
+ onRequestError: ((error: Exception) -> Unit) = {},
1732
+ onResponseError: ((error: ${clientName}Error) -> Unit) = {},
1710
1733
  bufferCapacity: Int,
1711
1734
  ) {
1712
1735
  val finalHeaders = headers?.invoke() ?: mutableMapOf()
1713
1736
  var lastId = lastEventId
1714
1737
  // exponential backoff maxing out at 32 seconds
1715
1738
  if (backoffTime > 0) {
1716
- withContext(scope.coroutineContext) {
1739
+ withContext(currentCoroutineContext()) {
1717
1740
  Thread.sleep(backoffTime)
1718
1741
  }
1719
1742
  }
@@ -1735,16 +1758,17 @@ private suspend fun __handleSseRequest(
1735
1758
  onOpen(httpResponse)
1736
1759
  } catch (e: CancellationException) {
1737
1760
  onClose()
1761
+ httpResponse.cancel()
1738
1762
  return@execute
1739
1763
  }
1740
1764
  if (httpResponse.status.value !in 200..299) {
1741
1765
  try {
1742
1766
  if (httpResponse.headers["Content-Type"] == "application/json") {
1743
- onConnectionError(
1767
+ onResponseError(
1744
1768
  ${clientName}Error.fromJson(httpResponse.bodyAsText())
1745
1769
  )
1746
1770
  } else {
1747
- onConnectionError(
1771
+ onResponseError(
1748
1772
  ${clientName}Error(
1749
1773
  code = httpResponse.status.value,
1750
1774
  errorMessage = httpResponse.status.description,
@@ -1755,10 +1779,10 @@ private suspend fun __handleSseRequest(
1755
1779
  }
1756
1780
  } catch (e: CancellationException) {
1757
1781
  onClose()
1782
+ httpResponse.cancel()
1758
1783
  return@execute
1759
1784
  }
1760
- __handleSseRequest(
1761
- scope = scope,
1785
+ return@execute __handleSseRequest(
1762
1786
  httpClient = httpClient,
1763
1787
  url = url,
1764
1788
  method = method,
@@ -1770,15 +1794,13 @@ private suspend fun __handleSseRequest(
1770
1794
  bufferCapacity = bufferCapacity,
1771
1795
  onOpen = onOpen,
1772
1796
  onClose = onClose,
1773
- onError = onError,
1774
1797
  onData = onData,
1775
- onConnectionError = onConnectionError,
1798
+ onResponseError = onResponseError,
1776
1799
  )
1777
- return@execute
1778
1800
  }
1779
1801
  if (httpResponse.headers["Content-Type"] != "text/event-stream") {
1780
1802
  try {
1781
- onConnectionError(
1803
+ onResponseError(
1782
1804
  ${clientName}Error(
1783
1805
  code = 0,
1784
1806
  errorMessage = "Expected server to return Content-Type \\"text/event-stream\\". Got \\"\${httpResponse.headers["Content-Type"]}\\"",
@@ -1787,10 +1809,10 @@ private suspend fun __handleSseRequest(
1787
1809
  )
1788
1810
  )
1789
1811
  } catch (e: CancellationException) {
1812
+ httpResponse.cancel()
1790
1813
  return@execute
1791
1814
  }
1792
- __handleSseRequest(
1793
- scope = scope,
1815
+ return@execute __handleSseRequest(
1794
1816
  httpClient = httpClient,
1795
1817
  url = url,
1796
1818
  method = method,
@@ -1802,14 +1824,12 @@ private suspend fun __handleSseRequest(
1802
1824
  bufferCapacity = bufferCapacity,
1803
1825
  onOpen = onOpen,
1804
1826
  onClose = onClose,
1805
- onError = onError,
1806
1827
  onData = onData,
1807
- onConnectionError = onConnectionError,
1828
+ onResponseError = onResponseError,
1808
1829
  )
1809
- return@execute
1810
1830
  }
1811
1831
  newBackoffTime = 0
1812
- val channel: ByteReadChannel = httpResponse.bodyAsChannel()
1832
+ val channel: ByteReadChannel = httpResponse.body()
1813
1833
  var pendingData = ""
1814
1834
  while (!channel.isClosedForRead) {
1815
1835
  val buffer = ByteBuffer.allocateDirect(bufferCapacity)
@@ -1829,6 +1849,7 @@ private suspend fun __handleSseRequest(
1829
1849
  onData(event.data)
1830
1850
  } catch (e: CancellationException) {
1831
1851
  onClose()
1852
+ httpResponse.cancel()
1832
1853
  return@execute
1833
1854
  }
1834
1855
  }
@@ -1838,22 +1859,11 @@ private suspend fun __handleSseRequest(
1838
1859
  return@execute
1839
1860
  }
1840
1861
 
1841
- "error" -> {
1842
- val error = ${clientName}Error.fromJson(event.data)
1843
- try {
1844
- onError(error)
1845
- } catch (e: CancellationException) {
1846
- onClose()
1847
- return@execute
1848
- }
1849
- }
1850
-
1851
1862
  else -> {}
1852
1863
  }
1853
1864
  }
1854
1865
  }
1855
- __handleSseRequest(
1856
- scope = scope,
1866
+ return@execute __handleSseRequest(
1857
1867
  httpClient = httpClient,
1858
1868
  url = url,
1859
1869
  method = method,
@@ -1865,22 +1875,13 @@ private suspend fun __handleSseRequest(
1865
1875
  bufferCapacity = bufferCapacity,
1866
1876
  onOpen = onOpen,
1867
1877
  onClose = onClose,
1868
- onError = onError,
1869
1878
  onData = onData,
1870
- onConnectionError = onConnectionError,
1879
+ onResponseError = onResponseError,
1871
1880
  )
1872
1881
  }
1873
1882
  } catch (e: java.net.ConnectException) {
1874
- onConnectionError(
1875
- ${clientName}Error(
1876
- code = 503,
1877
- errorMessage = if (e.message != null) e.message!! else "Error connecting to $url",
1878
- data = JsonPrimitive(e.toString()),
1879
- stack = e.stackTraceToString().split("\\n"),
1880
- )
1881
- )
1882
- __handleSseRequest(
1883
- scope = scope,
1883
+ onRequestError(e)
1884
+ return __handleSseRequest(
1884
1885
  httpClient = httpClient,
1885
1886
  url = url,
1886
1887
  method = method,
@@ -1892,14 +1893,12 @@ private suspend fun __handleSseRequest(
1892
1893
  bufferCapacity = bufferCapacity,
1893
1894
  onOpen = onOpen,
1894
1895
  onClose = onClose,
1895
- onError = onError,
1896
1896
  onData = onData,
1897
- onConnectionError = onConnectionError,
1897
+ onResponseError = onResponseError,
1898
1898
  )
1899
- return
1900
1899
  } catch (e: Exception) {
1901
- __handleSseRequest(
1902
- scope = scope,
1900
+ onRequestError(e)
1901
+ return __handleSseRequest(
1903
1902
  httpClient = httpClient,
1904
1903
  url = url,
1905
1904
  method = method,
@@ -1911,9 +1910,8 @@ private suspend fun __handleSseRequest(
1911
1910
  bufferCapacity = bufferCapacity,
1912
1911
  onOpen = onOpen,
1913
1912
  onClose = onClose,
1914
- onError = onError,
1915
1913
  onData = onData,
1916
- onConnectionError = onConnectionError,
1914
+ onResponseError = onResponseError,
1917
1915
  )
1918
1916
  }
1919
1917
  }`;
@@ -1926,14 +1924,14 @@ function getHeader(options) {
1926
1924
  )
1927
1925
 
1928
1926
  import io.ktor.client.*
1927
+ import io.ktor.client.call.*
1929
1928
  import io.ktor.client.plugins.*
1930
1929
  import io.ktor.client.request.*
1931
1930
  import io.ktor.client.statement.*
1932
1931
  import io.ktor.http.*
1933
1932
  import io.ktor.utils.io.*
1934
- import kotlinx.coroutines.CoroutineScope
1935
- import kotlinx.coroutines.Job
1936
- import kotlinx.coroutines.launch
1933
+ import kotlinx.coroutines.cancel
1934
+ import kotlinx.coroutines.currentCoroutineContext
1937
1935
  import kotlinx.coroutines.withContext
1938
1936
  import kotlinx.serialization.encodeToString
1939
1937
  import kotlinx.serialization.json.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arrirpc/codegen-kotlin",
3
- "version": "0.60.3",
3
+ "version": "0.61.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -22,6 +22,6 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@arrirpc/codegen-utils": "0.60.3"
25
+ "@arrirpc/codegen-utils": "0.61.0"
26
26
  }
27
27
  }