@c15t/node-sdk 2.2.1 → 3.0.0-alpha.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/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
  <a href="https://github.com/c15t/c15t/blob/main/LICENSE.md"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/github/c15t/c15t/license.svg?variant=outline&mode=dark"><img src="https://shieldcn.dev/github/c15t/c15t/license.svg?variant=outline&mode=light" alt="License"></picture></a>
16
16
  <a href="https://c15t.link/discord"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/discord/1312171102268690493.svg?variant=outline&mode=dark"><img src="https://shieldcn.dev/discord/1312171102268690493.svg?variant=outline&mode=light" alt="Discord"></picture></a>
17
17
  <a href="https://skills.sh/c15t/skills/c15t"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/skills/c15t/skills/c15t.svg?variant=outline&mode=dark"><img src="https://shieldcn.dev/skills/c15t/skills/c15t.svg?variant=outline&mode=light" alt="Skills"></picture></a>
18
- <a href="https://inth.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fnode-sdk"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/badge/Made%20By-Inth-ffc803.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAzOTMgNDAwIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTgyLjY2MiAwdjM2Ljg5NWgtNTkuMDMxdjgyLjczM2g1OS4wMzF2MzYuODkzSDI3LjQ4MnYtMzYuODkzaDU5LjAzVjM2Ljg5NWgtNTkuMDNWMHpNMzIxLjk0MSA4OS44NVYwaDM1LjM1NXYxNTYuNTIxaC0yNS43MTNsLTg2LjEzNy05MC4zNjR2OTAuMzY0aC0zNS4zNTVWMGgyNi4zNTV6Ii8%2BPHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzE4LjU3MSAxODUuNzE0aDc0LjI4NlY0MDBIMFYxODUuNzE0aDI3Mi44NTd2LTQ3LjE0M3ptLTI5MS4wOSAyOC45Njl2MzcuMTE4aDU4LjEzN3YxMTkuNjI4aDM2Ljg5NVYyNTEuODAxaDU4LjU4NHYtMzcuMTE4em0xODIuNjEuMjI0djE1Ni41MjJoMzYuODk0VjMxMy41OWg3My4zNDF2NTcuODM5aDM3LjExOFYyMTQuOTA3aC0zNy4xMTh2NjEuNzg4aC03My4zNDF2LTYxLjc4OHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg%3D%3D&color=ffc803&labelTextColor=000000&valueColor=000000&mode=dark"><img src="https://shieldcn.dev/badge/Made%20By-Inth-ffc803.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAzOTMgNDAwIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTgyLjY2MiAwdjM2Ljg5NWgtNTkuMDMxdjgyLjczM2g1OS4wMzF2MzYuODkzSDI3LjQ4MnYtMzYuODkzaDU5LjAzVjM2Ljg5NWgtNTkuMDNWMHpNMzIxLjk0MSA4OS44NVYwaDM1LjM1NXYxNTYuNTIxaC0yNS43MTNsLTg2LjEzNy05MC4zNjR2OTAuMzY0aC0zNS4zNTVWMGgyNi4zNTV6Ii8%2BPHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzE4LjU3MSAxODUuNzE0aDc0LjI4NlY0MDBIMFYxODUuNzE0aDI3Mi44NTd2LTQ3LjE0M3ptLTI5MS4wOSAyOC45Njl2MzcuMTE4aDU4LjEzN3YxMTkuNjI4aDM2Ljg5NVYyNTEuODAxaDU4LjU4NHYtMzcuMTE4em0xODIuNjEuMjI0djE1Ni41MjJoMzYuODk0VjMxMy41OWg3My4zNDF2NTcuODM5aDM3LjExOFYyMTQuOTA3aC0zNy4xMTh2NjEuNzg4aC03My4zNDF2LTYxLjc4OHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg%3D%3D&color=ffc803&labelTextColor=000000&valueColor=000000&mode=light" alt="Made by Inth"></picture></a>
18
+ <a href="https://inth.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fnode-sdk"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/badge/Made%20By-Inth-ffc803.svg?color=ffc803&labelTextColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAzOTMgNDAwIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTgyLjY2MiAwdjM2Ljg5NWgtNTkuMDMxdjgyLjczM2g1OS4wMzF2MzYuODkzSDI3LjQ4MnYtMzYuODkzaDU5LjAzVjM2Ljg5NWgtNTkuMDNWMHpNMzIxLjk0MSA4OS44NVYwaDM1LjM1NXYxNTYuNTIxaC0yNS43MTNsLTg2LjEzNy05MC4zNjR2OTAuMzY0aC0zNS4zNTVWMGgyNi4zNTV6Ii8%2BPHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzE4LjU3MSAxODUuNzE0aDc0LjI4NlY0MDBIMFYxODUuNzE0aDI3Mi44NTd2LTQ3LjE0M3ptLTI5MS4wOSAyOC45Njl2MzcuMTE4aDU4LjEzN3YxMTkuNjI4aDM2Ljg5NVYyNTEuODAxaDU4LjU4NHYtMzcuMTE4em0xODIuNjEuMjI0djE1Ni41MjJoMzYuODk0VjMxMy41OWg3My4zNDF2NTcuODM5aDM3LjExOFYyMTQuOTA3aC0zNy4xMTh2NjEuNzg4aC03My4zNDF2LTYxLjc4OHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg%3D%3D&valueColor=000000&mode=dark"><img src="https://shieldcn.dev/badge/Made%20By-Inth-ffc803.svg?color=ffc803&labelTextColor=000000&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCAzOTMgNDAwIj48cGF0aCBmaWxsPSIjMDAwIiBkPSJNMTgyLjY2MiAwdjM2Ljg5NWgtNTkuMDMxdjgyLjczM2g1OS4wMzF2MzYuODkzSDI3LjQ4MnYtMzYuODkzaDU5LjAzVjM2Ljg5NWgtNTkuMDNWMHpNMzIxLjk0MSA4OS44NVYwaDM1LjM1NXYxNTYuNTIxaC0yNS43MTNsLTg2LjEzNy05MC4zNjR2OTAuMzY0aC0zNS4zNTVWMGgyNi4zNTV6Ii8%2BPHBhdGggZmlsbD0iIzAwMCIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzE4LjU3MSAxODUuNzE0aDc0LjI4NlY0MDBIMFYxODUuNzE0aDI3Mi44NTd2LTQ3LjE0M3ptLTI5MS4wOSAyOC45Njl2MzcuMTE4aDU4LjEzN3YxMTkuNjI4aDM2Ljg5NVYyNTEuODAxaDU4LjU4NHYtMzcuMTE4em0xODIuNjEuMjI0djE1Ni41MjJoMzYuODk0VjMxMy41OWg3My4zNDF2NTcuODM5aDM3LjExOFYyMTQuOTA3aC0zNy4xMTh2NjEuNzg4aC03My4zNDF2LTYxLjc4OHoiIGNsaXAtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg%3D%3D&valueColor=000000&mode=light" alt="Made by Inth"></picture></a>
19
19
  </p>
