@robosystems/client 0.6.2 → 1.0.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.
@@ -29,7 +29,7 @@
29
29
  import type { TypedDocumentNode } from '@graphql-typed-document-node/core'
30
30
  import { ClientError } from 'graphql-request'
31
31
  import type { TokenProvider } from './graphql/client'
32
- import { GraphQLClientCache } from './graphql/client'
32
+ import { GraphQLClientCache, toGraphQLError } from './graphql/client'
33
33
  import {
34
34
  GetLibraryElementArcsDocument,
35
35
  GetLibraryElementClassificationsDocument,
@@ -53,6 +53,10 @@ import {
53
53
  type SearchLibraryElementsQuery,
54
54
  } from './graphql/generated/graphql'
55
55
 
56
+ // Re-export the structured GraphQL error type so consumers importing
57
+ // from the `@robosystems/client/library` subpath can `instanceof` it.
58
+ export { GraphQLError } from './graphql/client'
59
+
56
60
  // ── Friendly types derived from GraphQL codegen ────────────────────────
57
61
  //
58
62
  // These are the single source of truth for library payload shapes —
@@ -144,6 +148,8 @@ interface LibraryClientConfig {
144
148
  * request so refreshes flow through automatically.
145
149
  */
146
150
  tokenProvider?: TokenProvider
151
+ /** GraphQL request timeout in milliseconds (default 60s). */
152
+ timeout?: number
147
153
  }
148
154
 
149
155
  export class LibraryClient {
@@ -388,7 +394,7 @@ export class LibraryClient {
388
394
  return pick(data)
389
395
  } catch (err) {
390
396
  if (err instanceof ClientError) {
391
- throw new Error(`${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`)
397
+ throw toGraphQLError(label, err)
392
398
  }
393
399
  throw err
394
400
  }
@@ -18,7 +18,43 @@
18
18
  * comes from GraphQL Code Generator, which produces typed DocumentNodes
19
19
  * from the query files in clients/graphql/queries/.
20
20
  */
21
- import { GraphQLClient } from 'graphql-request';
21
+ import { ClientError, GraphQLClient } from 'graphql-request';
22
+ /**
23
+ * Default request timeout for GraphQL calls, in milliseconds.
24
+ *
25
+ * Matches the Python client's httpx default (60 seconds). Without a
26
+ * timeout a hung backend hangs callers forever — every GraphQL request
27
+ * carries an `AbortSignal.timeout(...)` so transport stalls surface as
28
+ * an abort error instead of an eternal pending promise. Override
29
+ * per-client via `GraphQLClientConfig.timeout`.
30
+ */
31
+ export declare const DEFAULT_GRAPHQL_TIMEOUT_MS = 60000;
32
+ /**
33
+ * Structured error thrown by facade GraphQL reads.
34
+ *
35
+ * Mirrors the Python client's `GraphQLError` (message, `errors`,
36
+ * `status_code`): the message keeps the legacy
37
+ * `"<label> failed: <json>"` format so string-matching consumers keep
38
+ * working, while the raw GraphQL error objects and HTTP status are
39
+ * available as structured fields for programmatic handling.
40
+ */
41
+ export declare class GraphQLError extends Error {
42
+ /** Raw GraphQL error objects from the response body (empty for HTTP-level failures). */
43
+ readonly errors: unknown[];
44
+ /** HTTP status code, when known. */
45
+ readonly statusCode?: number;
46
+ constructor(message: string, options?: {
47
+ errors?: unknown[];
48
+ statusCode?: number;
49
+ });
50
+ }
51
+ /**
52
+ * Convert a graphql-request `ClientError` into the facade's structured
53
+ * {@link GraphQLError}, preserving the legacy message format
54
+ * (`"<label> failed: <json>"`). Shared by the LedgerClient /
55
+ * InvestorClient / LibraryClient `gqlQuery` catch paths.
56
+ */
57
+ export declare function toGraphQLError(label: string, err: ClientError): GraphQLError;
22
58
  /**
23
59
  * Callback that returns the current auth credential on demand.
24
60
  *
@@ -51,6 +87,12 @@ export interface GraphQLClientConfig {
51
87
  tokenProvider?: TokenProvider;
52
88
  headers?: Record<string, string>;
53
89
  credentials?: 'include' | 'same-origin' | 'omit';
90
+ /**
91
+ * Request timeout in milliseconds. Defaults to
92
+ * {@link DEFAULT_GRAPHQL_TIMEOUT_MS} (60s, matching the Python
93
+ * client). Applied per request via `AbortSignal.timeout(...)`.
94
+ */
95
+ timeout?: number;
54
96
  }
55
97
  /**
56
98
  * Build a new GraphQL client for the given graph. Prefer
@@ -1,7 +1,8 @@
1
1
  'use client';
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.GraphQLClientCache = void 0;
4
+ exports.GraphQLClientCache = exports.GraphQLError = exports.DEFAULT_GRAPHQL_TIMEOUT_MS = void 0;
5
+ exports.toGraphQLError = toGraphQLError;
5
6
  exports.createGraphQLClient = createGraphQLClient;
6
7
  /**
7
8
  * GraphQL client factory used internally by the facade clients.
@@ -24,6 +25,72 @@ exports.createGraphQLClient = createGraphQLClient;
24
25
  * from the query files in clients/graphql/queries/.
25
26
  */
26
27
  const graphql_request_1 = require("graphql-request");
28
+ /**
29
+ * Default request timeout for GraphQL calls, in milliseconds.
30
+ *
31
+ * Matches the Python client's httpx default (60 seconds). Without a
32
+ * timeout a hung backend hangs callers forever — every GraphQL request
33
+ * carries an `AbortSignal.timeout(...)` so transport stalls surface as
34
+ * an abort error instead of an eternal pending promise. Override
35
+ * per-client via `GraphQLClientConfig.timeout`.
36
+ */
37
+ exports.DEFAULT_GRAPHQL_TIMEOUT_MS = 60000;
38
+ /**
39
+ * Structured error thrown by facade GraphQL reads.
40
+ *
41
+ * Mirrors the Python client's `GraphQLError` (message, `errors`,
42
+ * `status_code`): the message keeps the legacy
43
+ * `"<label> failed: <json>"` format so string-matching consumers keep
44
+ * working, while the raw GraphQL error objects and HTTP status are
45
+ * available as structured fields for programmatic handling.
46
+ */
47
+ class GraphQLError extends Error {
48
+ constructor(message, options) {
49
+ super(message);
50
+ this.name = 'GraphQLError';
51
+ this.errors = options?.errors ?? [];
52
+ this.statusCode = options?.statusCode;
53
+ }
54
+ }
55
+ exports.GraphQLError = GraphQLError;
56
+ /**
57
+ * Convert a graphql-request `ClientError` into the facade's structured
58
+ * {@link GraphQLError}, preserving the legacy message format
59
+ * (`"<label> failed: <json>"`). Shared by the LedgerClient /
60
+ * InvestorClient / LibraryClient `gqlQuery` catch paths.
61
+ */
62
+ function toGraphQLError(label, err) {
63
+ const errors = err.response.errors ?? [];
64
+ return new GraphQLError(`${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`, {
65
+ errors,
66
+ statusCode: err.response.status,
67
+ });
68
+ }
69
+ /**
70
+ * Wrap the global `fetch` so every request carries a timeout
71
+ * `AbortSignal`. If a signal is already present on the request we
72
+ * combine the two via `AbortSignal.any` (whichever aborts first wins);
73
+ * in environments without `AbortSignal.timeout` support the wrapper
74
+ * degrades to plain `fetch`.
75
+ *
76
+ * `fetch` is resolved from the global scope at call time (not
77
+ * captured at construction) so test harnesses that swap
78
+ * `globalThis.fetch` keep working.
79
+ */
80
+ function createTimeoutFetch(timeoutMs) {
81
+ return (input, init) => {
82
+ if (typeof AbortSignal.timeout !== 'function') {
83
+ return fetch(input, init);
84
+ }
85
+ const timeoutSignal = AbortSignal.timeout(timeoutMs);
86
+ const signal = init?.signal != null
87
+ ? typeof AbortSignal.any === 'function'
88
+ ? AbortSignal.any([init.signal, timeoutSignal])
89
+ : init.signal
90
+ : timeoutSignal;
91
+ return fetch(input, { ...init, signal });
92
+ };
93
+ }
27
94
  /**
28
95
  * Apply a credential to an in-progress request's headers, choosing
29
96
  * the right header based on token shape:
@@ -57,6 +124,7 @@ function createGraphQLClient(config, graphId) {
57
124
  const staticHeaders = {
58
125
  ...(config.headers ?? {}),
59
126
  };
127
+ const timeoutFetch = createTimeoutFetch(config.timeout ?? exports.DEFAULT_GRAPHQL_TIMEOUT_MS);
60
128
  // Dynamic-token path: defer credential injection to a per-request
61
129
  // middleware so JWT refreshes are picked up without rebuilding or
62
130
  // clearing the client. This is the recommended path for browser
@@ -66,21 +134,24 @@ function createGraphQLClient(config, graphId) {
66
134
  return new graphql_request_1.GraphQLClient(url, {
67
135
  headers: staticHeaders,
68
136
  credentials: config.credentials,
137
+ fetch: timeoutFetch,
69
138
  requestMiddleware: async (request) => {
70
139
  let token;
71
140
  try {
72
141
  token = await providerFn();
73
142
  }
74
143
  catch (err) {
75
- // A provider failure shouldn't crash the request — fall
76
- // through unauthenticated so the backend returns a clean
77
- // 401, which is easier to diagnose than a thrown middleware.
78
- // We still log a breadcrumb so the failure is visible in
79
- // devtools/log aggregators instead of silently disappearing;
80
- // silently swallowing provider bugs in production is worse
81
- // than the noise.
82
- console.warn('[RoboSystems SDK] tokenProvider threw — sending unauthenticated request:', err);
83
- token = undefined;
144
+ // Fail fast — a throwing provider means the caller *intended*
145
+ // to authenticate but couldn't produce a credential. Sending
146
+ // the request unauthenticated would surface as a confusing
147
+ // 401 far from the real failure. (Matches the Python client,
148
+ // which raises when its credential is missing.) A provider
149
+ // that deliberately has no credential should return `null`
150
+ // instead — that still sends an unauthenticated request.
151
+ const detail = err instanceof Error ? err.message : String(err);
152
+ throw new Error(`RoboSystems SDK: tokenProvider threw while resolving the request credential (${detail}). ` +
153
+ 'Fix the tokenProvider passed in the client config (or via setSDKClientConfig) so it ' +
154
+ 'returns the current token, or null to send an unauthenticated (cookie-based) request.');
84
155
  }
85
156
  if (!token) {
86
157
  return request;
@@ -103,6 +174,7 @@ function createGraphQLClient(config, graphId) {
103
174
  return new graphql_request_1.GraphQLClient(url, {
104
175
  headers,
105
176
  credentials: config.credentials,
177
+ fetch: timeoutFetch,
106
178
  });
107
179
  }
108
180
  // No credentials at all — used by unauthenticated introspection
@@ -110,6 +182,7 @@ function createGraphQLClient(config, graphId) {
110
182
  return new graphql_request_1.GraphQLClient(url, {
111
183
  headers: staticHeaders,
112
184
  credentials: config.credentials,
185
+ fetch: timeoutFetch,
113
186
  });
114
187
  }
115
188
  /**
@@ -21,7 +21,58 @@
21
21
  * from the query files in clients/graphql/queries/.
22
22
  */
23
23
 
24
- import { GraphQLClient } from 'graphql-request'
24
+ import { ClientError, GraphQLClient } from 'graphql-request'
25
+
26
+ /**
27
+ * Default request timeout for GraphQL calls, in milliseconds.
28
+ *
29
+ * Matches the Python client's httpx default (60 seconds). Without a
30
+ * timeout a hung backend hangs callers forever — every GraphQL request
31
+ * carries an `AbortSignal.timeout(...)` so transport stalls surface as
32
+ * an abort error instead of an eternal pending promise. Override
33
+ * per-client via `GraphQLClientConfig.timeout`.
34
+ */
35
+ export const DEFAULT_GRAPHQL_TIMEOUT_MS = 60_000
36
+
37
+ /**
38
+ * Structured error thrown by facade GraphQL reads.
39
+ *
40
+ * Mirrors the Python client's `GraphQLError` (message, `errors`,
41
+ * `status_code`): the message keeps the legacy
42
+ * `"<label> failed: <json>"` format so string-matching consumers keep
43
+ * working, while the raw GraphQL error objects and HTTP status are
44
+ * available as structured fields for programmatic handling.
45
+ */
46
+ export class GraphQLError extends Error {
47
+ /** Raw GraphQL error objects from the response body (empty for HTTP-level failures). */
48
+ readonly errors: unknown[]
49
+ /** HTTP status code, when known. */
50
+ readonly statusCode?: number
51
+
52
+ constructor(message: string, options?: { errors?: unknown[]; statusCode?: number }) {
53
+ super(message)
54
+ this.name = 'GraphQLError'
55
+ this.errors = options?.errors ?? []
56
+ this.statusCode = options?.statusCode
57
+ }
58
+ }
59
+
60
+ /**
61
+ * Convert a graphql-request `ClientError` into the facade's structured
62
+ * {@link GraphQLError}, preserving the legacy message format
63
+ * (`"<label> failed: <json>"`). Shared by the LedgerClient /
64
+ * InvestorClient / LibraryClient `gqlQuery` catch paths.
65
+ */
66
+ export function toGraphQLError(label: string, err: ClientError): GraphQLError {
67
+ const errors = err.response.errors ?? []
68
+ return new GraphQLError(
69
+ `${label} failed: ${JSON.stringify(err.response.errors ?? err.message)}`,
70
+ {
71
+ errors,
72
+ statusCode: err.response.status,
73
+ }
74
+ )
75
+ }
25
76
 
26
77
  /**
27
78
  * Callback that returns the current auth credential on demand.
@@ -56,6 +107,39 @@ export interface GraphQLClientConfig {
56
107
  tokenProvider?: TokenProvider
57
108
  headers?: Record<string, string>
58
109
  credentials?: 'include' | 'same-origin' | 'omit'
110
+ /**
111
+ * Request timeout in milliseconds. Defaults to
112
+ * {@link DEFAULT_GRAPHQL_TIMEOUT_MS} (60s, matching the Python
113
+ * client). Applied per request via `AbortSignal.timeout(...)`.
114
+ */
115
+ timeout?: number
116
+ }
117
+
118
+ /**
119
+ * Wrap the global `fetch` so every request carries a timeout
120
+ * `AbortSignal`. If a signal is already present on the request we
121
+ * combine the two via `AbortSignal.any` (whichever aborts first wins);
122
+ * in environments without `AbortSignal.timeout` support the wrapper
123
+ * degrades to plain `fetch`.
124
+ *
125
+ * `fetch` is resolved from the global scope at call time (not
126
+ * captured at construction) so test harnesses that swap
127
+ * `globalThis.fetch` keep working.
128
+ */
129
+ function createTimeoutFetch(timeoutMs: number): typeof fetch {
130
+ return (input, init) => {
131
+ if (typeof AbortSignal.timeout !== 'function') {
132
+ return fetch(input, init)
133
+ }
134
+ const timeoutSignal = AbortSignal.timeout(timeoutMs)
135
+ const signal =
136
+ init?.signal != null
137
+ ? typeof AbortSignal.any === 'function'
138
+ ? AbortSignal.any([init.signal, timeoutSignal])
139
+ : init.signal
140
+ : timeoutSignal
141
+ return fetch(input, { ...init, signal })
142
+ }
59
143
  }
