@c15t/node-sdk 3.0.0-alpha.2 → 3.0.0-alpha.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
@@ -7,7 +7,7 @@
7
7
  </a>
8
8
  </p>
9
9
 
10
- # @c15t/node-sdk: Type-Safe Node.js API Client
10
+ # @c15t/node-sdk: Node.js client for the c15t consent API
11
11
 
12
12
  <p>
13
13
  <a href="https://www.npmjs.com/package/@c15t/node-sdk"><picture><source media="(prefers-color-scheme: dark)" srcset="https://shieldcn.dev/npm/%40c15t%2Fnode-sdk.svg?variant=outline&mode=dark"><img src="https://shieldcn.dev/npm/%40c15t%2Fnode-sdk.svg?variant=outline&mode=light" alt="Latest NPM Version"></picture></a>
@@ -18,71 +18,79 @@
18
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
- Type-safe Node.js SDK for hosted and self-hosted c15t consent APIs, consent records, privacy preferences, and backend automation.
21
+ Typed client for hosted and self-hosted c15t backends. Check consent before sending email, link users after sign-in, export a user's consent records, publish legal document releases from CI and read banner experiment results.
22
22
 
23
23
  ## Key Features
24
24
 
25
- - Type-safe API client with full TypeScript support
26
- - Works with hosted c15t instances on inth.com and self-hosted @c15t/backend deployments
27
- - Read and write consent records, subjects, and privacy preferences from Node.js
28
- - Flexible client configuration with authentication and custom headers
29
- - Supports dynamic base URL and API prefix configuration
30
- - Built on top of @orpc/client for robust API interactions
31
- - Comprehensive error handling and URL validation
25
+ - One `createC15tClient()` call with an explicit backend URL. No environment variables are read
26
+ - Methods resolve to `{ ok: true, data }` or `{ ok: false, error }` and never reject. Error codes are typed per method
27
+ - Key-only methods (`subjects.list`, `experiments.summary`, `legalDocuments.publish`) exist only on a client created with an API key
28
+ - Input is validated before anything is sent, and response dates are `Date` objects
29
+ - Per-attempt timeouts and retries for network errors, timeouts and 408, 429, 500, 502, 503 and 504, honouring `Retry-After`
30
+ - A typed mock client in `@c15t/node-sdk/testing`
32
31
 
33
32
  ## Prerequisites
34
33
 
