@predictorsdk/client 0.10.0 → 0.12.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.
Files changed (51) hide show
  1. package/README.md +6 -4
  2. package/dist/BaseClient.d.ts +12 -0
  3. package/dist/Client.d.ts +35 -1
  4. package/dist/Client.js +115 -1
  5. package/dist/api/client/requests/GetMarketsRequest.d.ts +1 -1
  6. package/dist/api/errors/BadGatewayError.js +1 -1
  7. package/dist/api/errors/BadRequestError.js +1 -1
  8. package/dist/api/errors/ForbiddenError.js +1 -1
  9. package/dist/api/errors/NotFoundError.js +1 -1
  10. package/dist/api/errors/PaymentRequiredError.js +1 -1
  11. package/dist/api/errors/ServiceUnavailableError.js +1 -1
  12. package/dist/api/errors/TooManyRequestsError.js +1 -1
  13. package/dist/api/errors/UnauthorizedError.js +1 -1
  14. package/dist/api/types/PaymentRequiredErrorAction.d.ts +1 -1
  15. package/dist/api/types/PaymentRequiredErrorAction.js +1 -1
  16. package/dist/api/types/PaymentRequiredErrorBody.d.ts +0 -1
  17. package/dist/api/types/Plan.d.ts +22 -0
  18. package/dist/api/types/Plan.js +2 -0
  19. package/dist/api/types/PlansResponse.d.ts +4 -0
  20. package/dist/api/types/PlansResponse.js +2 -0
  21. package/dist/api/types/index.d.ts +2 -0
  22. package/dist/api/types/index.js +2 -0
  23. package/dist/auth/BearerAuthProvider.d.ts +1 -1
  24. package/dist/core/fetcher/Fetcher.js +1 -84
  25. package/dist/core/fetcher/getResponseBody.js +11 -0
  26. package/dist/core/fetcher/makePassthroughRequest.js +26 -4
  27. package/dist/core/fetcher/redactUrl.d.ts +2 -0
  28. package/dist/core/fetcher/redactUrl.js +84 -0
  29. package/dist/core/fetcher/requestWithRetries.d.ts +1 -0
  30. package/dist/core/fetcher/requestWithRetries.js +5 -4
  31. package/dist/core/fetcher/signals.js +9 -1
  32. package/dist/core/requestBody.d.ts +12 -0
  33. package/dist/core/requestBody.js +23 -0
  34. package/dist/core/runtime/index.d.ts +1 -1
  35. package/dist/core/runtime/index.js +1 -1
  36. package/dist/core/runtime/runtime.d.ts +19 -0
  37. package/dist/core/runtime/runtime.js +71 -0
  38. package/dist/core/schemas/builders/schema-utils/JsonError.js +2 -2
  39. package/dist/core/schemas/builders/schema-utils/ParseError.js +2 -2
  40. package/dist/core/url/qs.js +2 -2
  41. package/dist/errors/PredictorSDKError.d.ts +1 -0
  42. package/dist/errors/PredictorSDKError.js +4 -1
  43. package/dist/errors/PredictorSDKTimeoutError.d.ts +2 -2
  44. package/dist/errors/PredictorSDKTimeoutError.js +7 -7
  45. package/dist/serialization/types/Plan.d.ts +22 -0
  46. package/dist/serialization/types/Plan.js +18 -0
  47. package/dist/serialization/types/PlansResponse.d.ts +10 -0
  48. package/dist/serialization/types/PlansResponse.js +6 -0
  49. package/dist/serialization/types/index.d.ts +2 -0
  50. package/dist/serialization/types/index.js +2 -0
  51. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @predictorsdk/client
2
2
 