60
144
 
61
145
  /**
@@ -91,6 +175,7 @@ export function createGraphQLClient(config: GraphQLClientConfig, graphId: string
91
175
  const staticHeaders: Record<string, string> = {
92
176
  ...(config.headers ?? {}),
93
177
  }
178
+ const timeoutFetch = createTimeoutFetch(config.timeout ?? DEFAULT_GRAPHQL_TIMEOUT_MS)
94
179
 
95
180
  // Dynamic-token path: defer credential injection to a per-request
96
181
  // middleware so JWT refreshes are picked up without rebuilding or
@@ -101,24 +186,25 @@ export function createGraphQLClient(config: GraphQLClientConfig, graphId: string
101
186
  return new GraphQLClient(url, {
102
187
  headers: staticHeaders,
103
188
  credentials: config.credentials,
189
+ fetch: timeoutFetch,
104
190
  requestMiddleware: async (request) => {
105
191
  let token: string | null | undefined
106
192
  try {
107
193
  token = await providerFn()
108
194
  } catch (err) {
109
- // A provider failure shouldn't crash the request — fall
110
- // through unauthenticated so the backend returns a clean
111
- // 401, which is easier to diagnose than a thrown middleware.
112
- // We still log a breadcrumb so the failure is visible in
113
- // devtools/log aggregators instead of silently disappearing;
114
- // silently swallowing provider bugs in production is worse
115
- // than the noise.
116
-
117
- console.warn(
118
- '[RoboSystems SDK] tokenProvider threw — sending unauthenticated request:',
119
- err
195
+ // Fail fast — a throwing provider means the caller *intended*
196
+ // to authenticate but couldn't produce a credential. Sending
197
+ // the request unauthenticated would surface as a confusing
198
+ // 401 far from the real failure. (Matches the Python client,
199
+ // which raises when its credential is missing.) A provider
200
+ // that deliberately has no credential should return `null`
201
+ // instead — that still sends an unauthenticated request.
202
+ const detail = err instanceof Error ? err.message : String(err)
203
+ throw new Error(
204
+ `RoboSystems SDK: tokenProvider threw while resolving the request credential (${detail}). ` +
205
+ 'Fix the tokenProvider passed in the client config (or via setSDKClientConfig) so it ' +
206
+ 'returns the current token, or null to send an unauthenticated (cookie-based) request.'
120
207
  )
121
- token = undefined
122
208
  }
123
209
  if (!token) {
124
210
  return request
@@ -142,6 +228,7 @@ export function createGraphQLClient(config: GraphQLClientConfig, graphId: string
142
228
  return new GraphQLClient(url, {
143
229
  headers,
144
230
  credentials: config.credentials,
231
+ fetch: timeoutFetch,
145
232
  })
146
233
  }
147
234
 
@@ -150,6 +237,7 @@ export function createGraphQLClient(config: GraphQLClientConfig, graphId: string
150
237
  return new GraphQLClient(url, {
151
238
  headers: staticHeaders,
152
239
  credentials: config.credentials,
240
+ fetch: timeoutFetch,
153
241
  })
154
242
  }
155
243
 
@@ -11,6 +11,7 @@ import { OperatorClient } from './OperatorClient';
11
11
  import { QueryClient } from './QueryClient';
12
12
  import { SSEClient } from './SSEClient';
13
13
  export type { TokenProvider } from './graphql/client';
14
+ export { DEFAULT_GRAPHQL_TIMEOUT_MS, GraphQLError } from './graphql/client';
14
15
  export interface RoboSystemsClientConfig {
15
16
  baseUrl?: string;
16
17
  credentials?: 'include' | 'same-origin' | 'omit';
@@ -29,6 +30,11 @@ export interface RoboSystemsClientConfig {
29
30
  headers?: Record<string, string>;
30
31
  maxRetries?: number;
31
32
  retryDelay?: number;
33
+ /**
34
+ * GraphQL request timeout in milliseconds. Defaults to 60s
35
+ * (matching the Python client's httpx default) when omitted.
36
+ */
37
+ timeout?: number;
32
38
  }
