@s2-dev/streamstore 0.3.9 → 0.3.13

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.
Files changed (188) hide show
  1. package/README.md +15 -12
  2. package/docs/sdks/account/README.md +38 -35
  3. package/docs/sdks/basin/README.md +38 -35
  4. package/docs/sdks/stream/README.md +22 -27
  5. package/funcs/accountCreateBasin.d.ts +2 -1
  6. package/funcs/accountCreateBasin.d.ts.map +1 -1
  7. package/funcs/accountCreateBasin.js +3 -4
  8. package/funcs/accountCreateBasin.js.map +1 -1
  9. package/funcs/accountDeleteBasin.d.ts +1 -1
  10. package/funcs/accountDeleteBasin.d.ts.map +1 -1
  11. package/funcs/accountDeleteBasin.js +3 -2
  12. package/funcs/accountDeleteBasin.js.map +1 -1
  13. package/funcs/accountGetBasinConfig.d.ts +2 -1
  14. package/funcs/accountGetBasinConfig.d.ts.map +1 -1
  15. package/funcs/accountGetBasinConfig.js +3 -4
  16. package/funcs/accountGetBasinConfig.js.map +1 -1
  17. package/funcs/accountListBasins.d.ts +1 -1
  18. package/funcs/accountListBasins.d.ts.map +1 -1
  19. package/funcs/accountListBasins.js +2 -4
  20. package/funcs/accountListBasins.js.map +1 -1
  21. package/funcs/accountReconfigureBasin.d.ts +2 -1
  22. package/funcs/accountReconfigureBasin.d.ts.map +1 -1
  23. package/funcs/accountReconfigureBasin.js +3 -4
  24. package/funcs/accountReconfigureBasin.js.map +1 -1
  25. package/funcs/basinCreateStream.d.ts +2 -1
  26. package/funcs/basinCreateStream.d.ts.map +1 -1
  27. package/funcs/basinCreateStream.js +14 -4
  28. package/funcs/basinCreateStream.js.map +1 -1
  29. package/funcs/basinDeleteStream.d.ts +1 -1
  30. package/funcs/basinDeleteStream.d.ts.map +1 -1
  31. package/funcs/basinDeleteStream.js +3 -2
  32. package/funcs/basinDeleteStream.js.map +1 -1
  33. package/funcs/basinGetStreamConfig.d.ts +2 -1
  34. package/funcs/basinGetStreamConfig.d.ts.map +1 -1
  35. package/funcs/basinGetStreamConfig.js +3 -4
  36. package/funcs/basinGetStreamConfig.js.map +1 -1
  37. package/funcs/basinListStreams.d.ts +1 -1
  38. package/funcs/basinListStreams.d.ts.map +1 -1
  39. package/funcs/basinListStreams.js +3 -3
  40. package/funcs/basinListStreams.js.map +1 -1
  41. package/funcs/basinReconfigureStream.d.ts +2 -1
  42. package/funcs/basinReconfigureStream.d.ts.map +1 -1
  43. package/funcs/basinReconfigureStream.js +3 -4
  44. package/funcs/basinReconfigureStream.js.map +1 -1
  45. package/funcs/streamAppend.d.ts +2 -1
  46. package/funcs/streamAppend.d.ts.map +1 -1
  47. package/funcs/streamAppend.js +3 -4
  48. package/funcs/streamAppend.js.map +1 -1
  49. package/funcs/streamCheckTail.d.ts +2 -1
  50. package/funcs/streamCheckTail.d.ts.map +1 -1
  51. package/funcs/streamCheckTail.js +3 -4
  52. package/funcs/streamCheckTail.js.map +1 -1
  53. package/funcs/streamRead.d.ts +1 -1
  54. package/funcs/streamRead.d.ts.map +1 -1
  55. package/funcs/streamRead.js +2 -2
  56. package/funcs/streamRead.js.map +1 -1
  57. package/index.extras.d.ts +13 -5
  58. package/index.extras.d.ts.map +1 -1
  59. package/index.extras.js +64 -25
  60. package/index.extras.js.map +1 -1
  61. package/jsr.json +1 -1
  62. package/lib/config.d.ts +2 -2
  63. package/lib/config.d.ts.map +1 -1
  64. package/lib/config.js +2 -2
  65. package/lib/config.js.map +1 -1
  66. package/lib/matchers.d.ts +1 -1
  67. package/lib/matchers.d.ts.map +1 -1
  68. package/lib/matchers.js +11 -10
  69. package/lib/matchers.js.map +1 -1
  70. package/models/components/index.d.ts +0 -1
  71. package/models/components/index.d.ts.map +1 -1
  72. package/models/components/index.js +0 -1
  73. package/models/components/index.js.map +1 -1
  74. package/models/errors/apierror.d.ts +5 -8
  75. package/models/errors/apierror.d.ts.map +1 -1
  76. package/models/errors/apierror.js +9 -3
  77. package/models/errors/apierror.js.map +1 -1
  78. package/models/errors/index.d.ts +1 -0
  79. package/models/errors/index.d.ts.map +1 -1
  80. package/models/errors/index.js +1 -0
  81. package/models/errors/index.js.map +1 -1
  82. package/models/errors/retryableerror.d.ts +31 -0
  83. package/models/errors/retryableerror.d.ts.map +1 -0
  84. package/models/errors/retryableerror.js +77 -0
  85. package/models/errors/retryableerror.js.map +1 -0
  86. package/models/operations/append.d.ts +0 -27
  87. package/models/operations/append.d.ts.map +1 -1
  88. package/models/operations/append.js +1 -40
  89. package/models/operations/append.js.map +1 -1
  90. package/models/operations/checktail.d.ts +0 -28
  91. package/models/operations/checktail.d.ts.map +1 -1
  92. package/models/operations/checktail.js +1 -42
  93. package/models/operations/checktail.js.map +1 -1
  94. package/models/operations/createbasin.d.ts +0 -27
  95. package/models/operations/createbasin.d.ts.map +1 -1
  96. package/models/operations/createbasin.js +1 -40
  97. package/models/operations/createbasin.js.map +1 -1
  98. package/models/operations/createstream.d.ts +0 -27
  99. package/models/operations/createstream.d.ts.map +1 -1
  100. package/models/operations/createstream.js +1 -40
  101. package/models/operations/createstream.js.map +1 -1
  102. package/models/operations/deletebasin.d.ts +0 -26
  103. package/models/operations/deletebasin.d.ts.map +1 -1
  104. package/models/operations/deletebasin.js +1 -38
  105. package/models/operations/deletebasin.js.map +1 -1
  106. package/models/operations/deletestream.d.ts +0 -26
  107. package/models/operations/deletestream.d.ts.map +1 -1
  108. package/models/operations/deletestream.js +1 -38
  109. package/models/operations/deletestream.js.map +1 -1
  110. package/models/operations/getbasinconfig.d.ts +0 -28
  111. package/models/operations/getbasinconfig.d.ts.map +1 -1
  112. package/models/operations/getbasinconfig.js +1 -42
  113. package/models/operations/getbasinconfig.js.map +1 -1
  114. package/models/operations/getstreamconfig.d.ts +0 -28
  115. package/models/operations/getstreamconfig.d.ts.map +1 -1
  116. package/models/operations/getstreamconfig.js +1 -42
  117. package/models/operations/getstreamconfig.js.map +1 -1
  118. package/models/operations/listbasins.d.ts +2 -4
  119. package/models/operations/listbasins.d.ts.map +1 -1
  120. package/models/operations/listbasins.js +4 -8
  121. package/models/operations/listbasins.js.map +1 -1
  122. package/models/operations/liststreams.d.ts +2 -4
  123. package/models/operations/liststreams.d.ts.map +1 -1
  124. package/models/operations/liststreams.js +4 -8
  125. package/models/operations/liststreams.js.map +1 -1
  126. package/models/operations/read.d.ts +2 -10
  127. package/models/operations/read.d.ts.map +1 -1
  128. package/models/operations/read.js +6 -23
  129. package/models/operations/read.js.map +1 -1
  130. package/models/operations/reconfigurebasin.d.ts +0 -27
  131. package/models/operations/reconfigurebasin.d.ts.map +1 -1
  132. package/models/operations/reconfigurebasin.js +1 -40
  133. package/models/operations/reconfigurebasin.js.map +1 -1
  134. package/models/operations/reconfigurestream.d.ts +0 -27
  135. package/models/operations/reconfigurestream.d.ts.map +1 -1
  136. package/models/operations/reconfigurestream.js +1 -40
  137. package/models/operations/reconfigurestream.js.map +1 -1
  138. package/package.json +1 -1
  139. package/sdk/account.d.ts +5 -4
  140. package/sdk/account.d.ts.map +1 -1
  141. package/sdk/account.js.map +1 -1
  142. package/sdk/basin.d.ts +5 -4
  143. package/sdk/basin.d.ts.map +1 -1
  144. package/sdk/basin.js.map +1 -1
  145. package/sdk/stream.d.ts +3 -2
  146. package/sdk/stream.d.ts.map +1 -1
  147. package/sdk/stream.js.map +1 -1
  148. package/src/funcs/accountCreateBasin.ts +12 -10
  149. package/src/funcs/accountDeleteBasin.ts +12 -8
  150. package/src/funcs/accountGetBasinConfig.ts +12 -10
  151. package/src/funcs/accountListBasins.ts +11 -9
  152. package/src/funcs/accountReconfigureBasin.ts +12 -10
  153. package/src/funcs/basinCreateStream.ts +23 -10
  154. package/src/funcs/basinDeleteStream.ts +12 -8
  155. package/src/funcs/basinGetStreamConfig.ts +12 -10
  156. package/src/funcs/basinListStreams.ts +11 -7
  157. package/src/funcs/basinReconfigureStream.ts +12 -10
  158. package/src/funcs/streamAppend.ts +12 -10
  159. package/src/funcs/streamCheckTail.ts +12 -10
  160. package/src/funcs/streamRead.ts +10 -7
  161. package/src/index.extras.ts +139 -48
  162. package/src/lib/config.ts +3 -2
  163. package/src/lib/matchers.ts +16 -10
  164. package/src/models/components/index.ts +0 -1
  165. package/src/models/errors/apierror.ts +13 -7
  166. package/src/models/errors/index.ts +1 -0
  167. package/src/models/errors/retryableerror.ts +69 -0
  168. package/src/models/operations/append.ts +0 -68
  169. package/src/models/operations/checktail.ts +0 -74
  170. package/src/models/operations/createbasin.ts +0 -72
  171. package/src/models/operations/createstream.ts +0 -72
  172. package/src/models/operations/deletebasin.ts +0 -68
  173. package/src/models/operations/deletestream.ts +0 -68
  174. package/src/models/operations/getbasinconfig.ts +0 -74
  175. package/src/models/operations/getstreamconfig.ts +0 -74
  176. package/src/models/operations/listbasins.ts +6 -12
  177. package/src/models/operations/liststreams.ts +6 -12
  178. package/src/models/operations/read.ts +10 -33
  179. package/src/models/operations/reconfigurebasin.ts +0 -72
  180. package/src/models/operations/reconfigurestream.ts +0 -72
  181. package/src/sdk/account.ts +5 -4
  182. package/src/sdk/basin.ts +5 -4
  183. package/src/sdk/stream.ts +3 -2
  184. package/models/components/httpmetadata.d.ts +0 -37
  185. package/models/components/httpmetadata.d.ts.map +0 -1
  186. package/models/components/httpmetadata.js +0 -86
  187. package/models/components/httpmetadata.js.map +0 -1
  188. package/src/models/components/httpmetadata.ts +0 -87
