@c15t/node-sdk 2.0.0 → 2.0.4

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
@@ -1,14 +1,14 @@
1
1
  <p align="center">
2
- <a href="https://c15t.com?utm_source=github&utm_medium=repopage_%40c15t%2Fnode-sdk" target="_blank" rel="noopener noreferrer">
2
+ <a href="https://c15t.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fnode-sdk" target="_blank" rel="noopener noreferrer">
3
3
  <picture>
4
4
  <source media="(prefers-color-scheme: dark)" srcset="../../docs/assets/c15t-banner-readme-dark.svg" type="image/svg+xml">
5
5
  <img src="../../docs/assets/c15t-banner-readme-light.svg" alt="c15t Banner" type="image/svg+xml">
6
6
  </picture>
7
7
  </a>
8
- <br />
9
- <h1 align="center">@c15t/node-sdk: Type-Safe Node.js API Client</h1>
10
8
  </p>
11
9
 
10
+ # @c15t/node-sdk: Type-Safe Node.js API Client
11
+
12
12
  [![GitHub stars](https://img.shields.io/github/stars/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t)
13
13
  [![CI](https://img.shields.io/github/actions/workflow/status/c15t/c15t/ci.yml?style=flat-square)](https://github.com/c15t/c15t/actions/workflows/ci.yml)
14
14
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](https://github.com/c15t/c15t/blob/main/LICENSE.md)
@@ -18,235 +18,61 @@
18
18
  [![Last Commit](https://img.shields.io/github/last-commit/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t/commits/main)
19
19
  [![Open Issues](https://img.shields.io/github/issues/c15t/c15t?style=flat-square)](https://github.com/c15t/c15t/issues)
20
20
 
21
- A fully typed, lightweight Node.js SDK for seamless interaction with the c15t consent management platform API.
21
+ A fully typed, flexible Node.js SDK for seamless interaction with the c15t consent management platform API.
22
22
 
23
23
  ## Key Features
24
24
 
25
- - **Type-safe API client** with full TypeScript support
26
- - **Zero-config setup** with environment variable auto-detection
27
- - **Result-like error handling** with `unwrap()`, `unwrapOr()`, and `expect()` helpers
28
- - **Custom error class** (`C15TError`) for typed error handling
29
- - **Automatic retries** with exponential backoff
30
- - **Namespaced API methods** for intuitive organization
31
- - **Lightweight** with minimal dependencies
25
+ - Type-safe API client with full TypeScript support
26
+ - Flexible client configuration with authentication and custom headers
27
+ - Supports dynamic base URL and API prefix configuration
28
+ - Built on top of @orpc/client for robust API interactions
29
+ - Easy integration with Node.js applications
30
+ - Comprehensive error handling and URL validation
32
31
 
33
32
  ## Prerequisites
34
33
 
35
34
  - Node.js 18.17.0 or later
36
- - A Hosted [c15t instance](https://consent.io) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/v2)
35
+ - A Hosted [c15t instance](https://inth.com) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/v2)
37
36
 
38
- ## Installation
37
+ ## Manual Installation
39
38
 
40
39
  ```bash
41
- # npm
42
- npm install @c15t/node-sdk
43
-
44
- # pnpm
45
40
  pnpm add @c15t/node-sdk
46
-
47
- # yarn
48
- yarn add @c15t/node-sdk
49
-
50
- # bun
51
- bun add @c15t/node-sdk
52
- ```
53
-
54
- ## Quick Start
55
-
56
- ### Basic Setup
57
-
58
- ```typescript
59
- import { c15tClient } from '@c15t/node-sdk';
60
-
61
- // Auto-configure from environment variables
62
- // Reads C15T_API_URL and C15T_API_TOKEN automatically
63
- const client = c15tClient();
64
-
65
- // Or provide explicit configuration
66
- const client = c15tClient({
67
- baseUrl: 'https://api.example.com',
68
- token: 'your-api-token',
69
- });
70
41
  ```
71
42
 
72
- ### Environment Variables
73
-
74
- The SDK automatically reads these environment variables:
43
+ ## Usage
75
44
 
76
- - `C15T_API_URL` - Base URL for the API server
77
- - `C15T_API_TOKEN` - Authentication token
45
+ 1. Import `c15tClient` from `@c15t/node-sdk`
46
+ 2. Configure with a base URL and token, or set `C15T_API_URL` and `C15T_API_TOKEN` so the client picks them up automatically
47
+ 3. Call API methods on `client.meta`, `client.subjects`, etc. — every method is fully typed
78
48
 
79
- ### Check Consent Status
49
+ ```ts
50
+ // server.ts
51
+ import { c15tClient } from '@c15t/node-sdk'
80
52
 
81
- ```typescript
82
- const result = await client.checkConsent({
83
- externalId: 'user_123',
84
- type: 'analytics',
85
- });
86
-
87
- if (result.ok) {
88
- console.log('Has consent:', result.data?.results.analytics?.hasConsent);
89
- } else {
90
- console.error('Error:', result.error?.message);
91
- }
92
- ```
53
+ // Auto-configure from C15T_API_URL + C15T_API_TOKEN env vars
54
+ const client = c15tClient()
93
55
 
94
- ### Using Result Helpers
95
-
96
- The SDK provides ergonomic helper methods inspired by Rust's Result type:
97
-
98
- ```typescript
99
- // Unwrap data or throw if error
100
- const subject = (await client.getSubject('sub_123')).unwrap();
101
-
102
- // Unwrap with custom error message
103
- const subject = (await client.getSubject('sub_123')).expect('Subject not found');
104
-
105
- // Unwrap with default value
106
- const subject = (await client.getSubject('sub_123')).unwrapOr(defaultSubject);
107
-
108
- // Transform data with map
109
- const name = (await client.getSubject('sub_123')).map(s => s.externalId);
110
- ```
111
-
112
- ### Error Handling
113
-
114
- ```typescript
115
- import { c15tClient, C15TError, isC15TError } from '@c15t/node-sdk';
116
-
117
- const client = c15tClient();
56
+ // Or pass options explicitly
57
+ // const client = c15tClient({
58
+ // baseUrl: process.env.C15T_API_URL!,
59
+ // token: process.env.C15T_API_TOKEN!,
60
+ // })
118
61
 
119
62
  try {
120
- const subject = (await client.getSubject('sub_123')).unwrap();
63
+ const status = await client.meta.status()
64
+ console.log('c15t API status:', status)
65
+
66
+ const subject = await client.subjects.create({
67
+ type: 'cookie_banner',
68
+ subjectId: 'sub_123',
69
+ domain: 'example.com',
70
+ preferences: { analytics: true },
71
+ givenAt: Date.now(),
72
+ })
73
+ console.log('Created subject', subject.id)
121
74
  } catch (error) {
122
- if (isC15TError(error)) {
123
- console.log('Status:', error.status); // 404
124
- console.log('Code:', error.code); // 'NOT_FOUND'
125
- console.log('Details:', error.details);
126
-
127
- if (error.isNotFound()) {
128
- // Handle not found
129
- } else if (error.isServerError()) {
130
- // Handle server error
131
- }
132
- }
133
- }
134
- ```
135
-
136
- ### Create Subject with Consent
137
-
138
- ```typescript
139
- const result = await client.createSubject({
140
- type: 'cookie_banner',
141
- subjectId: 'sub_123',
142
- externalSubjectId: 'user_123',
143
- domain: 'example.com',
144
- preferences: {
145
- analytics: true,
146
- marketing: false,
147
- },
148
- givenAt: Date.now(),
149
- });
150
-
151
- if (result.ok) {
152
- console.log('Subject created:', result.data?.subjectId);
153
- }
154
- ```
155
-
156
- ### Server Component Usage (Next.js)
157
-
158
- ```typescript
159
- // lib/c15t-client.ts
160
- import { c15tClient } from '@c15t/node-sdk';
161
-
162
- export const consentClient = c15tClient({
163
- baseUrl: process.env.C15T_API_URL || 'http://localhost:3000/api/self-host',
164
- });
165
-
166
- // app/consent-check/page.tsx
167
- import { consentClient } from '@/lib/c15t-client';
168
-
169
- export default async function ConsentCheckPage({ searchParams }) {
170
- const { externalId } = await searchParams;
171
-
172
- const result = await consentClient.checkConsent({
173
- externalId,
174
- type: 'analytics',
175
- });
176
-
177
- if (!result.ok) {
178
- return <div>Error: {result.error?.message}</div>;
179
- }
180
-
181
- return <pre>{JSON.stringify(result.data, null, 2)}</pre>;
182
- }
183
- ```
184
-
185
- ## API Reference
186
-
187
- ### Client Methods
188
-
189
- | Method | Description |
190
- |--------|-------------|
191
- | `client.status()` | Check API status |
192
- | `client.init()` | Initialize consent manager |
193
- | `client.checkConsent(query)` | Check consent status |
194
- | `client.createSubject(input)` | Create a new subject |
195
- | `client.getSubject(id)` | Get subject by ID |
196
- | `client.patchSubject(id, input)` | Update subject |
197
- | `client.listSubjects(query)` | List subjects |
198
-
199
- ### Namespaced Methods
200
-
201
- ```typescript
202
- // Meta operations
203
- client.meta.status();
204
- client.meta.init();
205
-
206
- // Consent operations
207
- client.consent.check(query);
208
-
209
- // Subject operations
210
- client.subjects.create(input);
211
- client.subjects.get(id);
212
- client.subjects.patch(id, input);
213
- client.subjects.list(query);
214
- ```
215
-
216
- ### ResponseContext
217
-
218
- All methods return a `ResponseContext<T>` with:
219
-
220
- ```typescript
221
- interface ResponseContext<T> {
222
- data: T | null; // Response data
223
- error: {...} | null; // Error details
224
- ok: boolean; // Success status
225
- response: Response | null; // Raw Response object
226
-
227
- // Helper methods
228
- unwrap(): T; // Get data or throw
229
- unwrapOr(default: T): T; // Get data or return default
230
- expect(msg: string): T; // Get data or throw with custom message
231
- map<U>(fn: (T) => U): ResponseContext<U>; // Transform data
232
- }
233
- ```
234
-
235
- ### Configuration Options
236
-
237
- ```typescript
238
- interface C15TClientOptions {
239
- baseUrl?: string; // API base URL (or use C15T_API_URL env var)
240
- token?: string; // Auth token (or use C15T_API_TOKEN env var)
241
- headers?: Record<string, string>; // Custom headers
242
- prefix?: string; // API path prefix
243
- retryConfig?: {
244
- maxRetries?: number; // Default: 3
245
- initialDelayMs?: number; // Default: 100
246
- backoffFactor?: number; // Default: 2
247
- retryableStatusCodes?: number[]; // Default: [500, 502, 503, 504]
248
- retryOnNetworkError?: boolean; // Default: true
249
- };
75
+ console.error('c15t request failed:', error)
250
76
  }
251
77
  ```
252
78
 
@@ -254,24 +80,24 @@ interface C15TClientOptions {
254
80
 
255
81
  - Join our [Discord community](https://c15t.link/discord)
256
82
  - Open an issue on our [GitHub repository](https://github.com/c15t/c15t/issues)
257
- - Visit [consent.io](https://consent.io) and use the chat widget
258
- - Contact our support team via email [support@consent.io](mailto:support@consent.io)
83
+ - Visit [inth.com](https://inth.com) and use the chat widget
84
+ - Contact our support team via email [support@inth.com](mailto:support@inth.com)
259
85
 
260
86
  ## Contributing
261
87
 
262
- - We're open to all community contributions!
88
+ - We're open to all community contributions.
263
89
  - Read our [Contribution Guidelines](https://c15t.com/docs/oss/contributing)
264
90
  - Review our [Code of Conduct](https://c15t.com/docs/oss/code-of-conduct)
265
91
  - Fork the repository
266
92
  - Create a new branch for your feature
267
93
  - Submit a pull request
268
- - **All contributions, big or small, are welcome and appreciated!**
94
+ - **All contributions, big or small, are welcome and appreciated.**
269
95
 
270
96
  ## Security
271
97
 
272
98
  If you believe you have found a security vulnerability in c15t, we encourage you to **_responsibly disclose this and NOT open a public issue_**. We will investigate all legitimate reports.
273
99
 
274
- Our preference is that you make use of GitHub's private vulnerability reporting feature to disclose potential security vulnerabilities in our Open Source Software. To do this, please visit [https://github.com/c15t/c15t/security](https://github.com/c15t/c15t/security) and click the "Report a vulnerability" button.
100
+ Our preference is that you make use of GitHub's private vulnerability reporting feature to disclose potential security vulnerabilities in our open-source software. To do this, please visit [https://github.com/c15t/c15t/security](https://github.com/c15t/c15t/security) and click the "Report a vulnerability" button.
275
101
 
276
102
  ### Security Policy
277
103
 
@@ -286,4 +112,4 @@ Our preference is that you make use of GitHub's private vulnerability reporting
286
112
 
287
113
  ---
288
114
 
289
- **Built by [Inth](https://inth.com?utm_source=github&utm_medium=repopage_%40c15t%2Fnode-sdk)**
115
+ **Built by [Inth](https://inth.com?utm_source=npm&utm_medium=readme&utm_campaign=oss_readme&utm_content=%40c15t%2Fnode-sdk)**
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.d = (exports1, definition)=>{
5
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
6
+ enumerable: true,
7
+ get: definition[key]
8
+ });
9
+ };
10
+ })();
11
+ (()=>{
12
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
13
+ })();
14
+ (()=>{
15
+ __webpack_require__.r = (exports1)=>{
16
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
17
+ value: 'Module'
18
+ });
19
+ Object.defineProperty(exports1, '__esModule', {
20
+ value: true
21
+ });
22
+ };
23
+ })();
24
+ var __webpack_exports__ = {};
25
+ __webpack_require__.r(__webpack_exports__);
26
+ __webpack_require__.d(__webpack_exports__, {
27
+ createMockClient: ()=>createMockClient,
28
+ createMockErrorResponse: ()=>createMockErrorResponse,
29
+ createMockResponse: ()=>createMockResponse
30
+ });
31
+ function createMockResponse(data, options = {}) {
32
+ const isSuccess = options.ok ?? true;
33
+ const error = options.error ?? null;
34
+ const response = options.response ?? null;
35
+ return {
36
+ data: isSuccess ? data : null,
37
+ error,
38
+ ok: isSuccess,
39
+ response,
40
+ unwrap () {
41
+ if (!isSuccess || null === data) throw new Error(error?.message || 'Request failed');
42
+ return data;
43
+ },
44
+ unwrapOr (defaultValue) {
45
+ if (!isSuccess || null === data) return defaultValue;
46
+ return data;
47
+ },
48
+ expect (message) {
49
+ if (!isSuccess || null === data) throw new Error(message);
50
+ return data;
51
+ },
52
+ map (fn) {
53
+ if (!isSuccess || null === data) return createMockResponse(null, {
54
+ ok: false,
55
+ error: error ?? void 0
56
+ });
57
+ return createMockResponse(fn(data));
58
+ }
59
+ };
60
+ }
61
+ function createMockErrorResponse(error) {
62
+ return createMockResponse(null, {
63
+ ok: false,
64
+ error
65
+ });
66
+ }
67
+ function createMockClient(overrides = {}) {
68
+ const defaultNotImplemented = ()=>createMockErrorResponse({
69
+ message: 'Method not implemented in mock',
70
+ status: 501,
71
+ code: 'NOT_IMPLEMENTED'
72
+ });
73
+ const status = overrides.status ?? defaultNotImplemented;
74
+ const init = overrides.init ?? defaultNotImplemented;
75
+ const checkConsent = overrides.checkConsent ?? defaultNotImplemented;
76
+ const createSubject = overrides.createSubject ?? defaultNotImplemented;
77
+ const getSubject = overrides.getSubject ?? defaultNotImplemented;
78
+ const patchSubject = overrides.patchSubject ?? defaultNotImplemented;
79
+ const listSubjects = overrides.listSubjects ?? defaultNotImplemented;
80
+ return {
81
+ status: ()=>Promise.resolve(status()),
82
+ init: ()=>Promise.resolve(init()),
83
+ checkConsent: (query)=>Promise.resolve(checkConsent(query)),
84
+ createSubject: (input)=>Promise.resolve(createSubject(input)),
85
+ getSubject: (id)=>Promise.resolve(getSubject(id)),
86
+ patchSubject: (id, input)=>Promise.resolve(patchSubject({
87
+ id,
88
+ ...'object' == typeof input && null !== input ? input : {}
89
+ })),
90
+ listSubjects: (query)=>Promise.resolve(listSubjects(query)),
91
+ consent: {
92
+ check: (query)=>Promise.resolve(checkConsent(query))
93
+ },
94
+ subjects: {
95
+ create: (input)=>Promise.resolve(createSubject(input)),
96
+ get: (id)=>Promise.resolve(getSubject(id)),
97
+ patch: (id, input)=>Promise.resolve(patchSubject({
98
+ id,
99
+ ...'object' == typeof input && null !== input ? input : {}
100
+ })),
101
+ list: (query)=>Promise.resolve(listSubjects(query))
102
+ },
103
+ meta: {
104
+ status: ()=>Promise.resolve(status()),
105
+ init: ()=>Promise.resolve(init())
106
+ }
107
+ };
108
+ }
109
+ exports.createMockClient = __webpack_exports__.createMockClient;
110
+ exports.createMockErrorResponse = __webpack_exports__.createMockErrorResponse;
111
+ exports.createMockResponse = __webpack_exports__.createMockResponse;
112
+ for(var __rspack_i in __webpack_exports__)if (-1 === [
113
+ "createMockClient",
114
+ "createMockErrorResponse",
115
+ "createMockResponse"
116
+ ].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
117
+ Object.defineProperty(exports, '__esModule', {
118
+ value: true
119
+ });
@@ -0,0 +1,79 @@
1
+ function createMockResponse(data, options = {}) {
2
+ const isSuccess = options.ok ?? true;
3
+ const error = options.error ?? null;
4
+ const response = options.response ?? null;
5
+ return {
6
+ data: isSuccess ? data : null,
7
+ error,
8
+ ok: isSuccess,
9
+ response,
10
+ unwrap () {
11
+ if (!isSuccess || null === data) throw new Error(error?.message || 'Request failed');
12
+ return data;
13
+ },
14
+ unwrapOr (defaultValue) {
15
+ if (!isSuccess || null === data) return defaultValue;
16
+ return data;
17
+ },
18
+ expect (message) {
19
+ if (!isSuccess || null === data) throw new Error(message);
20
+ return data;
21
+ },
22
+ map (fn) {
23
+ if (!isSuccess || null === data) return createMockResponse(null, {
24
+ ok: false,
25
+ error: error ?? void 0
26
+ });
27
+ return createMockResponse(fn(data));
28
+ }
29
+ };
30
+ }
31
+ function createMockErrorResponse(error) {
32
+ return createMockResponse(null, {
33
+ ok: false,
34
+ error
35
+ });
36
+ }
37
+ function createMockClient(overrides = {}) {
38
+ const defaultNotImplemented = ()=>createMockErrorResponse({
39
+ message: 'Method not implemented in mock',
40
+ status: 501,
41
+ code: 'NOT_IMPLEMENTED'
42
+ });
43
+ const status = overrides.status ?? defaultNotImplemented;
44
+ const init = overrides.init ?? defaultNotImplemented;
45
+ const checkConsent = overrides.checkConsent ?? defaultNotImplemented;
46
+ const createSubject = overrides.createSubject ?? defaultNotImplemented;
47
+ const getSubject = overrides.getSubject ?? defaultNotImplemented;
48
+ const patchSubject = overrides.patchSubject ?? defaultNotImplemented;
49
+ const listSubjects = overrides.listSubjects ?? defaultNotImplemented;
50
+ return {
51
+ status: ()=>Promise.resolve(status()),
52
+ init: ()=>Promise.resolve(init()),
53
+ checkConsent: (query)=>Promise.resolve(checkConsent(query)),
54
+ createSubject: (input)=>Promise.resolve(createSubject(input)),
55
+ getSubject: (id)=>Promise.resolve(getSubject(id)),
56
+ patchSubject: (id, input)=>Promise.resolve(patchSubject({
57
+ id,
58
+ ...'object' == typeof input && null !== input ? input : {}
59
+ })),
60
+ listSubjects: (query)=>Promise.resolve(listSubjects(query)),
61
+ consent: {
62
+ check: (query)=>Promise.resolve(checkConsent(query))
63
+ },
64
+ subjects: {
65
+ create: (input)=>Promise.resolve(createSubject(input)),
66
+ get: (id)=>Promise.resolve(getSubject(id)),
67
+ patch: (id, input)=>Promise.resolve(patchSubject({
68
+ id,
69
+ ...'object' == typeof input && null !== input ? input : {}
70
+ })),
71
+ list: (query)=>Promise.resolve(listSubjects(query))
72
+ },
73
+ meta: {
74
+ status: ()=>Promise.resolve(status()),
75
+ init: ()=>Promise.resolve(init())
76
+ }
77
+ };
78
+ }
79
+ export { createMockClient, createMockErrorResponse, createMockResponse };
package/package.json CHANGED
@@ -1,25 +1,27 @@
1
1
  {
2
2
  "name": "@c15t/node-sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.4",
4
4
  "description": "Official Node.js SDK for c15t. Connects to the Consent Engine to read and write consent records and preferences. TypeScript-first, simple APIs, built-in auth and retries.",
5
5
  "keywords": [
6
- "react",
6
+ "c15t",
7
+ "node",
8
+ "nodejs",
9
+ "sdk",
7
10
  "consent",
11
+ "consent-api",
12
+ "consent-management",
8
13
  "privacy",
9
14
  "gdpr",
10
15
  "ccpa",
11
16
  "lgpd",
12
- "headless",
13
- "typescript",
14
- "cookie-banner",
15
- "consent-management-platform",
16
17
  "cmp",
17
- "consent-banner",
18
- "user-consent",
19
- "privacy-compliance",
20
- "web-privacy"
18
+ "typescript",
19
+ "server-side"
21
20
  ],
22
21
  "homepage": "https://c15t.com",
22
+ "bugs": {
23
+ "url": "https://github.com/c15t/c15t/issues"
24
+ },
23
25
  "repository": {
24
26
  "type": "git",
25
27
  "url": "https://github.com/c15t/c15t.git",
@@ -50,14 +52,14 @@
50
52
  "build": "rslib build && bun ../../scripts/normalize-dist-types.mjs",
51
53
  "check-types": "tsc --noEmit",
52
54
  "check-types:test": "tsc -p tsconfig.test.json",
53
- "dev": "rslib build --watch",
55
+ "dev": "sh -c 'rslib build --no-dts --no-clean && rslib build --watch --no-dts --no-clean'",
54
56
  "fmt": "bun biome format --write . && bun biome check --formatter-enabled=false --linter-enabled=false --write",
55
57
  "lint": "bun biome lint ./src",
56
58
  "test": "vitest run",
57
59
  "test:watch": "vitest"
58
60
  },
59
61
  "dependencies": {
60
- "@c15t/backend": "2.0.0",
62
+ "@c15t/backend": "2.0.4",
61
63
  "@orpc/client": "1.13.13",
62
64
  "@orpc/contract": "1.13.13",
63
65
  "@orpc/openapi-client": "^1.13.13",
package/readme.json CHANGED
@@ -11,13 +11,15 @@
11
11
  ],
12
12
  "prerequisites": [
13
13
  "Node.js 18.17.0 or later",
14
- "A Hosted [c15t instance](https://consent.io) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/v2)"
14
+ "A Hosted [c15t instance](https://inth.com) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/v2)"
15
15
  ],
16
16
  "manualInstallation": ["", "```bash\npnpm add @c15t/node-sdk\n```"],
17
17
  "usage": [
18
- "Import the c15tClient function from the SDK",
19
- "Configure the client with your API base URL",
20
- "Interact with the c15t API using type-safe methods"
18
+ "Import `c15tClient` from `@c15t/node-sdk`",
19
+ "Configure with a base URL and token, or set `C15T_API_URL` and `C15T_API_TOKEN` so the client picks them up automatically",
20
+ "Call API methods on `client.meta`, `client.subjects`, etc. — every method is fully typed",
21
+
22
+ "```ts\n// server.ts\nimport { c15tClient } from '@c15t/node-sdk'\n\n// Auto-configure from C15T_API_URL + C15T_API_TOKEN env vars\nconst client = c15tClient()\n\n// Or pass options explicitly\n// const client = c15tClient({\n// baseUrl: process.env.C15T_API_URL!,\n// token: process.env.C15T_API_TOKEN!,\n// })\n\ntry {\n const status = await client.meta.status()\n console.log('c15t API status:', status)\n\n const subject = await client.subjects.create({\n type: 'cookie_banner',\n subjectId: 'sub_123',\n domain: 'example.com',\n preferences: { analytics: true },\n givenAt: Date.now(),\n })\n console.log('Created subject', subject.id)\n} catch (error) {\n console.error('c15t request failed:', error)\n}\n```"
21
23
  ],
22
24
  "showCLIGeneration": false
23
25
  }