33
39
  export declare class RoboSystemsClients {
34
40
  readonly query: QueryClient;
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
18
18
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
19
19
  };
20
20
  Object.defineProperty(exports, "__esModule", { value: true });
21
- exports.analyzeFinancials = exports.operatorQuery = exports.streamQuery = exports.executeQuery = exports.monitorOperation = exports.clients = exports.useStreamingQuery = exports.useSDKClients = exports.useQuery = exports.useOperation = exports.useMultipleOperations = exports.SSEClient = exports.QueryClient = exports.OperatorClient = exports.OperationClient = exports.LibraryClient = exports.LedgerClient = exports.InvestorClient = exports.RoboSystemsClients = void 0;
21
+ exports.analyzeFinancials = exports.operatorQuery = exports.streamQuery = exports.executeQuery = exports.monitorOperation = exports.clients = exports.useStreamingQuery = exports.useSDKClients = exports.useQuery = exports.useOperation = exports.useMultipleOperations = exports.SSEClient = exports.QueryClient = exports.OperatorClient = exports.OperationClient = exports.LibraryClient = exports.LedgerClient = exports.InvestorClient = exports.RoboSystemsClients = exports.GraphQLError = exports.DEFAULT_GRAPHQL_TIMEOUT_MS = void 0;
22
22
  const client_gen_1 = require("../client.gen");
