@newmo/graphql-codegen-fake-server-client 0.23.2 → 0.24.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/templates/method-generators.js +8 -8
- package/dist/templates/runtime.js +9 -4
- package/package.json +2 -2
- package/src/templates/method-generators.ts +8 -8
- package/src/templates/runtime.ts +9 -4
- package/dist/runtime/fake-client-runtime.js +0 -141
- package/dist/runtime-template.js +0 -175
- package/dist/template-helpers.js +0 -291
|
@@ -178,9 +178,9 @@ function generateCalledQuery(params) {
|
|
|
178
178
|
};
|
|
179
179
|
};
|
|
180
180
|
response: {
|
|
181
|
-
|
|
181
|
+
status: number;
|
|
182
182
|
headers: Record<string, unknown>;
|
|
183
|
-
body: ${params.name}Query;
|
|
183
|
+
body: { data: ${params.name}Query };
|
|
184
184
|
};
|
|
185
185
|
}[]
|
|
186
186
|
}`,
|
|
@@ -217,9 +217,9 @@ return result as {
|
|
|
217
217
|
};
|
|
218
218
|
};
|
|
219
219
|
response: {
|
|
220
|
-
|
|
220
|
+
status: number;
|
|
221
221
|
headers: Record<string, unknown>;
|
|
222
|
-
body: ${params.name}Query;
|
|
222
|
+
body: { data: ${params.name}Query };
|
|
223
223
|
};
|
|
224
224
|
}[];
|
|
225
225
|
};`,
|
|
@@ -245,9 +245,9 @@ function generateCalledMutation(params) {
|
|
|
245
245
|
};
|
|
246
246
|
};
|
|
247
247
|
response: {
|
|
248
|
-
|
|
248
|
+
status: number;
|
|
249
249
|
headers: Record<string, unknown>;
|
|
250
|
-
body: ${params.name}Mutation;
|
|
250
|
+
body: { data: ${params.name}Mutation };
|
|
251
251
|
};
|
|
252
252
|
}[];
|
|
253
253
|
}`,
|
|
@@ -284,9 +284,9 @@ return result as {
|
|
|
284
284
|
};
|
|
285
285
|
};
|
|
286
286
|
response: {
|
|
287
|
-
|
|
287
|
+
status: number;
|
|
288
288
|
headers: Record<string, unknown>;
|
|
289
|
-
body: ${params.name}Mutation;
|
|
289
|
+
body: { data: ${params.name}Mutation };
|
|
290
290
|
};
|
|
291
291
|
}[];
|
|
292
292
|
};`,
|
|
@@ -15,6 +15,13 @@ export type CreateFakeClientOptions = {
|
|
|
15
15
|
fakeServerEndpoint: string;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// Simple logger for FakeClient
|
|
19
|
+
const logger = {
|
|
20
|
+
error: (...args: unknown[]) => {
|
|
21
|
+
console.error('[FakeClient]', ...args);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
18
25
|
// Request queue implementation for rate limiting
|
|
19
26
|
class RequestQueue {
|
|
20
27
|
#queue: Array<() => Promise<unknown>> = [];
|
|
@@ -106,14 +113,13 @@ async function fetchWithRetry(
|
|
|
106
113
|
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
107
114
|
};
|
|
108
115
|
|
|
109
|
-
|
|
116
|
+
logger.error('Server error, will retry:', requestInfo);
|
|
110
117
|
|
|
111
118
|
// Calculate delay with exponential backoff and jitter
|
|
112
119
|
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
113
120
|
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
114
121
|
const delay = baseDelay + jitter;
|
|
115
122
|
|
|
116
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
117
123
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
118
124
|
continue;
|
|
119
125
|
}
|
|
@@ -148,7 +154,7 @@ async function fetchWithRetry(
|
|
|
148
154
|
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
149
155
|
};
|
|
150
156
|
|
|
151
|
-
|
|
157
|
+
logger.error('Request failed:', requestInfo);
|
|
152
158
|
|
|
153
159
|
if (shouldRetry && attempt < maxAttempts - 1) {
|
|
154
160
|
// Calculate delay with exponential backoff and jitter
|
|
@@ -156,7 +162,6 @@ async function fetchWithRetry(
|
|
|
156
162
|
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
157
163
|
const delay = baseDelay + jitter;
|
|
158
164
|
|
|
159
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
160
165
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
161
166
|
continue;
|
|
162
167
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newmo/graphql-codegen-fake-server-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "GraphQL Codegen plugin for generating a fake server client",
|
|
6
6
|
"keywords": [
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"access": "public",
|
|
63
63
|
"registry": "https://registry.npmjs.org/"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "abbdbd8c0dd8eaf96a5b5dc3221a45e03e23aee6"
|
|
66
66
|
}
|
|
@@ -203,9 +203,9 @@ export function generateCalledQuery(params: {
|
|
|
203
203
|
};
|
|
204
204
|
};
|
|
205
205
|
response: {
|
|
206
|
-
|
|
206
|
+
status: number;
|
|
207
207
|
headers: Record<string, unknown>;
|
|
208
|
-
body: ${params.name}Query;
|
|
208
|
+
body: { data: ${params.name}Query };
|
|
209
209
|
};
|
|
210
210
|
}[]
|
|
211
211
|
}`,
|
|
@@ -242,9 +242,9 @@ return result as {
|
|
|
242
242
|
};
|
|
243
243
|
};
|
|
244
244
|
response: {
|
|
245
|
-
|
|
245
|
+
status: number;
|
|
246
246
|
headers: Record<string, unknown>;
|
|
247
|
-
body: ${params.name}Query;
|
|
247
|
+
body: { data: ${params.name}Query };
|
|
248
248
|
};
|
|
249
249
|
}[];
|
|
250
250
|
};`,
|
|
@@ -275,9 +275,9 @@ export function generateCalledMutation(params: {
|
|
|
275
275
|
};
|
|
276
276
|
};
|
|
277
277
|
response: {
|
|
278
|
-
|
|
278
|
+
status: number;
|
|
279
279
|
headers: Record<string, unknown>;
|
|
280
|
-
body: ${params.name}Mutation;
|
|
280
|
+
body: { data: ${params.name}Mutation };
|
|
281
281
|
};
|
|
282
282
|
}[];
|
|
283
283
|
}`,
|
|
@@ -314,9 +314,9 @@ return result as {
|
|
|
314
314
|
};
|
|
315
315
|
};
|
|
316
316
|
response: {
|
|
317
|
-
|
|
317
|
+
status: number;
|
|
318
318
|
headers: Record<string, unknown>;
|
|
319
|
-
body: ${params.name}Mutation;
|
|
319
|
+
body: { data: ${params.name}Mutation };
|
|
320
320
|
};
|
|
321
321
|
}[];
|
|
322
322
|
};`,
|
package/src/templates/runtime.ts
CHANGED
|
@@ -12,6 +12,13 @@ export type CreateFakeClientOptions = {
|
|
|
12
12
|
fakeServerEndpoint: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// Simple logger for FakeClient
|
|
16
|
+
const logger = {
|
|
17
|
+
error: (...args: unknown[]) => {
|
|
18
|
+
console.error('[FakeClient]', ...args);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
15
22
|
// Request queue implementation for rate limiting
|
|
16
23
|
class RequestQueue {
|
|
17
24
|
#queue: Array<() => Promise<unknown>> = [];
|
|
@@ -103,14 +110,13 @@ async function fetchWithRetry(
|
|
|
103
110
|
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
104
111
|
};
|
|
105
112
|
|
|
106
|
-
|
|
113
|
+
logger.error('Server error, will retry:', requestInfo);
|
|
107
114
|
|
|
108
115
|
// Calculate delay with exponential backoff and jitter
|
|
109
116
|
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
110
117
|
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
111
118
|
const delay = baseDelay + jitter;
|
|
112
119
|
|
|
113
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
114
120
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
115
121
|
continue;
|
|
116
122
|
}
|
|
@@ -145,7 +151,7 @@ async function fetchWithRetry(
|
|
|
145
151
|
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
146
152
|
};
|
|
147
153
|
|
|
148
|
-
|
|
154
|
+
logger.error('Request failed:', requestInfo);
|
|
149
155
|
|
|
150
156
|
if (shouldRetry && attempt < maxAttempts - 1) {
|
|
151
157
|
// Calculate delay with exponential backoff and jitter
|
|
@@ -153,7 +159,6 @@ async function fetchWithRetry(
|
|
|
153
159
|
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
154
160
|
const delay = baseDelay + jitter;
|
|
155
161
|
|
|
156
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
157
162
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
158
163
|
continue;
|
|
159
164
|
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Runtime utilities for generated fake client
|
|
3
|
-
// This file is embedded into the generated code
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.RequestQueue = void 0;
|
|
6
|
-
exports.fetchWithRetry = fetchWithRetry;
|
|
7
|
-
// Request queue implementation for rate limiting
|
|
8
|
-
class RequestQueue {
|
|
9
|
-
queue = [];
|
|
10
|
-
running = 0;
|
|
11
|
-
maxConcurrent = 5; // Reduced default for better stability
|
|
12
|
-
requestDelay = 10; // Small delay to prevent overwhelming the server
|
|
13
|
-
lastRequestTime = 0;
|
|
14
|
-
async add(fn) {
|
|
15
|
-
return new Promise((resolve, reject) => {
|
|
16
|
-
this.queue.push(async () => {
|
|
17
|
-
try {
|
|
18
|
-
// Apply request delay if configured
|
|
19
|
-
if (this.requestDelay > 0) {
|
|
20
|
-
const now = Date.now();
|
|
21
|
-
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
22
|
-
if (timeSinceLastRequest < this.requestDelay) {
|
|
23
|
-
await new Promise(r => setTimeout(r, this.requestDelay - timeSinceLastRequest));
|
|
24
|
-
}
|
|
25
|
-
this.lastRequestTime = Date.now();
|
|
26
|
-
}
|
|
27
|
-
const result = await fn();
|
|
28
|
-
resolve(result);
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
reject(error);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
this.process();
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
async process() {
|
|
38
|
-
if (this.running >= this.maxConcurrent || this.queue.length === 0) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
this.running++;
|
|
42
|
-
const fn = this.queue.shift();
|
|
43
|
-
if (fn) {
|
|
44
|
-
await fn();
|
|
45
|
-
this.running--;
|
|
46
|
-
this.process();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
exports.RequestQueue = RequestQueue;
|
|
51
|
-
// Retry helper function with exponential backoff
|
|
52
|
-
async function fetchWithRetry(url, options) {
|
|
53
|
-
const maxAttempts = 3;
|
|
54
|
-
const initialDelay = 100;
|
|
55
|
-
const maxDelay = 2000;
|
|
56
|
-
const backoffFactor = 2;
|
|
57
|
-
// Apply HTTP options with sensible defaults
|
|
58
|
-
const fetchOptions = {
|
|
59
|
-
...options,
|
|
60
|
-
// Enable keepalive for connection reuse
|
|
61
|
-
keepalive: true,
|
|
62
|
-
// Set a reasonable timeout (30 seconds)
|
|
63
|
-
signal: AbortSignal.timeout(30000),
|
|
64
|
-
};
|
|
65
|
-
let lastError;
|
|
66
|
-
let lastResponse;
|
|
67
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
68
|
-
try {
|
|
69
|
-
const response = await fetch(url, fetchOptions);
|
|
70
|
-
lastResponse = response;
|
|
71
|
-
// Success (2xx) or client error (4xx) - don't retry
|
|
72
|
-
if (response.status < 500) {
|
|
73
|
-
return response;
|
|
74
|
-
}
|
|
75
|
-
// Server error (5xx) - should retry
|
|
76
|
-
if (attempt < maxAttempts - 1) {
|
|
77
|
-
const requestInfo = {
|
|
78
|
-
url,
|
|
79
|
-
status: response.status,
|
|
80
|
-
statusText: response.statusText,
|
|
81
|
-
attempt: attempt + 1,
|
|
82
|
-
maxAttempts,
|
|
83
|
-
operationName: JSON.parse(options.body)?.operationName,
|
|
84
|
-
sequenceId: options.headers?.['sequence-id'],
|
|
85
|
-
};
|
|
86
|
-
console.error(`[FakeClient] Server error, will retry:`, requestInfo);
|
|
87
|
-
// Calculate delay with exponential backoff and jitter
|
|
88
|
-
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
89
|
-
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
90
|
-
const delay = baseDelay + jitter;
|
|
91
|
-
console.log(`[FakeClient] Retrying in ${Math.round(delay)}ms...`);
|
|
92
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
93
|
-
continue;
|
|
94
|
-
}
|
|
95
|
-
// Last attempt and still server error
|
|
96
|
-
return response;
|
|
97
|
-
}
|
|
98
|
-
catch (error) {
|
|
99
|
-
lastError = error;
|
|
100
|
-
// Determine if error is retryable
|
|
101
|
-
let shouldRetry = false;
|
|
102
|
-
let errorType = 'unknown';
|
|
103
|
-
if (error instanceof TypeError) {
|
|
104
|
-
// Network errors from fetch (connection failures)
|
|
105
|
-
shouldRetry = true;
|
|
106
|
-
errorType = 'network';
|
|
107
|
-
}
|
|
108
|
-
else if (error instanceof Error && error.name === 'AbortError') {
|
|
109
|
-
// Timeout errors
|
|
110
|
-
shouldRetry = true;
|
|
111
|
-
errorType = 'timeout';
|
|
112
|
-
}
|
|
113
|
-
const requestInfo = {
|
|
114
|
-
url,
|
|
115
|
-
errorType,
|
|
116
|
-
error: error instanceof Error ? error.message : String(error),
|
|
117
|
-
attempt: attempt + 1,
|
|
118
|
-
maxAttempts,
|
|
119
|
-
operationName: JSON.parse(options.body)?.operationName,
|
|
120
|
-
sequenceId: options.headers?.['sequence-id'],
|
|
121
|
-
};
|
|
122
|
-
console.error(`[FakeClient] Request failed:`, requestInfo);
|
|
123
|
-
if (shouldRetry && attempt < maxAttempts - 1) {
|
|
124
|
-
// Calculate delay with exponential backoff and jitter
|
|
125
|
-
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
126
|
-
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
127
|
-
const delay = baseDelay + jitter;
|
|
128
|
-
console.log(`[FakeClient] Retrying in ${Math.round(delay)}ms...`);
|
|
129
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
// Not retryable or max attempts reached
|
|
133
|
-
throw error;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
// Should not reach here, but just in case
|
|
137
|
-
if (lastResponse) {
|
|
138
|
-
return lastResponse;
|
|
139
|
-
}
|
|
140
|
-
throw new Error('Max retry attempts reached', { cause: lastError });
|
|
141
|
-
}
|
package/dist/runtime-template.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRuntimeCode = getRuntimeCode;
|
|
4
|
-
/**
|
|
5
|
-
* Returns the runtime code as a string template
|
|
6
|
-
* This is used to embed the runtime code in the generated client
|
|
7
|
-
*/
|
|
8
|
-
function getRuntimeCode() {
|
|
9
|
-
return `// Runtime utilities for generated fake client
|
|
10
|
-
export type CreateFakeClientOptions = {
|
|
11
|
-
/**
|
|
12
|
-
* The URL of the fake server
|
|
13
|
-
* @example 'http://localhost:4000/fake'
|
|
14
|
-
*/
|
|
15
|
-
fakeServerEndpoint: string;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Request queue implementation for rate limiting
|
|
19
|
-
class RequestQueue {
|
|
20
|
-
private queue: Array<() => Promise<any>> = [];
|
|
21
|
-
private running = 0;
|
|
22
|
-
private maxConcurrent: number = 5; // Reduced default for better stability
|
|
23
|
-
private requestDelay: number = 10; // Small delay to prevent overwhelming the server
|
|
24
|
-
private lastRequestTime = 0;
|
|
25
|
-
|
|
26
|
-
async add<T>(fn: () => Promise<T>): Promise<T> {
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
this.queue.push(async () => {
|
|
29
|
-
try {
|
|
30
|
-
// Apply request delay if configured
|
|
31
|
-
if (this.requestDelay > 0) {
|
|
32
|
-
const now = Date.now();
|
|
33
|
-
const timeSinceLastRequest = now - this.lastRequestTime;
|
|
34
|
-
if (timeSinceLastRequest < this.requestDelay) {
|
|
35
|
-
await new Promise(r => setTimeout(r, this.requestDelay - timeSinceLastRequest));
|
|
36
|
-
}
|
|
37
|
-
this.lastRequestTime = Date.now();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const result = await fn();
|
|
41
|
-
resolve(result);
|
|
42
|
-
} catch (error) {
|
|
43
|
-
reject(error);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
this.process();
|
|
47
|
-
});
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
private async process() {
|
|
51
|
-
if (this.running >= this.maxConcurrent || this.queue.length === 0) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
this.running++;
|
|
56
|
-
const fn = this.queue.shift();
|
|
57
|
-
if (fn) {
|
|
58
|
-
await fn();
|
|
59
|
-
this.running--;
|
|
60
|
-
this.process();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Retry helper function with exponential backoff
|
|
66
|
-
async function fetchWithRetry(
|
|
67
|
-
url: string,
|
|
68
|
-
options: RequestInit
|
|
69
|
-
): Promise<Response> {
|
|
70
|
-
const maxAttempts = 3;
|
|
71
|
-
const initialDelay = 100;
|
|
72
|
-
const maxDelay = 2000;
|
|
73
|
-
const backoffFactor = 2;
|
|
74
|
-
|
|
75
|
-
// Apply HTTP options with sensible defaults
|
|
76
|
-
const fetchOptions: RequestInit = {
|
|
77
|
-
...options,
|
|
78
|
-
// Enable keepalive for connection reuse
|
|
79
|
-
keepalive: true,
|
|
80
|
-
// Set a reasonable timeout (30 seconds)
|
|
81
|
-
signal: AbortSignal.timeout(30000),
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
let lastError: Error | undefined;
|
|
85
|
-
let lastResponse: Response | undefined;
|
|
86
|
-
|
|
87
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
88
|
-
try {
|
|
89
|
-
const response = await fetch(url, fetchOptions);
|
|
90
|
-
lastResponse = response;
|
|
91
|
-
|
|
92
|
-
// Success (2xx) or client error (4xx) - don't retry
|
|
93
|
-
if (response.status < 500) {
|
|
94
|
-
return response;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Server error (5xx) - should retry
|
|
98
|
-
if (attempt < maxAttempts - 1) {
|
|
99
|
-
const requestInfo = {
|
|
100
|
-
url,
|
|
101
|
-
status: response.status,
|
|
102
|
-
statusText: response.statusText,
|
|
103
|
-
attempt: attempt + 1,
|
|
104
|
-
maxAttempts,
|
|
105
|
-
operationName: JSON.parse(options.body as string)?.operationName,
|
|
106
|
-
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
console.error(\`[FakeClient] Server error, will retry:\`, requestInfo);
|
|
110
|
-
|
|
111
|
-
// Calculate delay with exponential backoff and jitter
|
|
112
|
-
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
113
|
-
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
114
|
-
const delay = baseDelay + jitter;
|
|
115
|
-
|
|
116
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
117
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Last attempt and still server error
|
|
122
|
-
return response;
|
|
123
|
-
|
|
124
|
-
} catch (error) {
|
|
125
|
-
lastError = error as Error;
|
|
126
|
-
|
|
127
|
-
// Determine if error is retryable
|
|
128
|
-
let shouldRetry = false;
|
|
129
|
-
let errorType = 'unknown';
|
|
130
|
-
|
|
131
|
-
if (error instanceof TypeError) {
|
|
132
|
-
// Network errors from fetch (connection failures)
|
|
133
|
-
shouldRetry = true;
|
|
134
|
-
errorType = 'network';
|
|
135
|
-
} else if (error instanceof Error && error.name === 'AbortError') {
|
|
136
|
-
// Timeout errors
|
|
137
|
-
shouldRetry = true;
|
|
138
|
-
errorType = 'timeout';
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const requestInfo = {
|
|
142
|
-
url,
|
|
143
|
-
errorType,
|
|
144
|
-
error: error instanceof Error ? error.message : String(error),
|
|
145
|
-
attempt: attempt + 1,
|
|
146
|
-
maxAttempts,
|
|
147
|
-
operationName: JSON.parse(options.body as string)?.operationName,
|
|
148
|
-
sequenceId: (options.headers as any)?.['sequence-id'],
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
console.error(\`[FakeClient] Request failed:\`, requestInfo);
|
|
152
|
-
|
|
153
|
-
if (shouldRetry && attempt < maxAttempts - 1) {
|
|
154
|
-
// Calculate delay with exponential backoff and jitter
|
|
155
|
-
const baseDelay = Math.min(initialDelay * Math.pow(backoffFactor, attempt), maxDelay);
|
|
156
|
-
const jitter = Math.random() * 0.1 * baseDelay; // 10% jitter
|
|
157
|
-
const delay = baseDelay + jitter;
|
|
158
|
-
|
|
159
|
-
console.log(\`[FakeClient] Retrying in \${Math.round(delay)}ms...\`);
|
|
160
|
-
await new Promise(resolve => setTimeout(resolve, delay));
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// Not retryable or max attempts reached
|
|
165
|
-
throw error;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Should not reach here, but just in case
|
|
170
|
-
if (lastResponse) {
|
|
171
|
-
return lastResponse;
|
|
172
|
-
}
|
|
173
|
-
throw new Error('Max retry attempts reached', { cause: lastError });
|
|
174
|
-
}`;
|
|
175
|
-
}
|
package/dist/template-helpers.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateRegisterQuery = generateRegisterQuery;
|
|
4
|
-
exports.generateRegisterQueryError = generateRegisterQueryError;
|
|
5
|
-
exports.generateRegisterMutation = generateRegisterMutation;
|
|
6
|
-
exports.generateRegisterMutationError = generateRegisterMutationError;
|
|
7
|
-
exports.generateCalledQuery = generateCalledQuery;
|
|
8
|
-
exports.generateCalledMutation = generateCalledMutation;
|
|
9
|
-
/**
|
|
10
|
-
* Helper to indent each line of a string
|
|
11
|
-
*/
|
|
12
|
-
function indent(str, spaces = 4) {
|
|
13
|
-
const indentStr = ' '.repeat(spaces);
|
|
14
|
-
return str.split('\n').map(line => line ? indentStr + line : line).join('\n');
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Helper to create method templates with better readability
|
|
18
|
-
*/
|
|
19
|
-
function createMethod(config) {
|
|
20
|
-
return `async ${config.name}(${config.params}): Promise<${config.returnType}> {
|
|
21
|
-
${indent(config.body)}
|
|
22
|
-
}`;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Generate register query method template
|
|
26
|
-
*/
|
|
27
|
-
function generateRegisterQuery(params) {
|
|
28
|
-
return createMethod({
|
|
29
|
-
name: `register${params.name}QueryResponse`,
|
|
30
|
-
params: `sequenceId:string, queryResponse: ${params.name}Query, sequenceOptions?: FakeClientRegisterSequenceOptions<${params.variablesType}>`,
|
|
31
|
-
returnType: params.responseType,
|
|
32
|
-
body: `const requestCondition = sequenceOptions?.requestCondition ?? { type: "always" };
|
|
33
|
-
const response = await requestQueue.add(() => fetchWithRetry(
|
|
34
|
-
${params.endpoint},
|
|
35
|
-
{
|
|
36
|
-
method: 'POST',
|
|
37
|
-
headers: {
|
|
38
|
-
'Content-Type': 'application/json',
|
|
39
|
-
'sequence-id': sequenceId
|
|
40
|
-
},
|
|
41
|
-
body: JSON.stringify({
|
|
42
|
-
type: "operation",
|
|
43
|
-
operationName: "${params.name}",
|
|
44
|
-
data: queryResponse,
|
|
45
|
-
requestCondition: requestCondition
|
|
46
|
-
}),
|
|
47
|
-
}
|
|
48
|
-
));
|
|
49
|
-
|
|
50
|
-
const result = await response.json();
|
|
51
|
-
if (!response.ok) {
|
|
52
|
-
const errorResult = result as { errors?: string[] };
|
|
53
|
-
throw new Error(\`Failed to register fake response: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
54
|
-
}
|
|
55
|
-
return result as ${params.responseType};`
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
/**
|
|
59
|
-
* Generate register query error method template
|
|
60
|
-
*/
|
|
61
|
-
function generateRegisterQueryError(params) {
|
|
62
|
-
return createMethod({
|
|
63
|
-
name: `register${params.name}QueryErrorResponse`,
|
|
64
|
-
params: `sequenceId:string, { errors, responseStatusCode }: { errors: Record<string, unknown>[]; responseStatusCode: number }`,
|
|
65
|
-
returnType: params.responseType,
|
|
66
|
-
body: `const response = await requestQueue.add(() => fetchWithRetry(
|
|
67
|
-
${params.endpoint},
|
|
68
|
-
{
|
|
69
|
-
method: 'POST',
|
|
70
|
-
headers: {
|
|
71
|
-
'Content-Type': 'application/json',
|
|
72
|
-
'sequence-id': sequenceId
|
|
73
|
-
},
|
|
74
|
-
body: JSON.stringify({
|
|
75
|
-
type: "network-error",
|
|
76
|
-
operationName: "${params.name}",
|
|
77
|
-
responseStatusCode,
|
|
78
|
-
errors
|
|
79
|
-
}),
|
|
80
|
-
}
|
|
81
|
-
));
|
|
82
|
-
|
|
83
|
-
const result = await response.json();
|
|
84
|
-
if (!response.ok) {
|
|
85
|
-
const errorResult = result as { errors?: string[] };
|
|
86
|
-
throw new Error(\`Failed to register fake error response: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
87
|
-
}
|
|
88
|
-
return result as ${params.responseType};`
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Generate register mutation method template
|
|
93
|
-
*/
|
|
94
|
-
function generateRegisterMutation(params) {
|
|
95
|
-
return createMethod({
|
|
96
|
-
name: `register${params.name}MutationResponse`,
|
|
97
|
-
params: `sequenceId:string, mutationResponse: ${params.name}Mutation, sequenceOptions?: FakeClientRegisterSequenceOptions<${params.variablesType}>`,
|
|
98
|
-
returnType: params.responseType,
|
|
99
|
-
body: `const requestCondition = sequenceOptions?.requestCondition ?? { type: "always" };
|
|
100
|
-
const response = await requestQueue.add(() => fetchWithRetry(
|
|
101
|
-
${params.endpoint},
|
|
102
|
-
{
|
|
103
|
-
method: 'POST',
|
|
104
|
-
headers: {
|
|
105
|
-
'Content-Type': 'application/json',
|
|
106
|
-
'sequence-id': sequenceId
|
|
107
|
-
},
|
|
108
|
-
body: JSON.stringify({
|
|
109
|
-
type: "operation",
|
|
110
|
-
operationName: "${params.name}",
|
|
111
|
-
data: mutationResponse,
|
|
112
|
-
requestCondition: requestCondition
|
|
113
|
-
}),
|
|
114
|
-
}
|
|
115
|
-
));
|
|
116
|
-
|
|
117
|
-
const result = await response.json();
|
|
118
|
-
if (!response.ok) {
|
|
119
|
-
const errorResult = result as { errors?: string[] };
|
|
120
|
-
throw new Error(\`Failed to register fake response: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
121
|
-
}
|
|
122
|
-
return result as ${params.responseType};`
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Generate register mutation error method template
|
|
127
|
-
*/
|
|
128
|
-
function generateRegisterMutationError(params) {
|
|
129
|
-
return createMethod({
|
|
130
|
-
name: `register${params.name}MutationErrorResponse`,
|
|
131
|
-
params: `sequenceId:string, { errors, responseStatusCode }: { errors: Record<string, unknown>[]; responseStatusCode: number }`,
|
|
132
|
-
returnType: params.responseType,
|
|
133
|
-
body: `const response = await requestQueue.add(() => fetchWithRetry(
|
|
134
|
-
${params.endpoint},
|
|
135
|
-
{
|
|
136
|
-
method: 'POST',
|
|
137
|
-
headers: {
|
|
138
|
-
'Content-Type': 'application/json',
|
|
139
|
-
'sequence-id': sequenceId
|
|
140
|
-
},
|
|
141
|
-
body: JSON.stringify({
|
|
142
|
-
type: "network-error",
|
|
143
|
-
operationName: "${params.name}",
|
|
144
|
-
responseStatusCode,
|
|
145
|
-
errors
|
|
146
|
-
}),
|
|
147
|
-
}
|
|
148
|
-
));
|
|
149
|
-
|
|
150
|
-
const result = await response.json();
|
|
151
|
-
if (!response.ok) {
|
|
152
|
-
const errorResult = result as { errors?: string[] };
|
|
153
|
-
throw new Error(\`Failed to register fake error response: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
154
|
-
}
|
|
155
|
-
return result as ${params.responseType};`
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Generate called query method template
|
|
160
|
-
*/
|
|
161
|
-
function generateCalledQuery(params) {
|
|
162
|
-
return createMethod({
|
|
163
|
-
name: `called${params.name}Query`,
|
|
164
|
-
params: `sequenceId:string`,
|
|
165
|
-
returnType: `{
|
|
166
|
-
ok: true;
|
|
167
|
-
data: {
|
|
168
|
-
requestTimestamp: number;
|
|
169
|
-
request: {
|
|
170
|
-
headers: Record<string, unknown>;
|
|
171
|
-
body: {
|
|
172
|
-
operationName: string;
|
|
173
|
-
query: string;
|
|
174
|
-
variables: ${params.variablesType};
|
|
175
|
-
};
|
|
176
|
-
};
|
|
177
|
-
response: {
|
|
178
|
-
statusCode: number;
|
|
179
|
-
headers: Record<string, unknown>;
|
|
180
|
-
body: ${params.name}Query;
|
|
181
|
-
};
|
|
182
|
-
}[]
|
|
183
|
-
}`,
|
|
184
|
-
body: `const response = await requestQueue.add(() => fetchWithRetry(
|
|
185
|
-
${params.endpoint},
|
|
186
|
-
{
|
|
187
|
-
method: 'POST',
|
|
188
|
-
headers: {
|
|
189
|
-
'Content-Type': 'application/json',
|
|
190
|
-
'sequence-id': sequenceId
|
|
191
|
-
},
|
|
192
|
-
body: JSON.stringify({
|
|
193
|
-
operationName: "${params.name}"
|
|
194
|
-
}),
|
|
195
|
-
}
|
|
196
|
-
));
|
|
197
|
-
|
|
198
|
-
const result = await response.json();
|
|
199
|
-
if (!response.ok) {
|
|
200
|
-
const errorResult = result as { errors?: string[] };
|
|
201
|
-
throw new Error(\`Failed to get called data: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return result as {
|
|
205
|
-
ok: true;
|
|
206
|
-
data: {
|
|
207
|
-
requestTimestamp: number;
|
|
208
|
-
request: {
|
|
209
|
-
headers: Record<string, unknown>;
|
|
210
|
-
body: {
|
|
211
|
-
operationName: string;
|
|
212
|
-
query: string;
|
|
213
|
-
variables: ${params.variablesType};
|
|
214
|
-
};
|
|
215
|
-
};
|
|
216
|
-
response: {
|
|
217
|
-
statusCode: number;
|
|
218
|
-
headers: Record<string, unknown>;
|
|
219
|
-
body: ${params.name}Query;
|
|
220
|
-
};
|
|
221
|
-
}[];
|
|
222
|
-
};`
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Generate called mutation method template
|
|
227
|
-
*/
|
|
228
|
-
function generateCalledMutation(params) {
|
|
229
|
-
return createMethod({
|
|
230
|
-
name: `called${params.name}Mutation`,
|
|
231
|
-
params: `sequenceId:string`,
|
|
232
|
-
returnType: `{
|
|
233
|
-
ok: true;
|
|
234
|
-
data: {
|
|
235
|
-
requestTimestamp: number;
|
|
236
|
-
request: {
|
|
237
|
-
headers: Record<string, unknown>;
|
|
238
|
-
body: {
|
|
239
|
-
operationName: string;
|
|
240
|
-
query: string;
|
|
241
|
-
variables: ${params.variablesType};
|
|
242
|
-
};
|
|
243
|
-
};
|
|
244
|
-
response: {
|
|
245
|
-
statusCode: number;
|
|
246
|
-
headers: Record<string, unknown>;
|
|
247
|
-
body: ${params.name}Mutation;
|
|
248
|
-
};
|
|
249
|
-
}[];
|
|
250
|
-
}`,
|
|
251
|
-
body: `const response = await requestQueue.add(() => fetchWithRetry(
|
|
252
|
-
${params.endpoint},
|
|
253
|
-
{
|
|
254
|
-
method: 'POST',
|
|
255
|
-
headers: {
|
|
256
|
-
'Content-Type': 'application/json',
|
|
257
|
-
'sequence-id': sequenceId
|
|
258
|
-
},
|
|
259
|
-
body: JSON.stringify({
|
|
260
|
-
operationName: "${params.name}"
|
|
261
|
-
}),
|
|
262
|
-
}
|
|
263
|
-
));
|
|
264
|
-
|
|
265
|
-
const result = await response.json();
|
|
266
|
-
if (!response.ok) {
|
|
267
|
-
const errorResult = result as { errors?: string[] };
|
|
268
|
-
throw new Error(\`Failed to get called data: \${response.status} \${response.statusText}\${errorResult.errors ? ' - ' + JSON.stringify(errorResult.errors) : ''}\`);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return result as {
|
|
272
|
-
ok: true;
|
|
273
|
-
data: {
|
|
274
|
-
requestTimestamp: number;
|
|
275
|
-
request: {
|
|
276
|
-
headers: Record<string, unknown>;
|
|
277
|
-
body: {
|
|
278
|
-
operationName: string;
|
|
279
|
-
query: string;
|
|
280
|
-
variables: ${params.variablesType};
|
|
281
|
-
};
|
|
282
|
-
};
|
|
283
|
-
response: {
|
|
284
|
-
statusCode: number;
|
|
285
|
-
headers: Record<string, unknown>;
|
|
286
|
-
body: ${params.name}Mutation;
|
|
287
|
-
};
|
|
288
|
-
}[];
|
|
289
|
-
};`
|
|
290
|
-
});
|
|
291
|
-
}
|