3
- The official TypeScript/JavaScript client for the [PredictorSDK](https://predictorsdk.com) matching markets API.
3
+ The official TypeScript/JavaScript client for the [PredictorSDK](https://predictorsdk.com) prediction-market data API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -15,9 +15,11 @@ import { PredictorSDKClient } from "@predictorsdk/client";
15
15
 
16
16
  const client = new PredictorSDKClient({ token: "your-api-key" });
17
17
 
18
- const { markets } = await client.getSportsMatchingMarkets({
19
- kalshiEventTicker: "KXMLB-25-NYM-COL-2025-04-03",
20
- });
18
+ const plans = await client.getPlans();
19
+ const categories = await client.getCategories();
20
+ const markets = await client.getMarkets({ limit: 10, category: "sports" });
21
+
22
+ console.log(plans.data, categories.data, markets.data);
21
23
  ```
22
24
 
23
25
  ## Documentation
@@ -16,6 +16,11 @@ export type BaseClientOptions = {
16
16
  fetch?: typeof fetch;
17
17
  /** Configure logging for the client. */
18
18
  logging?: core.logging.LogConfig | core.logging.Logger;
19
+ /** Default options for SSE stream reconnection behavior. Has no effect on non-resumable endpoints. */
20
+ stream?: {
21
+ reconnectionEnabled?: boolean;
22
+ maxReconnectionAttempts?: number;
23
+ };
19
24
  /** Override auth. Pass false to disable, a function returning auth headers, an AuthProvider, or auth options. */
20
25
  auth?: AuthOption;
21
26
  } & BearerAuthProvider.AuthOptions;
@@ -28,8 +33,15 @@ export interface BaseRequestOptions {
28
33
  abortSignal?: AbortSignal;
29
34
  /** Additional query string parameters to include in the request. */
30
35
  queryParams?: Record<string, unknown>;
36
+ /** A dictionary containing additional parameters to spread into the request's body. */
37
+ additionalBodyParameters?: Record<string, unknown>;
31
38
  /** Additional headers to include in the request. */
32
39
  headers?: Record<string, string | core.Supplier<string | null | undefined> | null | undefined>;
40
+ /** Options for SSE stream reconnection behavior. Has no effect on non-resumable endpoints. */
41
+ stream?: {
42
+ reconnectionEnabled?: boolean;
43
+ maxReconnectionAttempts?: number;
44
+ };
33
45
  }
34
46
  export type NormalizedClientOptions<T extends BaseClientOptions = BaseClientOptions> = T & {
35
47
  logging: core.logging.Logger;
package/dist/Client.d.ts CHANGED
@@ -9,7 +9,21 @@ export declare namespace PredictorSDKClient {
9
9
  }
10
10
  export declare class PredictorSDKClient {
11
11
  protected readonly _options: NormalizedClientOptionsWithAuth<PredictorSDKClient.Options>;
12
- constructor(options: PredictorSDKClient.Options);
12
+ constructor(options?: PredictorSDKClient.Options);
13
+ /**
14
+ * Returns the machine-readable public billing catalog used by API consumers and pricing surfaces. This endpoint is intentionally unauthenticated. Stripe price IDs and all other provisioning secrets are excluded from the response.
15
+ *
16
+ * @param {PredictorSDKClient.RequestOptions} requestOptions - Request-specific configuration.
17
+ *
18
+ * @throws {@link PredictorSDK.ServiceUnavailableError}
19
+ * @throws {@link errors.PredictorSDKError}
20
+ * @throws {@link errors.PredictorSDKTimeoutError}
21
+ *
22
+ * @example
23
+ * await client.getPlans()
24
+ */
25
+ getPlans(requestOptions?: PredictorSDKClient.RequestOptions): core.HttpResponsePromise<PredictorSDK.PlansResponse>;
26
+ private __getPlans;
13
27
  /**
14
28
  * Find cross-platform market matches for sports events. When called without parameters, returns all currently matched sports markets with cursor-based pagination (default `limit=25`, max `100`). Provide a canonical event key, Kalshi event ticker, Polymarket slug, Predict market ID, or SX Bet market ID to look up a specific event — lookups return the full match immediately and skip pagination.
15
29
  *
@@ -21,7 +35,10 @@ export declare class PredictorSDKClient {
21
35
  * @throws {@link PredictorSDK.PaymentRequiredError}
22
36
  * @throws {@link PredictorSDK.ForbiddenError}
23
37
  * @throws {@link PredictorSDK.TooManyRequestsError}
38
+ * @throws {@link PredictorSDK.BadGatewayError}
24
39
  * @throws {@link PredictorSDK.ServiceUnavailableError}
40
+ * @throws {@link errors.PredictorSDKError}
41
+ * @throws {@link errors.PredictorSDKTimeoutError}
25
42
  *
26
43
  * @example
27
44
  * await client.getSportsMatchingMarkets()
@@ -39,7 +56,10 @@ export declare class PredictorSDKClient {
39
56
  * @throws {@link PredictorSDK.PaymentRequiredError}
40
57
  * @throws {@link PredictorSDK.ForbiddenError}
41
58
  * @throws {@link PredictorSDK.TooManyRequestsError}
59
+ * @throws {@link PredictorSDK.BadGatewayError}
42
60
  * @throws {@link PredictorSDK.ServiceUnavailableError}
61
+ * @throws {@link errors.PredictorSDKError}
62
+ * @throws {@link errors.PredictorSDKTimeoutError}
43
63
  *
44
64
  * @example
45
65
  * await client.getMarkets()
@@ -55,6 +75,10 @@ export declare class PredictorSDKClient {
55
75
  * @throws {@link PredictorSDK.PaymentRequiredError}
56
76
  * @throws {@link PredictorSDK.ForbiddenError}
57
77
  * @throws {@link PredictorSDK.TooManyRequestsError}
78
+ * @throws {@link PredictorSDK.BadGatewayError}
79
+ * @throws {@link PredictorSDK.ServiceUnavailableError}
80
+ * @throws {@link errors.PredictorSDKError}
81
+ * @throws {@link errors.PredictorSDKTimeoutError}
58
82
  *
59
83
  * @example
60
84
  * await client.getCategories()
@@ -79,6 +103,8 @@ export declare class PredictorSDKClient {
79
103
  * @throws {@link PredictorSDK.TooManyRequestsError}
80
104
  * @throws {@link PredictorSDK.BadGatewayError}
81
105
  * @throws {@link PredictorSDK.ServiceUnavailableError}
106
+ * @throws {@link errors.PredictorSDKError}
107
+ * @throws {@link errors.PredictorSDKTimeoutError}
82
108
  *
83
109
  * @example
84
110
  * await client.getMarket({
@@ -100,6 +126,8 @@ export declare class PredictorSDKClient {
100
126
  * @throws {@link PredictorSDK.TooManyRequestsError}
101
127
  * @throws {@link PredictorSDK.BadGatewayError}
102
128
  * @throws {@link PredictorSDK.ServiceUnavailableError}
129
+ * @throws {@link errors.PredictorSDKError}
130
+ * @throws {@link errors.PredictorSDKTimeoutError}
103
131
  *
104
132
  * @example
105
133
  * await client.getBinanceCryptoPrices({
@@ -126,6 +154,8 @@ export declare class PredictorSDKClient {
126
154
  * @throws {@link PredictorSDK.TooManyRequestsError}
127
155
  * @throws {@link PredictorSDK.BadGatewayError}
128
156
  * @throws {@link PredictorSDK.ServiceUnavailableError}
157
+ * @throws {@link errors.PredictorSDKError}
158
+ * @throws {@link errors.PredictorSDKTimeoutError}
129
159
  *
130
160
  * @example
131
161
  * await client.getPolymarketWallet({
@@ -154,6 +184,8 @@ export declare class PredictorSDKClient {
154
184
  * @throws {@link PredictorSDK.TooManyRequestsError}
155
185
  * @throws {@link PredictorSDK.BadGatewayError}
156
186
  * @throws {@link PredictorSDK.ServiceUnavailableError}
187
+ * @throws {@link errors.PredictorSDKError}
188
+ * @throws {@link errors.PredictorSDKTimeoutError}
157
189
  *
158
190
  * @example
159
191
  * await client.listPolymarketWalletPositions({
@@ -182,6 +214,8 @@ export declare class PredictorSDKClient {
182
214
  * @throws {@link PredictorSDK.TooManyRequestsError}
183
215
  * @throws {@link PredictorSDK.BadGatewayError}
184
216
  * @throws {@link PredictorSDK.ServiceUnavailableError}
217
+ * @throws {@link errors.PredictorSDKError}
218
+ * @throws {@link errors.PredictorSDKTimeoutError}
185
219
  *
186
220
  * @example
187
221
  * await client.getEvent({
package/dist/Client.js CHANGED
@@ -9,9 +9,71 @@ import * as errors from "./errors/index.js";
9
9
  import * as serializers from "./serialization/index.js";
10
10
  export class PredictorSDKClient {
11
11
  _options;
12
- constructor(options) {
12
+ constructor(options = {}) {
13
13
  this._options = normalizeClientOptionsWithAuth(options);
14
14
  }
15
+ /**
16
+ * Returns the machine-readable public billing catalog used by API consumers and pricing surfaces. This endpoint is intentionally unauthenticated. Stripe price IDs and all other provisioning secrets are excluded from the response.
17
+ *
18
+ * @param {PredictorSDKClient.RequestOptions} requestOptions - Request-specific configuration.
19
+ *
20
+ * @throws {@link PredictorSDK.ServiceUnavailableError}
21
+ * @throws {@link errors.PredictorSDKError}
22
+ * @throws {@link errors.PredictorSDKTimeoutError}
23
+ *
24
+ * @example
25
+ * await client.getPlans()
26
+ */
27
+ getPlans(requestOptions) {
28
+ return core.HttpResponsePromise.fromPromise(this.__getPlans(requestOptions));
29
+ }
30
+ async __getPlans(requestOptions) {
31
+ const _headers = mergeHeaders(this._options?.headers, requestOptions?.headers);
32
+ const _response = await core.fetcher({
33
+ url: core.url.join((await core.Supplier.get(this._options.baseUrl)) ??
34
+ (await core.Supplier.get(this._options.environment)) ??
35
+ environments.PredictorSDKEnvironment.Production, "v1/plans"),
36
+ method: "GET",
37
+ headers: _headers,
38
+ queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
39
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
40
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
41
+ abortSignal: requestOptions?.abortSignal,
42
+ fetchFn: this._options?.fetch,
43
+ logging: this._options.logging,
44
+ });
45
+ if (_response.ok) {
46
+ return {
47
+ data: serializers.PlansResponse.parseOrThrow(_response.body, {
48
+ unrecognizedObjectKeys: "passthrough",
49
+ allowUnrecognizedUnionMembers: true,
50
+ allowUnrecognizedEnumValues: true,
51
+ skipValidation: true,
52
+ breadcrumbsPrefix: ["response"],
53
+ }),
54
+ rawResponse: _response.rawResponse,
55
+ };
56
+ }
57
+ if (_response.error.reason === "status-code") {
58
+ switch (_response.error.statusCode) {
59
+ case 503:
60
+ throw new PredictorSDK.ServiceUnavailableError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
61
+ unrecognizedObjectKeys: "passthrough",
62
+ allowUnrecognizedUnionMembers: true,
63
+ allowUnrecognizedEnumValues: true,
64
+ skipValidation: true,
65
+ breadcrumbsPrefix: ["response"],
66
+ }), _response.rawResponse);
67
+ default:
68
+ throw new errors.PredictorSDKError({
69
+ statusCode: _response.error.statusCode,
70
+ body: _response.error.body,
71
+ rawResponse: _response.rawResponse,
72
+ });
73
+ }
74
+ }
75
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v1/plans");
76
+ }
15
77
  /**
16
78
  * Find cross-platform market matches for sports events. When called without parameters, returns all currently matched sports markets with cursor-based pagination (default `limit=25`, max `100`). Provide a canonical event key, Kalshi event ticker, Polymarket slug, Predict market ID, or SX Bet market ID to look up a specific event — lookups return the full match immediately and skip pagination.
17
79
  *
@@ -23,7 +85,10 @@ export class PredictorSDKClient {
23
85
  * @throws {@link PredictorSDK.PaymentRequiredError}
24
86
  * @throws {@link PredictorSDK.ForbiddenError}
25
87
  * @throws {@link PredictorSDK.TooManyRequestsError}
88
+ * @throws {@link PredictorSDK.BadGatewayError}
26
89
  * @throws {@link PredictorSDK.ServiceUnavailableError}
90
+ * @throws {@link errors.PredictorSDKError}
91
+ * @throws {@link errors.PredictorSDKTimeoutError}
27
92
  *
28
93
  * @example
29
94
  * await client.getSportsMatchingMarkets()
@@ -117,6 +182,14 @@ export class PredictorSDKClient {
117
182
  skipValidation: true,
118
183
  breadcrumbsPrefix: ["response"],
119
184
  }), _response.rawResponse);
185
+ case 502:
186
+ throw new PredictorSDK.BadGatewayError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
187
+ unrecognizedObjectKeys: "passthrough",
188
+ allowUnrecognizedUnionMembers: true,
189
+ allowUnrecognizedEnumValues: true,
190
+ skipValidation: true,
191
+ breadcrumbsPrefix: ["response"],
192
+ }), _response.rawResponse);
120
193
  case 503:
121
194
  throw new PredictorSDK.ServiceUnavailableError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
122
195
  unrecognizedObjectKeys: "passthrough",
@@ -146,7 +219,10 @@ export class PredictorSDKClient {
146
219
  * @throws {@link PredictorSDK.PaymentRequiredError}
147
220
  * @throws {@link PredictorSDK.ForbiddenError}
148
221
  * @throws {@link PredictorSDK.TooManyRequestsError}
222
+ * @throws {@link PredictorSDK.BadGatewayError}
149
223
  * @throws {@link PredictorSDK.ServiceUnavailableError}
224
+ * @throws {@link errors.PredictorSDKError}
225
+ * @throws {@link errors.PredictorSDKTimeoutError}
150
226
  *
151
227
  * @example
152
228
  * await client.getMarkets()
@@ -239,6 +315,14 @@ export class PredictorSDKClient {
239
315
  skipValidation: true,
240
316
  breadcrumbsPrefix: ["response"],
241
317
  }), _response.rawResponse);
318
+ case 502:
319
+ throw new PredictorSDK.BadGatewayError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
320
+ unrecognizedObjectKeys: "passthrough",
321
+ allowUnrecognizedUnionMembers: true,
322
+ allowUnrecognizedEnumValues: true,
323
+ skipValidation: true,
324
+ breadcrumbsPrefix: ["response"],
325
+ }), _response.rawResponse);
242
326
  case 503:
243
327
  throw new PredictorSDK.ServiceUnavailableError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
244
328
  unrecognizedObjectKeys: "passthrough",
@@ -266,6 +350,10 @@ export class PredictorSDKClient {
266
350
  * @throws {@link PredictorSDK.PaymentRequiredError}
267
351
  * @throws {@link PredictorSDK.ForbiddenError}
268
352
  * @throws {@link PredictorSDK.TooManyRequestsError}
353
+ * @throws {@link PredictorSDK.BadGatewayError}
354
+ * @throws {@link PredictorSDK.ServiceUnavailableError}
355
+ * @throws {@link errors.PredictorSDKError}
356
+ * @throws {@link errors.PredictorSDKTimeoutError}
269
357
  *
270
358
  * @example
271
359
  * await client.getCategories()
@@ -335,6 +423,22 @@ export class PredictorSDKClient {
335
423
  skipValidation: true,
336
424
  breadcrumbsPrefix: ["response"],
337
425
  }), _response.rawResponse);
426
+ case 502:
427
+ throw new PredictorSDK.BadGatewayError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
428
+ unrecognizedObjectKeys: "passthrough",
429
+ allowUnrecognizedUnionMembers: true,
430
+ allowUnrecognizedEnumValues: true,
431
+ skipValidation: true,
432
+ breadcrumbsPrefix: ["response"],
433
+ }), _response.rawResponse);
434
+ case 503:
435
+ throw new PredictorSDK.ServiceUnavailableError(serializers.ErrorResponse.parseOrThrow(_response.error.body, {
436
+ unrecognizedObjectKeys: "passthrough",
437
+ allowUnrecognizedUnionMembers: true,
438
+ allowUnrecognizedEnumValues: true,
439
+ skipValidation: true,
440
+ breadcrumbsPrefix: ["response"],
441
+ }), _response.rawResponse);
338
442
  default:
339
443
  throw new errors.PredictorSDKError({
340
444
  statusCode: _response.error.statusCode,
@@ -363,6 +467,8 @@ export class PredictorSDKClient {
363
467
  * @throws {@link PredictorSDK.TooManyRequestsError}
364
468
  * @throws {@link PredictorSDK.BadGatewayError}
365
469
  * @throws {@link PredictorSDK.ServiceUnavailableError}
470
+ * @throws {@link errors.PredictorSDKError}
471
+ * @throws {@link errors.PredictorSDKTimeoutError}
366
472
  *
367
473
  * @example
368
474
  * await client.getMarket({
@@ -502,6 +608,8 @@ export class PredictorSDKClient {
502
608
  * @throws {@link PredictorSDK.TooManyRequestsError}
503
609
  * @throws {@link PredictorSDK.BadGatewayError}
504
610
  * @throws {@link PredictorSDK.ServiceUnavailableError}
611
+ * @throws {@link errors.PredictorSDKError}
612
+ * @throws {@link errors.PredictorSDKTimeoutError}
505
613
  *
506
614
  * @example
507
615
  * await client.getBinanceCryptoPrices({
@@ -637,6 +745,8 @@ export class PredictorSDKClient {
637
745
  * @throws {@link PredictorSDK.TooManyRequestsError}
638
746
  * @throws {@link PredictorSDK.BadGatewayError}
639
747
  * @throws {@link PredictorSDK.ServiceUnavailableError}
748
+ * @throws {@link errors.PredictorSDKError}
749
+ * @throws {@link errors.PredictorSDKTimeoutError}
640
750
  *
641
751
  * @example
642
752
  * await client.getPolymarketWallet({
@@ -779,6 +889,8 @@ export class PredictorSDKClient {
779
889
  * @throws {@link PredictorSDK.TooManyRequestsError}
780
890
  * @throws {@link PredictorSDK.BadGatewayError}
781
891
  * @throws {@link PredictorSDK.ServiceUnavailableError}
892
+ * @throws {@link errors.PredictorSDKError}
893
+ * @throws {@link errors.PredictorSDKTimeoutError}
782
894
  *
783
895
  * @example
784
896
  * await client.listPolymarketWalletPositions({
@@ -923,6 +1035,8 @@ export class PredictorSDKClient {
923
1035
  * @throws {@link PredictorSDK.TooManyRequestsError}
924
1036
  * @throws {@link PredictorSDK.BadGatewayError}
925
1037
  * @throws {@link PredictorSDK.ServiceUnavailableError}
1038
+ * @throws {@link errors.PredictorSDKError}
1039
+ * @throws {@link errors.PredictorSDKTimeoutError}
926
1040
  *
927
1041
  * @example
928
1042
  * await client.getEvent({
@@ -6,7 +6,7 @@ import type * as PredictorSDK from "../../index.js";
6
6
  export interface GetMarketsRequest {
7
7
  /** Maximum number of markets to return per page. Range 1–100, default 25. */
8
8
  limit?: number;
9
- /** Opaque cursor from a previous response's `pagination.nextCursor` in the SDKs (raw JSON: `pagination.next_cursor`). */
9
+ /** Opaque cursor from a previous response's `pagination.nextCursor` in the SDKs (raw JSON: `pagination.next_cursor`). Market cursors stay bound to the immutable catalog snapshot that issued them. Replaced snapshots normally remain available for up to 24 hours, but storage pressure can evict a retained snapshot sooner; retry from the first page after a stale-cursor `400`. */
10
10
  cursor?: string;
11
11
  /** Canonical top-level category filter. This is PredictorSDK's normalized category, not a provider-native tag. Cursors are bound to the category filter used to create them. */
12
12
  category?: PredictorSDK.MarketCategory;
@@ -12,6 +12,6 @@ export class BadGatewayError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "BadGatewayError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class BadRequestError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "BadRequestError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class ForbiddenError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "ForbiddenError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class NotFoundError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "NotFoundError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class PaymentRequiredError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "PaymentRequiredError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class ServiceUnavailableError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "ServiceUnavailableError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class TooManyRequestsError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "TooManyRequestsError";
16
16
  }
17
17
  }
@@ -12,6 +12,6 @@ export class UnauthorizedError extends errors.PredictorSDKError {
12
12
  if (Error.captureStackTrace) {
13
13
  Error.captureStackTrace(this, this.constructor);
14
14
  }
15
- this.name = this.constructor.name;
15
+ this.name = "UnauthorizedError";
16
16
  }
17
17
  }
@@ -1,4 +1,4 @@
1
- /** Recommended client action for this 402. */
1
+ /** Recommended client action for an HTTP 402 response. */
2
2
  export declare const PaymentRequiredErrorAction: {
3
3
  readonly UpgradePlan: "upgrade_plan";
4
4
  readonly ResolvePayment: "resolve_payment";
@@ -1,5 +1,5 @@
1
1
  // This file was auto-generated by Fern from our API Definition.
2
- /** Recommended client action for this 402. */
2
+ /** Recommended client action for an HTTP 402 response. */
3
3
  export const PaymentRequiredErrorAction = {
4
4
  UpgradePlan: "upgrade_plan",
5
5
  ResolvePayment: "resolve_payment",
@@ -7,7 +7,6 @@ export interface PaymentRequiredErrorBody {
7
7
  /** Additional detail about the error. */
8
8
  message?: string;
9
9
  statusCode: number;
10
- /** Recommended client action for this 402. */
11
10
  action: PredictorSDK.PaymentRequiredErrorAction;
12
11
  /** Billing tier that would satisfy the gate (e.g. `starter`, `pro`, `business`, `enterprise`). */
13
12
  requiredTier: string;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Public plan metadata. Stripe price IDs and legacy provisioning IDs are intentionally absent.
3
+ */
4
+ export interface Plan {
5
+ /** Stable public plan key. */
6
+ key: string;
7
+ name: string;
8
+ /** Runtime entitlement tier; empty for a manually provisioned contact-sales plan. */
9
+ billingTier: string;
10
+ trialDays: number;
11
+ tagline: string;
12
+ /** Monthly display price in US cents; zero for free or contact-sales plans. */
13
+ monthlyPriceCents: number;
14
+ includedRequestsPerMonth: number;
15
+ overageCentsPer1K: number;
16
+ rateLimitPerMin: number;
17
+ maxKeys: number;
18
+ features: string[];
19
+ ctaLabel: string;
20
+ highlighted: boolean;
21
+ contactSales: boolean;
22
+ }
@@ -0,0 +1,2 @@
1
+ // This file was auto-generated by Fern from our API Definition.
2
+ export {};
@@ -0,0 +1,4 @@
1
+ import type * as PredictorSDK from "../index.js";
2
+ export interface PlansResponse {
3
+ data: PredictorSDK.Plan[];
4
+ }
@@ -0,0 +1,2 @@
1
+ // This file was auto-generated by Fern from our API Definition.
2
+ export {};
@@ -31,6 +31,8 @@ export * from "./MarketsListResponse.js";
31
31
  export * from "./PaginationBlock.js";
32
32
  export * from "./PaymentRequiredErrorAction.js";
33
33
  export * from "./PaymentRequiredErrorBody.js";
34
+ export * from "./Plan.js";
35
+ export * from "./PlansResponse.js";
34
36
  export * from "./PlatformMarket.js";
35
37
  export * from "./PlatformMarketPlatform.js";
36
38
  export * from "./PolymarketPosition.js";
@@ -31,6 +31,8 @@ export * from "./MarketsListResponse.js";
31
31
  export * from "./PaginationBlock.js";
32
32
  export * from "./PaymentRequiredErrorAction.js";
33
33
  export * from "./PaymentRequiredErrorBody.js";
34
+ export * from "./Plan.js";
35
+ export * from "./PlansResponse.js";
34
36
  export * from "./PlatformMarket.js";
35
37
  export * from "./PlatformMarketPlatform.js";
36
38
  export * from "./PolymarketPosition.js";
@@ -13,7 +13,7 @@ export declare namespace BearerAuthProvider {
13
13
  const AUTH_CONFIG_ERROR_MESSAGE: string;
14
14
  type Options = AuthOptions;
15
15
  type AuthOptions = {
16
- [TOKEN_PARAM]: core.Supplier<core.BearerToken>;
16
+ [TOKEN_PARAM]?: core.Supplier<core.BearerToken>;
17
17
  };
18
18
  function createInstance(options: Options): core.AuthProvider;
19
19
  }
@@ -9,6 +9,7 @@ import { getResponseBody } from "./getResponseBody.js";
9
9
  import { Headers } from "./Headers.js";
10
10
  import { makeRequest } from "./makeRequest.js";
11
11
  import { abortRawResponse, toRawResponse, unknownRawResponse } from "./RawResponse.js";
12
+ import { redactUrl, SENSITIVE_QUERY_PARAMS } from "./redactUrl.js";
12
13
  import { requestWithRetries } from "./requestWithRetries.js";
13
14
  const SENSITIVE_HEADERS = new Set([
14
15
  "authorization",
@@ -40,26 +41,6 @@ function redactHeaders(headers) {
40
41
  }
41
42
  return filtered;
42
43
  }
43
- const SENSITIVE_QUERY_PARAMS = new Set([
44
- "api_key",
45
- "api-key",
46
- "apikey",
47
- "token",
48
- "access_token",
49
- "access-token",
50
- "auth_token",
51
- "auth-token",
52
- "password",
53
- "passwd",
54
- "secret",
55
- "api_secret",
56
- "api-secret",
57
- "apisecret",
58
- "key",
59
- "session",
60
- "session_id",
61
- "session-id",
62
- ]);
63
44
  function redactQueryParameters(queryParameters) {
64
45
  if (queryParameters == null) {
65
46
  return undefined;
@@ -70,70 +51,6 @@ function redactQueryParameters(queryParameters) {
70
51
  }
71
52
  return redacted;
72
53
  }
73
- function redactUrl(url) {
74
- const protocolIndex = url.indexOf("://");
75
- if (protocolIndex === -1)
76
- return url;
77
- const afterProtocol = protocolIndex + 3;
78
- // Find the first delimiter that marks the end of the authority section
79
- const pathStart = url.indexOf("/", afterProtocol);
80
- let queryStart = url.indexOf("?", afterProtocol);
81
- let fragmentStart = url.indexOf("#", afterProtocol);
82
- const firstDelimiter = Math.min(pathStart === -1 ? url.length : pathStart, queryStart === -1 ? url.length : queryStart, fragmentStart === -1 ? url.length : fragmentStart);
83
- // Find the LAST @ before the delimiter (handles multiple @ in credentials)
84
- let atIndex = -1;
85
- for (let i = afterProtocol; i < firstDelimiter; i++) {
86
- if (url[i] === "@") {
87
- atIndex = i;
88
- }
89
- }
90
- if (atIndex !== -1) {
91
- url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`;
92
- }
93
- // Recalculate queryStart since url might have changed
94
- queryStart = url.indexOf("?");
95
- if (queryStart === -1)
96
- return url;
97
- fragmentStart = url.indexOf("#", queryStart);
98
- const queryEnd = fragmentStart !== -1 ? fragmentStart : url.length;
99
- const queryString = url.slice(queryStart + 1, queryEnd);
100
- if (queryString.length === 0)
101
- return url;
102
- // FAST PATH: Quick check if any sensitive keywords present
103
- // Using indexOf is faster than regex for simple substring matching
104
- const lower = queryString.toLowerCase();
105
- const hasSensitive = lower.includes("token") ||
106
- lower.includes("key") ||
107
- lower.includes("password") ||
108
- lower.includes("passwd") ||
109
- lower.includes("secret") ||
110
- lower.includes("session") ||
111
- lower.includes("auth");
112
- if (!hasSensitive) {
113
- return url;
114
- }
115
- // SLOW PATH: Parse and redact
116
- const redactedParams = [];
117
- const params = queryString.split("&");
118
- for (const param of params) {
119
- const equalIndex = param.indexOf("=");
120
- if (equalIndex === -1) {
121
- redactedParams.push(param);
122
- continue;
123
- }
124
- const key = param.slice(0, equalIndex);
125
- let shouldRedact = SENSITIVE_QUERY_PARAMS.has(key.toLowerCase());
126
- if (!shouldRedact && key.includes("%")) {
127
- try {
128
- const decodedKey = decodeURIComponent(key);
129
- shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase());
130
- }
131
- catch { }
132
- }
133
- redactedParams.push(shouldRedact ? `${key}=[REDACTED]` : param);
134
- }
135
- return url.slice(0, queryStart + 1) + redactedParams.join("&") + url.slice(queryEnd);
136
- }
137
54
  async function getHeaders(args) {
138
55
  const newHeaders = new Headers();
139
56
  newHeaders.set("Accept", args.responseType === "json"
@@ -1,5 +1,14 @@
1
1
  import { fromJson } from "../json.js";
2
2
  import { getBinaryResponse } from "./BinaryResponse.js";
3
+ // Pins the upstream Response so undici's FinalizationRegistry can't GC it and cancel the body stream.
4
+ function retainResponse(target, response) {
5
+ Object.defineProperty(target, "__fern_response_ref", {
6
+ value: response,
7
+ enumerable: false,
8
+ configurable: true,
9
+ writable: false,
10
+ });
11
+ }
3
12
  export async function getResponseBody(response, responseType) {
4
13
  switch (responseType) {
5
14
  case "binary-response":
@@ -18,6 +27,7 @@ export async function getResponseBody(response, responseType) {
18
27
  },
19
28
  };
20
29
  }
30
+ retainResponse(response.body, response);
21
31
  return response.body;
22
32
  case "streaming":
23
33
  if (response.body == null) {
@@ -29,6 +39,7 @@ export async function getResponseBody(response, responseType) {
29
39
  },
30
40
  };
31
41
  }
42
+ retainResponse(response.body, response);
32
43
  return response.body;
33
44
  case "text":
34
45
  return await response.text();
@@ -3,6 +3,7 @@ import { join } from "../url/join.js";
3
3
  import { EndpointSupplier } from "./EndpointSupplier.js";
4
4
  import { getFetchFn } from "./getFetchFn.js";
5
5
  import { makeRequest } from "./makeRequest.js";
6
+ import { redactUrl } from "./redactUrl.js";
6
7
  import { requestWithRetries } from "./requestWithRetries.js";
7
8
  import { Supplier } from "./Supplier.js";
8
9
  /**
@@ -66,8 +67,10 @@ export async function makePassthroughRequest(input, init, clientOptions, request
66
67
  }
67
68
  }
68
69
  }
69
- // Apply auth headers
70
- if (clientOptions.getAuthHeaders != null) {
70
+ // Apply auth headers, but only when the resolved URL targets the configured base URL.
71
+ // This prevents the SDK's credentials from leaking to an unrelated host when a caller
72
+ // passes an absolute cross-origin URL into the passthrough fetch escape hatch.
73
+ if (clientOptions.getAuthHeaders != null && targetsBaseUrl(fullUrl, baseUrl)) {
71
74
  const authHeaders = await clientOptions.getAuthHeaders();
72
75
  for (const [key, value] of Object.entries(authHeaders)) {
73
76
  mergedHeaders[key.toLowerCase()] = value;
@@ -102,7 +105,7 @@ export async function makePassthroughRequest(input, init, clientOptions, request
102
105
  if (logger.isDebug()) {
103
106
  logger.debug("Making passthrough HTTP request", {
104
107
  method,
105
- url: fullUrl,
108
+ url: redactUrl(fullUrl),
106
109
  hasBody: body != null,
107
110
  });
108
111
  }
@@ -111,9 +114,28 @@ export async function makePassthroughRequest(input, init, clientOptions, request
111
114
  if (logger.isDebug()) {
112
115
  logger.debug("Passthrough HTTP request completed", {
113
116
  method,
114
- url: fullUrl,
117
+ url: redactUrl(fullUrl),
115
118
  statusCode: response.status,
116
119
  });
117
120
  }
118
121
  return response;
119
122
  }
123
+ /**
124
+ * Returns true when the resolved request URL points at the same origin as the
125
+ * configured base URL. Relative paths are always joined onto the base URL, so
126
+ * they resolve to the base origin and return true. Absolute URLs only match when
127
+ * their origin equals the base origin. When there is no base URL to compare
128
+ * against, or either value is not a parseable absolute URL, this returns false so
129
+ * auth headers are not attached.
130
+ */
131
+ function targetsBaseUrl(fullUrl, baseUrl) {
132
+ if (baseUrl == null) {
133
+ return false;
134
+ }
135
+ try {
136
+ return new URL(fullUrl).origin === new URL(baseUrl).origin;
137
+ }
138
+ catch {
139
+ return false;
140
+ }
141
+ }
@@ -0,0 +1,2 @@
1
+ export declare const SENSITIVE_QUERY_PARAMS: Set<string>;
2
+ export declare function redactUrl(url: string): string;
@@ -0,0 +1,84 @@
1
+ export const SENSITIVE_QUERY_PARAMS = new Set([
2
+ "api_key",
3
+ "api-key",
4
+ "apikey",
5
+ "token",
6
+ "access_token",
7
+ "access-token",
8
+ "auth_token",
9
+ "auth-token",
10
+ "password",
11
+ "passwd",
12
+ "secret",
13
+ "api_secret",
14
+ "api-secret",
15
+ "apisecret",
16
+ "key",
17
+ "session",
18
+ "session_id",
19
+ "session-id",
20
+ ]);
21
+ export function redactUrl(url) {
22
+ const protocolIndex = url.indexOf("://");
23
+ if (protocolIndex === -1)
24
+ return url;
25
+ const afterProtocol = protocolIndex + 3;
26
+ // Find the first delimiter that marks the end of the authority section
27
+ const pathStart = url.indexOf("/", afterProtocol);
28
+ let queryStart = url.indexOf("?", afterProtocol);
29
+ let fragmentStart = url.indexOf("#", afterProtocol);
30
+ const firstDelimiter = Math.min(pathStart === -1 ? url.length : pathStart, queryStart === -1 ? url.length : queryStart, fragmentStart === -1 ? url.length : fragmentStart);
31
+ // Find the LAST @ before the delimiter (handles multiple @ in credentials)
32
+ let atIndex = -1;
33
+ for (let i = afterProtocol; i < firstDelimiter; i++) {
34
+ if (url[i] === "@") {
35
+ atIndex = i;
36
+ }
37
+ }
38
+ if (atIndex !== -1) {
39
+ url = `${url.slice(0, afterProtocol)}[REDACTED]@${url.slice(atIndex + 1)}`;
40
+ }
41
+ // Recalculate queryStart since url might have changed
42
+ queryStart = url.indexOf("?");
43
+ if (queryStart === -1)
44
+ return url;
45
+ fragmentStart = url.indexOf("#", queryStart);
46
+ const queryEnd = fragmentStart !== -1 ? fragmentStart : url.length;
47
+ const queryString = url.slice(queryStart + 1, queryEnd);
48
+ if (queryString.length === 0)
49
+ return url;
50
+ // FAST PATH: Quick check if any sensitive keywords present
51
+ // Using indexOf is faster than regex for simple substring matching
52
+ const lower = queryString.toLowerCase();
53
+ const hasSensitive = lower.includes("token") ||
54
+ lower.includes("key") ||
55
+ lower.includes("password") ||
56
+ lower.includes("passwd") ||
57
+ lower.includes("secret") ||
58
+ lower.includes("session") ||
59
+ lower.includes("auth");
60
+ if (!hasSensitive) {
61
+ return url;
62
+ }
63
+ // SLOW PATH: Parse and redact
64
+ const redactedParams = [];
65
+ const params = queryString.split("&");
66
+ for (const param of params) {
67
+ const equalIndex = param.indexOf("=");
68
+ if (equalIndex === -1) {
69
+ redactedParams.push(param);
70
+ continue;
71
+ }
72
+ const key = param.slice(0, equalIndex);
73
+ let shouldRedact = SENSITIVE_QUERY_PARAMS.has(key.toLowerCase());
74
+ if (!shouldRedact && key.includes("%")) {
75
+ try {
76
+ const decodedKey = decodeURIComponent(key);
77
+ shouldRedact = SENSITIVE_QUERY_PARAMS.has(decodedKey.toLowerCase());
78
+ }
79
+ catch { }
80
+ }
81
+ redactedParams.push(shouldRedact ? `${key}=[REDACTED]` : param);
82
+ }
83
+ return url.slice(0, queryStart + 1) + redactedParams.join("&") + url.slice(queryEnd);
84
+ }
@@ -1 +1,2 @@
1
+ export declare function getRetryDelayFromHeaders(response: Response, retryAttempt: number): number;
1
2
  export declare function requestWithRetries(requestFn: () => Promise<Response>, maxRetries?: number): Promise<Response>;
@@ -13,7 +13,7 @@ function addSymmetricJitter(delay) {
13
13
  const jitterMultiplier = 1 + (Math.random() - 0.5) * JITTER_FACTOR;
14
14
  return delay * jitterMultiplier;
15
15
  }
16
- function getRetryDelayFromHeaders(response, retryAttempt) {
16
+ export function getRetryDelayFromHeaders(response, retryAttempt) {
17
17
  const retryAfter = response.headers.get("Retry-After");
18
18
  if (retryAfter) {
19
19
  const retryAfterSeconds = parseInt(retryAfter, 10);
@@ -32,13 +32,14 @@ function getRetryDelayFromHeaders(response, retryAttempt) {
32
32
  if (rateLimitReset) {
33
33
  const resetTime = parseInt(rateLimitReset, 10);
34
34
  if (!Number.isNaN(resetTime)) {
35
- const delay = resetTime * 1000 - Date.now();
35
+ const resetTimeMilliseconds = resetTime >= 1_000_000_000_000 ? resetTime : resetTime * 1000;
36
+ const delay = resetTimeMilliseconds - Date.now();
36
37
  if (delay > 0) {
37
- return addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY));
38
+ return Math.min(addPositiveJitter(Math.min(delay, MAX_RETRY_DELAY)), MAX_RETRY_DELAY);
38
39
  }
39
40
  }
40
41
  }
41
- return addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * 2 ** retryAttempt, MAX_RETRY_DELAY));
42
+ return Math.min(addSymmetricJitter(Math.min(INITIAL_RETRY_DELAY * 2 ** retryAttempt, MAX_RETRY_DELAY)), MAX_RETRY_DELAY);
42
43
  }
