@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 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
@@ -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 };
@@ -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
- // Make the ActionCable subscription behave like an Apollo subscription
134
- return Object.assign(channel, {
135
- closed: false
136
- });
139
+ // Return teardown logic
140
+ return ()=>{
141
+ cancelled = true;
142
+ channel.unsubscribe();
143
+ };
137
144
  });
138
145
  }
139
146
  }
@@ -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
- // Make the ActionCable subscription behave like an Apollo subscription
134
- return Object.assign(channel, {
135
- closed: false
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-wjkChfxO.cjs');
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-ufJBKwu1.js';
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 };
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  var name = "@quiltt/core";
4
- var version$1 = "5.0.3";
4
+ var version$1 = "5.1.0";
5
5
 
6
6
  const QUILTT_API_INSECURE = (()=>{
7
7
  try {
@@ -1,5 +1,5 @@
1
1
  var name = "@quiltt/core";
2
- var version$1 = "5.0.3";
2
+ var version$1 = "5.1.0";
3
3
 
4
4
  const QUILTT_API_INSECURE = (()=>{
5
5
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quiltt/core",
3
- "version": "5.0.3",
3
+ "version": "5.1.0",
4
4
  "description": "Javascript API client and utilities for Quiltt",
5
5
  "keywords": [
6
6
  "quiltt",
@@ -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
- // Make the ActionCable subscription behave like an Apollo subscription
107
- return Object.assign(channel, { closed: false })
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
@@ -2,6 +2,7 @@ export * from './AuthLink'
2
2
  export * from './BatchHttpLink'
3
3
  export * from './ErrorLink'
4
4
  export * from './ForwardableLink'
5
+ export * from './HeadersLink'
5
6
  export * from './HttpLink'
6
7
  export * from './RetryLink'
7
8
  export * from './SubscriptionLink'