@c15t/node-sdk 1.8.0 → 2.0.0-rc.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/index.d.ts CHANGED
@@ -1,47 +1,44 @@
1
- import { contracts } from '@c15t/backend/contracts';
2
- import type { ContractRouterClient } from '@orpc/contract';
3
- import type { JsonifiedClient } from '@orpc/openapi-client';
4
- /**
5
- * Configuration options for the C15T SDK client
6
- */
7
- export interface C15TClientOptions {
8
- /**
9
- * Base URL for the API server
10
- * @example "https://api.example.com"
11
- */
12
- baseUrl: string;
13
- /**
14
- * Authentication token (if needed)
15
- * @example "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
16
- */
17
- token?: string;
18
- /**
19
- * Additional headers to include with each request
20
- */
21
- headers?: Record<string, string>;
22
- /**
23
- * Prefix path for API endpoints
24
- * @default "/"
25
- */
26
- prefix?: string;
27
- }
1
+ import { C15TClient } from './client';
2
+ import type { C15TClientOptions } from './types';
28
3
  /**
29
4
  * Creates a type-safe C15T client instance
30
5
  *
31
- * @param options - Configuration options for the client
32
- * @returns A fully typed client for interacting with the C15T API
6
+ * @param options - Configuration options for the client. If not provided,
7
+ * falls back to C15T_API_URL and C15T_API_TOKEN environment variables.
8
+ * @returns A C15TClient instance for interacting with the C15T API
33
9
  *
34
10
  * @example
35
11
  * ```typescript
36
- * // Create a client with authentication
37
- * const client = createC15TClient({
12
+ * // Auto-configure from environment variables
13
+ * const client = c15tClient();
14
+ *
15
+ * // Or provide explicit options
16
+ * const client = c15tClient({
38
17
  * baseUrl: "https://api.example.com",
39
18
  * token: "your-auth-token"
40
19
  * });
41
20
  *
42
- * // Now use the client with full type safety
43
- * const response = await client.users.getProfile({ userId: "123" });
21
+ * // Check API status
22
+ * const status = await client.meta.status();
23
+ *
24
+ * // Initialize consent manager
25
+ * const init = await client.meta.init();
26
+ *
27
+ * // Create a subject with consent
28
+ * const subject = await client.subjects.create({
29
+ * type: 'cookie_banner',
30
+ * subjectId: 'sub_123',
31
+ * domain: 'example.com',
32
+ * preferences: { analytics: true },
33
+ * givenAt: Date.now(),
34
+ * });
44
35
  * ```
45
36
  */
