cf-service-sdk 0.0.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/dist/client.d.ts +25 -0
- package/dist/client.js +262 -0
- package/dist/generated/graphql.d.ts +13163 -0
- package/dist/generated/graphql.js +9962 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +5 -0
- package/dist/mutations.d.ts +59 -0
- package/dist/mutations.js +3700 -0
- package/dist/queries.d.ts +41 -0
- package/dist/queries.js +3300 -0
- package/dist/sdk.d.ts +109 -0
- package/dist/sdk.js +604 -0
- package/package.json +61 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ApolloClient, NormalizedCacheObject } from '@apollo/client';
|
|
2
|
+
export interface CloudForgeClientOptions {
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
token?: string;
|
|
5
|
+
onUnauthorized?: () => void;
|
|
6
|
+
onError?: (error: Error) => void;
|
|
7
|
+
onValidationError?: (validationErrors: ValidationError[]) => void;
|
|
8
|
+
refreshToken?: () => Promise<string | null>;
|
|
9
|
+
}
|
|
10
|
+
export interface ValidationError {
|
|
11
|
+
field: string;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
export declare class CloudForgeClient {
|
|
15
|
+
private apolloClient;
|
|
16
|
+
private options;
|
|
17
|
+
private isRefreshing;
|
|
18
|
+
constructor(options: CloudForgeClientOptions);
|
|
19
|
+
private createApolloClient;
|
|
20
|
+
setToken(token: string): void;
|
|
21
|
+
getClient(): ApolloClient<NormalizedCacheObject>;
|
|
22
|
+
getBaseUrl(): string;
|
|
23
|
+
refreshToken(): Promise<boolean>;
|
|
24
|
+
logout(): void;
|
|
25
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CloudForgeClient = void 0;
|
|
4
|
+
const client_1 = require("@apollo/client");
|
|
5
|
+
const error_1 = require("@apollo/client/link/error");
|
|
6
|
+
const context_1 = require("@apollo/client/link/context");
|
|
7
|
+
const defaultOptions = {
|
|
8
|
+
baseUrl: 'http://localhost:8000/api/graph/',
|
|
9
|
+
};
|
|
10
|
+
// Detect if we're in a React Native environment
|
|
11
|
+
const isReactNative = () => {
|
|
12
|
+
return typeof global.HermesInternal !== 'undefined' ||
|
|
13
|
+
typeof navigator !== 'undefined' && navigator.product === 'ReactNative';
|
|
14
|
+
};
|
|
15
|
+
class CloudForgeClient {
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.isRefreshing = false;
|
|
18
|
+
this.options = { ...defaultOptions, ...options };
|
|
19
|
+
this.apolloClient = this.createApolloClient();
|
|
20
|
+
}
|
|
21
|
+
createApolloClient() {
|
|
22
|
+
// Mobile device workaround: replace localhost with the device's network IP
|
|
23
|
+
// This is needed because localhost on a mobile device refers to the device itself
|
|
24
|
+
let apiUrl = this.options.baseUrl;
|
|
25
|
+
// Note: We previously modified the URL here, but now we expect the URL to be
|
|
26
|
+
// properly configured by the application that uses this SDK, especially for React Native
|
|
27
|
+
// applications where localhost means different things on different platforms.
|
|
28
|
+
// HTTP link
|
|
29
|
+
const httpLink = (0, client_1.createHttpLink)({
|
|
30
|
+
uri: apiUrl,
|
|
31
|
+
});
|
|
32
|
+
// Auth link for adding the token to headers
|
|
33
|
+
const authLink = (0, context_1.setContext)((_, { headers }) => {
|
|
34
|
+
const token = this.options.token;
|
|
35
|
+
return {
|
|
36
|
+
headers: {
|
|
37
|
+
...headers,
|
|
38
|
+
authorization: token ? `JWT ${token}` : '',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
// Error handling link
|
|
43
|
+
const errorLink = (0, error_1.onError)(({ graphQLErrors, networkError, operation, forward }) => {
|
|
44
|
+
var _a, _b, _c, _d;
|
|
45
|
+
console.log('==== ERROR LINK ====');
|
|
46
|
+
console.log('==== GRAPHQL ERRORS ====');
|
|
47
|
+
console.log(graphQLErrors);
|
|
48
|
+
console.log('==== NETWORK ERROR ====');
|
|
49
|
+
console.log(networkError);
|
|
50
|
+
console.log('==== OPERATION ====');
|
|
51
|
+
console.log(operation);
|
|
52
|
+
if (graphQLErrors) {
|
|
53
|
+
const validationErrors = [];
|
|
54
|
+
graphQLErrors.forEach(({ message, locations, path }) => {
|
|
55
|
+
var _a, _b;
|
|
56
|
+
console.error(`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`);
|
|
57
|
+
// Check for unauthorized errors
|
|
58
|
+
if (message.includes('Authentication') ||
|
|
59
|
+
message.includes('Error decoding signature') ||
|
|
60
|
+
message.includes('JWT') ||
|
|
61
|
+
message.toLowerCase().includes('token') ||
|
|
62
|
+
message.includes('Signature has expired')) {
|
|
63
|
+
console.log('==== JWT ERROR DETECTED ====', message);
|
|
64
|
+
// Try to refresh the token if a refresh function is provided
|
|
65
|
+
if (this.options.refreshToken && !this.isRefreshing) {
|
|
66
|
+
this.isRefreshing = true;
|
|
67
|
+
// Attempt to refresh the token
|
|
68
|
+
this.options.refreshToken()
|
|
69
|
+
.then(newToken => {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
if (newToken) {
|
|
72
|
+
console.log('==== TOKEN REFRESHED ====');
|
|
73
|
+
// Set the new token
|
|
74
|
+
this.setToken(newToken);
|
|
75
|
+
// Retry the failed request
|
|
76
|
+
const oldHeaders = operation.getContext().headers;
|
|
77
|
+
operation.setContext({
|
|
78
|
+
headers: {
|
|
79
|
+
...oldHeaders,
|
|
80
|
+
authorization: `JWT ${newToken}`,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
// Retry the operation
|
|
84
|
+
return forward(operation);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log('==== TOKEN REFRESH FAILED ====');
|
|
88
|
+
// If refresh token failed, call onUnauthorized
|
|
89
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.catch(error => {
|
|
93
|
+
var _a, _b;
|
|
94
|
+
console.error('Token refresh failed:', error);
|
|
95
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
96
|
+
})
|
|
97
|
+
.finally(() => {
|
|
98
|
+
this.isRefreshing = false;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// If no refresh function is provided, just call onUnauthorized
|
|
103
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Check for validation errors
|
|
107
|
+
if (message.includes('got invalid value') || message.includes('Field') && message.includes('was not provided')) {
|
|
108
|
+
// Extract field name from validation error
|
|
109
|
+
const fieldMatch = message.match(/Field '([^']+)'/);
|
|
110
|
+
if (fieldMatch && fieldMatch[1]) {
|
|
111
|
+
validationErrors.push({
|
|
112
|
+
field: fieldMatch[1],
|
|
113
|
+
message: message.trim()
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// If we found validation errors, call the validation error handler
|
|
119
|
+
if (validationErrors.length > 0 && this.options.onValidationError) {
|
|
120
|
+
this.options.onValidationError(validationErrors);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (networkError) {
|
|
124
|
+
console.error(`[Network error]: ${networkError}`);
|
|
125
|
+
// Check if network error is related to expired signature
|
|
126
|
+
if (networkError.message && networkError.message.includes('Signature has expired')) {
|
|
127
|
+
console.log('==== JWT NETWORK ERROR DETECTED ====', networkError.message);
|
|
128
|
+
// Try to refresh the token if a refresh function is provided
|
|
129
|
+
if (this.options.refreshToken && !this.isRefreshing) {
|
|
130
|
+
this.isRefreshing = true;
|
|
131
|
+
// Attempt to refresh the token
|
|
132
|
+
this.options.refreshToken()
|
|
133
|
+
.then(newToken => {
|
|
134
|
+
var _a, _b;
|
|
135
|
+
if (newToken) {
|
|
136
|
+
console.log('==== TOKEN REFRESHED (NETWORK) ====');
|
|
137
|
+
// Set the new token
|
|
138
|
+
this.setToken(newToken);
|
|
139
|
+
// Retry the failed request
|
|
140
|
+
const oldHeaders = operation.getContext().headers;
|
|
141
|
+
operation.setContext({
|
|
142
|
+
headers: {
|
|
143
|
+
...oldHeaders,
|
|
144
|
+
authorization: `JWT ${newToken}`,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
// Retry the operation
|
|
148
|
+
return forward(operation);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log('==== TOKEN REFRESH FAILED (NETWORK) ====');
|
|
152
|
+
// If refresh token failed, call onUnauthorized
|
|
153
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
.catch(error => {
|
|
157
|
+
var _a, _b;
|
|
158
|
+
console.error('Token refresh failed:', error);
|
|
159
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
160
|
+
})
|
|
161
|
+
.finally(() => {
|
|
162
|
+
this.isRefreshing = false;
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// If no refresh function is provided, just call onUnauthorized
|
|
167
|
+
(_b = (_a = this.options).onUnauthorized) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// For server errors (400/500), try to extract more information
|
|
171
|
+
const serverError = networkError;
|
|
172
|
+
if (serverError.name === 'ServerError' &&
|
|
173
|
+
serverError.result &&
|
|
174
|
+
typeof serverError.result === 'object') {
|
|
175
|
+
// Handle validation errors that might be in the response body
|
|
176
|
+
try {
|
|
177
|
+
const errorResult = serverError.result;
|
|
178
|
+
if (errorResult.errors && Array.isArray(errorResult.errors)) {
|
|
179
|
+
const validationErrors = [];
|
|
180
|
+
errorResult.errors.forEach((error) => {
|
|
181
|
+
if (error.message && (error.message.includes('got invalid value') ||
|
|
182
|
+
(error.message.includes('Field') && error.message.includes('was not provided')))) {
|
|
183
|
+
const fieldMatch = error.message.match(/Field '([^']+)'/);
|
|
184
|
+
if (fieldMatch && fieldMatch[1]) {
|
|
185
|
+
validationErrors.push({
|
|
186
|
+
field: fieldMatch[1],
|
|
187
|
+
message: error.message.trim()
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
if (validationErrors.length > 0 && this.options.onValidationError) {
|
|
193
|
+
this.options.onValidationError(validationErrors);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
console.error('Error parsing server error response:', e);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
(_d = (_c = this.options).onError) === null || _d === void 0 ? void 0 : _d.call(_c, networkError);
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
// Combine the links
|
|
205
|
+
const link = client_1.ApolloLink.from([errorLink, authLink, httpLink]);
|
|
206
|
+
// Create the Apollo Client
|
|
207
|
+
return new client_1.ApolloClient({
|
|
208
|
+
link,
|
|
209
|
+
cache: new client_1.InMemoryCache(),
|
|
210
|
+
defaultOptions: {
|
|
211
|
+
watchQuery: {
|
|
212
|
+
fetchPolicy: 'network-only',
|
|
213
|
+
errorPolicy: 'all',
|
|
214
|
+
},
|
|
215
|
+
query: {
|
|
216
|
+
fetchPolicy: 'network-only',
|
|
217
|
+
errorPolicy: 'all',
|
|
218
|
+
},
|
|
219
|
+
mutate: {
|
|
220
|
+
errorPolicy: 'all',
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
// Method to update the token
|
|
226
|
+
setToken(token) {
|
|
227
|
+
this.options.token = token;
|
|
228
|
+
// Recreate the client with the new token
|
|
229
|
+
this.apolloClient = this.createApolloClient();
|
|
230
|
+
}
|
|
231
|
+
// Get the Apollo client instance
|
|
232
|
+
getClient() {
|
|
233
|
+
return this.apolloClient;
|
|
234
|
+
}
|
|
235
|
+
// Get the base URL
|
|
236
|
+
getBaseUrl() {
|
|
237
|
+
return this.options.baseUrl;
|
|
238
|
+
}
|
|
239
|
+
// Refresh token - attempt to get a new token
|
|
240
|
+
async refreshToken() {
|
|
241
|
+
if (this.options.refreshToken) {
|
|
242
|
+
try {
|
|
243
|
+
const newToken = await this.options.refreshToken();
|
|
244
|
+
if (newToken) {
|
|
245
|
+
this.setToken(newToken);
|
|
246
|
+
return true;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
console.error('Failed to refresh token:', error);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
// Logout - clear the token
|
|
256
|
+
logout() {
|
|
257
|
+
this.options.token = undefined;
|
|
258
|
+
this.apolloClient = this.createApolloClient();
|
|
259
|
+
this.apolloClient.resetStore();
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
exports.CloudForgeClient = CloudForgeClient;
|