@typeb-digital/nucleus-sdk 0.0.6 → 0.1.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/CHANGELOG.md ADDED
@@ -0,0 +1,94 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@typeb-digital/nucleus-sdk` are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
6
+ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). While the
7
+ package is pre-`1.0.0`, **breaking changes may land in a minor version** (e.g. `0.0.x` → `0.1.0`).
8
+
9
+ ## [0.1.1] - 2026-06-22
10
+
11
+ ### Changed
12
+
13
+ - **Employees are read-only.** Nucleus owns employee writes (sourced via Google/HRIS
14
+ sync), so the scope system no longer accepts `create` / `update` / `delete` grants
15
+ for `employees`:
16
+ - `ScopeDeclaration` types `employees` as read-only — declaring a write action on it
17
+ is now a compile-time error.
18
+ - Removed `employees.update()` / `employees.delete()` from the SDK.
19
+
20
+ (The platform also rejects employee write grants at app-registration / group-permission
21
+ time, and the dashboard scope matrix shows `employees` as read-only.)
22
+
23
+ ## [0.1.0] - 2026-06-22
24
+
25
+ Action-typed scopes and write support. **This is a breaking release** — every consumer's
26
+ `scopes` config must be migrated (see _Migration_ below).
27
+
28
+ ### Changed
29
+
30
+ - **BREAKING — `scopes` is now per-action.** Each resource declares an object of action →
31
+ buckets instead of a flat bucket array:
32
+
33
+ ```diff
34
+ new NucleusClient({
35
+ token: process.env.NUCLEUS_TOKEN!,
36
+ scopes: {
37
+ - employees: ['identity', 'employment'],
38
+ - leaves: ['core'],
39
+ + employees: { read: ['identity', 'employment'], update: ['contact'] },
40
+ + leaves: { read: ['core'], create: ['core'], delete: true },
41
+ },
42
+ });
43
+ ```
44
+
45
+ `read` drives the return types of `list()` / `getById()` (unchanged behaviour, just nested
46
+ under `read`). `create` / `update` are bucket lists; `delete` is a boolean.
47
+
48
+ ### Added
49
+
50
+ - **Mutation methods** on writable resources: `create(data)`, `update(id, data)`, and
51
+ `delete(id)`. They are **gated at compile time by the declared scope** — calling
52
+ `nucleus.leaves.create(...)` is a type error unless `leaves.create` is declared. The
53
+ platform also enforces the same per-bucket authorization at runtime (`INVALID_SCOPE`).
54
+ Mutations return the same `SingleResult<T>` shape as reads and never throw; `delete`
55
+ returns `{ data: null }`.
56
+ - **Test sandbox tokens.** An `el_test_` token reads/writes the anonymized test sandbox; an
57
+ `el_live_` token hits real data once the app is published. The token prefix is the only
58
+ switch — no SDK config change.
59
+
60
+ ### Fixed
61
+
62
+ - **`apps.me()` (`AppInfo`) realigned with the API.** Each token now carries `mode`
63
+ (`'live'` | `'test'`); added the publish-lifecycle fields `status`, `submittedAt`,
64
+ `publishedAt`, `reviewNote`, and `redirectUris`.
65
+
66
+ ### Removed
67
+
68
+ - **BREAKING — `AppInfo.environment` and `tokens[].environment`.** The platform dropped the
69
+ `environment` concept; a token's environment is now its `mode`. (The fields had been
70
+ returning `undefined` at runtime since the platform change.)
71
+
72
+ ### Migration
73
+
74
+ 1. Wrap each resource's bucket array in `{ read: [...] }`.
75
+ 2. Add `create` / `update` / `delete` only for the actions your app token is approved for —
76
+ the dashboard's **Init Script** generates the correct config.
77
+ 3. Replace any reads of `app.environment` / `token.environment` with `token.mode`.
78
+
79
+ ## [0.0.x] - Initial development
80
+
81
+ Pre-`0.1.0` releases (read-only data access). These were not individually version-tagged;
82
+ this entry summarizes the surface that existed before `0.1.0`:
83
+
84
+ ### Added
85
+
86
+ - `NucleusClient` with compile-time scope→type inference (bucket arrays).
87
+ - Read accessors (`list` / `getById`, with `expand`) for: employees, projects, clients,
88
+ partners, departments, projectTypes, currencies, genericRates, jurisdictions, leaveTypes,
89
+ leaves, leaveBalances, policies, policyAcknowledgements, calendarEvents, timesheets.
90
+ - `files` accessor (R2-backed) including `getUrl({ asUser })` for user-scoped private files.
91
+ - `auth.verifyToken()` (RS256 / JWKS) for the dual-token (app + forwarded user token) model.
92
+ - `apps.me()` self-service app info, including the normalized `permissions[]` rows plus the
93
+ back-compat aggregated `scopes[]`.
94
+ - `isError()` result-narrowing helper; results never throw.
package/README.md CHANGED
@@ -96,16 +96,18 @@ async function projectHandler(req, res) {
96
96
  import { NucleusClient } from '@typeb-digital/nucleus-sdk';
97
97
 
98
98
  export const nucleus = new NucleusClient({
99
- token: process.env.NUCLEUS_TOKEN!,
99
+ token: process.env.NUCLEUS_TOKEN!, // el_live_… or el_test_… (sandbox)
100
100
  scopes: {
101
- employees: ['identity', 'employment'],
102
- projects: ['core'],
103
- clients: ['identity'],
101
+ employees: { read: ['identity', 'employment'], update: ['contact'] },
102
+ projects: { read: ['core'] },
103
+ leaves: { read: ['core'], create: ['core'], delete: true },
104
104
  },
105
105
  });
106
106
  ```
