@typeb-digital/nucleus-sdk 0.0.2 → 0.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 ADDED
@@ -0,0 +1,236 @@
1
+ # @typeb-digital/nucleus-sdk
2
+
3
+ Server-side TypeScript SDK for the **Nucleus data platform** — the company source of truth for people, projects, and clients.
4
+
5
+ Install this in your **app backend** (Node.js). It holds the app token and handles all data access. Never import it in browser code.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @typeb-digital/nucleus-sdk
13
+ # or
14
+ yarn add @typeb-digital/nucleus-sdk
15
+ ```
16
+
17
+ Requires Node.js ≥ 18.
18
+
19
+ ---
20
+
21
+ ## Quick start
22
+
23
+ ```typescript
24
+ import { NucleusClient } from '@typeb-digital/nucleus-sdk';
25
+
26
+ export const nucleus = new NucleusClient({
27
+ token: process.env.NUCLEUS_TOKEN!,
28
+ scopes: {
29
+ employees: ['identity', 'employment'],
30
+ projects: ['core'],
31
+ clients: ['identity'],
32
+ },
33
+ });
34
+ ```
35
+
36
+ The `scopes` object is the heart of the type system. Declare it once; every method on the client returns types that reflect exactly those buckets — nothing more, nothing less. TypeScript infers the types automatically; no explicit type parameters needed.
37
+
38
+ > **Get your token and init script** from the Nucleus dashboard → Apps → your app → Init Script.
39
+
40
+ ---
41
+
42
+ ## Scopes & buckets
43
+
44
+ Nucleus groups fields into **buckets** per resource. Your app only receives fields for the buckets you've been approved for.
45
+
46
+ | Resource | Available buckets |
47
+ | -------------- | ------------------------------------------------------------------------------------------------ |
48
+ | `employees` | `identity` · `contact` · `employment` · `sensitive`¹ · `compensation`¹ · `compensation_history`¹ |
49
+ | `projects` | `core` · `team` · `financials` · `integrations` |
50
+ | `clients` | `identity` · `contact` · `financials` · `notes` |
51
+ | `partners` | `identity` · `contact` · `notes` |
52
+ | `departments` | `core` |
53
+ | `projectTypes` | `core` |
54
+ | `currencies` | `core` |
55
+ | `genericRates` | `core` · `financials`¹ |
56
+
57
+ ¹ Requires platform-team approval.
58
+
59
+ ---
60
+
61
+ ## Data access
62
+
63
+ ### Employees
64
+
65
+ ```typescript
66
+ // List — type reflects declared buckets
67
+ const result = await nucleus.employees.list({
68
+ department: 'Engineering',
69
+ page: 1,
70
+ pageSize: 50,
71
+ });
72
+
73
+ if (!isError(result)) {
74
+ result.data; // Employee[] typed to your scopes
75
+ result.meta.total; // number
76
+ result.meta.hasMore; // boolean
77
+ }
78
+
79
+ // Single record
80
+ const { data: emp } = await nucleus.employees.getById('emp_123');
81
+
82
+ // With expansion — manager is typed as an Employee object, not just a string ID
83
+ const { data: emp } = await nucleus.employees.getById('emp_123', {
84
+ expand: ['manager'],
85
+ });
86
+ if (emp.manager) {
87
+ emp.manager.email; // ✓ typed
88
+ }
89
+ ```
90
+
91
+ ### Projects
92
+
93
+ ```typescript
94
+ const result = await nucleus.projects.list({ status: 'active' });
95
+
96
+ // Expand client and team members in one call
97
+ const { data: project } = await nucleus.projects.getById('proj_123', {
98
+ expand: ['client', 'projectManager', 'memberships.employee'],
99
+ });
100
+ ```
101
+
102
+ ### Clients, Partners, Departments, Currencies, Generic Rates
103
+
104
+ Same pattern — `list(params?)` and `getById(id, options?)` on every resource accessor.
105
+
106
+ ---
107
+
108
+ ## Result type
109
+
110
+ Every method returns a result object — **never throws** by default:
111
+
112
+ ```typescript
113
+ import { NucleusClient, isError } from '@typeb-digital/nucleus-sdk';
114
+
115
+ const result = await nucleus.employees.getById('emp_123');
116
+
117
+ if (isError(result)) {
118
+ // result.error.code: 'FORBIDDEN' | 'NOT_FOUND' | 'INVALID_SCOPE' | 'RATE_LIMITED' | 'NETWORK_ERROR'
119
+ console.error(result.error.message);
120
+ return;
121
+ }
122
+
123
+ // result.data is fully typed here
124
+ console.log(result.data.email);
125
+ ```
126
+
127
+ ---
128
+
129
+ ## File storage
130
+
131
+ ```typescript
132
+ // Upload — app provides a path-style key; upsert semantics
133
+ const { data: file } = await nucleus.files.upload({
134
+ key: 'users/123/avatar',
135
+ file: buffer, // Buffer
136
+ mimeType: 'image/png',
137
+ visibility: 'private',
138
+ allowedUsers: ['emp_123'], // optional — omit for app-wide access
139
+ metadata: { type: 'avatar' },
140
+ });
141
+
142
+ // Resolve a URL to pass to your frontend
143
+ // Public → CDN URL (instant, no signing)
144
+ // Private → fresh short-lived pre-signed URL
145
+ const { data } = await nucleus.files.getUrl('users/123/avatar');
146
+ // data.url — hand this to the browser
147
+
148
+ // Private file scoped to a specific user
149
+ const { data } = await nucleus.files.getUrl('users/123/avatar', {
150
+ asUser: userAccessToken, // from the client SDK's getSession().accessToken
151
+ });
152
+
153
+ // List files
154
+ const result = await nucleus.files.list({ prefix: 'users/123/' });
155
+
156
+ // Soft delete
157
+ await nucleus.files.delete('users/123/avatar');
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Self-service app info
163
+
164
+ ```typescript
165
+ const { data: app } = await nucleus.apps.me();
166
+ // app.name, app.scopes (declared), app.status per-bucket
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Pagination
172
+
173
+ All `list()` methods return explicit pagination metadata:
174
+
175
+ ```typescript
176
+ const result = await nucleus.employees.list({ page: 2, pageSize: 25 });
177
+
178
+ if (!isError(result)) {
179
+ result.meta.total; // total records
180
+ result.meta.page; // current page
181
+ result.meta.pageSize; // records per page
182
+ result.meta.hasMore; // boolean shortcut
183
+ }
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Expansion
189
+
190
+ Related records are not included by default. Request them explicitly:
191
+
192
+ ```typescript
193
+ // Depth 1
194
+ const { data } = await nucleus.projects.getById('proj_123', {
195
+ expand: ['client', 'projectManager'],
196
+ });
197
+
198
+ // Depth 2 (max)
199
+ const { data } = await nucleus.projects.getById('proj_123', {
200
+ expand: ['projectManager.manager'],
201
+ });
202
+ ```
203
+
204
+ Valid expand paths per resource are typed — invalid paths or three-segment paths are compile errors.
205
+
206
+ ---
207
+
208
+ ## TypeScript
209
+
210
+ The SDK is fully typed with no `any`. Bucket scopes drive the return types at compile time:
211
+
212
+ ```typescript
213
+ // scopes.employees = ['identity'] only
214
+ const { data: emp } = await nucleus.employees.getById('emp_123');
215
+ emp.email; // ✓ string
216
+ emp.phone; // ✗ compile error — contact bucket not declared
217
+ emp.managerId; // ✗ compile error — employment bucket not declared
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Configuration
223
+
224
+ ```typescript
225
+ new NucleusClient({
226
+ token: process.env.NUCLEUS_TOKEN!, // required
227
+ baseUrl: 'https://nucleus.example.com', // optional, defaults to platform URL
228
+ scopes: { ... }, // required
229
+ })
230
+ ```
231
+
232
+ ---
233
+
234
+ ## License
235
+
236
+ MIT — Type B Digital
@@ -2,7 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  var ofetch = require('ofetch');
4
4
 
5
- const DEFAULT_BASE_URL = 'https://nucleus.typeb.digital';
5
+ const DEFAULT_BASE_URL = 'https://nucleus.typeb-lab.online';
6
6
  function statusToCode(status, apiCode) {
7
7
  if (apiCode === 'INVALID_SCOPE') return 'INVALID_SCOPE';
8
8
  if (status === 404) return 'NOT_FOUND';
package/dist/es/index.js CHANGED
@@ -2,7 +2,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
2
2
 
3
3
  var ofetch = require('ofetch');
4
4
 
5
- const DEFAULT_BASE_URL = 'https://nucleus.typeb.digital';
5
+ const DEFAULT_BASE_URL = 'https://nucleus.typeb-lab.online';
6
6
  function statusToCode(status, apiCode) {
7
7
  if (apiCode === 'INVALID_SCOPE') return 'INVALID_SCOPE';
8
8
  if (status === 404) return 'NOT_FOUND';
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "@typeb-digital/nucleus-sdk",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Server-side TypeScript SDK for the Nucleus data platform",
5
5
  "engines": {
6
6
  "node": ">=18"
7
7
  },
8
8
  "files": [
9
- "dist"
9
+ "dist",
10
+ "README.md"
10
11
  ],
11
12
  "main": "./dist/cjs/index.cjs",
12
13
  "module": "./dist/es/index.js",