23
23
  const config_1 = require("./config");
24
24
  const InvestorClient_1 = require("./InvestorClient");
@@ -35,6 +35,11 @@ const QueryClient_1 = require("./QueryClient");
35
35
  Object.defineProperty(exports, "QueryClient", { enumerable: true, get: function () { return QueryClient_1.QueryClient; } });
36
36
  const SSEClient_1 = require("./SSEClient");
37
37
  Object.defineProperty(exports, "SSEClient", { enumerable: true, get: function () { return SSEClient_1.SSEClient; } });
38
+ // Structured GraphQL error thrown by facade reads (LedgerClient /
39
+ // InvestorClient / LibraryClient), plus the default request timeout.
40
+ var client_1 = require("./graphql/client");
41
+ Object.defineProperty(exports, "DEFAULT_GRAPHQL_TIMEOUT_MS", { enumerable: true, get: function () { return client_1.DEFAULT_GRAPHQL_TIMEOUT_MS; } });
42
+ Object.defineProperty(exports, "GraphQLError", { enumerable: true, get: function () { return client_1.GraphQLError; } });
38
43
  class RoboSystemsClients {
39
44
  constructor(config = {}) {
40
45
  // Get base URL from SDK client config or use provided/default
@@ -53,6 +58,7 @@ class RoboSystemsClients {
53
58
  headers: config.headers,
54
59
  maxRetries: config.maxRetries || 5,
55
60
  retryDelay: config.retryDelay || 1000,
61
+ timeout: config.timeout,
56
62
  };
57
63
  this.query = new QueryClient_1.QueryClient({
58
64
  baseUrl: this.config.baseUrl,
@@ -81,6 +87,7 @@ class RoboSystemsClients {
81
87
  token: this.config.token,
82
88
  tokenProvider: this.config.tokenProvider,
83
89
  headers: this.config.headers,
90
+ timeout: this.config.timeout,
84
91
  });
85
92
  this.investor = new InvestorClient_1.InvestorClient({
86
93
  baseUrl: this.config.baseUrl,
@@ -88,6 +95,7 @@ class RoboSystemsClients {
88
95
  token: this.config.token,
89
96
  tokenProvider: this.config.tokenProvider,
90
97
  headers: this.config.headers,
98
+ timeout: this.config.timeout,
91
99
  });
92
100
  // Library uses GraphQL and accepts graphId per-call — pass either
93
101
  // the `"library"` sentinel (canonical) or any tenant graph_id
@@ -98,6 +106,7 @@ class RoboSystemsClients {
98
106
  token: this.config.token,
99
107
  tokenProvider: this.config.tokenProvider,
100
108
  headers: this.config.headers,
109
+ timeout: this.config.timeout,
101
110
  });
102
111
  // Reports consolidated into LedgerClient — alias for backward compat
103
112
  this.reports = this.ledger;
@@ -20,6 +20,10 @@ import { SSEClient } from './SSEClient'
20
20
  // internal `./graphql/client` module path.
21
21
  export type { TokenProvider } from './graphql/client'
22
22
 
23
+ // Structured GraphQL error thrown by facade reads (LedgerClient /
24
+ // InvestorClient / LibraryClient), plus the default request timeout.
25
+ export { DEFAULT_GRAPHQL_TIMEOUT_MS, GraphQLError } from './graphql/client'
26
+
23
27
  export interface RoboSystemsClientConfig {
24
28
  baseUrl?: string
25
29
  credentials?: 'include' | 'same-origin' | 'omit'
@@ -38,6 +42,11 @@ export interface RoboSystemsClientConfig {
38
42
  headers?: Record<string, string>
39
43
  maxRetries?: number
40
44
  retryDelay?: number
45
+ /**
46
+ * GraphQL request timeout in milliseconds. Defaults to 60s
47
+ * (matching the Python client's httpx default) when omitted.
48
+ */
49
+ timeout?: number
41
50
  }
42
51
 
43
52
  // Properly typed configuration interface
@@ -49,6 +58,7 @@ interface ResolvedConfig {
49
58
  headers?: Record<string, string>
50
59
  maxRetries: number
51
60
  retryDelay: number
61
+ timeout?: number
52
62
  }
53
63
 
54
64
  export class RoboSystemsClients {
@@ -85,6 +95,7 @@ export class RoboSystemsClients {
85
95
  headers: config.headers,
86
96
  maxRetries: config.maxRetries || 5,
87
97
  retryDelay: config.retryDelay || 1000,
98
+ timeout: config.timeout,
88
99
  }
89
100
 
90
101
  this.query = new QueryClient({
@@ -117,6 +128,7 @@ export class RoboSystemsClients {
117
128
  token: this.config.token,
118
129
  tokenProvider: this.config.tokenProvider,
119
130
  headers: this.config.headers,
131
+ timeout: this.config.timeout,
120
132
  })
121
133
 
122
134
  this.investor = new InvestorClient({
@@ -125,6 +137,7 @@ export class RoboSystemsClients {
125
137
  token: this.config.token,
126
138
  tokenProvider: this.config.tokenProvider,
127
139
  headers: this.config.headers,
140
+ timeout: this.config.timeout,
128
141
  })
129
142
 
130
143
  // Library uses GraphQL and accepts graphId per-call — pass either
@@ -136,6 +149,7 @@ export class RoboSystemsClients {
136
149
  token: this.config.token,
137
150
  tokenProvider: this.config.tokenProvider,
138
151
  headers: this.config.headers,
152
+ timeout: this.config.timeout,
139
153
  })
140
154
 
141
155
  // Reports consolidated into LedgerClient — alias for backward compat
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robosystems/client",
3
- "version": "0.6.2",
3
+ "version": "1.0.0",
4
4
  "description": "TypeScript client library for RoboSystems Financial Knowledge Graph API",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -38,12 +38,6 @@
38
38
  "import": "./artifacts/LibraryClient.js",
39
39
  "default": "./artifacts/LibraryClient.js"
40
40
  },
41
- "./agent": {
42
- "types": "./artifacts/AgentClient.d.ts",
43
- "require": "./artifacts/AgentClient.js",
44
- "import": "./artifacts/AgentClient.js",
45
- "default": "./artifacts/AgentClient.js"
46
- },
47
41
  "./query": {
48
42
  "types": "./artifacts/QueryClient.d.ts",
49
43
  "require": "./artifacts/QueryClient.js",
@@ -138,7 +132,7 @@
138
132
  },
139
133
  "homepage": "https://github.com/RoboFinSystems/robosystems-typescript-client#readme",
140
134
  "engines": {
141
- "node": ">=18.0.0"
135
+ "node": ">=22.0.0"
142
136
  },
143
137
  "devDependencies": {
144
138
  "@eslint/js": "^9.39.2",
package/sdk/sdk.gen.d.ts CHANGED
@@ -434,7 +434,7 @@ export declare const changeSubscriptionPlan: <ThrowOnError extends boolean = fal
434
434
  /**
435
435
  * Create Repository Subscription
436
436
  *
437
- * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning.
437
+ * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning. Subscribes the caller by default; org owners and admins may subscribe another member of their organization by passing `user_id`. Billing is charged to the organization either way — repository access is per-user, so the subscriber determines who receives access.
438
438
  */
439
439
  export declare const createRepositorySubscription: <ThrowOnError extends boolean = false>(options: Options<CreateRepositorySubscriptionData, ThrowOnError>) => import("./client").RequestResult<CreateRepositorySubscriptionResponses, CreateRepositorySubscriptionErrors, ThrowOnError, "fields">;
440
440
  /**
package/sdk/sdk.gen.js CHANGED
@@ -889,7 +889,7 @@ exports.changeSubscriptionPlan = changeSubscriptionPlan;
889
889
  /**
890
890
  * Create Repository Subscription
891
891
  *
892
- * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning.
892
+ * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning. Subscribes the caller by default; org owners and admins may subscribe another member of their organization by passing `user_id`. Billing is charged to the organization either way — repository access is per-user, so the subscriber determines who receives access.
893
893
  */
894
894
  const createRepositorySubscription = (options) => (options.client ?? client_gen_1.client).post({
895
895
  security: [{ name: 'X-API-Key', type: 'apiKey' }, { scheme: 'bearer', type: 'http' }],
package/sdk/sdk.gen.ts CHANGED
@@ -901,7 +901,7 @@ export const changeSubscriptionPlan = <ThrowOnError extends boolean = false>(opt
901
901
  /**
902
902
  * Create Repository Subscription
903
903
  *
904
- * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning.
904
+ * For shared repositories only (sec, industry, etc.). User graph subscriptions are created automatically during provisioning. Subscribes the caller by default; org owners and admins may subscribe another member of their organization by passing `user_id`. Billing is charged to the organization either way — repository access is per-user, so the subscriber determines who receives access.
905
905
  */
906
906
  export const createRepositorySubscription = <ThrowOnError extends boolean = false>(options: Options<CreateRepositorySubscriptionData, ThrowOnError>) => (options.client ?? client).post<CreateRepositorySubscriptionResponses, CreateRepositorySubscriptionErrors, ThrowOnError>({
907
907
  security: [{ name: 'X-API-Key', type: 'apiKey' }, { scheme: 'bearer', type: 'http' }],
@@ -2779,6 +2779,12 @@ export type CreateRepositorySubscriptionRequest = {
2779
2779
  * Plan name for the repository subscription
2780
2780
  */
2781
2781
  plan_name: string;
2782
+ /**
2783
+ * User Id
2784
+ *
2785
+ * Subscribe this user instead of yourself. Org owners and admins only, and the target must belong to the same organization. Omit to subscribe yourself. Repository access is per-user while billing is org-level, so the subscriber is what determines who gets access.
2786
+ */
2787
+ user_id?: string | null;
2782
2788
  };
2783
2789
  /**
2784
2790
  * CreateRollforwardRequest
@@ -5112,12 +5118,24 @@ export type FactRecord = {
5112
5118
  * Element local name
5113
5119
  */
5114
5120
  element_name?: string | null;
5121
+ /**
5122
+ * Period Start
5123
+ *
5124
+ * Period start date (YYYY-MM-DD); null for instant facts. A duration fact is identified by (start, end) — two facts for the same element can share an end date and differ only here (e.g. a quarterly and a year-to-date figure from the same 10-Q).
5125
+ */
5126
+ period_start?: string | null;
5115
5127
  /**
5116
5128
  * Period End
5117
5129
  *
5118
5130
  * Period end date (YYYY-MM-DD)
5119
5131
  */
5120
5132
  period_end?: string | null;
5133
+ /**
5134
+ * Duration Type
5135
+ *
5136
+ * Period duration classification (e.g. 'quarterly', 'nine_months', 'annual'); null for instant facts. Use with period_start to tell overlapping windows apart.
5137
+ */
5138
+ duration_type?: string | null;
5121
5139
  /**
5122
5140
  * Value
5123
5141
  *
@@ -16151,7 +16169,7 @@ export type ViewResponse = {
16151
16169
  /**
16152
16170
  * Summary
16153
16171
  *
16154
- * Per-element aggregates, only when include_summary=true. Note that `total` sums across every returned period, which is meaningful for duration facts and not for instants.
16172
+ * Per-element aggregates, only when include_summary=true. Note that `total` sums across every returned period, which is meaningful for duration facts and not for instants. Overlapping duration windows sharing a period_end (quarter + year-to-date) contribute only the narrowest window, so a quarter is never double-counted inside its own YTD figure.
16155
16173
  */
16156
16174
  summary?: {
16157
16175
  [key: string]: ElementSummary;