20
20
 
21
21
  Type-safe Node.js SDK for hosted and self-hosted c15t consent APIs, consent records, privacy preferences, and backend automation.
@@ -32,7 +32,7 @@ Type-safe Node.js SDK for hosted and self-hosted c15t consent APIs, consent reco
32
32
 
33
33
  ## Prerequisites
34
34
 
35
- - Node.js 18.17.0 or later
35
+ - Node.js 20.19 or later
36
36
  - A hosted [c15t instance](https://inth.com) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/quickstart)
37
37
 
38
38
  ## Manual Installation
package/dist/index.js CHANGED
@@ -35,93 +35,185 @@ class C15TError extends Error {
35
35
  }
36
36
  toJSON() {
37
37
  return {
38
- name: this.name,
39
- message: this.message,
40
- status: this.status,
41
38
  code: this.code,
42
- details: this.details
39
+ details: this.details,
40
+ message: this.message,
41
+ name: this.name,
42
+ status: this.status
43
43
  };
44
44
  }
45
45
  }
46
- function isC15TError(error) {
46
+ const error_isC15TError = function(error) {
47
47
  return error instanceof C15TError;
48
- }
48
+ };
49
+ const version = '3.0.0-alpha.1';
49
50
  const C15T_VERSION_HEADERS = {
50
- 'x-c15t-version': "2.2.1"
51
+ 'x-c15t-version': version
51
52
  };