107
107
 
108
- The `scopes` object is the heart of the type system. Declare it once; every method on the client returns types that reflect exactly those bucketsnothing more, nothing less. TypeScript infers the types automatically; no explicit type parameters needed.
108
+ The `scopes` object is the heart of the type system. Each resource declares its **per-action** buckets — `read`, `create`, `update` (each a bucket list) and `delete` (boolean). `read` drives the return types of `list`/`getById`; `create`/`update`/`delete` **gate the mutation methods at compile time** calling `nucleus.leaves.create(...)` is a type error unless you declared `leaves.create`. Declare it once; TypeScript infers everything, no explicit type parameters needed.
109
+
110
+ > **Test vs live:** the token _is_ the environment — an `el_test_` token reads/writes the anonymized sandbox; an `el_live_` token hits real data (once your app is published). No SDK config change.
109
111
 
110
112
  > **Get your token and init script** from the Nucleus dashboard → Apps → your app → Init Script.
111
113
 
@@ -130,6 +132,31 @@ Nucleus groups fields into **buckets** per resource. Your app only receives fiel
130
132
 
131
133
  ---
132
134
 
135
+ ## Writing data (mutations)
136
+
137
+ Resources you've scoped for `create` / `update` / `delete` expose matching methods. They're **gated by your declared scope** — the method is uncallable unless the action is declared, so you can't even construct a call the server would reject.
138
+
139
+ ```typescript
140
+ // Requires `leaves: { create: [...] }`
141
+ const created = await nucleus.leaves.create({
142
+ employeeId: 'emp_…',
143
+ leaveTypeId: 'lt_…',
144
+ startDate: '2026-07-01',
145
+ endDate: '2026-07-03',
146
+ days: 3,
147
+ });
148
+
149
+ // Requires `leaves: { update: [...] }`
150
+ await nucleus.leaves.update('leave_…', { days: 2 });
151
+
152
+ // Requires `leaves: { delete: true }`
153
+ await nucleus.leaves.delete('leave_…');
154
+ ```
155
+
156
+ All mutations return the same `SingleResult<T>` shape as reads (`{ data }` or `{ error }`) — they never throw. `delete` returns `{ data: null }`. The server enforces the same per-bucket authorization independently, so an unapproved write fails with `INVALID_SCOPE` even if the types allowed it.
157
+
158
+ ---
159
+
133
160
  ## Data access
134
161
 
135
162
  ### Employees