@robosystems/client 0.2.49 → 0.3.1

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 (191) hide show
  1. package/extensions/InvestorClient.d.ts +98 -0
  2. package/extensions/InvestorClient.js +223 -0
  3. package/extensions/InvestorClient.ts +508 -0
  4. package/extensions/LedgerClient.d.ts +190 -309
  5. package/extensions/LedgerClient.js +268 -587
  6. package/extensions/LedgerClient.ts +784 -903
  7. package/extensions/ReportClient.d.ts +82 -113
  8. package/extensions/ReportClient.js +124 -211
  9. package/extensions/ReportClient.ts +305 -358
  10. package/extensions/config.d.ts +19 -0
  11. package/extensions/config.js +1 -1
  12. package/extensions/config.ts +22 -2
  13. package/extensions/graphql/client.d.ts +82 -0
  14. package/extensions/graphql/client.js +149 -0
  15. package/extensions/graphql/client.ts +189 -0
  16. package/extensions/graphql/generated/graphql.d.ts +1786 -0
  17. package/extensions/graphql/generated/graphql.js +2671 -0
  18. package/extensions/graphql/generated/graphql.ts +4491 -0
  19. package/extensions/graphql/queries/investor/holdings.d.ts +8 -0
  20. package/extensions/graphql/queries/investor/holdings.js +36 -0
  21. package/extensions/graphql/queries/investor/holdings.ts +34 -0
  22. package/extensions/graphql/queries/investor/portfolio.d.ts +4 -0
  23. package/extensions/graphql/queries/investor/portfolio.js +21 -0
  24. package/extensions/graphql/queries/investor/portfolio.ts +19 -0
  25. package/extensions/graphql/queries/investor/portfolios.d.ts +4 -0
  26. package/extensions/graphql/queries/investor/portfolios.js +29 -0
  27. package/extensions/graphql/queries/investor/portfolios.ts +27 -0
  28. package/extensions/graphql/queries/investor/position.d.ts +4 -0
  29. package/extensions/graphql/queries/investor/position.js +33 -0
  30. package/extensions/graphql/queries/investor/position.ts +31 -0
  31. package/extensions/graphql/queries/investor/positions.d.ts +8 -0
  32. package/extensions/graphql/queries/investor/positions.js +57 -0
  33. package/extensions/graphql/queries/investor/positions.ts +55 -0
  34. package/extensions/graphql/queries/investor/securities.d.ts +8 -0
  35. package/extensions/graphql/queries/investor/securities.js +50 -0
  36. package/extensions/graphql/queries/investor/securities.ts +48 -0
  37. package/extensions/graphql/queries/investor/security.d.ts +4 -0
  38. package/extensions/graphql/queries/investor/security.js +26 -0
  39. package/extensions/graphql/queries/investor/security.ts +24 -0
  40. package/extensions/graphql/queries/ledger/accountRollups.d.ts +7 -0
  41. package/extensions/graphql/queries/ledger/accountRollups.js +36 -0
  42. package/extensions/graphql/queries/ledger/accountRollups.ts +34 -0
  43. package/extensions/graphql/queries/ledger/accountTree.d.ts +11 -0
  44. package/extensions/graphql/queries/ledger/accountTree.js +61 -0
  45. package/extensions/graphql/queries/ledger/accountTree.ts +59 -0
  46. package/extensions/graphql/queries/ledger/accounts.d.ts +8 -0
  47. package/extensions/graphql/queries/ledger/accounts.js +45 -0
  48. package/extensions/graphql/queries/ledger/accounts.ts +43 -0
  49. package/extensions/graphql/queries/ledger/closingBookStructures.d.ts +6 -0
  50. package/extensions/graphql/queries/ledger/closingBookStructures.js +27 -0
  51. package/extensions/graphql/queries/ledger/closingBookStructures.ts +25 -0
  52. package/extensions/graphql/queries/ledger/elements.d.ts +6 -0
  53. package/extensions/graphql/queries/ledger/elements.js +56 -0
  54. package/extensions/graphql/queries/ledger/elements.ts +54 -0
  55. package/extensions/graphql/queries/ledger/entities.d.ts +7 -0
  56. package/extensions/graphql/queries/ledger/entities.js +31 -0
  57. package/extensions/graphql/queries/ledger/entities.ts +29 -0
  58. package/extensions/graphql/queries/ledger/entity.d.ts +14 -0
  59. package/extensions/graphql/queries/ledger/entity.js +55 -0
  60. package/extensions/graphql/queries/ledger/entity.ts +54 -0
  61. package/extensions/graphql/queries/ledger/fiscalCalendar.d.ts +8 -0
  62. package/extensions/graphql/queries/ledger/fiscalCalendar.js +35 -0
  63. package/extensions/graphql/queries/ledger/fiscalCalendar.ts +33 -0
  64. package/extensions/graphql/queries/ledger/mappedTrialBalance.d.ts +9 -0
  65. package/extensions/graphql/queries/ledger/mappedTrialBalance.js +29 -0
  66. package/extensions/graphql/queries/ledger/mappedTrialBalance.ts +27 -0
  67. package/extensions/graphql/queries/ledger/mapping.d.ts +5 -0
  68. package/extensions/graphql/queries/ledger/mapping.js +35 -0
  69. package/extensions/graphql/queries/ledger/mapping.ts +33 -0
  70. package/extensions/graphql/queries/ledger/mappingCoverage.d.ts +5 -0
  71. package/extensions/graphql/queries/ledger/mappingCoverage.js +22 -0
  72. package/extensions/graphql/queries/ledger/mappingCoverage.ts +20 -0
  73. package/extensions/graphql/queries/ledger/mappings.d.ts +6 -0
  74. package/extensions/graphql/queries/ledger/mappings.js +23 -0
  75. package/extensions/graphql/queries/ledger/mappings.ts +21 -0
  76. package/extensions/graphql/queries/ledger/periodCloseStatus.d.ts +6 -0
  77. package/extensions/graphql/queries/ledger/periodCloseStatus.js +29 -0
  78. package/extensions/graphql/queries/ledger/periodCloseStatus.ts +27 -0
  79. package/extensions/graphql/queries/ledger/periodDrafts.d.ts +8 -0
  80. package/extensions/graphql/queries/ledger/periodDrafts.js +45 -0
  81. package/extensions/graphql/queries/ledger/periodDrafts.ts +43 -0
  82. package/extensions/graphql/queries/ledger/publishList.d.ts +5 -0
  83. package/extensions/graphql/queries/ledger/publishList.js +29 -0
  84. package/extensions/graphql/queries/ledger/publishList.ts +27 -0
  85. package/extensions/graphql/queries/ledger/publishLists.d.ts +5 -0
  86. package/extensions/graphql/queries/ledger/publishLists.js +29 -0
  87. package/extensions/graphql/queries/ledger/publishLists.ts +27 -0
  88. package/extensions/graphql/queries/ledger/report.d.ts +5 -0
  89. package/extensions/graphql/queries/ledger/report.js +40 -0
  90. package/extensions/graphql/queries/ledger/report.ts +38 -0
  91. package/extensions/graphql/queries/ledger/reportingTaxonomy.d.ts +6 -0
  92. package/extensions/graphql/queries/ledger/reportingTaxonomy.js +27 -0
  93. package/extensions/graphql/queries/ledger/reportingTaxonomy.ts +25 -0
  94. package/extensions/graphql/queries/ledger/reports.d.ts +8 -0
  95. package/extensions/graphql/queries/ledger/reports.js +45 -0
  96. package/extensions/graphql/queries/ledger/reports.ts +43 -0
  97. package/extensions/graphql/queries/ledger/scheduleFacts.d.ts +7 -0
  98. package/extensions/graphql/queries/ledger/scheduleFacts.js +24 -0
  99. package/extensions/graphql/queries/ledger/scheduleFacts.ts +22 -0
  100. package/extensions/graphql/queries/ledger/schedules.d.ts +6 -0
  101. package/extensions/graphql/queries/ledger/schedules.js +24 -0
  102. package/extensions/graphql/queries/ledger/schedules.ts +22 -0
  103. package/extensions/graphql/queries/ledger/statement.d.ts +9 -0
  104. package/extensions/graphql/queries/ledger/statement.js +43 -0
  105. package/extensions/graphql/queries/ledger/statement.ts +41 -0
  106. package/extensions/graphql/queries/ledger/structures.d.ts +5 -0
  107. package/extensions/graphql/queries/ledger/structures.js +22 -0
  108. package/extensions/graphql/queries/ledger/structures.ts +20 -0
  109. package/extensions/graphql/queries/ledger/summary.d.ts +7 -0
  110. package/extensions/graphql/queries/ledger/summary.js +25 -0
  111. package/extensions/graphql/queries/ledger/summary.ts +23 -0
  112. package/extensions/graphql/queries/ledger/taxonomies.d.ts +5 -0
  113. package/extensions/graphql/queries/ledger/taxonomies.js +28 -0
  114. package/extensions/graphql/queries/ledger/taxonomies.ts +26 -0
  115. package/extensions/graphql/queries/ledger/transaction.d.ts +6 -0
  116. package/extensions/graphql/queries/ledger/transaction.js +49 -0
  117. package/extensions/graphql/queries/ledger/transaction.ts +47 -0
  118. package/extensions/graphql/queries/ledger/transactions.d.ts +7 -0
  119. package/extensions/graphql/queries/ledger/transactions.js +49 -0
  120. package/extensions/graphql/queries/ledger/transactions.ts +47 -0
  121. package/extensions/graphql/queries/ledger/trialBalance.d.ts +7 -0
  122. package/extensions/graphql/queries/ledger/trialBalance.js +28 -0
  123. package/extensions/graphql/queries/ledger/trialBalance.ts +26 -0
  124. package/extensions/graphql/queries/ledger/unmappedElements.d.ts +8 -0
  125. package/extensions/graphql/queries/ledger/unmappedElements.js +29 -0
  126. package/extensions/graphql/queries/ledger/unmappedElements.ts +27 -0
  127. package/extensions/hooks.d.ts +1 -1
  128. package/extensions/index.d.ts +18 -1
  129. package/extensions/index.js +26 -1
  130. package/extensions/index.ts +49 -2
  131. package/index.ts +2 -2
  132. package/package.json +14 -5
  133. package/sdk/index.d.ts +2 -2
  134. package/sdk/index.js +38 -73
  135. package/sdk/index.ts +2 -2
  136. package/sdk/sdk.gen.d.ts +100 -325
  137. package/sdk/sdk.gen.js +228 -592
  138. package/sdk/sdk.gen.ts +193 -556
  139. package/sdk/types.gen.d.ts +4522 -7708
  140. package/sdk/types.gen.ts +4569 -7983
  141. package/sdk.gen.d.ts +100 -325
  142. package/sdk.gen.js +228 -592
  143. package/sdk.gen.ts +193 -556
  144. package/types.gen.d.ts +4522 -7708
  145. package/types.gen.ts +4569 -7983
  146. package/extensions/AgentClient.test.ts +0 -403
  147. package/extensions/LedgerClient.test.ts +0 -1655
  148. package/extensions/OperationClient.test.ts +0 -365
  149. package/extensions/QueryClient.test.ts +0 -432
  150. package/extensions/ReportClient.test.ts +0 -828
  151. package/extensions/SSEClient.test.ts +0 -375
  152. package/extensions/config.test.ts +0 -199
  153. package/extensions/hooks.test.ts +0 -373
  154. package/extensions/index.test.ts +0 -420
  155. package/sdk-extensions/AgentClient.d.ts +0 -82
  156. package/sdk-extensions/AgentClient.js +0 -218
  157. package/sdk-extensions/AgentClient.test.ts +0 -403
  158. package/sdk-extensions/AgentClient.ts +0 -321
  159. package/sdk-extensions/LedgerClient.d.ts +0 -416
  160. package/sdk-extensions/LedgerClient.js +0 -737
  161. package/sdk-extensions/LedgerClient.test.ts +0 -1655
  162. package/sdk-extensions/LedgerClient.ts +0 -1249
  163. package/sdk-extensions/OperationClient.d.ts +0 -65
  164. package/sdk-extensions/OperationClient.js +0 -251
  165. package/sdk-extensions/OperationClient.test.ts +0 -365
  166. package/sdk-extensions/OperationClient.ts +0 -324
  167. package/sdk-extensions/QueryClient.d.ts +0 -52
  168. package/sdk-extensions/QueryClient.js +0 -313
  169. package/sdk-extensions/QueryClient.test.ts +0 -432
  170. package/sdk-extensions/QueryClient.ts +0 -420
  171. package/sdk-extensions/README.md +0 -901
  172. package/sdk-extensions/ReportClient.d.ts +0 -151
  173. package/sdk-extensions/ReportClient.js +0 -278
  174. package/sdk-extensions/ReportClient.test.ts +0 -828
  175. package/sdk-extensions/ReportClient.ts +0 -486
  176. package/sdk-extensions/SSEClient.d.ts +0 -62
  177. package/sdk-extensions/SSEClient.js +0 -154
  178. package/sdk-extensions/SSEClient.test.ts +0 -375
  179. package/sdk-extensions/SSEClient.ts +0 -210
  180. package/sdk-extensions/config.d.ts +0 -57
  181. package/sdk-extensions/config.js +0 -152
  182. package/sdk-extensions/config.test.ts +0 -199
  183. package/sdk-extensions/config.ts +0 -175
  184. package/sdk-extensions/hooks.d.ts +0 -110
  185. package/sdk-extensions/hooks.js +0 -384
  186. package/sdk-extensions/hooks.test.ts +0 -373
  187. package/sdk-extensions/hooks.ts +0 -459
  188. package/sdk-extensions/index.d.ts +0 -63
  189. package/sdk-extensions/index.js +0 -164
  190. package/sdk-extensions/index.test.ts +0 -420
  191. package/sdk-extensions/index.ts +0 -203