35
- - Node.js 20.19 or later
36
- - A hosted [c15t instance](https://inth.com) (free sign-up) or [self-hosted deployment](https://c15t.com/docs/self-host/quickstart)
34
+ - Node.js 20.19 or later, or another runtime with `fetch`, `AbortSignal.any` and `crypto.randomUUID`
35
+ - A hosted [c15t instance](https://inth.com) or a [self-hosted backend](https://c15t.com/docs/self-host/quickstart)
37
36
 
38
37
  ## Manual Installation
39
38
 
40
39
  ```bash
41
- pnpm add @c15t/node-sdk
40
+ pnpm add @c15t/node-sdk@alpha
42
41
  ```
43
42
 
44
43
  ## Usage
45
44
 
46
- 1. Import `c15tClient` from `@c15t/node-sdk`
47
- 2. Configure with a base URL and token, or set `C15T_API_URL` and `C15T_API_TOKEN` so the client picks them up automatically
48
- 3. Call API methods on `client.meta`, `client.subjects`, etc. — every method is fully typed
45
+ 1. Create a client with the URL where the backend is mounted, path included. Pass `apiKey` for the key-only methods
46
+ 2. Call a method and check `result.ok` before reading `result.data`, or use `unwrap(result)` to throw the error instead
49
47
 
50
48
  ```ts
51
49
  // server.ts
52
- import { c15tClient } from '@c15t/node-sdk'
53
-
54
- // Auto-configure from C15T_API_URL + C15T_API_TOKEN env vars
55
- const client = c15tClient()
56
-
57
- // Or pass options explicitly
58
- // const client = c15tClient({
59
- // baseUrl: process.env.C15T_API_URL!,
60
- // token: process.env.C15T_API_TOKEN!,
61
- // })
62
-
63
- try {
64
- const status = await client.meta.status()
65
- console.log('c15t API status:', status)
66
-
67
- const subject = await client.subjects.create({
68
- type: 'cookie_banner',
69
- subjectId: 'sub_123',
70
- domain: 'example.com',
71
- preferences: { analytics: true },
72
- givenAt: Date.now(),
73
- })
74
- console.log('Created subject', subject.id)
75
- } catch (error) {
76
- console.error('c15t request failed:', error)
50
+ import { createC15tClient } from '@c15t/node-sdk';
51
+
52
+ const apiKey = process.env.C15T_API_KEY;
53
+ if (!apiKey) throw new Error('Set C15T_API_KEY');
54
+
55
+ const c15t = createC15tClient({
56
+ baseUrl: 'https://app.example.com/api/c15t',
57
+ apiKey,
58
+ });
59
+
60
+ const result = await c15t.consents.check({
61
+ externalId: user.id,
62
+ types: ['marketing_communications'],
63
+ });
64
+
65
+ if (result.ok && result.data.results.marketing_communications.hasConsent) {
66
+ await sendNewsletter(user);
67
+ } else if (!result.ok) {
68
+ console.error(result.error.code, result.error.requestId);
77
69
  }
78
70
  ```
79
71
 
80
- ## Common Use Cases
72
+ ## Documentation
73
+
74
+ For further information, guides, and examples visit the [reference documentation](https://c15t.com/docs/self-host/api/node-sdk).
75
+
76
+ ## Methods
77
+
78
+ | Method | API key |
79
+ | --- | --- |
80
+ | `consents.check({ externalId, types })` | No |
81
+ | `subjects.identify(id, { externalId, identityProvider })` | No |
82
+ | `subjects.get(id, { types })` | No |
83
+ | `subjects.create(input)` | No |
84
+ | `subjects.list({ externalId })` | Required |
85
+ | `legalDocuments.publish(type, { version, hash, effectiveDate })` | Required |
86
+ | `experiments.summary(id, { from, to, domain })` | Required |
87
+ | `status()`, `init()`, `manifest()` | No |
88
+
89
+ Every method takes `{ signal, timeoutMs, headers, retry, requestId }` as its last argument.
90
+
91
+ ## Upgrading from v2
81
92
 
82
- - Sync consent records between your application and c15t
83
- - Build admin tooling around hosted or self-hosted consent APIs
84
- - Automate privacy preference workflows from server-side jobs
85
- - Integrate c15t consent records with internal data systems
93
+ `c15tClient()` and the `C15TClient` class are replaced by `createC15tClient()`. Results replace `ResponseContext`, `C15TError` is now `C15tError`, and `subjects.patch` is now `subjects.identify`. See the [migration guide](https://c15t.com/docs/upgrade-v3#update-the-nodejs-sdk).
86
94
 
87
95
  ## Support
88
96
 
package/dist/160.js ADDED
@@ -0,0 +1,68 @@
1
+ const C15T_API_ERROR_CODES = [
2
+ 'BAD_REQUEST',
3
+ 'CHOICE_OUT_OF_SCOPE',
4
+ 'CHOICE_PREFERENCE_MISMATCH',
5
+ 'CONFLICT',
6
+ 'DATABASE_ERROR',
7
+ 'EXTERNAL_ID_REQUIRED',
8
+ 'INPUT_VALIDATION_FAILED',
9
+ 'NOT_FOUND',
10
+ 'POLICY_SNAPSHOT_EXPIRED',
11
+ 'POLICY_SNAPSHOT_INVALID',
12
+ 'POLICY_SNAPSHOT_REQUIRED',
13
+ 'PURPOSE_NOT_ALLOWED',
14
+ 'SERVICE_UNAVAILABLE',
15
+ 'STALE_POLICY',
16
+ 'SUBJECT_CONFLICT',
17
+ 'TYPE_REQUIRED',
18
+ 'UNAUTHORIZED'
19
+ ];
20
+ const C15T_CLIENT_ERROR_CODES = [
21
+ 'ABORTED',
22
+ 'INVALID_INPUT',
23
+ 'MISSING_API_KEY',
24
+ 'NETWORK_ERROR',
25
+ 'TIMEOUT',
26
+ 'UNEXPECTED_RESPONSE'
27
+ ];
28
+ const isStalePolicyReason = (value)=>'decision-mismatch' === value || 'incomplete-inputs' === value || 'policy-changed' === value;
29
+ class C15tError extends Error {
30
+ name = 'C15tError';
31
+ code;
32
+ status;
33
+ reason;
34
+ requestId;
35
+ retryable;
36
+ issues;
37
+ serverCode;
38
+ constructor(init){
39
+ super(init.message, void 0 === init.cause ? {} : {
40
+ cause: init.cause
41
+ });
42
+ this.code = init.code;
43
+ this.status = init.status;
44
+ this.reason = 'STALE_POLICY' === init.code && isStalePolicyReason(init.reason) ? init.reason : void 0;
45
+ this.requestId = init.requestId;
46
+ this.retryable = init.retryable ?? false;
47
+ this.issues = init.issues;
48
+ this.serverCode = init.serverCode;
49
+ }
50
+ toJSON() {
51
+ return {
52
+ code: this.code,
53
+ issues: this.issues,
54
+ message: this.message,
55
+ name: this.name,
56
+ reason: this.reason,
57
+ requestId: this.requestId,
58
+ retryable: this.retryable,
59
+ serverCode: this.serverCode,
60
+ status: this.status
61
+ };
62
+ }
63
+ }
64
+ function isC15tError(error, ...codes) {
65
+ if (!(error instanceof C15tError)) return false;
66
+ return 0 === codes.length || codes.includes(error.code);
67
+ }
68
+ export { C15T_API_ERROR_CODES, C15T_CLIENT_ERROR_CODES, C15tError, isC15tError, isStalePolicyReason };