43
44
  export async function requestWithRetries(requestFn, maxRetries = DEFAULT_MAX_RETRIES) {
44
45
  let response = await requestFn();
@@ -10,11 +10,19 @@ export function anySignal(...args) {
10
10
  for (const signal of signals) {
11
11
  if (signal.aborted) {
12
12
  controller.abort(signal?.reason);
13
- break;
13
+ return controller.signal;
14
14
  }
15
15
  signal.addEventListener("abort", () => controller.abort(signal?.reason), {
16
16
  signal: controller.signal,
17
17
  });
18
+ // Re-check after adding listener: the signal may have aborted
19
+ // between the initial `signal.aborted` check and the `addEventListener`
20
+ // call above. If it did, the abort event was already dispatched and
21
+ // the listener will never fire — we must manually abort.
22
+ if (signal.aborted) {
23
+ controller.abort(signal?.reason);
24
+ return controller.signal;
25
+ }
18
26
  }
19
27
  return controller.signal;
20
28
  }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Spreads caller-supplied `additionalBodyParameters` (from `requestOptions.additionalBodyParameters`)
3
+ * on top of the request body. Caller-supplied properties win over the endpoint body. When no
4
+ * additional body parameters are provided, the original body is returned unchanged so serialization
5
+ * is unaffected.
6
+ *
7
+ * The merge only applies to plain-object (JSON object) bodies. When the body is `null`/`undefined`
8
+ * the additional parameters become the body; when the body is an array or a primitive JSON value it
9
+ * is returned unchanged, since object properties cannot be spread into it. This mirrors the Python
10
+ * SDK, which only merges additional body parameters into mapping bodies.
11
+ */
12
+ export declare function mergeAdditionalBodyParameters(body: unknown, additionalBodyParameters: Record<string, unknown> | undefined): unknown;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Spreads caller-supplied `additionalBodyParameters` (from `requestOptions.additionalBodyParameters`)
3
+ * on top of the request body. Caller-supplied properties win over the endpoint body. When no
4
+ * additional body parameters are provided, the original body is returned unchanged so serialization
5
+ * is unaffected.
6
+ *
7
+ * The merge only applies to plain-object (JSON object) bodies. When the body is `null`/`undefined`
8
+ * the additional parameters become the body; when the body is an array or a primitive JSON value it
9
+ * is returned unchanged, since object properties cannot be spread into it. This mirrors the Python
10
+ * SDK, which only merges additional body parameters into mapping bodies.
11
+ */
12
+ export function mergeAdditionalBodyParameters(body, additionalBodyParameters) {
13
+ if (additionalBodyParameters == null) {
14
+ return body;
15
+ }
16
+ if (body == null) {
17
+ return { ...additionalBodyParameters };
18
+ }
19
+ if (typeof body === "object" && !Array.isArray(body)) {
20
+ return { ...body, ...additionalBodyParameters };
21
+ }
22
+ return body;
23
+ }
@@ -1 +1 @@
1
- export { RUNTIME } from "./runtime.js";
1
+ export { getUserAgent, RUNTIME } from "./runtime.js";
@@ -1 +1 @@
1
- export { RUNTIME } from "./runtime.js";
1
+ export { getUserAgent, RUNTIME } from "./runtime.js";
@@ -6,4 +6,23 @@ export interface Runtime {
6
6
  type: "browser" | "web-worker" | "deno" | "bun" | "node" | "react-native" | "unknown" | "workerd" | "edge-runtime";
7
7
  version?: string;
8
8
  parsedVersion?: number;
9
+ /**
10
+ * The operating system the SDK is running on, when it can be determined
11
+ * (e.g. "linux", "darwin", "win32" on server runtimes). Undefined in
12
+ * environments where the OS is not observable (e.g. browsers).
13
+ */
14
+ os?: string;
15
+ /**
16
+ * The CPU architecture the SDK is running on, when it can be determined
17
+ * (e.g. "x64", "arm64" on server runtimes). Undefined in environments where
18
+ * the architecture is not observable (e.g. browsers).
19
+ */
20
+ arch?: string;
9
21
  }
22
+ /**
23
+ * Builds a structured User-Agent string of the form
24
+ * `{sdkName}/{sdkVersion} ({os}; {arch}) {runtime}/{runtimeVersion}`
25
+ * where the platform group and runtime segment are omitted gracefully when the
26
+ * underlying values cannot be determined (e.g. in a browser).
27
+ */
28
+ export declare function getUserAgent(sdkName: string, sdkVersion: string): string;
@@ -55,6 +55,8 @@ function evaluateRuntime() {
55
55
  return {
56
56
  type: "deno",
57
57
  version: Deno.version.deno,
58
+ os: Deno.build?.os,
59
+ arch: Deno.build?.arch,
58
60
  };
59
61
  }
60
62
  /**
@@ -65,6 +67,8 @@ function evaluateRuntime() {
65
67
  return {
66
68
  type: "bun",
67
69
  version: Bun.version,
70
+ os: typeof process !== "undefined" ? process.platform : undefined,
71
+ arch: typeof process !== "undefined" ? process.arch : undefined,
68
72
  };
69
73
  }
70
74
  /**
@@ -92,9 +96,76 @@ function evaluateRuntime() {
92
96
  type: "node",
93
97
  version: _process.versions.node,
94
98
  parsedVersion: Number(_process.versions.node.split(".")[0]),
99
+ os: _process.platform,
100
+ arch: _process.arch,
95
101
  };
96
102
  }
97
103
  return {
98
104
  type: "unknown",
99
105
  };
100
106
  }
107
+ /**
108
+ * Display names for the language runtimes whose version is meaningful to encode
109
+ * in a User-Agent. Environments where a version string is not useful (e.g.
110
+ * browsers, where `version` is the full navigator UA) are intentionally mapped
111
+ * to `undefined` so they are omitted from the User-Agent.
112
+ */
113
+ const RUNTIME_DISPLAY_NAMES = {
114
+ node: "Node",
115
+ deno: "Deno",
116
+ bun: "Bun",
117
+ browser: undefined,
118
+ "web-worker": undefined,
119
+ "react-native": undefined,
120
+ workerd: undefined,
121
+ "edge-runtime": undefined,
122
+ unknown: undefined,
123
+ };
124
+ /**
125
+ * CPU architecture aliases that all refer to 64-bit x86. They are normalized to
126
+ * the single canonical token `x86_64` so the User-Agent architecture label is
127
+ * consistent regardless of which runtime reports it (Node reports `x64`, others
128
+ * report `amd64` or `x86_64`).
129
+ */
130
+ const X86_64_ARCH_ALIASES = new Set(["x64", "amd64", "x86_64"]);
131
+ /**
132
+ * Normalizes a CPU architecture token, collapsing the 64-bit x86 aliases
133
+ * (`x64`, `amd64`, `x86_64`) to `x86_64`. Other architectures are returned
134
+ * unchanged.
135
+ */
136
+ function normalizeArch(arch) {
137
+ if (arch == null) {
138
+ return arch;
139
+ }
140
+ return X86_64_ARCH_ALIASES.has(arch.toLowerCase()) ? "x86_64" : arch;
141
+ }
142
+ /**
143
+ * Percent-encodes the `@` and `/` characters in an npm package name so the
144
+ * User-Agent product token stays within the RFC 7230 token grammar. The
145
+ * original scoped package name can be recovered by URL-decoding (e.g.
146
+ * `@dummy/sdk` becomes `%40dummy%2Fsdk`).
147
+ */
148
+ function encodeProductName(sdkName) {
149
+ return sdkName.replace(/@/g, "%40").replace(/\//g, "%2F");
150
+ }
151
+ /**
152
+ * Builds a structured User-Agent string of the form
153
+ * `{sdkName}/{sdkVersion} ({os}; {arch}) {runtime}/{runtimeVersion}`
154
+ * where the platform group and runtime segment are omitted gracefully when the
155
+ * underlying values cannot be determined (e.g. in a browser).
156
+ */
157
+ export function getUserAgent(sdkName, sdkVersion) {
158
+ let userAgent = `${encodeProductName(sdkName)}/${sdkVersion}`;
159
+ const platform = [RUNTIME.os, normalizeArch(RUNTIME.arch)].filter((part) => part != null && part.length > 0);
160
+ if (platform.length > 0) {
161
+ userAgent += ` (${platform.join("; ")})`;
162
+ }
163
+ const runtimeName = RUNTIME_DISPLAY_NAMES[RUNTIME.type];
164
+ if (runtimeName != null) {
165
+ userAgent += ` ${runtimeName}`;
166
+ if (RUNTIME.version != null && RUNTIME.version.length > 0) {
167
+ userAgent += `/${RUNTIME.version}`;
168
+ }
169
+ }
170
+ return userAgent;
171
+ }
@@ -4,7 +4,7 @@ export class JsonError extends Error {
4
4
  constructor(errors) {
5
5
  super(errors.map(stringifyValidationError).join("; "));
6
6
  this.errors = errors;
7
- Object.setPrototypeOf(this, new.target.prototype);
8
- this.name = this.constructor.name;
7
+ Object.setPrototypeOf(this, JsonError.prototype);
8
+ this.name = "JsonError";
9
9
  }
10
10
  }
@@ -4,7 +4,7 @@ export class ParseError extends Error {
4
4
  constructor(errors) {
5
5
  super(errors.map(stringifyValidationError).join("; "));
6
6
  this.errors = errors;
7
- Object.setPrototypeOf(this, new.target.prototype);
8
- this.name = this.constructor.name;
7
+ Object.setPrototypeOf(this, ParseError.prototype);
8
+ this.name = "ParseError";
9
9
  }
10
10
  }
@@ -16,7 +16,7 @@ function stringifyObject(obj, prefix = "", options) {
16
16
  const parts = [];
17
17
  for (const [key, value] of Object.entries(obj)) {
18
18
  const fullKey = prefix ? `${prefix}[${key}]` : key;
19
- if (value === undefined) {
19
+ if (value == null) {
20
20
  continue;
21
21
  }
22
22
  if (Array.isArray(value)) {
@@ -36,7 +36,7 @@ function stringifyObject(obj, prefix = "", options) {
36
36
  else {
37
37
  for (let i = 0; i < value.length; i++) {
38
38
  const item = value[i];
39
- if (item === undefined) {
39
+ if (item == null) {
40
40
  continue;
41
41
  }
42
42
  if (typeof item === "object" && !Array.isArray(item) && item !== null) {
@@ -11,4 +11,5 @@ export declare class PredictorSDKError extends Error {
11
11
  rawResponse?: core.RawResponse;
12
12
  cause?: unknown;
13
13
  });
14
+ get requestId(): string | undefined;
14
15
  }
@@ -11,7 +11,7 @@ export class PredictorSDKError extends Error {
11
11
  if (Error.captureStackTrace) {
12
12
  Error.captureStackTrace(this, this.constructor);
13
13
  }
14
- this.name = this.constructor.name;
14
+ this.name = "PredictorSDKError";
15
15
  this.statusCode = statusCode;
16
16
  this.body = body;
17
17
  this.rawResponse = rawResponse;
@@ -19,6 +19,9 @@ export class PredictorSDKError extends Error {
19
19
  this.cause = cause;
20
20
  }
21
21
  }
22
+ get requestId() {
23
+ return this.rawResponse?.headers?.get("x-request-id") ?? undefined;
24
+ }
22
25
  }
23
26
  function buildMessage({ message, statusCode, body, }) {
24
27
  const lines = [];
@@ -1,5 +1,5 @@
1
- export declare class PredictorSDKTimeoutError extends Error {
2
- readonly cause?: unknown;
1
+ import * as errors from "./index.js";
2
+ export declare class PredictorSDKTimeoutError extends errors.PredictorSDKError {
3
3
  constructor(message: string, opts?: {
4
4
  cause?: unknown;
5
5
  });
@@ -1,15 +1,15 @@
1
1
  // This file was auto-generated by Fern from our API Definition.
2
- export class PredictorSDKTimeoutError extends Error {
3
- cause;
2
+ import * as errors from "./index.js";
3
+ export class PredictorSDKTimeoutError extends errors.PredictorSDKError {
4
4
  constructor(message, opts) {
5
- super(message);
5
+ super({
6
+ message: message,
7
+ cause: opts?.cause,
8
+ });
6
9
  Object.setPrototypeOf(this, new.target.prototype);
7
10
  if (Error.captureStackTrace) {
8
11
  Error.captureStackTrace(this, this.constructor);
9
12
  }
10
- this.name = this.constructor.name;
11
- if (opts?.cause != null) {
12
- this.cause = opts.cause;
13
- }
13
+ this.name = "PredictorSDKTimeoutError";
14
14
  }
15
15
  }
@@ -0,0 +1,22 @@
1
+ import type * as PredictorSDK from "../../api/index.js";
2
+ import * as core from "../../core/index.js";
3
+ import type * as serializers from "../index.js";
4
+ export declare const Plan: core.serialization.ObjectSchema<serializers.Plan.Raw, PredictorSDK.Plan>;
5
+ export declare namespace Plan {
6
+ interface Raw {
7
+ key: string;
8
+ name: string;
9
+ billing_tier: string;
10
+ trial_days: number;
11
+ tagline: string;
12
+ monthly_price_cents: number;
13
+ included_requests_per_month: number;
14
+ overage_cents_per_1k: number;
15
+ rate_limit_per_min: number;
16
+ max_keys: number;
17
+ features: string[];
18
+ cta_label: string;
19
+ highlighted: boolean;
20
+ contact_sales: boolean;
21
+ }
22
+ }
@@ -0,0 +1,18 @@
1
+ // This file was auto-generated by Fern from our API Definition.
2
+ import * as core from "../../core/index.js";
3
+ export const Plan = core.serialization.object({
4
+ key: core.serialization.string(),
5
+ name: core.serialization.string(),
6
+ billingTier: core.serialization.property("billing_tier", core.serialization.string()),
7
+ trialDays: core.serialization.property("trial_days", core.serialization.number()),
8
+ tagline: core.serialization.string(),
9
+ monthlyPriceCents: core.serialization.property("monthly_price_cents", core.serialization.number()),
10
+ includedRequestsPerMonth: core.serialization.property("included_requests_per_month", core.serialization.number()),
11
+ overageCentsPer1K: core.serialization.property("overage_cents_per_1k", core.serialization.number()),
12
+ rateLimitPerMin: core.serialization.property("rate_limit_per_min", core.serialization.number()),
13
+ maxKeys: core.serialization.property("max_keys", core.serialization.number()),
14
+ features: core.serialization.list(core.serialization.string()),
15
+ ctaLabel: core.serialization.property("cta_label", core.serialization.string()),
16
+ highlighted: core.serialization.boolean(),
17
+ contactSales: core.serialization.property("contact_sales", core.serialization.boolean()),
18
+ });
@@ -0,0 +1,10 @@
1
+ import type * as PredictorSDK from "../../api/index.js";
2
+ import * as core from "../../core/index.js";
3
+ import type * as serializers from "../index.js";
4
+ import { Plan } from "./Plan.js";
5
+ export declare const PlansResponse: core.serialization.ObjectSchema<serializers.PlansResponse.Raw, PredictorSDK.PlansResponse>;
6
+ export declare namespace PlansResponse {
7
+ interface Raw {
8
+ data: Plan.Raw[];
9
+ }
10
+ }
@@ -0,0 +1,6 @@
1
+ // This file was auto-generated by Fern from our API Definition.
2
+ import * as core from "../../core/index.js";
3
+ import { Plan } from "./Plan.js";
4
+ export const PlansResponse = core.serialization.object({
5
+ data: core.serialization.list(Plan),
6
+ });
@@ -31,6 +31,8 @@ export * from "./MarketsListResponse.js";
31
31
  export * from "./PaginationBlock.js";
32
32
  export * from "./PaymentRequiredErrorAction.js";
33
33
  export * from "./PaymentRequiredErrorBody.js";
34
+ export * from "./Plan.js";
35
+ export * from "./PlansResponse.js";
34
36
  export * from "./PlatformMarket.js";
35
37
  export * from "./PlatformMarketPlatform.js";
36
38
  export * from "./PolymarketPosition.js";
@@ -31,6 +31,8 @@ export * from "./MarketsListResponse.js";
31
31
  export * from "./PaginationBlock.js";
32
32
  export * from "./PaymentRequiredErrorAction.js";
33
33
  export * from "./PaymentRequiredErrorBody.js";
34
+ export * from "./Plan.js";
35
+ export * from "./PlansResponse.js";
34
36
  export * from "./PlatformMarket.js";
35
37
  export * from "./PlatformMarketPlatform.js";
36
38
  export * from "./PolymarketPosition.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@predictorsdk/client",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "The official TypeScript/JavaScript client for the PredictorSDK matching markets API",
5
5
  "license": "MIT",
6
6
  "keywords": [