46
- export declare function c15tClient(options: C15TClientOptions): JsonifiedClient<ContractRouterClient<typeof contracts>>;
37
+ export declare function c15tClient(options?: C15TClientOptions): C15TClient;
38
+ export type { CheckConsentOutput, CheckConsentQuery, ConsentCheckResult, ConsentItem, GetSubjectInput, GetSubjectOutput, GetSubjectParams, GetSubjectQuery, InitOutput, ListSubjectsOutput, ListSubjectsQuery, PatchSubjectFullInput, PatchSubjectOutput, PostSubjectInput, PostSubjectOutput, StatusOutput, SubjectItem, } from '@c15t/schema/types';
39
+ export { C15TClient } from './client';
40
+ export { C15TError, isC15TError } from './error';
41
+ export type { FetcherContext } from './fetcher';
42
+ export { createResponseContext, fetcher, resolveUrl } from './fetcher';
43
+ export type { C15TClientOptions, FetchOptions, ResponseContext, RetryConfig, } from './types';
47
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG5D;;GAEG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GA0BnB,eAAe,CAC/C,oBAAoB,CAAC,OAAO,SAAS,CAAC,CACtC,CACD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,UAAU,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,UAAU,CAElE;AAGD,YAAY,EACX,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,EACrB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EACZ,WAAW,GACX,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,qBAAqB,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvE,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,WAAW,GACX,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -1,19 +1,368 @@
1
- import { contracts } from "@c15t/backend/contracts";
2
- import { createORPCClient } from "@orpc/client";
3
- import { OpenAPILink } from "@orpc/openapi-client/fetch";
4
- function c15tClient(options) {
5
- const authHeaders = options.token ? {
6
- Authorization: `Bearer ${options.token}`
7
- } : {};
8
- const baseUrl = new URL(options.baseUrl);
9
- if (options.prefix) baseUrl.pathname = options.prefix;
10
- const link = new OpenAPILink(contracts, {
11
- url: baseUrl.toString(),
12
- headers: {
13
- ...authHeaders,
14
- ...options.headers
1
+ class C15TError extends Error {
2
+ status;
3
+ code;
4
+ details;
5
+ cause;
6
+ constructor(options){
7
+ super(options.message);
8
+ this.name = 'C15TError';
9
+ this.status = options.status;
10
+ this.code = options.code;
11
+ this.details = options.details;
12
+ this.cause = options.cause;
13
+ if (Error.captureStackTrace) Error.captureStackTrace(this, C15TError);
14
+ }
15
+ isStatus(status) {
16
+ return this.status === status;
17
+ }
18
+ isNotFound() {
19
+ return 404 === this.status || 'NOT_FOUND' === this.code;
20
+ }
21
+ isValidationError() {
22
+ return 400 === this.status || 'VALIDATION_ERROR' === this.code;
23
+ }
24
+ isUnauthorized() {
25
+ return 401 === this.status || 'UNAUTHORIZED' === this.code;
26
+ }
27
+ isForbidden() {
28
+ return 403 === this.status || 'FORBIDDEN' === this.code;
29
+ }
30
+ isServerError() {
31
+ return this.status >= 500 && this.status < 600;
32
+ }
33
+ isNetworkError() {
34
+ return 0 === this.status || 'NETWORK_ERROR' === this.code;
35
+ }
36
+ toJSON() {
37
+ return {
38
+ name: this.name,
39
+ message: this.message,
40
+ status: this.status,
41
+ code: this.code,
42
+ details: this.details
43
+ };
44
+ }
45
+ }
46
+ function isC15TError(error) {
47
+ return error instanceof C15TError;
48
+ }
49
+ const DEFAULT_RETRY_CONFIG = {
50
+ maxRetries: 3,
51
+ initialDelayMs: 100,
52
+ backoffFactor: 2,
53
+ retryableStatusCodes: [
54
+ 500,
55
+ 502,
56
+ 503,
57
+ 504
58
+ ],
59
+ nonRetryableStatusCodes: [
60
+ 400,
61
+ 401,
62
+ 403,
63
+ 404
64
+ ],
65
+ retryOnNetworkError: true
66
+ };
67
+ const DEFAULT_TIMEOUT_MS = 30000;
68
+ function debugLog(debug, method, path, durationMs, status) {
69
+ if (!debug) return;
70
+ const timestamp = new Date().toISOString();
71
+ console.log(`[c15t] ${timestamp} ${method} ${path} (${durationMs}ms) -> ${status}`);
72
+ }
73
+ const delay = (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
74
+ function generateUUID() {
75
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c)=>{
76
+ const r = 16 * Math.random() | 0;
77
+ const v = 'x' === c ? r : 0x3 & r | 0x8;
78
+ return v.toString(16);
79
+ });
80
+ }
81
+ function createResponseContext(isSuccess, data = null, error = null, response = null) {
82
+ return {
83
+ data,
84
+ error,
85
+ ok: isSuccess,
86
+ response,
87
+ unwrap () {
88
+ if (!isSuccess || null === data) throw new C15TError({
89
+ message: error?.message || 'Request failed',
90
+ status: error?.status || 0,
91
+ code: error?.code,
92
+ details: error?.details,
93
+ cause: error?.cause
94
+ });
95
+ return data;
96
+ },
97
+ unwrapOr (defaultValue) {
98
+ if (!isSuccess || null === data) return defaultValue;
99
+ return data;
100
+ },
101
+ expect (message) {
102
+ if (!isSuccess || null === data) throw new C15TError({
103
+ message,
104
+ status: error?.status || 0,
105
+ code: error?.code,
106
+ details: error?.details,
107
+ cause: error?.cause
108
+ });
109
+ return data;
110
+ },
111
+ map (fn) {
112
+ if (!isSuccess || null === data) return createResponseContext(false, null, error, response);
113
+ return createResponseContext(true, fn(data), null, response);
15
114
  }
115
+ };
116
+ }
117
+ function resolveUrl(baseUrl, path) {
118
+ const cleanBase = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
119
+ const cleanPath = path.startsWith('/') ? path.slice(1) : path;
120
+ return `${cleanBase}/${cleanPath}`;
121
+ }
122
+ async function fetcher(context, path, options) {
123
+ const finalRetryConfig = {
124
+ ...DEFAULT_RETRY_CONFIG,
125
+ ...context.retryConfig,
126
+ ...options?.retryConfig || {}
127
+ };
128
+ const { maxRetries = 3, initialDelayMs = 100, backoffFactor = 2, retryableStatusCodes = [
129
+ 500,
130
+ 502,
131
+ 503,
132
+ 504
133
+ ], nonRetryableStatusCodes = [
134
+ 400,
135
+ 401,
136
+ 403,
137
+ 404
138
+ ], retryOnNetworkError = true } = finalRetryConfig;
139
+ let attemptsMade = 0;
140
+ let currentDelay = initialDelayMs;
141
+ let lastErrorResponse = null;
142
+ while(attemptsMade <= maxRetries){
143
+ const requestId = generateUUID();
144
+ const resolvedUrl = resolveUrl(context.baseUrl, path);
145
+ const url = new URL(resolvedUrl);
146
+ if (options?.query) {
147
+ for (const [key, value] of Object.entries(options.query))if (null != value) url.searchParams.append(key, String(value));
148
+ }
149
+ const timeoutMs = options?.timeout ?? context.timeout;
150
+ const controller = new AbortController();
151
+ let timeoutId;
152
+ if (timeoutMs > 0) timeoutId = setTimeout(()=>controller.abort(), timeoutMs);
153
+ const requestOptions = {
154
+ method: options?.method || 'GET',
155
+ headers: {
156
+ 'Content-Type': 'application/json',
157
+ ...context.headers,
158
+ 'X-Request-ID': requestId,
159
+ ...options?.headers
160
+ },
161
+ signal: controller.signal
162
+ };
163
+ if (options?.body && 'GET' !== requestOptions.method) requestOptions.body = JSON.stringify(options.body);
164
+ const startTime = Date.now();
165
+ try {
166
+ const response = await fetch(url.toString(), requestOptions);
167
+ if (timeoutId) clearTimeout(timeoutId);
168
+ const durationMs = Date.now() - startTime;
169
+ let data = null;
170
+ let parseError = null;
171
+ try {
172
+ const contentType = response.headers.get('content-type');
173
+ if (contentType?.includes('application/json') && 204 !== response.status && '0' !== response.headers.get('content-length')) data = await response.json();
174
+ else if (204 === response.status) data = null;
175
+ } catch (err) {
176
+ parseError = err;
177
+ }
178
+ if (parseError) {
179
+ const errorResponse = createResponseContext(false, null, {
180
+ message: 'Failed to parse response',
181
+ status: response.status,
182
+ code: 'PARSE_ERROR',
183
+ cause: parseError
184
+ }, response);
185
+ options?.onError?.(errorResponse, path);
186
+ if (options?.throw) throw new Error('Failed to parse response');
187
+ return errorResponse;
188
+ }
189
+ const isSuccess = response.status >= 200 && response.status < 300;
190
+ if (isSuccess) {
191
+ debugLog(context.debug, requestOptions.method || 'GET', path, durationMs, response.status);
192
+ const successResponse = createResponseContext(true, data, null, response);
193
+ options?.onSuccess?.(successResponse);
194
+ return successResponse;
195
+ }
196
+ const errorData = data;
197
+ const errorResponse = createResponseContext(false, null, {
198
+ message: errorData?.message || `Request failed with status ${response.status}`,
199
+ status: response.status,
200
+ code: errorData?.code || 'API_ERROR',
201
+ details: errorData?.details || null
202
+ }, response);
203
+ lastErrorResponse = errorResponse;
204
+ let shouldRetryThisRequest = false;
205
+ shouldRetryThisRequest = nonRetryableStatusCodes.includes(response.status) ? false : retryableStatusCodes.includes(response.status);
206
+ if (!shouldRetryThisRequest || attemptsMade >= maxRetries) {
207
+ debugLog(context.debug, requestOptions.method || 'GET', path, durationMs, response.status);
208
+ options?.onError?.(errorResponse, path);
209
+ if (options?.throw) throw new Error(errorResponse.error?.message || 'Request failed');
210
+ return errorResponse;
211
+ }
212
+ attemptsMade++;
213
+ await delay(currentDelay);
214
+ currentDelay *= backoffFactor;
215
+ } catch (fetchError) {
216
+ if (timeoutId) clearTimeout(timeoutId);
217
+ if (fetchError instanceof Error && 'Failed to parse response' === fetchError.message) throw fetchError;
218
+ const isAbortError = fetchError instanceof Error && 'AbortError' === fetchError.name;
219
+ const isNetworkError = !(fetchError instanceof Response);
220
+ const errorResponse = createResponseContext(false, null, {
221
+ message: isAbortError ? `Request timed out after ${timeoutMs}ms` : fetchError instanceof Error ? fetchError.message : String(fetchError),
222
+ status: 0,
223
+ code: isAbortError ? 'TIMEOUT' : 'NETWORK_ERROR',
224
+ cause: fetchError
225
+ }, null);
226
+ lastErrorResponse = errorResponse;
227
+ const shouldRetryThisRequest = isNetworkError && retryOnNetworkError;
228
+ if (!shouldRetryThisRequest || attemptsMade >= maxRetries) {
229
+ debugLog(context.debug, requestOptions.method || 'GET', path, Date.now() - startTime, 'ERROR');
230
+ options?.onError?.(errorResponse, path);
231
+ if (options?.throw) throw fetchError;
232
+ return errorResponse;
233
+ }
234
+ attemptsMade++;
235
+ await delay(currentDelay);
236
+ currentDelay *= backoffFactor;
237
+ }
238
+ }
239
+ const maxRetriesErrorResponse = lastErrorResponse || createResponseContext(false, null, {
240
+ message: `Request failed after ${maxRetries} retries`,
241
+ status: 0,
242
+ code: 'MAX_RETRIES_EXCEEDED'
243
+ }, null);
244
+ options?.onError?.(maxRetriesErrorResponse, path);
245
+ if (options?.throw) throw new Error(`Request failed after ${maxRetries} retries`);
246
+ return maxRetriesErrorResponse;
247
+ }
248
+ const CONSENT_CHECK_PATH = '/consents/check';
249
+ async function checkConsent(context, query, options) {
250
+ return fetcher(context, CONSENT_CHECK_PATH, {
251
+ method: 'GET',
252
+ query,
253
+ ...options
254
+ });
255
+ }
256
+ const INIT_PATH = '/init';
257
+ async function init(context, options) {
258
+ return fetcher(context, INIT_PATH, {
259
+ method: 'GET',
260
+ ...options
16
261
  });
17
- return createORPCClient(link);
18
262
  }
19
- export { c15tClient };
263
+ const STATUS_PATH = '/status';
264
+ async function status_status(context, options) {
265
+ return fetcher(context, STATUS_PATH, {
266
+ method: 'GET',
267
+ ...options
268
+ });
269
+ }
270
+ const SUBJECTS_PATH = '/subjects';
271
+ async function createSubject(context, input, options) {
272
+ return fetcher(context, SUBJECTS_PATH, {
273
+ method: 'POST',
274
+ body: input,
275
+ ...options
276
+ });
277
+ }
278
+ async function getSubject(context, id, query, options) {
279
+ return fetcher(context, `${SUBJECTS_PATH}/${id}`, {
280
+ method: 'GET',
281
+ query,
282
+ ...options
283
+ });
284
+ }
285
+ async function patchSubject(context, id, input, options) {
286
+ return fetcher(context, `${SUBJECTS_PATH}/${id}`, {
287
+ method: 'PATCH',
288
+ body: input,
289
+ ...options
290
+ });
291
+ }
292
+ async function listSubjects(context, query, options) {
293
+ return fetcher(context, SUBJECTS_PATH, {
294
+ method: 'GET',
295
+ query,
296
+ ...options
297
+ });
298
+ }
299
+ class C15TClient {
300
+ context;
301
+ constructor(options = {}){
302
+ const baseUrlString = options.baseUrl || ('undefined' != typeof process ? process.env?.C15T_API_URL : void 0);
303
+ if (!baseUrlString) throw new TypeError('baseUrl is required. Provide it in options or set C15T_API_URL environment variable.');
304
+ const baseUrl = new URL(baseUrlString);
305
+ if (options.prefix) baseUrl.pathname = options.prefix;
306
+ const token = options.token || ('undefined' != typeof process ? process.env?.C15T_API_TOKEN : void 0);
307
+ const authHeaders = token ? {
308
+ Authorization: `Bearer ${token}`
309
+ } : {};
310
+ const retryConfig = {
311
+ ...DEFAULT_RETRY_CONFIG,
312
+ ...options.retryConfig
313
+ };
314
+ const debug = options.debug ?? ('undefined' != typeof process ? process.env?.C15T_DEBUG === 'true' : false);
315
+ const timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
316
+ this.context = {
317
+ baseUrl: baseUrl.toString(),
318
+ headers: {
319
+ ...authHeaders,
320
+ ...options.headers
321
+ },
322
+ retryConfig,
323
+ debug,
324
+ timeout
325
+ };
326
+ }
327
+ async status(options) {
328
+ return status_status(this.context, options);
329
+ }
330
+ async init(options) {
331
+ return init(this.context, options);
332
+ }
333
+ async createSubject(input, options) {
334
+ return createSubject(this.context, input, options);
335
+ }
336
+ async getSubject(id, query, options) {
337
+ return getSubject(this.context, id, query, options);
338
+ }
339
+ async patchSubject(id, input, options) {
340
+ return patchSubject(this.context, id, input, options);
341
+ }
342
+ async listSubjects(query, options) {
343
+ return listSubjects(this.context, query, options);
344
+ }
345
+ async checkConsent(query, options) {
346
+ return checkConsent(this.context, query, options);
347
+ }
348
+ async $fetch(path, options) {
349
+ return fetcher(this.context, path, options);
350
+ }
351
+ consent = {
352
+ check: (query, options)=>this.checkConsent(query, options)
353
+ };
354
+ subjects = {
355
+ create: (input, options)=>this.createSubject(input, options),
356
+ get: (id, query, options)=>this.getSubject(id, query, options),
357
+ patch: (id, input, options)=>this.patchSubject(id, input, options),
358
+ list: (query, options)=>this.listSubjects(query, options)
359
+ };
360
+ meta = {
361
+ status: (options)=>this.status(options),
362
+ init: (options)=>this.init(options)
363
+ };
364
+ }
365
+ function c15tClient(options) {
366
+ return new C15TClient(options);
367
+ }
368
+ export { C15TClient, C15TError, c15tClient, createResponseContext, fetcher, isC15TError, resolveUrl };
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Testing utilities for @c15t/node-sdk
3
+ *
4
+ * These utilities help users mock the C15T client in their tests.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * import { createMockClient, createMockResponse } from '@c15t/node-sdk/testing';
9
+ *
10
+ * const mockClient = createMockClient({
11
+ * getSubject: async () => createMockResponse({ id: 'sub_123', consents: [] }),
12
+ * });
13
+ *
14
+ * // Use mockClient in your tests
15
+ * const result = await mockClient.getSubject('sub_123');
16
+ * expect(result.data?.id).toBe('sub_123');
17
+ * ```
18
+ */
19
+ import type { ResponseContext } from './types';
20
+ /**
21
+ * Creates a mock ResponseContext for testing
22
+ *
23
+ * @param data - The data to return in the response
24
+ * @param options - Optional configuration for the mock response
25
+ * @returns A ResponseContext object
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * const response = createMockResponse({ id: 'sub_123' });
30
+ * expect(response.ok).toBe(true);
31
+ * expect(response.data?.id).toBe('sub_123');
32
+ * ```
33
+ */
34
+ export declare function createMockResponse<T>(data: T, options?: {
35
+ ok?: boolean;
36
+ error?: {
37
+ message: string;
38
+ status: number;
39
+ code?: string;
40
+ details?: Record<string, unknown> | null;
41
+ };
42
+ response?: Response;
43
+ }): ResponseContext<T>;
44
+ /**
45
+ * Creates a mock error ResponseContext for testing
46
+ *
47
+ * @param error - The error details
48
+ * @returns A ResponseContext object representing an error
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const response = createMockErrorResponse({
53
+ * message: 'Not found',
54
+ * status: 404,
55
+ * code: 'NOT_FOUND',
56
+ * });
57
+ * expect(response.ok).toBe(false);
58
+ * expect(response.error?.status).toBe(404);
59
+ * ```
60
+ */
61
+ export declare function createMockErrorResponse<T = unknown>(error: {
62
+ message: string;
63
+ status: number;
64
+ code?: string;
65
+ details?: Record<string, unknown> | null;
66
+ }): ResponseContext<T>;
67
+ /**
68
+ * Type for mock method implementations
69
+ */
70
+ export type MockMethodImplementation<TInput, TOutput> = (input: TInput) => ResponseContext<TOutput> | Promise<ResponseContext<TOutput>>;
71
+ /**
72
+ * Type for mock client overrides
73
+ */
74
+ export interface MockClientOverrides {
75
+ status?: MockMethodImplementation<void, unknown>;
76
+ init?: MockMethodImplementation<void, unknown>;
77
+ checkConsent?: MockMethodImplementation<unknown, unknown>;
78
+ createSubject?: MockMethodImplementation<unknown, unknown>;
79
+ getSubject?: MockMethodImplementation<string, unknown>;
80
+ patchSubject?: MockMethodImplementation<unknown, unknown>;
81
+ listSubjects?: MockMethodImplementation<unknown, unknown>;
82
+ }
83
+ /**
84
+ * Creates a mock C15T client for testing
85
+ *
86
+ * @param overrides - Method implementations to override
87
+ * @returns A mock client object
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const mockClient = createMockClient({
92
+ * getSubject: async (id) => createMockResponse({
93
+ * id,
94
+ * externalId: 'user_123',
95
+ * consents: [],
96
+ * }),
97
+ * checkConsent: async () => createMockResponse({
98
+ * results: { analytics: { hasConsent: true } },
99
+ * }),
100
+ * });
101
+ *
102
+ * // Use in tests
103
+ * const result = await mockClient.getSubject('sub_123');
104
+ * ```
105
+ */
106
+ export declare function createMockClient(overrides?: MockClientOverrides): {
107
+ status: () => Promise<ResponseContext<unknown>>;
108
+ init: () => Promise<ResponseContext<unknown>>;
109
+ checkConsent: (query: unknown) => Promise<ResponseContext<unknown>>;
110
+ createSubject: (input: unknown) => Promise<ResponseContext<unknown>>;
111
+ getSubject: (id: string) => Promise<ResponseContext<unknown>>;
112
+ patchSubject: (id: string, input: unknown) => Promise<ResponseContext<unknown>>;
113
+ listSubjects: (query?: unknown) => Promise<ResponseContext<unknown>>;
114
+ consent: {
115
+ check: (query: unknown) => Promise<ResponseContext<unknown>>;
116
+ };
117
+ subjects: {
118
+ create: (input: unknown) => Promise<ResponseContext<unknown>>;
119
+ get: (id: string) => Promise<ResponseContext<unknown>>;
120
+ patch: (id: string, input: unknown) => Promise<ResponseContext<unknown>>;
121
+ list: (query?: unknown) => Promise<ResponseContext<unknown>>;
122
+ };
123
+ meta: {
124
+ status: () => Promise<ResponseContext<unknown>>;
125
+ init: () => Promise<ResponseContext<unknown>>;
126
+ };
127
+ };
128
+ /**
129
+ * Type representing the mock client returned by createMockClient
130
+ */
131
+ export type MockC15TClient = ReturnType<typeof createMockClient>;
132
+ //# sourceMappingURL=testing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EACnC,IAAI,EAAE,CAAC,EACP,OAAO,GAAE;IACR,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,KAAK,CAAC,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;KACzC,CAAC;IACF,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACf,GACJ,eAAe,CAAC,CAAC,CAAC,CA0CpB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CACzC,GAAG,eAAe,CAAC,CAAC,CAAC,CAErB;AAED;;GAEG;AACH,MAAM,MAAM,wBAAwB,CAAC,MAAM,EAAE,OAAO,IAAI,CACvD,KAAK,EAAE,MAAM,KACT,eAAe,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,MAAM,CAAC,EAAE,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,wBAAwB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/C,YAAY,CAAC,EAAE,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1D,aAAa,CAAC,EAAE,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3D,UAAU,CAAC,EAAE,wBAAwB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,YAAY,CAAC,EAAE,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC1D,YAAY,CAAC,EAAE,wBAAwB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;CAC1D;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,GAAE,mBAAwB;;;0BAoB5C,OAAO;2BACN,OAAO;qBACb,MAAM;uBACJ,MAAM,SAAS,OAAO;2BAOlB,OAAO;;uBAId,OAAO;;;wBAGN,OAAO;kBACb,MAAM;oBACJ,MAAM,SAAS,OAAO;uBAOnB,OAAO;;;;;;EAOxB;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}