@@ -10,6 +10,7 @@ import { safeParse } from "../lib/schemas.js";
10
10
  import { RequestOptions } from "../lib/sdks.js";
11
11
  import { extractSecurity, resolveGlobalSecurity } from "../lib/security.js";
12
12
  import { pathToFunc } from "../lib/url.js";
13
+ import * as components from "../models/components/index.js";
13
14
  import { APIError } from "../models/errors/apierror.js";
14
15
  import {
15
16
  ConnectionError,
@@ -36,9 +37,10 @@ export async function streamCheckTail(
36
37
  options?: RequestOptions,
37
38
  ): Promise<
38
39
  Result<
39
- operations.CheckTailResponse,
40
- | errors.ErrorResponse
40
+ components.CheckTailResponse,
41
41
  | errors.ErrorResponse
42
+ | errors.RetryableError
43
+ | errors.RetryableError
42
44
  | APIError
43
45
  | SDKValidationError
44
46
  | UnexpectedClientError
@@ -110,7 +112,7 @@ export async function streamCheckTail(
110
112
 
111
113
  const doResult = await client._do(req, {
112
114
  context,
113
- errorCodes: ["400", "401", "404", "4XX", "500", "5XX"],
115
+ errorCodes: ["400", "401", "404", "499", "4XX", "500", "503", "504", "5XX"],
114
116
  retryConfig: context.retryConfig,
115
117
  retryCodes: context.retryCodes,
116
118
  });
@@ -124,9 +126,10 @@ export async function streamCheckTail(
124
126
  };
125
127
 
126
128
  const [result] = await M.match<
127
- operations.CheckTailResponse,
128
- | errors.ErrorResponse
129
+ components.CheckTailResponse,
129
130
  | errors.ErrorResponse
131
+ | errors.RetryableError
132
+ | errors.RetryableError
130
133
  | APIError
131
134
  | SDKValidationError
132
135
  | UnexpectedClientError
@@ -135,14 +138,13 @@ export async function streamCheckTail(
135
138
  | RequestTimeoutError
136
139
  | ConnectionError
137
140
  >(
138
- M.json(200, operations.CheckTailResponse$inboundSchema, {
139
- key: "CheckTailResponse",
140
- }),
141
+ M.json(200, components.CheckTailResponse$inboundSchema),
141
142
  M.jsonErr([400, 401, 404], errors.ErrorResponse$inboundSchema),
142
- M.jsonErr(500, errors.ErrorResponse$inboundSchema),
143
+ M.jsonErr(499, errors.RetryableError$inboundSchema),
144
+ M.jsonErr([500, 503, 504], errors.RetryableError$inboundSchema),
143
145
  M.fail("4XX"),
144
146
  M.fail("5XX"),
145
- )(response, req, { extraFields: responseFields });
147
+ )(response, { extraFields: responseFields });
146
148
  if (!result.ok) {
147
149
  return result;
148
150
  }
@@ -43,7 +43,8 @@ export async function streamRead(
43
43
  Result<
44
44
  operations.ReadResponse,
45
45
  | errors.ErrorResponse
46
- | errors.ErrorResponse
46
+ | errors.RetryableError
47
+ | errors.RetryableError
47
48
  | APIError
48
49
  | SDKValidationError
49
50
  | UnexpectedClientError
@@ -126,7 +127,7 @@ export async function streamRead(
126
127
 
127
128
  const doResult = await client._do(req, {
128
129
  context,
129
- errorCodes: ["400", "401", "404", "4XX", "500", "5XX"],
130
+ errorCodes: ["400", "401", "404", "499", "4XX", "500", "503", "504", "5XX"],
130
131
  retryConfig: context.retryConfig,
131
132
  retryCodes: context.retryCodes,
132
133
  });
@@ -142,7 +143,8 @@ export async function streamRead(
142
143
  const [result] = await M.match<
143
144
  operations.ReadResponse,
144
145
  | errors.ErrorResponse
145
- | errors.ErrorResponse
146
+ | errors.RetryableError
147
+ | errors.RetryableError
146
148
  | APIError
147
149
  | SDKValidationError
148
150
  | UnexpectedClientError
@@ -151,13 +153,14 @@ export async function streamRead(
151
153
  | RequestTimeoutError
152
154
  | ConnectionError
153
155
  >(
154
- M.json(200, operations.ReadResponse$inboundSchema, { key: "Output" }),
155
- M.sse(200, operations.ReadResponse$inboundSchema, { key: "ReadResponse" }),
156
+ M.json(200, operations.ReadResponse$inboundSchema),
157
+ M.sse(200, operations.ReadResponse$inboundSchema),
156
158
  M.jsonErr([400, 401, 404], errors.ErrorResponse$inboundSchema),
157
- M.jsonErr(500, errors.ErrorResponse$inboundSchema),
159
+ M.jsonErr(499, errors.RetryableError$inboundSchema),
160
+ M.jsonErr([500, 503, 504], errors.RetryableError$inboundSchema),
158
161
  M.fail("4XX"),
159
162
  M.fail("5XX"),
160
- )(response, req, { extraFields: responseFields });
163
+ )(response, { extraFields: responseFields });
161
164
  if (!result.ok) {
162
165
  return result;
163
166
  }
@@ -14,7 +14,7 @@ import {
14
14
  StreamConfig,
15
15
  StreamInfo,
16
16
  } from "./models/components";
17
- import { ErrorResponse, NotFoundError } from "./models/errors";
17
+ import { NotFoundError, RetryableError } from "./models/errors";
18
18
  import {
19
19
  GetBasinConfigRequest,
20
20
  ListBasinsRequest,
@@ -66,13 +66,24 @@ export type S2ClientConfig = {
66
66
  authToken?: string;
67
67
  requestTimeout?: number;
68
68
  endpoints?: S2Endpoints;
69
+ appedRetryPolicy?: AppendRetryPolicy;
70
+ maxRetries?: number;
71
+ initialBackoffMs?: number;
72
+ maxBackoffMs?: number;
69
73
  };
70
74
 
75
+ export enum AppendRetryPolicy {
76
+ All,
77
+ NoSideEffects,
78
+ }
79
+
71
80
  const defaultS2ClientConfig: S2ClientConfig = {
72
81
  requestTimeout: 3000,
73
82
  endpoints: S2Endpoints.forCloud(S2Cloud.Aws),
83
+ appedRetryPolicy: AppendRetryPolicy.All,
74
84
  };
75
85
 
86
+
76
87
  export class S2Client {
77
88
  private config: S2ClientConfig;
78
89
  private _account?: S2Account;
@@ -116,15 +127,23 @@ class S2Account {
116
127
  request?: ListBasinsRequest
117
128
  ): Promise<PageIterator<ListBasinsResponse, { cursor: string }>> {
118
129
  const url = this.URL;
119
- return this._account.listBasins(request ?? {}, url ? { serverURL: url } : {});
130
+ return retryWithExponentialBackoff(
131
+ () => this._account.listBasins(request ?? {}, url ? { serverURL: url } : {}),
132
+ this.config.maxRetries,
133
+ this.config.initialBackoffMs,
134
+ this.config.maxBackoffMs
135
+ );
120
136
  }
121
137
 
122
138
  async getBasinConfig(basin: string): Promise<BasinConfig | undefined> {
123
139
  const _request: GetBasinConfigRequest = { basin };
124
140
  const url = this.URL;
125
- return (await this._account.getBasinConfig(_request
126
- , url ? { serverURL: url } : {}
127
- )).basinConfig;
141
+ return retryWithExponentialBackoff(
142
+ () => this._account.getBasinConfig(_request, url ? { serverURL: url } : {}),
143
+ this.config.maxRetries,
144
+ this.config.initialBackoffMs,
145
+ this.config.maxBackoffMs
146
+ );
128
147
  }
129
148
 
130
149
  async createBasin(basin: string, request?: CreateBasinRequest): Promise<BasinInfo | undefined> {
@@ -134,14 +153,22 @@ class S2Account {
134
153
  createBasinRequest: request ?? {},
135
154
  };
136
155
  const url = this.URL;
137
- return (await this._account.createBasin(_request,
138
- url ? { serverURL: url } : {}
139
- )).basinInfo;
156
+ return retryWithExponentialBackoff(
157
+ () => this._account.createBasin(_request, url ? { serverURL: url } : {}),
158
+ this.config.maxRetries,
159
+ this.config.initialBackoffMs,
160
+ this.config.maxBackoffMs
161
+ );
140
162
  }
141
163
 
142
- async deleteBasin(basin: string, if_exists?: boolean): Promise<void | undefined> {
164
+ async deleteBasin(basin: string, if_exists?: boolean): Promise<void> {
143
165
  const url = this.URL;
144
- const response = await accountDeleteBasin(this._account, { basin }, url ? { serverURL: url } : {});
166
+ const response = await retryWithExponentialBackoff(
167
+ () => accountDeleteBasin(this._account, { basin }, url ? { serverURL: url } : {}),
168
+ this.config.maxRetries,
169
+ this.config.initialBackoffMs,
170
+ this.config.maxBackoffMs
171
+ );
145
172
  if (if_exists && response.error instanceof NotFoundError) return;
146
173
  if (response.error) throw new Error(response.error.message);
147
174
  return;
@@ -150,9 +177,12 @@ class S2Account {
150
177
  async reconfigureBasin(basin: string, config: BasinConfig): Promise<BasinConfig | undefined> {
151
178
  const url = this.URL;
152
179
  const _request: ReconfigureBasinRequest = { basin, basinConfig: config };
153
- return (await this._account.reconfigureBasin(_request
154
- , url ? { serverURL: url } : {}
155
- )).basinConfig;
180
+ return retryWithExponentialBackoff(
181
+ () => this._account.reconfigureBasin(_request, url ? { serverURL: url } : {}),
182
+ this.config.maxRetries,
183
+ this.config.initialBackoffMs,
184
+ this.config.maxBackoffMs
185
+ );
156
186
  }
157
187
  }
158
188
 
@@ -185,13 +215,21 @@ class S2Basin {
185
215
  async listStreams(
186
216
  request: ListStreamsRequest
187
217
  ): Promise<PageIterator<ListStreamsResponse, { cursor: string }>> {
188
- return this._basin.listStreams(request, { serverURL: this.URL });
218
+ return retryWithExponentialBackoff(
219
+ () => this._basin.listStreams(request, { serverURL: this.URL }),
220
+ this.config.maxRetries,
221
+ this.config.initialBackoffMs,
222
+ this.config.maxBackoffMs
223
+ );
189
224
  }
190
225
 
191
226
  async getStreamConfig(stream: string): Promise<StreamConfig | undefined> {
192
- return (
193
- await this._basin.getStreamConfig({ stream }, { serverURL: this.URL })
194
- ).streamConfig;
227
+ return retryWithExponentialBackoff(
228
+ () => this._basin.getStreamConfig({ stream }, { serverURL: this.URL }),
229
+ this.config.maxRetries,
230
+ this.config.initialBackoffMs,
231
+ this.config.maxBackoffMs
232
+ );
195
233
  }
196
234
 
197
235
  async createStream(stream: string, request?: CreateStreamRequest): Promise<StreamInfo | undefined> {
@@ -200,27 +238,33 @@ class S2Basin {
200
238
  s2RequestToken: genS2RequestToken(),
201
239
  createStreamRequest: request ?? {},
202
240
  };
203
- return (
204
- await this._basin.createStream(_request, { serverURL: this.URL })
205
- ).streamInfo;
241
+ return retryWithExponentialBackoff(
242
+ () => this._basin.createStream(_request, { serverURL: this.URL }),
243
+ this.config.maxRetries,
244
+ this.config.initialBackoffMs,
245
+ this.config.maxBackoffMs
246
+ );
206
247
  }
207
248
 
208
249
  async deleteStream(stream: string, if_exists?: boolean): Promise<void | undefined> {
209
- const response = await basinDeleteStream(this._basin, { stream }, {
210
- serverURL: this.URL,
211
- });
250
+ const response = await retryWithExponentialBackoff(
251
+ () => basinDeleteStream(this._basin, { stream }, { serverURL: this.URL }),
252
+ this.config.maxRetries,
253
+ this.config.initialBackoffMs,
254
+ this.config.maxBackoffMs
255
+ );
212
256
  if (if_exists && response instanceof NotFoundError) return;
213
257
  if (response.error) throw new Error(response.error.message);
214
258
  return;
215
259
  }
216
260
 
217
- async reconfigureStream(stream: string, config: StreamConfig): Promise<StreamConfig | undefined> {
218
- return (
219
- await this._basin.reconfigureStream(
220
- { stream, streamConfig: config },
221
- { serverURL: this.URL }
222
- )
223
- ).streamConfig;
261
+ async reconfigureStream(stream: string, config: StreamConfig): Promise<StreamConfig> {
262
+ return retryWithExponentialBackoff(
263
+ () => this._basin.reconfigureStream({ stream, streamConfig: config }, { serverURL: this.URL }),
264
+ this.config.maxRetries,
265
+ this.config.initialBackoffMs,
266
+ this.config.maxBackoffMs
267
+ );
224
268
  }
225
269
  }
226
270
 
@@ -245,29 +289,44 @@ class Stream {
245
289
  });
246
290
  }
247
291
 
248
- async checkTail(): Promise<CheckTailResponse | undefined> {
292
+ async checkTail(): Promise<CheckTailResponse> {
249
293
  return (
250
294
  await this._stream.checkTail({ stream: this.streamName }, { serverURL: this.basinURL })
251
- ).checkTailResponse;
295
+ );
252
296
  }
253
297
 
254
- async append(request: AppendRequest): Promise<AppendOutput | undefined> {
255
- return (
256
- await this._stream.append({ ...request, stream: this.streamName }, { serverURL: this.basinURL })
257
- ).appendOutput;
298
+ async append(request: AppendRequest): Promise<AppendOutput> {
299
+ switch (this.config.appedRetryPolicy) {
300
+ case AppendRetryPolicy.All:
301
+ case undefined:
302
+ return retryWithExponentialBackoff(
303
+ () => this._stream.append({ ...request, stream: this.streamName }, { serverURL: this.basinURL }),
304
+ this.config.maxRetries,
305
+ this.config.initialBackoffMs,
306
+ this.config.maxBackoffMs
307
+ );
308
+ case AppendRetryPolicy.NoSideEffects:
309
+ return (
310
+ await this._stream.append({ ...request, stream: this.streamName }, {
311
+ serverURL: this.basinURL,
312
+ })
313
+ );
314
+ default:
315
+ throw new Error("Invalid AppendRetryPolicy");
316
+ }
258
317
  }
259
318
 
260
- async read(request: ReadRequest): Promise<Output | undefined> {
319
+ async read(request: ReadRequest): Promise<Output> {
261
320
  return (
262
- await this._stream.read({ ...request, stream: this.streamName }, { serverURL: this.basinURL })
263
- ).output;
321
+ await this._stream.read({ ...request, stream: this.streamName }, { serverURL: this.basinURL }) as Output
322
+ );
264
323
  }
265
324
 
266
325
  async *readStream(request: ReadRequest): AsyncGenerator<ReadResponse, void, undefined> {
267
326
  let currentRequest: ReadRequest = { ...request };
268
- let backoffMs = 100;
327
+ let initialBackoffMs = this.config.initialBackoffMs ?? 100;
269
328
  const maxBackoffMs = 5000;
270
- const maxRetries = 5;
329
+ const maxRetries = this.config.maxRetries ?? 5;
271
330
  let retryCount = 0;
272
331
 
273
332
  while (true) {
@@ -281,7 +340,7 @@ class Stream {
281
340
  acceptHeaderOverride: ReadAcceptEnum.textEventStream
282
341
  }
283
342
  );
284
- stream = response.readResponse;
343
+ stream = response as EventStream<ReadResponse>;
285
344
  if (!stream) return;
286
345
 
287
346
  for await (const event of stream) {
@@ -310,13 +369,16 @@ class Stream {
310
369
  }
311
370
  return;
312
371
  } catch (error) {
313
- if (error instanceof ErrorResponse || error instanceof NotFoundError) return;
314
- if (retryCount >= maxRetries) {
372
+ if (error instanceof RetryableError) {
373
+ if (retryCount >= maxRetries) {
374
+ throw error;
375
+ }
376
+ retryCount++;
377
+ await new Promise(resolve => setTimeout(resolve, initialBackoffMs));
378
+ initialBackoffMs = Math.min(initialBackoffMs * 2, maxBackoffMs);
379
+ } else {
315
380
  throw error;
316
381
  }
317
- retryCount++;
318
- await new Promise(resolve => setTimeout(resolve, backoffMs));
319
- backoffMs = Math.min(backoffMs * 2, maxBackoffMs);
320
382
  }
321
383
  }
322
384
  }
@@ -336,4 +398,33 @@ function meteredBatchSize(batch: SequencedRecordBatch): number {
336
398
 
337
399
  export function genS2RequestToken(): string {
338
400
  return uuidv4().replace(/-/g, "");
339
- }
401
+ }
402
+
403
+ async function retryWithExponentialBackoff<T>(
404
+ operation: () => Promise<T>,
405
+ maxAttempts: number = 5,
406
+ initialBackoffMs: number = 100,
407
+ maxBackoffMs: number = 5000
408
+ ): Promise<T> {
409
+ let attempt = 0;
410
+
411
+ while (attempt < maxAttempts) {
412
+ try {
413
+ return await operation();
414
+ } catch (error) {
415
+ if (error instanceof RetryableError) {
416
+ attempt++;
417
+ if (attempt >= maxAttempts) throw error;
418
+
419
+ const jitter = Math.random() * 0.3 + 0.85;
420
+ const delayMs = Math.min(initialBackoffMs * Math.pow(2, attempt) * jitter, maxBackoffMs);
421
+
422
+ await new Promise(resolve => setTimeout(resolve, delayMs));
423
+ } else {
424
+ throw error;
425
+ }
426
+ }
427
+ }
428
+
429
+ throw new Error("Max retry attempts reached");
430
+ }
package/src/lib/config.ts CHANGED
@@ -54,7 +54,8 @@ export function serverURLFromOptions(options: SDKOptions): URL | null {
54
54
  export const SDK_METADATA = {
55
55
  language: "typescript",
56
56
  openapiDocVersion: "1.0.0",
57
- sdkVersion: "0.3.9",
57
+ sdkVersion: "0.3.13",
58
58
  genVersion: "2.506.0",
59
- userAgent: "speakeasy-sdk/typescript 0.3.9 2.506.0 1.0.0 @s2-dev/streamstore",
59
+ userAgent:
60
+ "speakeasy-sdk/typescript 0.3.13 2.506.0 1.0.0 @s2-dev/streamstore",
60
61
  } as const;
@@ -160,7 +160,6 @@ export type MatchedError<Matchers> = Matchers extends Matcher<any, infer E>[]
160
160
  : never;
161
161
  export type MatchFunc<T, E> = (
162
162
  response: Response,
163
- request: Request,
164
163
  options?: { resultKey?: string; extraFields?: Record<string, unknown> },
165
164
  ) => Promise<[result: Result<T, E>, raw: unknown]>;
166
165
 
@@ -169,7 +168,6 @@ export function match<T, E>(
169
168
  ): MatchFunc<T, E | APIError | SDKValidationError> {
170
169
  return async function matchFunc(
171
170
  response: Response,
172
- request: Request,
173
171
  options?: { resultKey?: string; extraFields?: Record<string, unknown> },
174
172
  ): Promise<
175
173
  [result: Result<T, E | APIError | SDKValidationError>, raw: unknown]
@@ -191,14 +189,15 @@ export function match<T, E>(
191
189
  }
192
190
 
193
191
  if (!matcher) {
194
- await discardResponseBody(response);
192
+ const responseBody = await response.text();
195
193
  return [{
196
194
  ok: false,
197
- error: new APIError("Unexpected API response status or content-type", {
195
+ error: new APIError(
196
+ "Unexpected API response status or content-type",
198
197
  response,
199
- request,
200
- }),
201
- }, raw];
198
+ responseBody,
199
+ ),
200
+ }, responseBody];
202
201
  }
203
202
 
204
203
  const encoding = matcher.enc;
@@ -224,7 +223,7 @@ export function match<T, E>(
224
223
  raw = await discardResponseBody(response);
225
224
  break;
226
225
  case "fail":
227
- raw = await discardResponseBody(response);
226
+ raw = await response.text();
228
227
  break;
229
228
  default:
230
229
  encoding satisfies never;
@@ -234,7 +233,11 @@ export function match<T, E>(
234
233
  if (matcher.enc === "fail") {
235
234
  return [{
236
235
  ok: false,
237
- error: new APIError("API error occurred", { response, request }),
236
+ error: new APIError(
237
+ "API error occurred",
238
+ response,
239
+ typeof raw === "string" ? raw : "",
240
+ ),
238
241
  }, raw];
239
242
  }
240
243
 
@@ -253,11 +256,14 @@ export function match<T, E>(
253
256
  ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null),
254
257
  [resultKey]: raw,
255
258
  };
256
- } else {
259
+ } else if (matcher.hdrs) {
257
260
  data = {
258
261
  ...options?.extraFields,
259
262
  ...(matcher.hdrs ? { Headers: unpackHeaders(response.headers) } : null),
263
+ ...(isPlainObject(raw) ? raw : null),
260
264
  };
265
+ } else {
266
+ data = raw;
261
267
  }
262
268
 
263
269
  if ("err" in matcher) {
@@ -14,7 +14,6 @@ export * from "./createbasinrequest.js";
14
14
  export * from "./createstreamrequest.js";
15
15
  export * from "./formatoption.js";
16
16
  export * from "./header.js";
17
- export * from "./httpmetadata.js";
18
17
  export * from "./listbasinsresponse.js";
19
18
  export * from "./liststreamsresponse.js";
20
19
  export * from "./output.js";
@@ -3,19 +3,25 @@
3
3
  */
4
4
 
5
5
  export class APIError extends Error {
6
+ public readonly statusCode: number;
7
+ public readonly contentType: string;
8
+
6
9
  constructor(
7
10
  message: string,
8
- public readonly httpMeta: {
9
- response: Response;
10
- request: Request;
11
- },
11
+ public readonly rawResponse: Response,
12
+ public readonly body: string = "",
12
13
  ) {
14
+ const statusCode = rawResponse.status;
15
+ const contentType = rawResponse.headers.get("content-type") || "";
16
+ const bodyString = body.length > 0 ? `\n${body}` : "";
17
+
13
18
  super(
14
- `${message}: Status ${httpMeta.response.status} Content-Type ${
15
- httpMeta.response.headers.get("content-type") || ""
16
- }`,
19
+ `${message}: Status ${statusCode} Content-Type ${contentType} Body ${bodyString}`,
17
20
  );
18
21
 
22
+ this.statusCode = statusCode;
23
+ this.contentType = contentType;
24
+
19
25
  this.name = "APIError";
20
26
  }
21
27
  }
@@ -6,4 +6,5 @@ export * from "./apierror.js";
6
6
  export * from "./errorresponse.js";
7
7
  export * from "./httpclienterrors.js";
8
8
  export * from "./notfounderror.js";
9
+ export * from "./retryableerror.js";
9
10
  export * from "./sdkvalidationerror.js";
@@ -0,0 +1,69 @@
1
+ /*
2
+ * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
3
+ */
4
+
5
+ import * as z from "zod";
6
+
7
+ export type RetryableErrorData = {
8
+ error: string;
9
+ };
10
+
11
+ export class RetryableError extends Error {
12
+ error: string;
13
+
14
+ /** The original data that was passed to this error instance. */
15
+ data$: RetryableErrorData;
16
+
17
+ constructor(err: RetryableErrorData) {
18
+ const message = "message" in err && typeof err.message === "string"
19
+ ? err.message
20
+ : `API error occurred: ${JSON.stringify(err)}`;
21
+ super(message);
22
+ this.data$ = err;
23
+
24
+ this.error = err.error;
25
+
26
+ this.name = "RetryableError";
27
+ }
28
+ }
29
+
30
+ /** @internal */
31
+ export const RetryableError$inboundSchema: z.ZodType<
32
+ RetryableError,
33
+ z.ZodTypeDef,
34
+ unknown
35
+ > = z.object({
36
+ error: z.string(),
37
+ })
38
+ .transform((v) => {
39
+ return new RetryableError(v);
40
+ });
41
+
42
+ /** @internal */
43
+ export type RetryableError$Outbound = {
44
+ error: string;
45
+ };
46
+
47
+ /** @internal */
48
+ export const RetryableError$outboundSchema: z.ZodType<
49
+ RetryableError$Outbound,
50
+ z.ZodTypeDef,
51
+ RetryableError
52
+ > = z.instanceof(RetryableError)
53
+ .transform(v => v.data$)
54
+ .pipe(z.object({
55
+ error: z.string(),
56
+ }));
57
+
58
+ /**
59
+ * @internal
60
+ * @deprecated This namespace will be removed in future versions. Use schemas and types that are exported directly from this module.
61
+ */
62
+ export namespace RetryableError$ {
63
+ /** @deprecated use `RetryableError$inboundSchema` instead. */
64
+ export const inboundSchema = RetryableError$inboundSchema;
65
+ /** @deprecated use `RetryableError$outboundSchema` instead. */
66
+ export const outboundSchema = RetryableError$outboundSchema;
67
+ /** @deprecated use `RetryableError$Outbound` instead. */
68
+ export type Outbound = RetryableError$Outbound;
69
+ }