52
53
  const DEFAULT_RETRY_CONFIG = {
53
- maxRetries: 3,
54
- initialDelayMs: 100,
55
54
  backoffFactor: 2,
56
- retryableStatusCodes: [
57
- 500,
58
- 502,
59
- 503,
60
- 504
61
- ],
55
+ initialDelayMs: 100,
56
+ maxRetries: 3,
62
57
  nonRetryableStatusCodes: [
63
58
  400,
64
59
  401,
65
60
  403,
66
61
  404
67
62
  ],
68
- retryOnNetworkError: true
63
+ retryOnNetworkError: true,
64
+ retryableStatusCodes: [
65
+ 500,
66
+ 502,
67
+ 503,
68
+ 504
69
+ ]
69
70
  };
70
- function debugLog(debug, method, path, durationMs, status) {
71
+ const fetcher_debugLog = function(debug, method, path, durationMs, status) {
71
72
  if (!debug) return;
72
73
  const timestamp = new Date().toISOString();
73
74
  console.log(`[c15t] ${timestamp} ${method} ${path} (${durationMs}ms) -> ${status}`);
74
- }
75
- const delay = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
76
- function generateUUID() {
77
- return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c)=>{
78
- const r = 16 * Math.random() | 0;
79
- const v = 'x' === c ? r : 0x3 & r | 0x8;
75
+ };
76
+ const delay = (ms)=>new Promise((resolve)=>{
77
+ setTimeout(resolve, ms);
78
+ });
79
+ const fetcher_generateUUID = function() {
80
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/gu, (c)=>{
81
+ const r = Math.floor(16 * Math.random());
82
+ const v = 'x' === c ? r : r % 4 + 8;
80
83
  return v.toString(16);
81
84
  });
82
- }
83
- function createResponseContext(isSuccess, data = null, error = null, response = null) {
85
+ };
86
+ const fetcher_createResponseContext = function createResponseContext(isSuccess, data = null, error = null, response = null) {
84
87
  return {
85
88
  data,
86
89
  error,
87
- ok: isSuccess,
88
- response,
89
- unwrap () {
90
+ expect (message) {
90
91
  if (!isSuccess || null === data) throw new C15TError({
91
- message: error?.message || 'Request failed',
92
- status: error?.status || 0,
92
+ cause: error?.cause,
93
93
  code: error?.code,
94
94
  details: error?.details,
95
- cause: error?.cause
95
+ message,
96
+ status: error?.status || 0
96
97
  });
97
98
  return data;
98
99
  },
99
- unwrapOr (defaultValue) {
100
- if (!isSuccess || null === data) return defaultValue;
101
- return data;
100
+ map (fn) {
101
+ if (!isSuccess || null === data) return createResponseContext(false, null, error, response);
102
+ return createResponseContext(true, fn(data), null, response);
102
103
  },
103
- expect (message) {
104
+ ok: isSuccess,
105
+ response,
106
+ unwrap () {
104
107
  if (!isSuccess || null === data) throw new C15TError({
105
- message,
106
- status: error?.status || 0,
108
+ cause: error?.cause,
107
109
  code: error?.code,
108
110
  details: error?.details,
109
- cause: error?.cause
111
+ message: error?.message || 'Request failed',
112
+ status: error?.status || 0
110
113
  });
111
114
  return data;
112
115
  },
113
- map (fn) {
114
- if (!isSuccess || null === data) return createResponseContext(false, null, error, response);
115
- return createResponseContext(true, fn(data), null, response);
116
+ unwrapOr (defaultValue) {
117
+ if (!isSuccess || null === data) return defaultValue;
118
+ return data;
116
119
  }
117
120
  };
118
- }
119
- function resolveUrl(baseUrl, path) {
121
+ };
122
+ const fetcher_resolveUrl = function(baseUrl, path) {
120
123
  const cleanBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
121
124
  const cleanPath = path.startsWith('/') ? path.slice(1) : path;
122
125
  return `${cleanBase}/${cleanPath}`;
123
- }
124
- async function fetcher(context, path, options) {
126
+ };
127
+ const parseResponseData = async (response)=>{
128
+ try {
129
+ const contentType = response.headers.get('content-type');
130
+ if (contentType?.includes('application/json') && 204 !== response.status && '0' !== response.headers.get('content-length')) return {
131
+ data: await response.json(),
132
+ parseError: null
133
+ };
134
+ return {
135
+ data: null,
136
+ parseError: null
137
+ };
138
+ } catch (parseError) {
139
+ return {
140
+ data: null,
141
+ parseError
142
+ };
143
+ }
144
+ };
145
+ const processApiError = (response, data, requestMethod, path, durationMs, context, options, retryableStatusCodes, nonRetryableStatusCodes, attemptsMade, maxRetries)=>{
146
+ const errorData = data;
147
+ const errorResponse = fetcher_createResponseContext(false, null, {
148
+ code: errorData?.code || 'API_ERROR',
149
+ details: errorData?.details || null,
150
+ message: errorData?.message || `Request failed with status ${response.status}`,
151
+ status: response.status
152
+ }, response);
153
+ const retry = !nonRetryableStatusCodes.includes(response.status) && retryableStatusCodes.includes(response.status) && attemptsMade < maxRetries;
154
+ if (retry) return {
155
+ retry: true
156
+ };
157
+ fetcher_debugLog(context.debug, requestMethod, path, durationMs, response.status);
158
+ options?.onError?.(errorResponse, path);
159
+ if (options?.throw) throw new Error(errorResponse.error?.message || 'Request failed');
160
+ return {
161
+ response: errorResponse,
162
+ retry: false
163
+ };
164
+ };
165
+ const processResponse = async (response, requestMethod, path, durationMs, context, options, retryableStatusCodes, nonRetryableStatusCodes, attemptsMade, maxRetries)=>{
166
+ const { data, parseError } = await parseResponseData(response);
167
+ if (parseError) {
168
+ const errorResponse = fetcher_createResponseContext(false, null, {
169
+ cause: parseError,
170
+ code: 'PARSE_ERROR',
171
+ message: 'Failed to parse response',
172
+ status: response.status
173
+ }, response);
174
+ options?.onError?.(errorResponse, path);
175
+ if (options?.throw) throw new Error('Failed to parse response');
176
+ return {
177
+ response: errorResponse,
178
+ retry: false
179
+ };
180
+ }
181
+ if (response.ok) {
182
+ fetcher_debugLog(context.debug, requestMethod, path, durationMs, response.status);
183
+ const successResponse = fetcher_createResponseContext(true, data, null, response);
184
+ options?.onSuccess?.(successResponse);
185
+ return {
186
+ response: successResponse,
187
+ retry: false
188
+ };
189
+ }
190
+ return processApiError(response, data, requestMethod, path, durationMs, context, options, retryableStatusCodes, nonRetryableStatusCodes, attemptsMade, maxRetries);
191
+ };
192
+ const processFetchError = (fetchError, requestMethod, path, startTime, timeoutMs, context, options, retryOnNetworkError, attemptsMade, maxRetries)=>{
193
+ if (fetchError instanceof Error && 'Failed to parse response' === fetchError.message) throw fetchError;
194
+ const isAbortError = fetchError instanceof Error && 'AbortError' === fetchError.name;
195
+ let message = String(fetchError);
196
+ if (fetchError instanceof Error) ({ message } = fetchError);
197
+ if (isAbortError) message = `Request timed out after ${timeoutMs}ms`;
198
+ const errorResponse = fetcher_createResponseContext(false, null, {
199
+ cause: fetchError,
200
+ code: isAbortError ? 'TIMEOUT' : 'NETWORK_ERROR',
201
+ message,
202
+ status: 0
203
+ }, null);
204
+ const retry = !(fetchError instanceof Response) && retryOnNetworkError && attemptsMade < maxRetries;
205
+ if (retry) return {
206
+ retry: true
207
+ };
208
+ fetcher_debugLog(context.debug, requestMethod, path, Date.now() - startTime, 'ERROR');
209
+ options?.onError?.(errorResponse, path);
210
+ if (options?.throw) throw fetchError;
211
+ return {
212
+ response: errorResponse,
213
+ retry: false
214
+ };
215
+ };
216
+ const fetcher_fetcher = function(context, path, options) {
125
217
  const finalRetryConfig = {
126
218
  ...DEFAULT_RETRY_CONFIG,
127
219
  ...context.retryConfig,
@@ -140,20 +232,18 @@ async function fetcher(context, path, options) {
140
232
  ], retryOnNetworkError = true } = finalRetryConfig;
141
233
  let attemptsMade = 0;
142
234
  let currentDelay = initialDelayMs;
143
- let lastErrorResponse = null;
144
- while(attemptsMade <= maxRetries){
145
- const requestId = generateUUID();
146
- const resolvedUrl = resolveUrl(context.baseUrl, path);
235
+ const executeAttempt = async ()=>{
236
+ const requestId = fetcher_generateUUID();
237
+ const resolvedUrl = fetcher_resolveUrl(context.baseUrl, path);
147
238
  const url = new URL(resolvedUrl);
148
- if (options?.query) {
149
- for (const [key, value] of Object.entries(options.query))if (null != value) url.searchParams.append(key, String(value));
150
- }
239
+ if (options?.query) Object.entries(options.query).forEach(([key, value])=>{
240
+ if (null != value) url.searchParams.append(key, String(value));
241
+ });
151
242
  const timeoutMs = options?.timeout ?? context.timeout;
152
243
  const controller = new AbortController();
153
244
  let timeoutId;
154
245
  if (timeoutMs > 0) timeoutId = setTimeout(()=>controller.abort(), timeoutMs);
155
246
  const requestOptions = {
156
- method: options?.method || 'GET',
157
247
  headers: {
158
248
  'Content-Type': 'application/json',
159
249
  ...C15T_VERSION_HEADERS,
@@ -161,152 +251,88 @@ async function fetcher(context, path, options) {
161
251
  'X-Request-ID': requestId,
162
252
  ...options?.headers
163
253
  },
254
+ method: options?.method || 'GET',
164
255
  signal: controller.signal
165
256
  };
166
257
  if (options?.body && 'GET' !== requestOptions.method) requestOptions.body = JSON.stringify(options.body);
167
258
  const startTime = Date.now();
259
+ const requestMethod = requestOptions.method || 'GET';
168
260
  try {
169
261
  const response = await fetch(url.toString(), requestOptions);
170
262
  if (timeoutId) clearTimeout(timeoutId);
171
- const durationMs = Date.now() - startTime;
172
- let data = null;
173
- let parseError = null;
174
- try {
175
- const contentType = response.headers.get('content-type');
176
- if (contentType?.includes('application/json') && 204 !== response.status && '0' !== response.headers.get('content-length')) data = await response.json();
177
- else if (204 === response.status) data = null;
178
- } catch (err) {
179
- parseError = err;
180
- }
181
- if (parseError) {
182
- const errorResponse = createResponseContext(false, null, {
183
- message: 'Failed to parse response',
184
- status: response.status,
185
- code: 'PARSE_ERROR',
186
- cause: parseError
187
- }, response);
188
- options?.onError?.(errorResponse, path);
189
- if (options?.throw) throw new Error('Failed to parse response');
190
- return errorResponse;
191
- }
192
- const isSuccess = response.status >= 200 && response.status < 300;
193
- if (isSuccess) {
194
- debugLog(context.debug, requestOptions.method || 'GET', path, durationMs, response.status);
195
- const successResponse = createResponseContext(true, data, null, response);
196
- options?.onSuccess?.(successResponse);
197
- return successResponse;
198
- }
199
- const errorData = data;
200
- const errorResponse = createResponseContext(false, null, {
201
- message: errorData?.message || `Request failed with status ${response.status}`,
202
- status: response.status,
203
- code: errorData?.code || 'API_ERROR',
204
- details: errorData?.details || null
205
- }, response);
206
- lastErrorResponse = errorResponse;
207
- let shouldRetryThisRequest = false;
208
- shouldRetryThisRequest = nonRetryableStatusCodes.includes(response.status) ? false : retryableStatusCodes.includes(response.status);
209
- if (!shouldRetryThisRequest || attemptsMade >= maxRetries) {
210
- debugLog(context.debug, requestOptions.method || 'GET', path, durationMs, response.status);
211
- options?.onError?.(errorResponse, path);
212
- if (options?.throw) throw new Error(errorResponse.error?.message || 'Request failed');
213
- return errorResponse;
214
- }
215
- attemptsMade++;
216
- await delay(currentDelay);
217
- currentDelay *= backoffFactor;
263
+ const outcome = await processResponse(response, requestMethod, path, Date.now() - startTime, context, options, retryableStatusCodes, nonRetryableStatusCodes, attemptsMade, maxRetries);
264
+ if (!outcome.retry) return outcome.response;
218
265
  } catch (fetchError) {
219
266
  if (timeoutId) clearTimeout(timeoutId);
220
- if (fetchError instanceof Error && 'Failed to parse response' === fetchError.message) throw fetchError;
221
- const isAbortError = fetchError instanceof Error && 'AbortError' === fetchError.name;
222
- const isNetworkError = !(fetchError instanceof Response);
223
- const errorResponse = createResponseContext(false, null, {
224
- message: isAbortError ? `Request timed out after ${timeoutMs}ms` : fetchError instanceof Error ? fetchError.message : String(fetchError),
225
- status: 0,
226
- code: isAbortError ? 'TIMEOUT' : 'NETWORK_ERROR',
227
- cause: fetchError
228
- }, null);
229
- lastErrorResponse = errorResponse;
230
- const shouldRetryThisRequest = isNetworkError && retryOnNetworkError;
231
- if (!shouldRetryThisRequest || attemptsMade >= maxRetries) {
232
- debugLog(context.debug, requestOptions.method || 'GET', path, Date.now() - startTime, 'ERROR');
233
- options?.onError?.(errorResponse, path);
234
- if (options?.throw) throw fetchError;
235
- return errorResponse;
236
- }
237
- attemptsMade++;
238
- await delay(currentDelay);
239
- currentDelay *= backoffFactor;
267
+ const outcome = processFetchError(fetchError, requestMethod, path, startTime, timeoutMs, context, options, retryOnNetworkError, attemptsMade, maxRetries);
268
+ if (!outcome.retry) return outcome.response;
240
269
  }
241
- }
242
- const maxRetriesErrorResponse = lastErrorResponse || createResponseContext(false, null, {
243
- message: `Request failed after ${maxRetries} retries`,
244
- status: 0,
245
- code: 'MAX_RETRIES_EXCEEDED'
246
- }, null);
247
- options?.onError?.(maxRetriesErrorResponse, path);
248
- if (options?.throw) throw new Error(`Request failed after ${maxRetries} retries`);
249
- return maxRetriesErrorResponse;
250
- }
270
+ attemptsMade += 1;
271
+ await delay(currentDelay);
272
+ currentDelay *= backoffFactor;
273
+ return executeAttempt();
274
+ };
275
+ return executeAttempt();
276
+ };
251
277
  const CONSENT_CHECK_PATH = '/consents/check';
252
- async function checkConsent(context, query, options) {
253
- return fetcher(context, CONSENT_CHECK_PATH, {
278
+ const consent_checkConsent = function(context, query, options) {
279
+ return fetcher_fetcher(context, CONSENT_CHECK_PATH, {
254
280
  method: 'GET',
255
281
  query,
256
282
  ...options
257
283
  });
258
- }
284
+ };
259
285
  const INIT_PATH = '/init';
260
- async function init(context, options) {
261
- return fetcher(context, INIT_PATH, {
286
+ const init_init = function(context, options) {
287
+ return fetcher_fetcher(context, INIT_PATH, {
262
288
  method: 'GET',
263
289
  ...options
264
290
  });
265
- }
291
+ };
266
292
  const STATUS_PATH = '/status';
267
- async function status_status(context, options) {
268
- return fetcher(context, STATUS_PATH, {
293
+ const status_status = function(context, options) {
294
+ return fetcher_fetcher(context, STATUS_PATH, {
269
295
  method: 'GET',
270
296
  ...options
271
297
  });
272
- }
298
+ };
273
299
  const SUBJECTS_PATH = '/subjects';
274
- async function createSubject(context, input, options) {
275
- return fetcher(context, SUBJECTS_PATH, {
276
- method: 'POST',
300
+ const subjects_createSubject = function(context, input, options) {
301
+ return fetcher_fetcher(context, SUBJECTS_PATH, {
277
302
  body: input,
303
+ method: 'POST',
278
304
  ...options
279
305
  });
280
- }
281
- async function getSubject(context, id, query, options) {
282
- return fetcher(context, `${SUBJECTS_PATH}/${id}`, {
306
+ };
307
+ const subjects_getSubject = function(context, id, query, options) {
308
+ return fetcher_fetcher(context, `${SUBJECTS_PATH}/${id}`, {
283
309
  method: 'GET',
284
310
  query,
285
311
  ...options
286
312
  });
287
- }
288
- async function patchSubject(context, id, input, options) {
289
- return fetcher(context, `${SUBJECTS_PATH}/${id}`, {
290
- method: 'PATCH',
313
+ };
314
+ const subjects_patchSubject = function(context, id, input, options) {
315
+ return fetcher_fetcher(context, `${SUBJECTS_PATH}/${id}`, {
291
316
  body: input,
317
+ method: 'PATCH',
292
318
  ...options
293
319
  });
294
- }
295
- async function listSubjects(context, query, options) {
296
- return fetcher(context, SUBJECTS_PATH, {
320
+ };
321
+ const subjects_listSubjects = function(context, query, options) {
322
+ return fetcher_fetcher(context, SUBJECTS_PATH, {
297
323
  method: 'GET',
298
324
  query,
299
325
  ...options
300
326
  });
301
- }
327
+ };
302
328
  class C15TClient {
303
329
  context;
304
330
  constructor(options = {}){
305
- const baseUrlString = options.baseUrl || ("u" > typeof process ? process.env?.C15T_API_URL : void 0);
331
+ const baseUrlString = options.baseUrl || ("u" < typeof process ? void 0 : process.env?.C15T_API_URL);
306
332
  if (!baseUrlString) throw new TypeError('baseUrl is required. Provide it in options or set C15T_API_URL environment variable.');
307
333
  const baseUrl = new URL(baseUrlString);
308
334
  if (options.prefix) baseUrl.pathname = options.prefix;
309
- const token = options.token || ("u" > typeof process ? process.env?.C15T_API_TOKEN : void 0);
335
+ const token = options.token || ("u" < typeof process ? void 0 : process.env?.C15T_API_TOKEN);
310
336
  const authHeaders = token ? {
311
337
  Authorization: `Bearer ${token}`
312
338
  } : {};
@@ -314,42 +340,42 @@ class C15TClient {
314
340
  ...DEFAULT_RETRY_CONFIG,
315
341
  ...options.retryConfig
316
342
  };
317
- const debug = options.debug ?? ("u" > typeof process ? process.env?.C15T_DEBUG === 'true' : false);
343
+ const debug = options.debug ?? ("u" < typeof process ? false : process.env?.C15T_DEBUG === 'true');
318
344
  const timeout = options.timeout ?? 30000;
319
345
  this.context = {
320
346
  baseUrl: baseUrl.toString(),
347
+ debug,
321
348
  headers: {
322
349
  ...authHeaders,
323
350
  ...options.headers
324
351
  },
325
352
  retryConfig,
326
- debug,
327
353
  timeout
328
354
  };
329
355
  }
330
- async status(options) {
356
+ status(options) {
331
357
  return status_status(this.context, options);
332
358
  }
333
- async init(options) {
334
- return init(this.context, options);
359
+ init(options) {
360
+ return init_init(this.context, options);
335
361
  }
336
- async createSubject(input, options) {
337
- return createSubject(this.context, input, options);
362
+ createSubject(input, options) {
363
+ return subjects_createSubject(this.context, input, options);
338
364
  }
339
- async getSubject(id, query, options) {
340
- return getSubject(this.context, id, query, options);
365
+ getSubject(id, query, options) {
366
+ return subjects_getSubject(this.context, id, query, options);
341
367
  }
342
- async patchSubject(id, input, options) {
343
- return patchSubject(this.context, id, input, options);
368
+ patchSubject(id, input, options) {
369
+ return subjects_patchSubject(this.context, id, input, options);
344
370
  }
345
- async listSubjects(query, options) {
346
- return listSubjects(this.context, query, options);
371
+ listSubjects(query, options) {
372
+ return subjects_listSubjects(this.context, query, options);
347
373
  }
348
- async checkConsent(query, options) {
349
- return checkConsent(this.context, query, options);
374
+ checkConsent(query, options) {
375
+ return consent_checkConsent(this.context, query, options);
350
376
  }
351
- async $fetch(path, options) {
352
- return fetcher(this.context, path, options);
377
+ $fetch(path, options) {
378
+ return fetcher_fetcher(this.context, path, options);
353
379
  }
354
380
  consent = {
355
381
  check: (query, options)=>this.checkConsent(query, options)
@@ -357,15 +383,15 @@ class C15TClient {
357
383
  subjects = {
358
384
  create: (input, options)=>this.createSubject(input, options),
359
385
  get: (id, query, options)=>this.getSubject(id, query, options),
360
- patch: (id, input, options)=>this.patchSubject(id, input, options),
361
- list: (query, options)=>this.listSubjects(query, options)
386
+ list: (query, options)=>this.listSubjects(query, options),
387
+ patch: (id, input, options)=>this.patchSubject(id, input, options)
362
388
  };
363
389
  meta = {
364
- status: (options)=>this.status(options),
365
- init: (options)=>this.init(options)
390
+ init: (options)=>this.init(options),
391
+ status: (options)=>this.status(options)
366
392
  };
367
393
  }
368
- function c15tClient(options) {
394
+ const src_c15tClient = function(options) {
369
395
  return new C15TClient(options);
370
- }
371
- export { C15TClient, C15TError, c15tClient, createResponseContext, fetcher, isC15TError, resolveUrl };
396
+ };
397
+ export { C15TClient, C15TError, error_isC15TError as isC15TError, fetcher_createResponseContext as createResponseContext, fetcher_fetcher as fetcher, fetcher_resolveUrl as resolveUrl, src_c15tClient as c15tClient };