@quiltt/core 5.0.3 → 5.1.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.
- package/CHANGELOG.md +12 -0
- package/dist/api/browser.d.ts +6 -0
- package/dist/api/graphql/{SubscriptionLink-12s-wjkChfxO.cjs → SubscriptionLink-12s-DUvHs5WL.cjs} +11 -4
- package/dist/api/graphql/{SubscriptionLink-12s-ufJBKwu1.js → SubscriptionLink-12s-UDBUsy8w.js} +11 -4
- package/dist/api/graphql/index.cjs +58 -1
- package/dist/api/graphql/index.d.ts +22 -2
- package/dist/api/graphql/index.js +58 -2
- package/dist/config/index.cjs +1 -1
- package/dist/config/index.js +1 -1
- package/package.json +1 -1
- package/src/api/browser.ts +6 -0
- package/src/api/graphql/links/ActionCableLink.ts +14 -3
- package/src/api/graphql/links/AuthLink.ts +1 -1
- package/src/api/graphql/links/HeadersLink.ts +84 -0
- package/src/api/graphql/links/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @quiltt/core
|
|
2
2
|
|
|
3
|
+
## 5.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#406](https://github.com/quiltt/quiltt-js/pull/406) [`177a4fc`](https://github.com/quiltt/quiltt-js/commit/177a4fc3d70fa3f313f6586396719dae9763cf4b) Thanks [@zubairaziz](https://github.com/zubairaziz)! - Add OAuth redirect URL support to React SDK
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#418](https://github.com/quiltt/quiltt-js/pull/418) [`2d918a0`](https://github.com/quiltt/quiltt-js/commit/2d918a089f8546bb7d20db1eefd958beca296ee0) Thanks [@sirwolfgang](https://github.com/sirwolfgang)! - Internal: Add `headers` prop to QuilttProvider
|
|
12
|
+
|
|
13
|
+
For Quiltt internal usage. Not intended for public use.
|
|
14
|
+
|
|
3
15
|
## 5.0.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/api/browser.d.ts
CHANGED
|
@@ -101,6 +101,8 @@ type ConnectorSDKCallbackMetadata = {
|
|
|
101
101
|
type ConnectorSDKConnectOptions = ConnectorSDKCallbacks & {
|
|
102
102
|
/** The Institution ID or search term to connect */
|
|
103
103
|
institution?: string;
|
|
104
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
105
|
+
oauthRedirectUrl?: string;
|
|
104
106
|
};
|
|
105
107
|
/**
|
|
106
108
|
* Options for the Reconnect flow
|
|
@@ -109,6 +111,8 @@ type ConnectorSDKConnectOptions = ConnectorSDKCallbacks & {
|
|
|
109
111
|
type ConnectorSDKReconnectOptions = ConnectorSDKCallbacks & {
|
|
110
112
|
/** The ID of the Connection to reconnect */
|
|
111
113
|
connectionId: string;
|
|
114
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
115
|
+
oauthRedirectUrl?: string;
|
|
112
116
|
};
|
|
113
117
|
/** Options to initialize Connector
|
|
114
118
|
*
|
|
@@ -122,6 +126,8 @@ type ConnectorSDKConnectorOptions = ConnectorSDKCallbacks & {
|
|
|
122
126
|
connectionId?: string;
|
|
123
127
|
/** The nonce to use for the script tag */
|
|
124
128
|
nonce?: string;
|
|
129
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
130
|
+
oauthRedirectUrl?: string;
|
|
125
131
|
};
|
|
126
132
|
|
|
127
133
|
export { ConnectorSDKEventType };
|
package/dist/api/graphql/{SubscriptionLink-12s-wjkChfxO.cjs → SubscriptionLink-12s-DUvHs5WL.cjs}
RENAMED
|
@@ -99,6 +99,7 @@ class ActionCableLink extends core.ApolloLink {
|
|
|
99
99
|
this.cables[token] = actioncable.createConsumer(index_cjs$1.endpointWebsockets + (token ? `?token=${token}` : ''));
|
|
100
100
|
}
|
|
101
101
|
return new rxjs.Observable((observer)=>{
|
|
102
|
+
let cancelled = false;
|
|
102
103
|
const channelId = Math.round(Date.now() + Math.random() * 100000).toString(16);
|
|
103
104
|
const actionName = this.actionName;
|
|
104
105
|
const connectionParams = typeof this.connectionParams === 'function' ? this.connectionParams(operation) : this.connectionParams;
|
|
@@ -108,6 +109,7 @@ class ActionCableLink extends core.ApolloLink {
|
|
|
108
109
|
channelId: channelId
|
|
109
110
|
}, connectionParams), {
|
|
110
111
|
connected: (args)=>{
|
|
112
|
+
if (cancelled) return;
|
|
111
113
|
channel.perform(actionName, {
|
|
112
114
|
query: operation.query ? graphql.print(operation.query) : null,
|
|
113
115
|
variables: operation.variables,
|
|
@@ -118,6 +120,7 @@ class ActionCableLink extends core.ApolloLink {
|
|
|
118
120
|
callbacks.connected?.(args);
|
|
119
121
|
},
|
|
120
122
|
received: (payload)=>{
|
|
123
|
+
if (cancelled) return;
|
|
121
124
|
if (payload?.result?.data || payload?.result?.errors) {
|
|
122
125
|
observer.next(payload.result);
|
|
123
126
|
}
|
|
@@ -126,14 +129,18 @@ class ActionCableLink extends core.ApolloLink {
|
|
|
126
129
|
}
|
|
127
130
|
callbacks.received?.(payload);
|
|
128
131
|
},
|
|
132
|
+
// Intentionally not guarded by `cancelled` - disconnected represents
|
|
133
|
+
// the WebSocket connection state which users may want to know about
|
|
134
|
+
// for cleanup/status purposes, even after the observable completes.
|
|
129
135
|
disconnected: ()=>{
|
|
130
136
|
callbacks.disconnected?.();
|
|
131
137
|
}
|
|
132
138
|
});
|
|
133
|
-
//
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
// Return teardown logic
|
|
140
|
+
return ()=>{
|
|
141
|
+
cancelled = true;
|
|
142
|
+
channel.unsubscribe();
|
|
143
|
+
};
|
|
137
144
|
});
|
|
138
145
|
}
|
|
139
146
|
}
|
package/dist/api/graphql/{SubscriptionLink-12s-ufJBKwu1.js → SubscriptionLink-12s-UDBUsy8w.js}
RENAMED
|
@@ -99,6 +99,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
99
99
|
this.cables[token] = createConsumer(endpointWebsockets + (token ? `?token=${token}` : ''));
|
|
100
100
|
}
|
|
101
101
|
return new Observable((observer)=>{
|
|
102
|
+
let cancelled = false;
|
|
102
103
|
const channelId = Math.round(Date.now() + Math.random() * 100000).toString(16);
|
|
103
104
|
const actionName = this.actionName;
|
|
104
105
|
const connectionParams = typeof this.connectionParams === 'function' ? this.connectionParams(operation) : this.connectionParams;
|
|
@@ -108,6 +109,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
108
109
|
channelId: channelId
|
|
109
110
|
}, connectionParams), {
|
|
110
111
|
connected: (args)=>{
|
|
112
|
+
if (cancelled) return;
|
|
111
113
|
channel.perform(actionName, {
|
|
112
114
|
query: operation.query ? print(operation.query) : null,
|
|
113
115
|
variables: operation.variables,
|
|
@@ -118,6 +120,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
118
120
|
callbacks.connected?.(args);
|
|
119
121
|
},
|
|
120
122
|
received: (payload)=>{
|
|
123
|
+
if (cancelled) return;
|
|
121
124
|
if (payload?.result?.data || payload?.result?.errors) {
|
|
122
125
|
observer.next(payload.result);
|
|
123
126
|
}
|
|
@@ -126,14 +129,18 @@ class ActionCableLink extends ApolloLink {
|
|
|
126
129
|
}
|
|
127
130
|
callbacks.received?.(payload);
|
|
128
131
|
},
|
|
132
|
+
// Intentionally not guarded by `cancelled` - disconnected represents
|
|
133
|
+
// the WebSocket connection state which users may want to know about
|
|
134
|
+
// for cleanup/status purposes, even after the observable completes.
|
|
129
135
|
disconnected: ()=>{
|
|
130
136
|
callbacks.disconnected?.();
|
|
131
137
|
}
|
|
132
138
|
});
|
|
133
|
-
//
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
139
|
+
// Return teardown logic
|
|
140
|
+
return ()=>{
|
|
141
|
+
cancelled = true;
|
|
142
|
+
channel.unsubscribe();
|
|
143
|
+
};
|
|
137
144
|
});
|
|
138
145
|
}
|
|
139
146
|
}
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
3
3
|
var core = require('@apollo/client/core');
|
|
4
4
|
var index_cjs = require('../../config/index.cjs');
|
|
5
5
|
var rxjs = require('rxjs');
|
|
6
|
-
var SubscriptionLink12s = require('./SubscriptionLink-12s-
|
|
6
|
+
var SubscriptionLink12s = require('./SubscriptionLink-12s-DUvHs5WL.cjs');
|
|
7
7
|
var batchHttp = require('@apollo/client/link/batch-http');
|
|
8
8
|
var crossfetch = require('cross-fetch');
|
|
9
9
|
var error = require('@apollo/client/link/error');
|
|
@@ -88,6 +88,62 @@ const ErrorLink = new error.ErrorLink(({ error, result })=>{
|
|
|
88
88
|
|
|
89
89
|
const ForwardableLink = new core.ApolloLink((operation, forward)=>forward(operation));
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Apollo Link that adds custom headers to GraphQL requests.
|
|
93
|
+
*
|
|
94
|
+
* Headers can be provided statically or dynamically via a function.
|
|
95
|
+
* These headers are added before the AuthLink, so they will be preserved
|
|
96
|
+
* alongside the authorization header.
|
|
97
|
+
*/ class HeadersLink extends core.ApolloLink {
|
|
98
|
+
constructor(options = {}){
|
|
99
|
+
super();
|
|
100
|
+
this.headers = options.headers ?? {};
|
|
101
|
+
this.getHeaders = options.getHeaders;
|
|
102
|
+
}
|
|
103
|
+
request(operation, forward) {
|
|
104
|
+
// If we have a dynamic headers function, handle it
|
|
105
|
+
if (this.getHeaders) {
|
|
106
|
+
return new rxjs.Observable((observer)=>{
|
|
107
|
+
let innerSubscription;
|
|
108
|
+
let cancelled = false;
|
|
109
|
+
Promise.resolve(this.getHeaders()).then((dynamicHeaders)=>{
|
|
110
|
+
// Guard against late resolution after unsubscribe
|
|
111
|
+
if (cancelled) return;
|
|
112
|
+
operation.setContext(({ headers = {} })=>({
|
|
113
|
+
headers: {
|
|
114
|
+
...headers,
|
|
115
|
+
...this.headers,
|
|
116
|
+
...dynamicHeaders
|
|
117
|
+
}
|
|
118
|
+
}));
|
|
119
|
+
innerSubscription = forward(operation).subscribe({
|
|
120
|
+
next: (value)=>!cancelled && observer.next(value),
|
|
121
|
+
error: (err)=>!cancelled && observer.error(err),
|
|
122
|
+
complete: ()=>!cancelled && observer.complete()
|
|
123
|
+
});
|
|
124
|
+
}).catch((error)=>{
|
|
125
|
+
if (!cancelled) {
|
|
126
|
+
observer.error(error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
// Return teardown logic
|
|
130
|
+
return ()=>{
|
|
131
|
+
cancelled = true;
|
|
132
|
+
innerSubscription?.unsubscribe();
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Static headers only
|
|
137
|
+
operation.setContext(({ headers = {} })=>({
|
|
138
|
+
headers: {
|
|
139
|
+
...headers,
|
|
140
|
+
...this.headers
|
|
141
|
+
}
|
|
142
|
+
}));
|
|
143
|
+
return forward(operation);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
91
147
|
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
92
148
|
const effectiveFetch = typeof fetch === 'undefined' ? crossfetch__default.default : fetch;
|
|
93
149
|
const HttpLink = new http.HttpLink({
|
|
@@ -212,6 +268,7 @@ exports.AuthLink = AuthLink;
|
|
|
212
268
|
exports.BatchHttpLink = BatchHttpLink;
|
|
213
269
|
exports.ErrorLink = ErrorLink;
|
|
214
270
|
exports.ForwardableLink = ForwardableLink;
|
|
271
|
+
exports.HeadersLink = HeadersLink;
|
|
215
272
|
exports.HttpLink = HttpLink;
|
|
216
273
|
exports.QuilttClient = QuilttClient;
|
|
217
274
|
exports.RetryLink = RetryLink;
|
|
@@ -38,6 +38,26 @@ declare const ErrorLink: ErrorLink$1;
|
|
|
38
38
|
|
|
39
39
|
declare const ForwardableLink: ApolloLink;
|
|
40
40
|
|
|
41
|
+
type HeadersLinkOptions = {
|
|
42
|
+
/** Static headers to add to every request */
|
|
43
|
+
headers?: Record<string, string>;
|
|
44
|
+
/** Dynamic headers function called on each request */
|
|
45
|
+
getHeaders?: () => Record<string, string> | Promise<Record<string, string>>;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Apollo Link that adds custom headers to GraphQL requests.
|
|
49
|
+
*
|
|
50
|
+
* Headers can be provided statically or dynamically via a function.
|
|
51
|
+
* These headers are added before the AuthLink, so they will be preserved
|
|
52
|
+
* alongside the authorization header.
|
|
53
|
+
*/
|
|
54
|
+
declare class HeadersLink extends ApolloLink {
|
|
55
|
+
private headers;
|
|
56
|
+
private getHeaders?;
|
|
57
|
+
constructor(options?: HeadersLinkOptions);
|
|
58
|
+
request(operation: ApolloLink.Operation, forward: ApolloLink.ForwardFunction): Observable<ApolloLink.Result>;
|
|
59
|
+
}
|
|
60
|
+
|
|
41
61
|
declare const HttpLink: HttpLink$1;
|
|
42
62
|
|
|
43
63
|
declare const RetryLink: RetryLink$1;
|
|
@@ -78,5 +98,5 @@ declare const TerminatingLink: ApolloLink;
|
|
|
78
98
|
|
|
79
99
|
declare const createVersionLink: (platformInfo: string) => ApolloLink;
|
|
80
100
|
|
|
81
|
-
export { AuthLink, BatchHttpLink, ErrorLink, ForwardableLink, HttpLink, QuilttClient, RetryLink, SubscriptionLink, TerminatingLink, createVersionLink };
|
|
82
|
-
export type { QuilttClientOptions };
|
|
101
|
+
export { AuthLink, BatchHttpLink, ErrorLink, ForwardableLink, HeadersLink, HttpLink, QuilttClient, RetryLink, SubscriptionLink, TerminatingLink, createVersionLink };
|
|
102
|
+
export type { HeadersLinkOptions, QuilttClientOptions };
|
|
@@ -2,7 +2,7 @@ import { ApolloLink, ApolloClient } from '@apollo/client/core';
|
|
|
2
2
|
export { gql } from '@apollo/client/core';
|
|
3
3
|
import { endpointGraphQL, version, debugging } from '../../config/index.js';
|
|
4
4
|
import { Observable } from 'rxjs';
|
|
5
|
-
import { v as validateSessionToken, S as SubscriptionLink } from './SubscriptionLink-12s-
|
|
5
|
+
import { v as validateSessionToken, S as SubscriptionLink } from './SubscriptionLink-12s-UDBUsy8w.js';
|
|
6
6
|
import { BatchHttpLink as BatchHttpLink$1 } from '@apollo/client/link/batch-http';
|
|
7
7
|
import crossfetch from 'cross-fetch';
|
|
8
8
|
import { ErrorLink as ErrorLink$1 } from '@apollo/client/link/error';
|
|
@@ -83,6 +83,62 @@ const ErrorLink = new ErrorLink$1(({ error, result })=>{
|
|
|
83
83
|
|
|
84
84
|
const ForwardableLink = new ApolloLink((operation, forward)=>forward(operation));
|
|
85
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Apollo Link that adds custom headers to GraphQL requests.
|
|
88
|
+
*
|
|
89
|
+
* Headers can be provided statically or dynamically via a function.
|
|
90
|
+
* These headers are added before the AuthLink, so they will be preserved
|
|
91
|
+
* alongside the authorization header.
|
|
92
|
+
*/ class HeadersLink extends ApolloLink {
|
|
93
|
+
constructor(options = {}){
|
|
94
|
+
super();
|
|
95
|
+
this.headers = options.headers ?? {};
|
|
96
|
+
this.getHeaders = options.getHeaders;
|
|
97
|
+
}
|
|
98
|
+
request(operation, forward) {
|
|
99
|
+
// If we have a dynamic headers function, handle it
|
|
100
|
+
if (this.getHeaders) {
|
|
101
|
+
return new Observable((observer)=>{
|
|
102
|
+
let innerSubscription;
|
|
103
|
+
let cancelled = false;
|
|
104
|
+
Promise.resolve(this.getHeaders()).then((dynamicHeaders)=>{
|
|
105
|
+
// Guard against late resolution after unsubscribe
|
|
106
|
+
if (cancelled) return;
|
|
107
|
+
operation.setContext(({ headers = {} })=>({
|
|
108
|
+
headers: {
|
|
109
|
+
...headers,
|
|
110
|
+
...this.headers,
|
|
111
|
+
...dynamicHeaders
|
|
112
|
+
}
|
|
113
|
+
}));
|
|
114
|
+
innerSubscription = forward(operation).subscribe({
|
|
115
|
+
next: (value)=>!cancelled && observer.next(value),
|
|
116
|
+
error: (err)=>!cancelled && observer.error(err),
|
|
117
|
+
complete: ()=>!cancelled && observer.complete()
|
|
118
|
+
});
|
|
119
|
+
}).catch((error)=>{
|
|
120
|
+
if (!cancelled) {
|
|
121
|
+
observer.error(error);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
// Return teardown logic
|
|
125
|
+
return ()=>{
|
|
126
|
+
cancelled = true;
|
|
127
|
+
innerSubscription?.unsubscribe();
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// Static headers only
|
|
132
|
+
operation.setContext(({ headers = {} })=>({
|
|
133
|
+
headers: {
|
|
134
|
+
...headers,
|
|
135
|
+
...this.headers
|
|
136
|
+
}
|
|
137
|
+
}));
|
|
138
|
+
return forward(operation);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
86
142
|
// Use `cross-fetch` only if `fetch` is not available on the `globalThis` object
|
|
87
143
|
const effectiveFetch = typeof fetch === 'undefined' ? crossfetch : fetch;
|
|
88
144
|
const HttpLink = new HttpLink$1({
|
|
@@ -182,4 +238,4 @@ class QuilttClient extends ApolloClient {
|
|
|
182
238
|
}
|
|
183
239
|
}
|
|
184
240
|
|
|
185
|
-
export { AuthLink, BatchHttpLink, ErrorLink, ForwardableLink, HttpLink, QuilttClient, RetryLink, SubscriptionLink, TerminatingLink, createVersionLink };
|
|
241
|
+
export { AuthLink, BatchHttpLink, ErrorLink, ForwardableLink, HeadersLink, HttpLink, QuilttClient, RetryLink, SubscriptionLink, TerminatingLink, createVersionLink };
|
package/dist/config/index.cjs
CHANGED
package/dist/config/index.js
CHANGED
package/package.json
CHANGED
package/src/api/browser.ts
CHANGED
|
@@ -125,6 +125,8 @@ export type ConnectorSDKCallbackMetadata = {
|
|
|
125
125
|
export type ConnectorSDKConnectOptions = ConnectorSDKCallbacks & {
|
|
126
126
|
/** The Institution ID or search term to connect */
|
|
127
127
|
institution?: string
|
|
128
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
129
|
+
oauthRedirectUrl?: string
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
/**
|
|
@@ -134,6 +136,8 @@ export type ConnectorSDKConnectOptions = ConnectorSDKCallbacks & {
|
|
|
134
136
|
export type ConnectorSDKReconnectOptions = ConnectorSDKCallbacks & {
|
|
135
137
|
/** The ID of the Connection to reconnect */
|
|
136
138
|
connectionId: string
|
|
139
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
140
|
+
oauthRedirectUrl?: string
|
|
137
141
|
}
|
|
138
142
|
|
|
139
143
|
/** Options to initialize Connector
|
|
@@ -148,4 +152,6 @@ export type ConnectorSDKConnectorOptions = ConnectorSDKCallbacks & {
|
|
|
148
152
|
connectionId?: string
|
|
149
153
|
/** The nonce to use for the script tag */
|
|
150
154
|
nonce?: string
|
|
155
|
+
/** The OAuth redirect URL for mobile or embedded webview flows */
|
|
156
|
+
oauthRedirectUrl?: string
|
|
151
157
|
}
|
|
@@ -39,7 +39,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
39
39
|
|
|
40
40
|
// Interestingly, this link does _not_ call through to `next` because
|
|
41
41
|
// instead, it sends the request to ActionCable.
|
|
42
|
-
request(
|
|
42
|
+
override request(
|
|
43
43
|
operation: ApolloLink.Operation,
|
|
44
44
|
_next: ApolloLink.ForwardFunction
|
|
45
45
|
): Observable<RequestResult> {
|
|
@@ -58,6 +58,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
return new Observable((observer) => {
|
|
61
|
+
let cancelled = false
|
|
61
62
|
const channelId = Math.round(Date.now() + Math.random() * 100000).toString(16)
|
|
62
63
|
const actionName = this.actionName
|
|
63
64
|
const connectionParams =
|
|
@@ -77,6 +78,7 @@ class ActionCableLink extends ApolloLink {
|
|
|
77
78
|
),
|
|
78
79
|
{
|
|
79
80
|
connected: (args?: { reconnected: boolean }) => {
|
|
81
|
+
if (cancelled) return
|
|
80
82
|
channel.perform(actionName, {
|
|
81
83
|
query: operation.query ? print(operation.query) : null,
|
|
82
84
|
variables: operation.variables,
|
|
@@ -88,6 +90,8 @@ class ActionCableLink extends ApolloLink {
|
|
|
88
90
|
},
|
|
89
91
|
|
|
90
92
|
received: (payload: { result: RequestResult; more: any }) => {
|
|
93
|
+
if (cancelled) return
|
|
94
|
+
|
|
91
95
|
if (payload?.result?.data || payload?.result?.errors) {
|
|
92
96
|
observer.next(payload.result)
|
|
93
97
|
}
|
|
@@ -98,13 +102,20 @@ class ActionCableLink extends ApolloLink {
|
|
|
98
102
|
|
|
99
103
|
callbacks.received?.(payload)
|
|
100
104
|
},
|
|
105
|
+
// Intentionally not guarded by `cancelled` - disconnected represents
|
|
106
|
+
// the WebSocket connection state which users may want to know about
|
|
107
|
+
// for cleanup/status purposes, even after the observable completes.
|
|
101
108
|
disconnected: () => {
|
|
102
109
|
callbacks.disconnected?.()
|
|
103
110
|
},
|
|
104
111
|
}
|
|
105
112
|
)
|
|
106
|
-
|
|
107
|
-
|
|
113
|
+
|
|
114
|
+
// Return teardown logic
|
|
115
|
+
return () => {
|
|
116
|
+
cancelled = true
|
|
117
|
+
channel.unsubscribe()
|
|
118
|
+
}
|
|
108
119
|
})
|
|
109
120
|
}
|
|
110
121
|
}
|
|
@@ -13,7 +13,7 @@ import { validateSessionToken } from '@/utils/token-validation'
|
|
|
13
13
|
* - Emits GraphQL errors for consistent Apollo error handling
|
|
14
14
|
*/
|
|
15
15
|
export class AuthLink extends ApolloLink {
|
|
16
|
-
request(
|
|
16
|
+
override request(
|
|
17
17
|
operation: ApolloLink.Operation,
|
|
18
18
|
forward: ApolloLink.ForwardFunction
|
|
19
19
|
): Observable<ApolloLink.Result> {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ApolloLink } from '@apollo/client/core'
|
|
2
|
+
import type { Subscription } from 'rxjs'
|
|
3
|
+
import { Observable } from 'rxjs'
|
|
4
|
+
|
|
5
|
+
export type HeadersLinkOptions = {
|
|
6
|
+
/** Static headers to add to every request */
|
|
7
|
+
headers?: Record<string, string>
|
|
8
|
+
/** Dynamic headers function called on each request */
|
|
9
|
+
getHeaders?: () => Record<string, string> | Promise<Record<string, string>>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Apollo Link that adds custom headers to GraphQL requests.
|
|
14
|
+
*
|
|
15
|
+
* Headers can be provided statically or dynamically via a function.
|
|
16
|
+
* These headers are added before the AuthLink, so they will be preserved
|
|
17
|
+
* alongside the authorization header.
|
|
18
|
+
*/
|
|
19
|
+
export class HeadersLink extends ApolloLink {
|
|
20
|
+
private headers: Record<string, string>
|
|
21
|
+
private getHeaders?: () => Record<string, string> | Promise<Record<string, string>>
|
|
22
|
+
|
|
23
|
+
constructor(options: HeadersLinkOptions = {}) {
|
|
24
|
+
super()
|
|
25
|
+
this.headers = options.headers ?? {}
|
|
26
|
+
this.getHeaders = options.getHeaders
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override request(
|
|
30
|
+
operation: ApolloLink.Operation,
|
|
31
|
+
forward: ApolloLink.ForwardFunction
|
|
32
|
+
): Observable<ApolloLink.Result> {
|
|
33
|
+
// If we have a dynamic headers function, handle it
|
|
34
|
+
if (this.getHeaders) {
|
|
35
|
+
return new Observable((observer) => {
|
|
36
|
+
let innerSubscription: Subscription | undefined
|
|
37
|
+
let cancelled = false
|
|
38
|
+
|
|
39
|
+
Promise.resolve(this.getHeaders!())
|
|
40
|
+
.then((dynamicHeaders) => {
|
|
41
|
+
// Guard against late resolution after unsubscribe
|
|
42
|
+
if (cancelled) return
|
|
43
|
+
|
|
44
|
+
operation.setContext(({ headers = {} }) => ({
|
|
45
|
+
headers: {
|
|
46
|
+
...headers,
|
|
47
|
+
...this.headers,
|
|
48
|
+
...dynamicHeaders,
|
|
49
|
+
},
|
|
50
|
+
}))
|
|
51
|
+
|
|
52
|
+
innerSubscription = forward(operation).subscribe({
|
|
53
|
+
next: (value) => !cancelled && observer.next(value),
|
|
54
|
+
error: (err) => !cancelled && observer.error(err),
|
|
55
|
+
complete: () => !cancelled && observer.complete(),
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
.catch((error) => {
|
|
59
|
+
if (!cancelled) {
|
|
60
|
+
observer.error(error)
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
// Return teardown logic
|
|
65
|
+
return () => {
|
|
66
|
+
cancelled = true
|
|
67
|
+
innerSubscription?.unsubscribe()
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Static headers only
|
|
73
|
+
operation.setContext(({ headers = {} }) => ({
|
|
74
|
+
headers: {
|
|
75
|
+
...headers,
|
|
76
|
+
...this.headers,
|
|
77
|
+
},
|
|
78
|
+
}))
|
|
79
|
+
|
|
80
|
+
return forward(operation)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export default HeadersLink
|