@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.
- package/extensions/InvestorClient.d.ts +98 -0
- package/extensions/InvestorClient.js +223 -0
- package/extensions/InvestorClient.ts +508 -0
- package/extensions/LedgerClient.d.ts +190 -309
- package/extensions/LedgerClient.js +268 -587
- package/extensions/LedgerClient.ts +784 -903
- package/extensions/ReportClient.d.ts +82 -113
- package/extensions/ReportClient.js +124 -211
- package/extensions/ReportClient.ts +305 -358
- package/extensions/config.d.ts +19 -0
- package/extensions/config.js +1 -1
- package/extensions/config.ts +22 -2
- package/extensions/graphql/client.d.ts +82 -0
- package/extensions/graphql/client.js +149 -0
- package/extensions/graphql/client.ts +189 -0
- package/extensions/graphql/generated/graphql.d.ts +1786 -0
- package/extensions/graphql/generated/graphql.js +2671 -0
- package/extensions/graphql/generated/graphql.ts +4491 -0
- package/extensions/graphql/queries/investor/holdings.d.ts +8 -0
- package/extensions/graphql/queries/investor/holdings.js +36 -0
- package/extensions/graphql/queries/investor/holdings.ts +34 -0
- package/extensions/graphql/queries/investor/portfolio.d.ts +4 -0
- package/extensions/graphql/queries/investor/portfolio.js +21 -0
- package/extensions/graphql/queries/investor/portfolio.ts +19 -0
- package/extensions/graphql/queries/investor/portfolios.d.ts +4 -0
- package/extensions/graphql/queries/investor/portfolios.js +29 -0
- package/extensions/graphql/queries/investor/portfolios.ts +27 -0
- package/extensions/graphql/queries/investor/position.d.ts +4 -0
- package/extensions/graphql/queries/investor/position.js +33 -0
- package/extensions/graphql/queries/investor/position.ts +31 -0
- package/extensions/graphql/queries/investor/positions.d.ts +8 -0
- package/extensions/graphql/queries/investor/positions.js +57 -0
- package/extensions/graphql/queries/investor/positions.ts +55 -0
- package/extensions/graphql/queries/investor/securities.d.ts +8 -0
- package/extensions/graphql/queries/investor/securities.js +50 -0
- package/extensions/graphql/queries/investor/securities.ts +48 -0
- package/extensions/graphql/queries/investor/security.d.ts +4 -0
- package/extensions/graphql/queries/investor/security.js +26 -0
- package/extensions/graphql/queries/investor/security.ts +24 -0
- package/extensions/graphql/queries/ledger/accountRollups.d.ts +7 -0
- package/extensions/graphql/queries/ledger/accountRollups.js +36 -0
- package/extensions/graphql/queries/ledger/accountRollups.ts +34 -0
- package/extensions/graphql/queries/ledger/accountTree.d.ts +11 -0
- package/extensions/graphql/queries/ledger/accountTree.js +61 -0
- package/extensions/graphql/queries/ledger/accountTree.ts +59 -0
- package/extensions/graphql/queries/ledger/accounts.d.ts +8 -0
- package/extensions/graphql/queries/ledger/accounts.js +45 -0
- package/extensions/graphql/queries/ledger/accounts.ts +43 -0
- package/extensions/graphql/queries/ledger/closingBookStructures.d.ts +6 -0
- package/extensions/graphql/queries/ledger/closingBookStructures.js +27 -0
- package/extensions/graphql/queries/ledger/closingBookStructures.ts +25 -0
- package/extensions/graphql/queries/ledger/elements.d.ts +6 -0
- package/extensions/graphql/queries/ledger/elements.js +56 -0
- package/extensions/graphql/queries/ledger/elements.ts +54 -0
- package/extensions/graphql/queries/ledger/entities.d.ts +7 -0
- package/extensions/graphql/queries/ledger/entities.js +31 -0
- package/extensions/graphql/queries/ledger/entities.ts +29 -0
- package/extensions/graphql/queries/ledger/entity.d.ts +14 -0
- package/extensions/graphql/queries/ledger/entity.js +55 -0
- package/extensions/graphql/queries/ledger/entity.ts +54 -0
- package/extensions/graphql/queries/ledger/fiscalCalendar.d.ts +8 -0
- package/extensions/graphql/queries/ledger/fiscalCalendar.js +35 -0
- package/extensions/graphql/queries/ledger/fiscalCalendar.ts +33 -0
- package/extensions/graphql/queries/ledger/mappedTrialBalance.d.ts +9 -0
- package/extensions/graphql/queries/ledger/mappedTrialBalance.js +29 -0
- package/extensions/graphql/queries/ledger/mappedTrialBalance.ts +27 -0
- package/extensions/graphql/queries/ledger/mapping.d.ts +5 -0
- package/extensions/graphql/queries/ledger/mapping.js +35 -0
- package/extensions/graphql/queries/ledger/mapping.ts +33 -0
- package/extensions/graphql/queries/ledger/mappingCoverage.d.ts +5 -0
- package/extensions/graphql/queries/ledger/mappingCoverage.js +22 -0
- package/extensions/graphql/queries/ledger/mappingCoverage.ts +20 -0
- package/extensions/graphql/queries/ledger/mappings.d.ts +6 -0
- package/extensions/graphql/queries/ledger/mappings.js +23 -0
- package/extensions/graphql/queries/ledger/mappings.ts +21 -0
- package/extensions/graphql/queries/ledger/periodCloseStatus.d.ts +6 -0
- package/extensions/graphql/queries/ledger/periodCloseStatus.js +29 -0
- package/extensions/graphql/queries/ledger/periodCloseStatus.ts +27 -0
- package/extensions/graphql/queries/ledger/periodDrafts.d.ts +8 -0
- package/extensions/graphql/queries/ledger/periodDrafts.js +45 -0
- package/extensions/graphql/queries/ledger/periodDrafts.ts +43 -0
- package/extensions/graphql/queries/ledger/publishList.d.ts +5 -0
- package/extensions/graphql/queries/ledger/publishList.js +29 -0
- package/extensions/graphql/queries/ledger/publishList.ts +27 -0
- package/extensions/graphql/queries/ledger/publishLists.d.ts +5 -0
- package/extensions/graphql/queries/ledger/publishLists.js +29 -0
- package/extensions/graphql/queries/ledger/publishLists.ts +27 -0
- package/extensions/graphql/queries/ledger/report.d.ts +5 -0
- package/extensions/graphql/queries/ledger/report.js +40 -0
- package/extensions/graphql/queries/ledger/report.ts +38 -0
- package/extensions/graphql/queries/ledger/reportingTaxonomy.d.ts +6 -0
- package/extensions/graphql/queries/ledger/reportingTaxonomy.js +27 -0
- package/extensions/graphql/queries/ledger/reportingTaxonomy.ts +25 -0
- package/extensions/graphql/queries/ledger/reports.d.ts +8 -0
- package/extensions/graphql/queries/ledger/reports.js +45 -0
- package/extensions/graphql/queries/ledger/reports.ts +43 -0
- package/extensions/graphql/queries/ledger/scheduleFacts.d.ts +7 -0
- package/extensions/graphql/queries/ledger/scheduleFacts.js +24 -0
- package/extensions/graphql/queries/ledger/scheduleFacts.ts +22 -0
- package/extensions/graphql/queries/ledger/schedules.d.ts +6 -0
- package/extensions/graphql/queries/ledger/schedules.js +24 -0
- package/extensions/graphql/queries/ledger/schedules.ts +22 -0
- package/extensions/graphql/queries/ledger/statement.d.ts +9 -0
- package/extensions/graphql/queries/ledger/statement.js +43 -0
- package/extensions/graphql/queries/ledger/statement.ts +41 -0
- package/extensions/graphql/queries/ledger/structures.d.ts +5 -0
- package/extensions/graphql/queries/ledger/structures.js +22 -0
- package/extensions/graphql/queries/ledger/structures.ts +20 -0
- package/extensions/graphql/queries/ledger/summary.d.ts +7 -0
- package/extensions/graphql/queries/ledger/summary.js +25 -0
- package/extensions/graphql/queries/ledger/summary.ts +23 -0
- package/extensions/graphql/queries/ledger/taxonomies.d.ts +5 -0
- package/extensions/graphql/queries/ledger/taxonomies.js +28 -0
- package/extensions/graphql/queries/ledger/taxonomies.ts +26 -0
- package/extensions/graphql/queries/ledger/transaction.d.ts +6 -0
- package/extensions/graphql/queries/ledger/transaction.js +49 -0
- package/extensions/graphql/queries/ledger/transaction.ts +47 -0
- package/extensions/graphql/queries/ledger/transactions.d.ts +7 -0
- package/extensions/graphql/queries/ledger/transactions.js +49 -0
- package/extensions/graphql/queries/ledger/transactions.ts +47 -0
- package/extensions/graphql/queries/ledger/trialBalance.d.ts +7 -0
- package/extensions/graphql/queries/ledger/trialBalance.js +28 -0
- package/extensions/graphql/queries/ledger/trialBalance.ts +26 -0
- package/extensions/graphql/queries/ledger/unmappedElements.d.ts +8 -0
- package/extensions/graphql/queries/ledger/unmappedElements.js +29 -0
- package/extensions/graphql/queries/ledger/unmappedElements.ts +27 -0
- package/extensions/hooks.d.ts +1 -1
- package/extensions/index.d.ts +18 -1
- package/extensions/index.js +26 -1
- package/extensions/index.ts +49 -2
- package/index.ts +2 -2
- package/package.json +14 -5
- package/sdk/index.d.ts +2 -2
- package/sdk/index.js +38 -73
- package/sdk/index.ts +2 -2
- package/sdk/sdk.gen.d.ts +100 -325
- package/sdk/sdk.gen.js +228 -592
- package/sdk/sdk.gen.ts +193 -556
- package/sdk/types.gen.d.ts +4522 -7708
- package/sdk/types.gen.ts +4569 -7983
- package/sdk.gen.d.ts +100 -325
- package/sdk.gen.js +228 -592
- package/sdk.gen.ts +193 -556
- package/types.gen.d.ts +4522 -7708
- package/types.gen.ts +4569 -7983
- package/extensions/AgentClient.test.ts +0 -403
- package/extensions/LedgerClient.test.ts +0 -1655
- package/extensions/OperationClient.test.ts +0 -365
- package/extensions/QueryClient.test.ts +0 -432
- package/extensions/ReportClient.test.ts +0 -828
- package/extensions/SSEClient.test.ts +0 -375
- package/extensions/config.test.ts +0 -199
- package/extensions/hooks.test.ts +0 -373
- package/extensions/index.test.ts +0 -420
- package/sdk-extensions/AgentClient.d.ts +0 -82
- package/sdk-extensions/AgentClient.js +0 -218
- package/sdk-extensions/AgentClient.test.ts +0 -403
- package/sdk-extensions/AgentClient.ts +0 -321
- package/sdk-extensions/LedgerClient.d.ts +0 -416
- package/sdk-extensions/LedgerClient.js +0 -737
- package/sdk-extensions/LedgerClient.test.ts +0 -1655
- package/sdk-extensions/LedgerClient.ts +0 -1249
- package/sdk-extensions/OperationClient.d.ts +0 -65
- package/sdk-extensions/OperationClient.js +0 -251
- package/sdk-extensions/OperationClient.test.ts +0 -365
- package/sdk-extensions/OperationClient.ts +0 -324
- package/sdk-extensions/QueryClient.d.ts +0 -52
- package/sdk-extensions/QueryClient.js +0 -313
- package/sdk-extensions/QueryClient.test.ts +0 -432
- package/sdk-extensions/QueryClient.ts +0 -420
- package/sdk-extensions/README.md +0 -901
- package/sdk-extensions/ReportClient.d.ts +0 -151
- package/sdk-extensions/ReportClient.js +0 -278
- package/sdk-extensions/ReportClient.test.ts +0 -828
- package/sdk-extensions/ReportClient.ts +0 -486
- package/sdk-extensions/SSEClient.d.ts +0 -62
- package/sdk-extensions/SSEClient.js +0 -154
- package/sdk-extensions/SSEClient.test.ts +0 -375
- package/sdk-extensions/SSEClient.ts +0 -210
- package/sdk-extensions/config.d.ts +0 -57
- package/sdk-extensions/config.js +0 -152
- package/sdk-extensions/config.test.ts +0 -199
- package/sdk-extensions/config.ts +0 -175
- package/sdk-extensions/hooks.d.ts +0 -110
- package/sdk-extensions/hooks.js +0 -384
- package/sdk-extensions/hooks.test.ts +0 -373
- package/sdk-extensions/hooks.ts +0 -459
- package/sdk-extensions/index.d.ts +0 -63
- package/sdk-extensions/index.js +0 -164
- package/sdk-extensions/index.test.ts +0 -420
- package/sdk-extensions/index.ts +0 -203
package/extensions/config.d.ts
CHANGED
|
@@ -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;
|
package/extensions/config.js
CHANGED
|
@@ -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('../
|
|
84
|
+
const { client } = require('../client.gen');
|
|
85
85
|
const sdkConfig = getSDKExtensionsConfig();
|
|
86
86
|
// Priority 1: Use explicitly configured token
|
|
87
87
|
if (sdkConfig.token) {
|
package/extensions/config.ts
CHANGED
|
@@ -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
|
-
|
|
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('../
|
|
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
|
+
}
|