@@ -2,11 +2,30 @@
2
2
  * Configuration for SDK extensions
3
3
  * Provides centralized configuration for CORS, credentials, and other settings
4
4
  */
5
+ import type { TokenProvider } from './graphql/client';
5
6
  export interface SDKExtensionsConfig {
6
7
  baseUrl?: string;
7
8
  credentials?: 'include' | 'same-origin' | 'omit';
8
9
  headers?: Record<string, string>;
10
+ /**
11
+ * Static credential captured at singleton construction. Fine for
12
+ * long-lived API keys — use `tokenProvider` instead when the
13
+ * JWT can rotate mid-session (browser login flows).
14
+ *
15
+ * When both `token` and `tokenProvider` are set, `tokenProvider`
16
+ * wins — the static value is effectively ignored. Pass
17
+ * `tokenProvider: undefined` to explicitly switch back to the
18
+ * static-token path.
19
+ */
9
20
  token?: string;
21
+ /**
22
+ * Dynamic credential callback, invoked on every GraphQL request.
23
+ * When set, JWT refresh flows through automatically: the lazy
24
+ * `extensions` singleton picks it up at construction, and each
25
+ * request consults the callback for the current token instead of
26
+ * reusing a stale captured value.
27
+ */
28
+ tokenProvider?: TokenProvider;
10
29
  timeout?: number;
11
30
  maxRetries?: number;
12
31
  retryDelay?: number;
@@ -81,7 +81,7 @@ function isValidJWT(token) {
81
81
  */
82
82
  function extractTokenFromSDKClient() {
83
83
  // Import dynamically to avoid circular dependency
84
- const { client } = require('../sdk/client.gen');
84
+ const { client } = require('../client.gen');
85
85
  const sdkConfig = getSDKExtensionsConfig();
86
86
  // Priority 1: Use explicitly configured token
87
87
  if (sdkConfig.token) {
@@ -5,11 +5,31 @@
5
5
  * Provides centralized configuration for CORS, credentials, and other settings
6
6
  */
7
7
 
8
+ import type { TokenProvider } from './graphql/client'
9
+
8
10
  export interface SDKExtensionsConfig {
9
11
  baseUrl?: string
10
12
  credentials?: 'include' | 'same-origin' | 'omit'
11
13
  headers?: Record<string, string>
12
- token?: string // JWT token for authentication
14
+ /**
15
+ * Static credential captured at singleton construction. Fine for
16
+ * long-lived API keys — use `tokenProvider` instead when the
17
+ * JWT can rotate mid-session (browser login flows).
18
+ *
19
+ * When both `token` and `tokenProvider` are set, `tokenProvider`
20
+ * wins — the static value is effectively ignored. Pass
21
+ * `tokenProvider: undefined` to explicitly switch back to the
22
+ * static-token path.
23
+ */
24
+ token?: string
25
+ /**
26
+ * Dynamic credential callback, invoked on every GraphQL request.
27
+ * When set, JWT refresh flows through automatically: the lazy
28
+ * `extensions` singleton picks it up at construction, and each
29
+ * request consults the callback for the current token instead of
30
+ * reusing a stale captured value.
31
+ */
32
+ tokenProvider?: TokenProvider
13
33
  timeout?: number
14
34
  maxRetries?: number
15
35
  retryDelay?: number
@@ -94,7 +114,7 @@ export function isValidJWT(token: string | undefined): boolean {
94
114
  */
95
115
  export function extractTokenFromSDKClient(): string | undefined {
96
116
  // Import dynamically to avoid circular dependency
97
- const { client } = require('../sdk/client.gen')
117
+ const { client } = require('../client.gen')
98
118
 
99
119
  const sdkConfig = getSDKExtensionsConfig()
100
120
 
@@ -0,0 +1,82 @@
1
+ /**
2
+ * GraphQL client factory used internally by the facade clients.
3
+ *
4
+ * This is an implementation detail — consumers never interact with it
5
+ * directly. They call methods on LedgerClient / InvestorClient / etc.,
6
+ * which use this to execute GraphQL queries against
7
+ * `/extensions/{graph_id}/graphql`.
8
+ *
9
+ * **Graph scoping.** The GraphQL endpoint is mounted per-graph at
10
+ * `/extensions/{graph_id}/graphql`. Resolvers read the graph from the URL
11
+ * path parameter — never from GraphQL variables. Every facade method
12
+ * takes a `graphId` and resolves the correct per-graph client via
13
+ * `getGraphQLClient(graphId)`, which caches one `GraphQLClient` instance
14
+ * per graph to avoid rebuilding headers + URLs on every call.
15
+ *
16
+ * We pick graphql-request (tiny, no React, no caching) because the facade
17
+ * doesn't need the hook ergonomics that urql/Apollo provide. Type safety
18
+ * comes from GraphQL Code Generator, which produces typed DocumentNodes
19
+ * from the query files in sdk-extensions/graphql/queries/.
20
+ */
21
+ import { GraphQLClient } from 'graphql-request';
22
+ /**
23
+ * Callback that returns the current auth credential on demand.
24
+ *
25
+ * Use this instead of the static `token` field when the credential
26
+ * can rotate during the lifetime of the client — the primary case
27
+ * is short-lived JWTs that auto-refresh from browser token storage.
28
+ * The provider is invoked on **every** GraphQL request, so the
29
+ * returned value should be cheap to obtain (a localStorage read or
30
+ * an in-memory lookup, not a network call if avoidable).
31
+ *
32
+ * May return `null`/`undefined` to indicate "no credential available
33
+ * right now" — the request will be sent unauthenticated in that
34
+ * case, which lets the caller distinguish auth-expired errors from
35
+ * never-authed errors at the transport layer.
36
+ */
37
+ export type TokenProvider = () => string | null | undefined | Promise<string | null | undefined>;
38
+ export interface GraphQLClientConfig {
39
+ baseUrl: string;
40
+ /**
41
+ * Static credential captured at construction time. Use this when
42
+ * the token won't rotate (e.g. CLI/server flows using a long-lived
43
+ * API key). For JWT flows prefer `tokenProvider` so refreshes are
44
+ * picked up without rebuilding the client.
45
+ */
46
+ token?: string;
47
+ /**
48
+ * Dynamic credential callback, read on every request. Wins over
49
+ * `token` when both are set. See `TokenProvider` for semantics.
50
+ */
51
+ tokenProvider?: TokenProvider;
52
+ headers?: Record<string, string>;
53
+ credentials?: 'include' | 'same-origin' | 'omit';
54
+ }
55
+ /**
56
+ * Build a new GraphQL client for the given graph. Prefer
57
+ * `GraphQLClientCache.get(graphId)` in facade code — this is the raw
58
+ * factory and bypasses the cache.
59
+ */
60
+ export declare function createGraphQLClient(config: GraphQLClientConfig, graphId: string): GraphQLClient;
61
+ /**
62
+ * Per-graph cache of GraphQL clients. Facade clients own one instance of
63
+ * this and call `.get(graphId)` on every GraphQL method — cheap after the
64
+ * first call per graph.
65
+ */
66
+ export declare class GraphQLClientCache {
67
+ private config;
68
+ private clients;
69
+ constructor(config: GraphQLClientConfig);
70
+ get(graphId: string): GraphQLClient;
71
+ /**
72
+ * Drop all cached clients. Only needed when swapping **static**
73
+ * credentials — e.g. replacing the `token` field on a long-lived
74
+ * facade between tenants, or resetting a CLI session. When the
75
+ * cache was built from a `tokenProvider`, rotation is handled
76
+ * per-request inside `requestMiddleware` and `clear()` is a no-op
77
+ * for auth purposes (the cached `GraphQLClient` instances keep
78
+ * using the same provider reference and will pick up the next
79
+ * token automatically).
80
+ */
81
+ clear(): void;
82
+ }
@@ -0,0 +1,149 @@
1
+ 'use client';
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.GraphQLClientCache = void 0;
5
+ exports.createGraphQLClient = createGraphQLClient;
6
+ /**
7
+ * GraphQL client factory used internally by the facade clients.
8
+ *
9
+ * This is an implementation detail — consumers never interact with it
10
+ * directly. They call methods on LedgerClient / InvestorClient / etc.,
11
+ * which use this to execute GraphQL queries against
12
+ * `/extensions/{graph_id}/graphql`.
13
+ *
14
+ * **Graph scoping.** The GraphQL endpoint is mounted per-graph at
15
+ * `/extensions/{graph_id}/graphql`. Resolvers read the graph from the URL
16
+ * path parameter — never from GraphQL variables. Every facade method
17
+ * takes a `graphId` and resolves the correct per-graph client via
18
+ * `getGraphQLClient(graphId)`, which caches one `GraphQLClient` instance
19
+ * per graph to avoid rebuilding headers + URLs on every call.
20
+ *
21
+ * We pick graphql-request (tiny, no React, no caching) because the facade
22
+ * doesn't need the hook ergonomics that urql/Apollo provide. Type safety
23
+ * comes from GraphQL Code Generator, which produces typed DocumentNodes
24
+ * from the query files in sdk-extensions/graphql/queries/.
25
+ */
26
+ const graphql_request_1 = require("graphql-request");
27
+ /**
28
+ * Apply a credential to an in-progress request's headers, choosing
29
+ * the right header based on token shape:
30
+ *
31
+ * - `rfs…` prefix → `X-API-Key` (long-lived API key, validated
32
+ * against the database's api_keys table).
33
+ * - anything else → `Authorization: Bearer …` (short-lived JWT,
34
+ * validated by JWT middleware).
35
+ *
36
+ * The two credential types are NOT interchangeable at the backend —
37
+ * sending a JWT as `X-API-Key` or an API key as Bearer both 401.
38
+ */
39
+ function applyAuthHeader(headers, token) {
40
+ if (token.startsWith('rfs')) {
41
+ headers.set('X-API-Key', token);
42
+ }
43
+ else {
44
+ headers.set('Authorization', `Bearer ${token}`);
45
+ }
46
+ }
47
+ /**
48
+ * Build a new GraphQL client for the given graph. Prefer
49
+ * `GraphQLClientCache.get(graphId)` in facade code — this is the raw
50
+ * factory and bypasses the cache.
51
+ */
52
+ function createGraphQLClient(config, graphId) {
53
+ if (!graphId) {
54
+ throw new Error('createGraphQLClient requires a non-empty graphId');
55
+ }
56
+ const url = `${config.baseUrl.replace(/\/$/, '')}/extensions/${graphId}/graphql`;
57
+ const staticHeaders = {
58
+ ...(config.headers ?? {}),
59
+ };
60
+ // Dynamic-token path: defer credential injection to a per-request
61
+ // middleware so JWT refreshes are picked up without rebuilding or
62
+ // clearing the client. This is the recommended path for browser
63
+ // flows where the token in localStorage rotates every ~30 minutes.
64
+ if (config.tokenProvider) {
65
+ const providerFn = config.tokenProvider;
66
+ return new graphql_request_1.GraphQLClient(url, {
67
+ headers: staticHeaders,
68
+ credentials: config.credentials,
69
+ requestMiddleware: async (request) => {
70
+ let token;
71
+ try {
72
+ token = await providerFn();
73
+ }
74
+ 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
+ // eslint-disable-next-line no-console
83
+ console.warn('[RoboSystems SDK] tokenProvider threw — sending unauthenticated request:', err);
84
+ token = undefined;
85
+ }
86
+ if (!token) {
87
+ return request;
88
+ }
89
+ // `request.headers` is a HeadersInit (Headers | string[][] |
90
+ // Record<string, string>), so normalize via Headers before
91
+ // mutating. Spreading it directly loses keys when it's a
92
+ // Headers instance.
93
+ const merged = new Headers(request.headers);
94
+ applyAuthHeader(merged, token);
95
+ return { ...request, headers: merged };
96
+ },
97
+ });
98
+ }
99
+ // Static-token path: pick the right header at construction time.
100
+ // Suitable for long-lived API keys that never rotate.
101
+ if (config.token) {
102
+ const headers = new Headers(staticHeaders);
103
+ applyAuthHeader(headers, config.token);
104
+ return new graphql_request_1.GraphQLClient(url, {
105
+ headers,
106
+ credentials: config.credentials,
107
+ });
108
+ }
109
+ // No credentials at all — used by unauthenticated introspection
110
+ // queries against public dev endpoints.
111
+ return new graphql_request_1.GraphQLClient(url, {
112
+ headers: staticHeaders,
113
+ credentials: config.credentials,
114
+ });
115
+ }
116
+ /**
117
+ * Per-graph cache of GraphQL clients. Facade clients own one instance of
118
+ * this and call `.get(graphId)` on every GraphQL method — cheap after the
119
+ * first call per graph.
120
+ */
121
+ class GraphQLClientCache {
122
+ constructor(config) {
123
+ this.config = config;
124
+ this.clients = new Map();
125
+ }
126
+ get(graphId) {
127
+ const existing = this.clients.get(graphId);
128
+ if (existing !== undefined) {
129
+ return existing;
130
+ }
131
+ const client = createGraphQLClient(this.config, graphId);
132
+ this.clients.set(graphId, client);
133
+ return client;
134
+ }
135
+ /**
136
+ * Drop all cached clients. Only needed when swapping **static**
137
+ * credentials — e.g. replacing the `token` field on a long-lived
138
+ * facade between tenants, or resetting a CLI session. When the
139
+ * cache was built from a `tokenProvider`, rotation is handled
140
+ * per-request inside `requestMiddleware` and `clear()` is a no-op
141
+ * for auth purposes (the cached `GraphQLClient` instances keep
142
+ * using the same provider reference and will pick up the next
143
+ * token automatically).
144
+ */
145
+ clear() {
146
+ this.clients.clear();
147
+ }
148
+ }
149
+ exports.GraphQLClientCache = GraphQLClientCache;
@@ -0,0 +1,189 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * GraphQL client factory used internally by the facade clients.
5
+ *
6
+ * This is an implementation detail — consumers never interact with it
7
+ * directly. They call methods on LedgerClient / InvestorClient / etc.,
8
+ * which use this to execute GraphQL queries against
9
+ * `/extensions/{graph_id}/graphql`.
10
+ *
11
+ * **Graph scoping.** The GraphQL endpoint is mounted per-graph at
12
+ * `/extensions/{graph_id}/graphql`. Resolvers read the graph from the URL
13
+ * path parameter — never from GraphQL variables. Every facade method
14
+ * takes a `graphId` and resolves the correct per-graph client via
15
+ * `getGraphQLClient(graphId)`, which caches one `GraphQLClient` instance
16
+ * per graph to avoid rebuilding headers + URLs on every call.
17
+ *
18
+ * We pick graphql-request (tiny, no React, no caching) because the facade
19
+ * doesn't need the hook ergonomics that urql/Apollo provide. Type safety
20
+ * comes from GraphQL Code Generator, which produces typed DocumentNodes
21
+ * from the query files in sdk-extensions/graphql/queries/.
22
+ */
23
+
24
+ import { GraphQLClient } from 'graphql-request'
25
+
26
+ /**
27
+ * Callback that returns the current auth credential on demand.
28
+ *
29
+ * Use this instead of the static `token` field when the credential
30
+ * can rotate during the lifetime of the client — the primary case
31
+ * is short-lived JWTs that auto-refresh from browser token storage.
32
+ * The provider is invoked on **every** GraphQL request, so the
33
+ * returned value should be cheap to obtain (a localStorage read or
34
+ * an in-memory lookup, not a network call if avoidable).
35
+ *
36
+ * May return `null`/`undefined` to indicate "no credential available
37
+ * right now" — the request will be sent unauthenticated in that
38
+ * case, which lets the caller distinguish auth-expired errors from
39
+ * never-authed errors at the transport layer.
40
+ */
41
+ export type TokenProvider = () => string | null | undefined | Promise<string | null | undefined>
42
+
43
+ export interface GraphQLClientConfig {
44
+ baseUrl: string
45
+ /**
46
+ * Static credential captured at construction time. Use this when
47
+ * the token won't rotate (e.g. CLI/server flows using a long-lived
48
+ * API key). For JWT flows prefer `tokenProvider` so refreshes are
49
+ * picked up without rebuilding the client.
50
+ */
51
+ token?: string
52
+ /**
53
+ * Dynamic credential callback, read on every request. Wins over
54
+ * `token` when both are set. See `TokenProvider` for semantics.
55
+ */
56
+ tokenProvider?: TokenProvider
57
+ headers?: Record<string, string>
58
+ credentials?: 'include' | 'same-origin' | 'omit'
59
+ }
60
+
61
+ /**
62
+ * Apply a credential to an in-progress request's headers, choosing
63
+ * the right header based on token shape:
64
+ *
65
+ * - `rfs…` prefix → `X-API-Key` (long-lived API key, validated
66
+ * against the database's api_keys table).
67
+ * - anything else → `Authorization: Bearer …` (short-lived JWT,
68
+ * validated by JWT middleware).
69
+ *
70
+ * The two credential types are NOT interchangeable at the backend —
71
+ * sending a JWT as `X-API-Key` or an API key as Bearer both 401.
72
+ */
73
+ function applyAuthHeader(headers: Headers, token: string): void {
74
+ if (token.startsWith('rfs')) {
75
+ headers.set('X-API-Key', token)
76
+ } else {
77
+ headers.set('Authorization', `Bearer ${token}`)
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Build a new GraphQL client for the given graph. Prefer
83
+ * `GraphQLClientCache.get(graphId)` in facade code — this is the raw
84
+ * factory and bypasses the cache.
85
+ */
86
+ export function createGraphQLClient(config: GraphQLClientConfig, graphId: string): GraphQLClient {
87
+ if (!graphId) {
88
+ throw new Error('createGraphQLClient requires a non-empty graphId')
89
+ }
90
+ const url = `${config.baseUrl.replace(/\/$/, '')}/extensions/${graphId}/graphql`
91
+ const staticHeaders: Record<string, string> = {
92
+ ...(config.headers ?? {}),
93
+ }
94
+
95
+ // Dynamic-token path: defer credential injection to a per-request
96
+ // middleware so JWT refreshes are picked up without rebuilding or
97
+ // clearing the client. This is the recommended path for browser
98
+ // flows where the token in localStorage rotates every ~30 minutes.
99
+ if (config.tokenProvider) {
100
+ const providerFn = config.tokenProvider
101
+ return new GraphQLClient(url, {
102
+ headers: staticHeaders,
103
+ credentials: config.credentials,
104
+ requestMiddleware: async (request) => {
105
+ let token: string | null | undefined
106
+ try {
107
+ token = await providerFn()
108
+ } 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
+ // eslint-disable-next-line no-console
117
+ console.warn(
118
+ '[RoboSystems SDK] tokenProvider threw — sending unauthenticated request:',
119
+ err
120
+ )
121
+ token = undefined
122
+ }
123
+ if (!token) {
124
+ return request
125
+ }
126
+ // `request.headers` is a HeadersInit (Headers | string[][] |
127
+ // Record<string, string>), so normalize via Headers before
128
+ // mutating. Spreading it directly loses keys when it's a
129
+ // Headers instance.
130
+ const merged = new Headers(request.headers as HeadersInit | undefined)
131
+ applyAuthHeader(merged, token)
132
+ return { ...request, headers: merged }
133
+ },
134
+ })
135
+ }
136
+
137
+ // Static-token path: pick the right header at construction time.
138
+ // Suitable for long-lived API keys that never rotate.
139
+ if (config.token) {
140
+ const headers = new Headers(staticHeaders)
141
+ applyAuthHeader(headers, config.token)
142
+ return new GraphQLClient(url, {
143
+ headers,
144
+ credentials: config.credentials,
145
+ })
146
+ }
147
+
148
+ // No credentials at all — used by unauthenticated introspection
149
+ // queries against public dev endpoints.
150
+ return new GraphQLClient(url, {
151
+ headers: staticHeaders,
152
+ credentials: config.credentials,
153
+ })
154
+ }
155
+
156
+ /**
157
+ * Per-graph cache of GraphQL clients. Facade clients own one instance of
158
+ * this and call `.get(graphId)` on every GraphQL method — cheap after the
159
+ * first call per graph.
160
+ */
161
+ export class GraphQLClientCache {
162
+ private clients = new Map<string, GraphQLClient>()
163
+
164
+ constructor(private config: GraphQLClientConfig) {}
165
+
166
+ get(graphId: string): GraphQLClient {
167
+ const existing = this.clients.get(graphId)
168
+ if (existing !== undefined) {
169
+ return existing
170
+ }
171
+ const client = createGraphQLClient(this.config, graphId)
172
+ this.clients.set(graphId, client)
173
+ return client
174
+ }
175
+
176
+ /**
177
+ * Drop all cached clients. Only needed when swapping **static**
178
+ * credentials — e.g. replacing the `token` field on a long-lived
179
+ * facade between tenants, or resetting a CLI session. When the
180
+ * cache was built from a `tokenProvider`, rotation is handled
181
+ * per-request inside `requestMiddleware` and `clear()` is a no-op
182
+ * for auth purposes (the cached `GraphQLClient` instances keep
183
+ * using the same provider reference and will pick up the next
184
+ * token automatically).
185
+ */
186
+ clear(): void {
187
+ this.clients.clear()
188
+ }
189
+ }