@typeb-digital/nucleus-sdk 0.2.1 → 0.3.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 +108 -0
- package/dist/cjs/index.cjs +125 -20
- package/dist/cjs/index.d.cts +126 -17
- package/dist/cjs/index.d.cts.map +1 -1
- package/dist/es/index.d.ts +126 -17
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +125 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,114 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). While the
|
|
7
7
|
package is pre-`1.0.0`, **breaking changes may land in a minor version** (e.g. `0.0.x` → `0.1.0`).
|
|
8
8
|
|
|
9
|
+
## [0.3.1] - 2026-07-07
|
|
10
|
+
|
|
11
|
+
Calendar-event jurisdiction support. Additive and non-breaking.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- **`calendarEvents` expose jurisdiction.** `CalendarEventCore` now includes
|
|
16
|
+
`jurisdictionId: string | null` (which jurisdiction a holiday applies to; null for
|
|
17
|
+
non-holiday events) and `national: boolean` (national vs region-specific holiday).
|
|
18
|
+
- **Expandable `jurisdiction`.** `calendarEvents.list(...)` and `calendarEvents.getById(...)`
|
|
19
|
+
accept `expand: ['jurisdiction']` to hydrate the full jurisdiction inline
|
|
20
|
+
(`event.jurisdiction` → the resolved jurisdiction, or `null`). Requires a `jurisdictions`
|
|
21
|
+
read scope on the token (the platform enforces scope on expanded resources). Example:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
const { data } = await nucleus.calendarEvents.list({
|
|
25
|
+
type: 'holiday',
|
|
26
|
+
expand: ['jurisdiction'],
|
|
27
|
+
});
|
|
28
|
+
data[0].jurisdiction?.name; // typed only when expanded
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## [0.3.0] - 2026-07-01
|
|
32
|
+
|
|
33
|
+
Leveling model v2 and app-writable employee data. **This is a breaking release** — the
|
|
34
|
+
`employees` and `jobLevels` scope shapes changed (see _Migration_ below).
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- **BREAKING — `jobLevels` is now many-to-many with departments.** A level applies to any
|
|
39
|
+
number of departments (empty = company-wide), replacing the single-department field:
|
|
40
|
+
|
|
41
|
+
```diff
|
|
42
|
+
- jobLevels.core.departmentId: string | null
|
|
43
|
+
+ jobLevels.core.departmentIds: string[]
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The create/update input follows suit (`departmentId?` → `departmentIds?: string[]`), and
|
|
47
|
+
`jobLevels.list({ departmentId })` filters to levels that include that department.
|
|
48
|
+
|
|
49
|
+
- **BREAKING — `employees` is now update-only, not read-only.** The scope moved from
|
|
50
|
+
`{ read }` to `{ read, update }`, and the readable fields were re-bucketed. A new writable
|
|
51
|
+
**`placement`** bucket holds `managerId`, `partnerId`, `departmentId`, `jurisdictionId`,
|
|
52
|
+
`jobLevelId`, `employmentType`, `isExternal`, and `timezone`; identity/contact/sensitive/
|
|
53
|
+
employment remain read-only (Google/HRIS-owned). Create and delete are still rejected
|
|
54
|
+
(onboarding requires Google Workspace provisioning).
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **`employees.update(id, data)`** — patch the `placement` bucket, gated at compile time by a
|
|
59
|
+
declared `employees.update` scope and per-bucket-authorized at runtime. Writing any
|
|
60
|
+
read-only field (identity/contact/etc.) is rejected with `400` / `INVALID_SCOPE`.
|
|
61
|
+
- **`employeeProfiles` accessor** — work-arrangement records: `get(employeeId)` and
|
|
62
|
+
`upsert(employeeId, data)` (daily hours, probation months, overtime enabled).
|
|
63
|
+
- **`employeeReviews` accessor** — `list` / `create` / `update` / `delete`. The `feedback`
|
|
64
|
+
bucket (rating + written feedback) is confidential and approval-gated, separate from the
|
|
65
|
+
`core` review metadata.
|
|
66
|
+
- **`salaryBands.departmentId`** — bands can now be scoped to a department (null = company-wide
|
|
67
|
+
fallback); added to reads, create/update input, and the `list({ departmentId })` filter.
|
|
68
|
+
- **`genericRates.jobLevelId`** — an optional link from a generic rate to a job level; added to
|
|
69
|
+
reads, create input, and the `list({ jobLevelId })` filter.
|
|
70
|
+
|
|
71
|
+
### Migration
|
|
72
|
+
|
|
73
|
+
1. `jobLevels`: replace any `departmentId` read/write with `departmentIds` (a `string[]`; use
|
|
74
|
+
`[]` for a company-wide level).
|
|
75
|
+
2. `employees`: change the scope from a bucket array / read-only form to
|
|
76
|
+
`{ read: [...], update: ['placement'] }` if the app writes placement fields; call
|
|
77
|
+
`nucleus.employees.update(id, { ... })` for those writes. No create/delete.
|
|
78
|
+
3. New optional fields (`salaryBands.departmentId`, `genericRates.jobLevelId`) are additive —
|
|
79
|
+
no action needed unless you want to set or filter by them.
|
|
80
|
+
|
|
81
|
+
## [0.2.1] - 2026-06-30
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
|
|
85
|
+
- **Removed `Department.titles`.** The unused `titles: string[]` field was dropped from the
|
|
86
|
+
`Department` type.
|
|
87
|
+
|
|
88
|
+
### Fixed
|
|
89
|
+
|
|
90
|
+
- **Inlined resource path literals.** Internal accessors (employee-compensation, project
|
|
91
|
+
members) previously built request paths through private helper methods; these are now inline
|
|
92
|
+
string literals. No behavioural change — this keeps the paths discoverable by the OpenAPI
|
|
93
|
+
sync check.
|
|
94
|
+
- **`AddProjectMemberInput` is now a `type` alias** (was an `interface`), fixing a
|
|
95
|
+
snake-case body-cast type error. Field shape is unchanged.
|
|
96
|
+
|
|
97
|
+
## [0.2.0] - 2026-06-29
|
|
98
|
+
|
|
99
|
+
Reference data, compensation writes, and communication surfaces.
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
|
|
103
|
+
- **`jobLevels` accessor** — read the career-ladder levels (code, name, per-department scope).
|
|
104
|
+
- **`salaryBands` accessor** — read per-`(level, jurisdiction)` pay ranges (financial figures
|
|
105
|
+
are sensitivity-gated).
|
|
106
|
+
- **`employeeCompensation` accessor** — `list(employeeId)`, `current(employeeId)`,
|
|
107
|
+
`create(...)`, and `delete(employeeId, id)` for an employee's compensation history.
|
|
108
|
+
- **`calendar.listEvents(params)`** — query Google Calendar events for a workspace user.
|
|
109
|
+
- **`email.send(input)`** — send mode-aware email (live sends via Gmail; test mode is
|
|
110
|
+
sandboxed).
|
|
111
|
+
- **`timesheets.bulkCreate(...)`** — create many timesheet entries in one request.
|
|
112
|
+
- **Project team membership** — `projects.listMembers`, `addMember`, and `removeMember`.
|
|
113
|
+
- **Incremental sync** — list accessors accept `updatedSince` (ISO-8601) to return only records
|
|
114
|
+
changed at or after that time.
|
|
115
|
+
- **`projects.list({ stage })`** — filter projects by pipeline stage.
|
|
116
|
+
|
|
9
117
|
## [0.1.1] - 2026-06-22
|
|
10
118
|
|
|
11
119
|
### Changed
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -399,6 +399,7 @@ function transformGenericRate(raw) {
|
|
|
399
399
|
if ('id' in r) out['id'] = r['id'];
|
|
400
400
|
if ('title' in r) out['title'] = str(r['title']);
|
|
401
401
|
if ('department' in r) out['department'] = str(r['department']);
|
|
402
|
+
if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
|
|
402
403
|
if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
|
|
403
404
|
if ('cost_rate' in r) out['costRate'] = num(r['cost_rate']);
|
|
404
405
|
if ('billable_rate' in r) out['billableRate'] = num(r['billable_rate']);
|
|
@@ -421,7 +422,10 @@ function transformJobLevel(raw) {
|
|
|
421
422
|
if ('id' in r) out['id'] = r['id'];
|
|
422
423
|
if ('name' in r) out['name'] = str(r['name']);
|
|
423
424
|
if ('code' in r) out['code'] = str(r['code']);
|
|
424
|
-
|
|
425
|
+
// The API returns the join rows under `departments`; flatten to a string[] of ids.
|
|
426
|
+
if ('departments' in r && Array.isArray(r['departments'])) {
|
|
427
|
+
out['departmentIds'] = r['departments'].map((d)=>d?.['department_id']).filter((v)=>typeof v === 'string');
|
|
428
|
+
}
|
|
425
429
|
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
426
430
|
return out;
|
|
427
431
|
}
|
|
@@ -431,6 +435,7 @@ function transformSalaryBand(raw) {
|
|
|
431
435
|
const out = {};
|
|
432
436
|
if ('id' in r) out['id'] = r['id'];
|
|
433
437
|
if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
|
|
438
|
+
if ('department_id' in r) out['departmentId'] = str(r['department_id']);
|
|
434
439
|
if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
|
|
435
440
|
if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
|
|
436
441
|
if ('min_salary' in r) out['minSalary'] = num(r['min_salary']);
|
|
@@ -547,6 +552,12 @@ function transformCalendarEvent(raw) {
|
|
|
547
552
|
if ('location' in r) out['location'] = str(r['location']);
|
|
548
553
|
if ('color' in r) out['color'] = str(r['color']);
|
|
549
554
|
if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
|
|
555
|
+
if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
|
|
556
|
+
if ('national' in r) out['national'] = bool(r['national']);
|
|
557
|
+
// Expand: jurisdiction (recursively transformed)
|
|
558
|
+
if ('jurisdiction' in r) {
|
|
559
|
+
out['jurisdiction'] = r['jurisdiction'] ? transformJurisdiction(r['jurisdiction']) : null;
|
|
560
|
+
}
|
|
550
561
|
return out;
|
|
551
562
|
}
|
|
552
563
|
function transformTimesheet(raw) {
|
|
@@ -607,6 +618,18 @@ class EmployeesAccessor {
|
|
|
607
618
|
data: transformEmployee(result.data)
|
|
608
619
|
};
|
|
609
620
|
}
|
|
621
|
+
/**
|
|
622
|
+
* Update an employee's placement (manager, partner, department, jurisdiction, job
|
|
623
|
+
* level, employment type, external flag, timezone). Requires `employees` update on the
|
|
624
|
+
* `placement` bucket. Identity/contact/sensitive fields are Google-owned and read-only;
|
|
625
|
+
* employees cannot be created or deleted via the SDK.
|
|
626
|
+
*/ async update(id, data) {
|
|
627
|
+
const result = await this.transport.patch(`/api/v1/data/employees/${id}`, toSnakeBody(data));
|
|
628
|
+
if ('error' in result) return result;
|
|
629
|
+
return {
|
|
630
|
+
data: transformEmployee(result.data)
|
|
631
|
+
};
|
|
632
|
+
}
|
|
610
633
|
}
|
|
611
634
|
|
|
612
635
|
function transformMember(raw) {
|
|
@@ -671,25 +694,22 @@ class ProjectsAccessor {
|
|
|
671
694
|
// ─── Team membership (the projects `team` bucket) ──────────────────────────
|
|
672
695
|
// Membership is the project↔employee join. Reads need `projects` read on `team`;
|
|
673
696
|
// add/remove need `projects` update on `team` (re-adding restores a soft-deleted row).
|
|
674
|
-
membersBase(projectId) {
|
|
675
|
-
return `/api/v1/data/project-memberships/projects/${projectId}/members`;
|
|
676
|
-
}
|
|
677
697
|
/** List a project's team members. Requires `projects` read on the `team` bucket. */ async listMembers(projectId) {
|
|
678
|
-
const result = await this.transport.get(
|
|
698
|
+
const result = await this.transport.get(`/api/v1/data/project-memberships/projects/${projectId}/members`);
|
|
679
699
|
if ('error' in result) return result;
|
|
680
700
|
return {
|
|
681
701
|
data: (result.data ?? []).map((r)=>transformMember(r))
|
|
682
702
|
};
|
|
683
703
|
}
|
|
684
704
|
/** Add a team member. Requires `projects` update on the `team` bucket. */ async addMember(projectId, data) {
|
|
685
|
-
const result = await this.transport.post(
|
|
705
|
+
const result = await this.transport.post(`/api/v1/data/project-memberships/projects/${projectId}/members`, toSnakeBody(data));
|
|
686
706
|
if ('error' in result) return result;
|
|
687
707
|
return {
|
|
688
708
|
data: transformMember(result.data)
|
|
689
709
|
};
|
|
690
710
|
}
|
|
691
711
|
/** Remove a team member. Requires `projects` update on the `team` bucket. */ async removeMember(projectId, employeeId) {
|
|
692
|
-
const result = await this.transport.del(
|
|
712
|
+
const result = await this.transport.del(`/api/v1/data/project-memberships/projects/${projectId}/members/${employeeId}`);
|
|
693
713
|
if ('error' in result) return result;
|
|
694
714
|
return {
|
|
695
715
|
data: null
|
|
@@ -1093,6 +1113,7 @@ class JurisdictionsAccessor {
|
|
|
1093
1113
|
async list(params) {
|
|
1094
1114
|
const query = {};
|
|
1095
1115
|
if (params?.jobLevelId) query['jobLevelId'] = params.jobLevelId;
|
|
1116
|
+
if (params?.departmentId) query['departmentId'] = params.departmentId;
|
|
1096
1117
|
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1097
1118
|
if (params?.page) query['page'] = params.page;
|
|
1098
1119
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
@@ -1396,6 +1417,7 @@ class CalendarEventsAccessor {
|
|
|
1396
1417
|
if (params?.page) query['page'] = params.page;
|
|
1397
1418
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1398
1419
|
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1420
|
+
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1399
1421
|
const result = await this.transport.getList('/api/v1/data/calendar-events', query);
|
|
1400
1422
|
if ('error' in result) return result;
|
|
1401
1423
|
return {
|
|
@@ -1403,8 +1425,10 @@ class CalendarEventsAccessor {
|
|
|
1403
1425
|
meta: result.meta
|
|
1404
1426
|
};
|
|
1405
1427
|
}
|
|
1406
|
-
async getById(id) {
|
|
1407
|
-
const
|
|
1428
|
+
async getById(id, options) {
|
|
1429
|
+
const query = {};
|
|
1430
|
+
if (options?.expand?.length) query['expand'] = options.expand.join(',');
|
|
1431
|
+
const result = await this.transport.get(`/api/v1/data/calendar-events/${id}`, query);
|
|
1408
1432
|
if ('error' in result) return result;
|
|
1409
1433
|
return {
|
|
1410
1434
|
data: transformCalendarEvent(result.data)
|
|
@@ -1538,7 +1562,7 @@ class TimesheetsAccessor {
|
|
|
1538
1562
|
}
|
|
1539
1563
|
}
|
|
1540
1564
|
|
|
1541
|
-
function transform(raw) {
|
|
1565
|
+
function transform$2(raw) {
|
|
1542
1566
|
return {
|
|
1543
1567
|
id: raw['id'],
|
|
1544
1568
|
employeeId: raw['employee_id'],
|
|
@@ -1560,32 +1584,111 @@ function transform(raw) {
|
|
|
1560
1584
|
constructor(transport){
|
|
1561
1585
|
this.transport = transport;
|
|
1562
1586
|
}
|
|
1563
|
-
base(employeeId) {
|
|
1564
|
-
return `/api/v1/data/employee-compensation/employees/${employeeId}/compensation`;
|
|
1565
|
-
}
|
|
1566
1587
|
/** Full history, newest first. */ async list(employeeId) {
|
|
1567
|
-
const result = await this.transport.get(
|
|
1588
|
+
const result = await this.transport.get(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation`);
|
|
1568
1589
|
if ('error' in result) return result;
|
|
1569
1590
|
return {
|
|
1570
|
-
data: (result.data ?? []).map((r)=>transform(r))
|
|
1591
|
+
data: (result.data ?? []).map((r)=>transform$2(r))
|
|
1571
1592
|
};
|
|
1572
1593
|
}
|
|
1573
1594
|
/** The current (open) record, or null. */ async current(employeeId) {
|
|
1574
|
-
const result = await this.transport.get(
|
|
1595
|
+
const result = await this.transport.get(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation/current`);
|
|
1575
1596
|
if ('error' in result) return result;
|
|
1576
1597
|
return {
|
|
1577
|
-
data: result.data ? transform(result.data) : null
|
|
1598
|
+
data: result.data ? transform$2(result.data) : null
|
|
1578
1599
|
};
|
|
1579
1600
|
}
|
|
1580
1601
|
/** Add a new effective-dated record (closes the prior open one). */ async create(employeeId, data) {
|
|
1581
|
-
const result = await this.transport.post(
|
|
1602
|
+
const result = await this.transport.post(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation`, toSnakeBody(data));
|
|
1582
1603
|
if ('error' in result) return result;
|
|
1583
1604
|
return {
|
|
1584
|
-
data: transform(result.data)
|
|
1605
|
+
data: transform$2(result.data)
|
|
1585
1606
|
};
|
|
1586
1607
|
}
|
|
1587
1608
|
/** Soft-delete a compensation record. */ async delete(employeeId, id) {
|
|
1588
|
-
const result = await this.transport.del(
|
|
1609
|
+
const result = await this.transport.del(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation/${id}`);
|
|
1610
|
+
if ('error' in result) return result;
|
|
1611
|
+
return {
|
|
1612
|
+
data: null
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
function transform$1(raw) {
|
|
1618
|
+
return {
|
|
1619
|
+
id: raw['id'],
|
|
1620
|
+
employeeId: raw['employee_id'],
|
|
1621
|
+
dailyHours: raw['daily_hours'] ?? 8,
|
|
1622
|
+
probationMonths: raw['probation_months'] ?? null,
|
|
1623
|
+
isOvertimeEnabled: raw['is_overtime_enabled'] ?? false
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* EmployeeProfilesAccessor — an employee's work-arrangement profile (Iteration 4).
|
|
1628
|
+
* Gated server-side by the `employee-profiles` scope.
|
|
1629
|
+
*/ class EmployeeProfilesAccessor {
|
|
1630
|
+
constructor(transport){
|
|
1631
|
+
this.transport = transport;
|
|
1632
|
+
}
|
|
1633
|
+
async get(employeeId) {
|
|
1634
|
+
const result = await this.transport.get(`/api/v1/data/employee-profiles/employees/${employeeId}/profile`);
|
|
1635
|
+
if ('error' in result) return result;
|
|
1636
|
+
return {
|
|
1637
|
+
data: result.data ? transform$1(result.data) : null
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
/** Create-or-update the profile. Requires `employee-profiles` update scope. */ async upsert(employeeId, data) {
|
|
1641
|
+
const result = await this.transport.put(`/api/v1/data/employee-profiles/employees/${employeeId}/profile`, toSnakeBody(data));
|
|
1642
|
+
if ('error' in result) return result;
|
|
1643
|
+
return {
|
|
1644
|
+
data: transform$1(result.data)
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
function transform(raw) {
|
|
1650
|
+
return {
|
|
1651
|
+
id: raw['id'],
|
|
1652
|
+
employeeId: raw['employee_id'],
|
|
1653
|
+
reviewType: raw['review_type'],
|
|
1654
|
+
dueDate: raw['due_date'] ?? null,
|
|
1655
|
+
completedDate: raw['completed_date'] ?? null,
|
|
1656
|
+
status: raw['status'],
|
|
1657
|
+
rating: raw['rating'] ?? null,
|
|
1658
|
+
feedback: raw['feedback'] ?? null,
|
|
1659
|
+
reviewerId: raw['reviewer_id'] ?? null
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* EmployeeReviewsAccessor — performance reviews (Iteration 4). Gated server-side by the
|
|
1664
|
+
* `employee-reviews` scope; the `feedback` bucket (rating + feedback) is approval-gated.
|
|
1665
|
+
*/ class EmployeeReviewsAccessor {
|
|
1666
|
+
constructor(transport){
|
|
1667
|
+
this.transport = transport;
|
|
1668
|
+
}
|
|
1669
|
+
async list(employeeId) {
|
|
1670
|
+
const result = await this.transport.get(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews`);
|
|
1671
|
+
if ('error' in result) return result;
|
|
1672
|
+
return {
|
|
1673
|
+
data: (result.data ?? []).map((r)=>transform(r))
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
async create(employeeId, data) {
|
|
1677
|
+
const result = await this.transport.post(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews`, toSnakeBody(data));
|
|
1678
|
+
if ('error' in result) return result;
|
|
1679
|
+
return {
|
|
1680
|
+
data: transform(result.data)
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
async update(employeeId, id, data) {
|
|
1684
|
+
const result = await this.transport.patch(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews/${id}`, toSnakeBody(data));
|
|
1685
|
+
if ('error' in result) return result;
|
|
1686
|
+
return {
|
|
1687
|
+
data: transform(result.data)
|
|
1688
|
+
};
|
|
1689
|
+
}
|
|
1690
|
+
async delete(employeeId, id) {
|
|
1691
|
+
const result = await this.transport.del(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews/${id}`);
|
|
1589
1692
|
if ('error' in result) return result;
|
|
1590
1693
|
return {
|
|
1591
1694
|
data: null
|
|
@@ -1759,6 +1862,8 @@ class AuthAccessor {
|
|
|
1759
1862
|
this.calendar = new CalendarAccessor(transport);
|
|
1760
1863
|
this.email = new EmailAccessor(transport);
|
|
1761
1864
|
this.employeeCompensation = new EmployeeCompensationAccessor(transport);
|
|
1865
|
+
this.employeeProfiles = new EmployeeProfilesAccessor(transport);
|
|
1866
|
+
this.employeeReviews = new EmployeeReviewsAccessor(transport);
|
|
1762
1867
|
this.apps = new AppsAccessor(transport);
|
|
1763
1868
|
this.files = new FilesAccessor(transport);
|
|
1764
1869
|
this.auth = new AuthAccessor(config.baseUrl);
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -49,8 +49,6 @@ type EmployeeIdentity = {
|
|
|
49
49
|
jobTitle: string | null;
|
|
50
50
|
department: string | null;
|
|
51
51
|
employmentStatus: string;
|
|
52
|
-
employmentType: string | null;
|
|
53
|
-
isExternal: boolean;
|
|
54
52
|
};
|
|
55
53
|
type EmployeeContact = {
|
|
56
54
|
profile: {
|
|
@@ -62,13 +60,21 @@ type EmployeeContact = {
|
|
|
62
60
|
type EmployeeEmployment = {
|
|
63
61
|
startDate: string | null;
|
|
64
62
|
weeklyCapacity: number | null;
|
|
63
|
+
profile: {
|
|
64
|
+
biography?: string | null;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/** HR-managed org placement — the only app-writable employee bucket (update-only). */
|
|
68
|
+
type EmployeePlacement = {
|
|
65
69
|
managerId: string | null;
|
|
66
70
|
partnerId: string | null;
|
|
71
|
+
departmentId: string | null;
|
|
72
|
+
jurisdictionId: string | null;
|
|
73
|
+
jobLevelId: string | null;
|
|
74
|
+
employmentType: string | null;
|
|
75
|
+
isExternal: boolean;
|
|
67
76
|
/** IANA timezone string, e.g. "Asia/Colombo". Null when not yet set. */
|
|
68
77
|
timezone: string | null;
|
|
69
|
-
profile: {
|
|
70
|
-
biography?: string | null;
|
|
71
|
-
};
|
|
72
78
|
};
|
|
73
79
|
type EmployeeSensitive = {
|
|
74
80
|
birthday: string | null;
|
|
@@ -107,10 +113,22 @@ type EmployeeBucketMap = {
|
|
|
107
113
|
identity: EmployeeIdentity;
|
|
108
114
|
contact: EmployeeContact;
|
|
109
115
|
employment: EmployeeEmployment;
|
|
116
|
+
placement: EmployeePlacement;
|
|
110
117
|
sensitive: EmployeeSensitive;
|
|
111
118
|
compensation: EmployeeCompensation;
|
|
112
119
|
compensation_history: EmployeeCompensationHistory;
|
|
113
120
|
};
|
|
121
|
+
/** Body for `employees.update` — the writable `placement` fields only. */
|
|
122
|
+
type EmployeePlacementUpdateInput = {
|
|
123
|
+
managerId?: string | null;
|
|
124
|
+
partnerId?: string | null;
|
|
125
|
+
departmentId?: string | null;
|
|
126
|
+
jurisdictionId?: string | null;
|
|
127
|
+
jobLevelId?: string | null;
|
|
128
|
+
employmentType?: string | null;
|
|
129
|
+
isExternal?: boolean;
|
|
130
|
+
timezone?: string | null;
|
|
131
|
+
};
|
|
114
132
|
type ProjectMembership = {
|
|
115
133
|
employeeId: string;
|
|
116
134
|
role: string | null;
|
|
@@ -226,6 +244,7 @@ type GenericRateCore = {
|
|
|
226
244
|
id: string;
|
|
227
245
|
title: string;
|
|
228
246
|
department: string;
|
|
247
|
+
jobLevelId: string | null;
|
|
229
248
|
currencyCode: string;
|
|
230
249
|
};
|
|
231
250
|
type GenericRateFinancials = {
|
|
@@ -249,7 +268,8 @@ type JobLevelCore = {
|
|
|
249
268
|
id: string;
|
|
250
269
|
name: string;
|
|
251
270
|
code: string | null;
|
|
252
|
-
|
|
271
|
+
/** Departments this level applies to. Empty = company-wide. */
|
|
272
|
+
departmentIds: string[];
|
|
253
273
|
sortOrder: number;
|
|
254
274
|
};
|
|
255
275
|
type JobLevelBucketMap = {
|
|
@@ -258,6 +278,7 @@ type JobLevelBucketMap = {
|
|
|
258
278
|
type SalaryBandCore = {
|
|
259
279
|
id: string;
|
|
260
280
|
jobLevelId: string;
|
|
281
|
+
departmentId: string | null;
|
|
261
282
|
jurisdictionId: string | null;
|
|
262
283
|
currencyCode: string;
|
|
263
284
|
};
|
|
@@ -346,6 +367,10 @@ type CalendarEventCore = {
|
|
|
346
367
|
location: string | null;
|
|
347
368
|
color: string | null;
|
|
348
369
|
isPublished: boolean;
|
|
370
|
+
/** Jurisdiction this event applies to (holidays); null for non-holiday events. */
|
|
371
|
+
jurisdictionId: string | null;
|
|
372
|
+
/** For holidays: national (country-level) vs region-specific. */
|
|
373
|
+
national: boolean;
|
|
349
374
|
};
|
|
350
375
|
type CalendarEventBucketMap = {
|
|
351
376
|
core: CalendarEventCore;
|
|
@@ -387,12 +412,13 @@ type ResourceScope<M> = {
|
|
|
387
412
|
update?: readonly (keyof M)[];
|
|
388
413
|
delete?: boolean;
|
|
389
414
|
};
|
|
390
|
-
/** A resource
|
|
391
|
-
type
|
|
415
|
+
/** A resource that may be read or updated, but never created/deleted (e.g. employees). */
|
|
416
|
+
type UpdateOnlyResourceScope<M> = {
|
|
392
417
|
read?: readonly (keyof M)[];
|
|
418
|
+
update?: readonly (keyof M)[];
|
|
393
419
|
};
|
|
394
420
|
type ScopeDeclaration = {
|
|
395
|
-
employees?:
|
|
421
|
+
employees?: UpdateOnlyResourceScope<EmployeeBucketMap>;
|
|
396
422
|
projects?: ResourceScope<ProjectBucketMap>;
|
|
397
423
|
clients?: ResourceScope<ClientBucketMap>;
|
|
398
424
|
partners?: ResourceScope<PartnerBucketMap>;
|
|
@@ -505,6 +531,10 @@ type WithTimesheetExpand<T, E extends readonly TimesheetExpandPath[], S extends
|
|
|
505
531
|
} : unknown) & ('project' extends E[number] ? {
|
|
506
532
|
project: ResolveProject<S> | null;
|
|
507
533
|
} : unknown);
|
|
534
|
+
type CalendarEventExpandPath = 'jurisdiction';
|
|
535
|
+
type WithCalendarEventExpand<T, E extends readonly CalendarEventExpandPath[], S extends ScopeDeclaration> = T & ('jurisdiction' extends E[number] ? {
|
|
536
|
+
jurisdiction: ResolveJurisdiction<S> | null;
|
|
537
|
+
} : unknown);
|
|
508
538
|
type LeaveCreateInput = {
|
|
509
539
|
employeeId: string;
|
|
510
540
|
leaveTypeId: string;
|
|
@@ -577,6 +607,7 @@ type CurrencyUpdateInput = Partial<Omit<CurrencyCreateInput, 'code'>>;
|
|
|
577
607
|
type GenericRateCreateInput = {
|
|
578
608
|
title: string;
|
|
579
609
|
department: string;
|
|
610
|
+
jobLevelId?: string | null;
|
|
580
611
|
costRate: number;
|
|
581
612
|
billableRate: number;
|
|
582
613
|
currencyCode?: string;
|
|
@@ -595,13 +626,15 @@ type JurisdictionUpdateInput = Partial<JurisdictionCreateInput>;
|
|
|
595
626
|
type JobLevelCreateInput = {
|
|
596
627
|
name: string;
|
|
597
628
|
code?: string | null;
|
|
598
|
-
/**
|
|
599
|
-
|
|
629
|
+
/** Departments this level applies to. Empty/omitted = company-wide rung. */
|
|
630
|
+
departmentIds?: string[];
|
|
600
631
|
sortOrder?: number;
|
|
601
632
|
};
|
|
602
633
|
type JobLevelUpdateInput = Partial<JobLevelCreateInput>;
|
|
603
634
|
type SalaryBandCreateInput = {
|
|
604
635
|
jobLevelId: string;
|
|
636
|
+
/** Null = applies to all departments. */
|
|
637
|
+
departmentId?: string | null;
|
|
605
638
|
/** Null = applies to all jurisdictions (org-wide band). */
|
|
606
639
|
jurisdictionId?: string | null;
|
|
607
640
|
currencyCode?: string;
|
|
@@ -748,6 +781,13 @@ declare class EmployeesAccessor<S extends ScopeDeclaration> {
|
|
|
748
781
|
getById<E extends readonly EmployeeExpandPath[] = never[]>(id: string, options?: {
|
|
749
782
|
expand?: E;
|
|
750
783
|
}): Promise<SingleResult<WithEmployeeExpand<ResolveEmployee<S>, E, S>>>;
|
|
784
|
+
/**
|
|
785
|
+
* Update an employee's placement (manager, partner, department, jurisdiction, job
|
|
786
|
+
* level, employment type, external flag, timezone). Requires `employees` update on the
|
|
787
|
+
* `placement` bucket. Identity/contact/sensitive fields are Google-owned and read-only;
|
|
788
|
+
* employees cannot be created or deleted via the SDK.
|
|
789
|
+
*/
|
|
790
|
+
update(id: string, data: IfUpdate<S['employees'], EmployeePlacementUpdateInput>): Promise<SingleResult<ResolveEmployee<S>>>;
|
|
751
791
|
}
|
|
752
792
|
|
|
753
793
|
type ProjectListParams = {
|
|
@@ -769,10 +809,10 @@ interface ProjectMember {
|
|
|
769
809
|
employeeId: string;
|
|
770
810
|
role: string | null;
|
|
771
811
|
}
|
|
772
|
-
|
|
812
|
+
type AddProjectMemberInput = {
|
|
773
813
|
employeeId: string;
|
|
774
814
|
role?: string | null;
|
|
775
|
-
}
|
|
815
|
+
};
|
|
776
816
|
declare class ProjectsAccessor<S extends ScopeDeclaration> {
|
|
777
817
|
private readonly transport;
|
|
778
818
|
constructor(transport: NucleusTransport);
|
|
@@ -788,7 +828,6 @@ declare class ProjectsAccessor<S extends ScopeDeclaration> {
|
|
|
788
828
|
update(id: string, data: IfUpdate<S['projects'], ProjectUpdateInput>): Promise<SingleResult<ResolveProject<S>>>;
|
|
789
829
|
/** Soft-delete a project. Requires `projects.delete` scope. */
|
|
790
830
|
delete(id: IfDelete<S['projects'], string>): Promise<SingleResult<null>>;
|
|
791
|
-
private membersBase;
|
|
792
831
|
/** List a project's team members. Requires `projects` read on the `team` bucket. */
|
|
793
832
|
listMembers(projectId: string): Promise<SingleResult<ProjectMember[]>>;
|
|
794
833
|
/** Add a team member. Requires `projects` update on the `team` bucket. */
|
|
@@ -912,6 +951,7 @@ declare class CurrenciesAccessor<S extends ScopeDeclaration> {
|
|
|
912
951
|
|
|
913
952
|
type GenericRateListParams = {
|
|
914
953
|
department?: string;
|
|
954
|
+
jobLevelId?: string;
|
|
915
955
|
page?: number;
|
|
916
956
|
pageSize?: number;
|
|
917
957
|
/** ISO-8601 — return only records changed (created/updated/deleted) at or after this time (incremental sync). */
|
|
@@ -974,6 +1014,7 @@ declare class JobLevelsAccessor<S extends ScopeDeclaration> {
|
|
|
974
1014
|
|
|
975
1015
|
type SalaryBandListParams = {
|
|
976
1016
|
jobLevelId?: string;
|
|
1017
|
+
departmentId?: string;
|
|
977
1018
|
jurisdictionId?: string;
|
|
978
1019
|
page?: number;
|
|
979
1020
|
pageSize?: number;
|
|
@@ -1127,12 +1168,18 @@ type CalendarEventListParams = {
|
|
|
1127
1168
|
pageSize?: number;
|
|
1128
1169
|
/** ISO-8601 — return only records changed (created/updated/deleted) at or after this time (incremental sync). */
|
|
1129
1170
|
updatedSince?: string;
|
|
1171
|
+
/** Hydrate related resources inline (e.g. the event's jurisdiction). */
|
|
1172
|
+
expand?: readonly CalendarEventExpandPath[];
|
|
1130
1173
|
};
|
|
1131
1174
|
declare class CalendarEventsAccessor<S extends ScopeDeclaration> {
|
|
1132
1175
|
private readonly transport;
|
|
1133
1176
|
constructor(transport: NucleusTransport);
|
|
1134
|
-
list(params?: CalendarEventListParams
|
|
1135
|
-
|
|
1177
|
+
list<E extends readonly CalendarEventExpandPath[] = never[]>(params?: CalendarEventListParams & {
|
|
1178
|
+
expand?: E;
|
|
1179
|
+
}): Promise<PaginatedResult<WithCalendarEventExpand<ResolveCalendarEvent<S>, E, S>>>;
|
|
1180
|
+
getById<E extends readonly CalendarEventExpandPath[] = never[]>(id: string, options?: {
|
|
1181
|
+
expand?: E;
|
|
1182
|
+
}): Promise<SingleResult<WithCalendarEventExpand<ResolveCalendarEvent<S>, E, S>>>;
|
|
1136
1183
|
/** Create a calendar event. Requires `calendarEvents.create` scope. */
|
|
1137
1184
|
create(data: IfCreate<S['calendarEvents'], CalendarEventCreateInput>): Promise<SingleResult<ResolveCalendarEvent<S>>>;
|
|
1138
1185
|
/** Update a calendar event. Requires `calendarEvents.update` scope. */
|
|
@@ -1266,7 +1313,6 @@ interface EmployeeCompensationInput {
|
|
|
1266
1313
|
declare class EmployeeCompensationAccessor {
|
|
1267
1314
|
private readonly transport;
|
|
1268
1315
|
constructor(transport: NucleusTransport);
|
|
1269
|
-
private base;
|
|
1270
1316
|
/** Full history, newest first. */
|
|
1271
1317
|
list(employeeId: string): Promise<SingleResult<EmployeeCompensationRecord[]>>;
|
|
1272
1318
|
/** The current (open) record, or null. */
|
|
@@ -1277,6 +1323,67 @@ declare class EmployeeCompensationAccessor {
|
|
|
1277
1323
|
delete(employeeId: string, id: string): Promise<SingleResult<null>>;
|
|
1278
1324
|
}
|
|
1279
1325
|
|
|
1326
|
+
/** Per-employee work-arrangement settings. */
|
|
1327
|
+
interface EmployeeProfile {
|
|
1328
|
+
id: string;
|
|
1329
|
+
employeeId: string;
|
|
1330
|
+
dailyHours: number;
|
|
1331
|
+
probationMonths: number | null;
|
|
1332
|
+
isOvertimeEnabled: boolean;
|
|
1333
|
+
}
|
|
1334
|
+
type EmployeeProfileInput = {
|
|
1335
|
+
dailyHours?: number;
|
|
1336
|
+
probationMonths?: number | null;
|
|
1337
|
+
isOvertimeEnabled?: boolean;
|
|
1338
|
+
};
|
|
1339
|
+
/**
|
|
1340
|
+
* EmployeeProfilesAccessor — an employee's work-arrangement profile (Iteration 4).
|
|
1341
|
+
* Gated server-side by the `employee-profiles` scope.
|
|
1342
|
+
*/
|
|
1343
|
+
declare class EmployeeProfilesAccessor {
|
|
1344
|
+
private readonly transport;
|
|
1345
|
+
constructor(transport: NucleusTransport);
|
|
1346
|
+
get(employeeId: string): Promise<SingleResult<EmployeeProfile | null>>;
|
|
1347
|
+
/** Create-or-update the profile. Requires `employee-profiles` update scope. */
|
|
1348
|
+
upsert(employeeId: string, data: EmployeeProfileInput): Promise<SingleResult<EmployeeProfile>>;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/** A performance review. `rating`/`feedback` are in the approval-gated `feedback` bucket. */
|
|
1352
|
+
interface EmployeeReview {
|
|
1353
|
+
id: string;
|
|
1354
|
+
employeeId: string;
|
|
1355
|
+
reviewType: string;
|
|
1356
|
+
dueDate: string | null;
|
|
1357
|
+
completedDate: string | null;
|
|
1358
|
+
status: string;
|
|
1359
|
+
rating: string | null;
|
|
1360
|
+
feedback: string | null;
|
|
1361
|
+
reviewerId: string | null;
|
|
1362
|
+
}
|
|
1363
|
+
type EmployeeReviewCreateInput = {
|
|
1364
|
+
reviewType: string;
|
|
1365
|
+
dueDate?: string | null;
|
|
1366
|
+
status?: string;
|
|
1367
|
+
rating?: string | null;
|
|
1368
|
+
feedback?: string | null;
|
|
1369
|
+
reviewerId?: string | null;
|
|
1370
|
+
};
|
|
1371
|
+
type EmployeeReviewUpdateInput = Partial<EmployeeReviewCreateInput> & {
|
|
1372
|
+
completedDate?: string | null;
|
|
1373
|
+
};
|
|
1374
|
+
/**
|
|
1375
|
+
* EmployeeReviewsAccessor — performance reviews (Iteration 4). Gated server-side by the
|
|
1376
|
+
* `employee-reviews` scope; the `feedback` bucket (rating + feedback) is approval-gated.
|
|
1377
|
+
*/
|
|
1378
|
+
declare class EmployeeReviewsAccessor {
|
|
1379
|
+
private readonly transport;
|
|
1380
|
+
constructor(transport: NucleusTransport);
|
|
1381
|
+
list(employeeId: string): Promise<SingleResult<EmployeeReview[]>>;
|
|
1382
|
+
create(employeeId: string, data: EmployeeReviewCreateInput): Promise<SingleResult<EmployeeReview>>;
|
|
1383
|
+
update(employeeId: string, id: string, data: EmployeeReviewUpdateInput): Promise<SingleResult<EmployeeReview>>;
|
|
1384
|
+
delete(employeeId: string, id: string): Promise<SingleResult<null>>;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1280
1387
|
/**
|
|
1281
1388
|
* AppsAccessor — wraps the self-service app info endpoint (§3.8, §6).
|
|
1282
1389
|
* Calls GET /api/v1/platform/apps/me with the app token.
|
|
@@ -1442,6 +1549,8 @@ declare class NucleusClient<const S extends ScopeDeclaration> {
|
|
|
1442
1549
|
readonly email: EmailAccessor;
|
|
1443
1550
|
/** Read/write an employee's compensation history (requires `employee-compensation` scope). */
|
|
1444
1551
|
readonly employeeCompensation: EmployeeCompensationAccessor;
|
|
1552
|
+
readonly employeeProfiles: EmployeeProfilesAccessor;
|
|
1553
|
+
readonly employeeReviews: EmployeeReviewsAccessor;
|
|
1445
1554
|
readonly apps: AppsAccessor;
|
|
1446
1555
|
readonly files: FilesAccessor;
|
|
1447
1556
|
readonly auth: AuthAccessor;
|