@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/dist/es/index.js CHANGED
@@ -397,6 +397,7 @@ function transformGenericRate(raw) {
397
397
  if ('id' in r) out['id'] = r['id'];
398
398
  if ('title' in r) out['title'] = str(r['title']);
399
399
  if ('department' in r) out['department'] = str(r['department']);
400
+ if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
400
401
  if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
401
402
  if ('cost_rate' in r) out['costRate'] = num(r['cost_rate']);
402
403
  if ('billable_rate' in r) out['billableRate'] = num(r['billable_rate']);
@@ -419,7 +420,10 @@ function transformJobLevel(raw) {
419
420
  if ('id' in r) out['id'] = r['id'];
420
421
  if ('name' in r) out['name'] = str(r['name']);
421
422
  if ('code' in r) out['code'] = str(r['code']);
422
- if ('department_id' in r) out['departmentId'] = str(r['department_id']);
423
+ // The API returns the join rows under `departments`; flatten to a string[] of ids.
424
+ if ('departments' in r && Array.isArray(r['departments'])) {
425
+ out['departmentIds'] = r['departments'].map((d)=>d?.['department_id']).filter((v)=>typeof v === 'string');
426
+ }
423
427
  if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
424
428
  return out;
425
429
  }
@@ -429,6 +433,7 @@ function transformSalaryBand(raw) {
429
433
  const out = {};
430
434
  if ('id' in r) out['id'] = r['id'];
431
435
  if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
436
+ if ('department_id' in r) out['departmentId'] = str(r['department_id']);
432
437
  if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
433
438
  if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
434
439
  if ('min_salary' in r) out['minSalary'] = num(r['min_salary']);
@@ -545,6 +550,12 @@ function transformCalendarEvent(raw) {
545
550
  if ('location' in r) out['location'] = str(r['location']);
546
551
  if ('color' in r) out['color'] = str(r['color']);
547
552
  if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
553
+ if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
554
+ if ('national' in r) out['national'] = bool(r['national']);
555
+ // Expand: jurisdiction (recursively transformed)
556
+ if ('jurisdiction' in r) {
557
+ out['jurisdiction'] = r['jurisdiction'] ? transformJurisdiction(r['jurisdiction']) : null;
558
+ }
548
559
  return out;
549
560
  }
550
561
  function transformTimesheet(raw) {
@@ -605,6 +616,18 @@ class EmployeesAccessor {
605
616
  data: transformEmployee(result.data)
606
617
  };
607
618
  }
619
+ /**
620
+ * Update an employee's placement (manager, partner, department, jurisdiction, job
621
+ * level, employment type, external flag, timezone). Requires `employees` update on the
622
+ * `placement` bucket. Identity/contact/sensitive fields are Google-owned and read-only;
623
+ * employees cannot be created or deleted via the SDK.
624
+ */ async update(id, data) {
625
+ const result = await this.transport.patch(`/api/v1/data/employees/${id}`, toSnakeBody(data));
626
+ if ('error' in result) return result;
627
+ return {
628
+ data: transformEmployee(result.data)
629
+ };
630
+ }
608
631
  }
609
632
 
610
633
  function transformMember(raw) {
@@ -669,25 +692,22 @@ class ProjectsAccessor {
669
692
  // ─── Team membership (the projects `team` bucket) ──────────────────────────
670
693
  // Membership is the project↔employee join. Reads need `projects` read on `team`;
671
694
  // add/remove need `projects` update on `team` (re-adding restores a soft-deleted row).
672
- membersBase(projectId) {
673
- return `/api/v1/data/project-memberships/projects/${projectId}/members`;
674
- }
675
695
  /** List a project's team members. Requires `projects` read on the `team` bucket. */ async listMembers(projectId) {
676
- const result = await this.transport.get(this.membersBase(projectId));
696
+ const result = await this.transport.get(`/api/v1/data/project-memberships/projects/${projectId}/members`);
677
697
  if ('error' in result) return result;
678
698
  return {
679
699
  data: (result.data ?? []).map((r)=>transformMember(r))
680
700
  };
681
701
  }
682
702
  /** Add a team member. Requires `projects` update on the `team` bucket. */ async addMember(projectId, data) {
683
- const result = await this.transport.post(this.membersBase(projectId), toSnakeBody(data));
703
+ const result = await this.transport.post(`/api/v1/data/project-memberships/projects/${projectId}/members`, toSnakeBody(data));
684
704
  if ('error' in result) return result;
685
705
  return {
686
706
  data: transformMember(result.data)
687
707
  };
688
708
  }
689
709
  /** Remove a team member. Requires `projects` update on the `team` bucket. */ async removeMember(projectId, employeeId) {
690
- const result = await this.transport.del(`${this.membersBase(projectId)}/${employeeId}`);
710
+ const result = await this.transport.del(`/api/v1/data/project-memberships/projects/${projectId}/members/${employeeId}`);
691
711
  if ('error' in result) return result;
692
712
  return {
693
713
  data: null
@@ -1091,6 +1111,7 @@ class JurisdictionsAccessor {
1091
1111
  async list(params) {
1092
1112
  const query = {};
1093
1113
  if (params?.jobLevelId) query['jobLevelId'] = params.jobLevelId;
1114
+ if (params?.departmentId) query['departmentId'] = params.departmentId;
1094
1115
  if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
1095
1116
  if (params?.page) query['page'] = params.page;
1096
1117
  if (params?.pageSize) query['pageSize'] = params.pageSize;
@@ -1394,6 +1415,7 @@ class CalendarEventsAccessor {
1394
1415
  if (params?.page) query['page'] = params.page;
1395
1416
  if (params?.pageSize) query['pageSize'] = params.pageSize;
1396
1417
  if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
1418
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1397
1419
  const result = await this.transport.getList('/api/v1/data/calendar-events', query);
1398
1420
  if ('error' in result) return result;
1399
1421
  return {
@@ -1401,8 +1423,10 @@ class CalendarEventsAccessor {
1401
1423
  meta: result.meta
1402
1424
  };
1403
1425
  }
1404
- async getById(id) {
1405
- const result = await this.transport.get(`/api/v1/data/calendar-events/${id}`);
1426
+ async getById(id, options) {
1427
+ const query = {};
1428
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1429
+ const result = await this.transport.get(`/api/v1/data/calendar-events/${id}`, query);
1406
1430
  if ('error' in result) return result;
1407
1431
  return {
1408
1432
  data: transformCalendarEvent(result.data)
@@ -1536,7 +1560,7 @@ class TimesheetsAccessor {
1536
1560
  }
1537
1561
  }
1538
1562
 
1539
- function transform(raw) {
1563
+ function transform$2(raw) {
1540
1564
  return {
1541
1565
  id: raw['id'],
1542
1566
  employeeId: raw['employee_id'],
@@ -1558,32 +1582,111 @@ function transform(raw) {
1558
1582
  constructor(transport){
1559
1583
  this.transport = transport;
1560
1584
  }
1561
- base(employeeId) {
1562
- return `/api/v1/data/employee-compensation/employees/${employeeId}/compensation`;
1563
- }
1564
1585
  /** Full history, newest first. */ async list(employeeId) {
1565
- const result = await this.transport.get(this.base(employeeId));
1586
+ const result = await this.transport.get(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation`);
1566
1587
  if ('error' in result) return result;
1567
1588
  return {
1568
- data: (result.data ?? []).map((r)=>transform(r))
1589
+ data: (result.data ?? []).map((r)=>transform$2(r))
1569
1590
  };
1570
1591
  }
1571
1592
  /** The current (open) record, or null. */ async current(employeeId) {
1572
- const result = await this.transport.get(`${this.base(employeeId)}/current`);
1593
+ const result = await this.transport.get(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation/current`);
1573
1594
  if ('error' in result) return result;
1574
1595
  return {
1575
- data: result.data ? transform(result.data) : null
1596
+ data: result.data ? transform$2(result.data) : null
1576
1597
  };
1577
1598
  }
1578
1599
  /** Add a new effective-dated record (closes the prior open one). */ async create(employeeId, data) {
1579
- const result = await this.transport.post(this.base(employeeId), toSnakeBody(data));
1600
+ const result = await this.transport.post(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation`, toSnakeBody(data));
1580
1601
  if ('error' in result) return result;
1581
1602
  return {
1582
- data: transform(result.data)
1603
+ data: transform$2(result.data)
1583
1604
  };
1584
1605
  }
1585
1606
  /** Soft-delete a compensation record. */ async delete(employeeId, id) {
1586
- const result = await this.transport.del(`${this.base(employeeId)}/${id}`);
1607
+ const result = await this.transport.del(`/api/v1/data/employee-compensation/employees/${employeeId}/compensation/${id}`);
1608
+ if ('error' in result) return result;
1609
+ return {
1610
+ data: null
1611
+ };
1612
+ }
1613
+ }
1614
+
1615
+ function transform$1(raw) {
1616
+ return {
1617
+ id: raw['id'],
1618
+ employeeId: raw['employee_id'],
1619
+ dailyHours: raw['daily_hours'] ?? 8,
1620
+ probationMonths: raw['probation_months'] ?? null,
1621
+ isOvertimeEnabled: raw['is_overtime_enabled'] ?? false
1622
+ };
1623
+ }
1624
+ /**
1625
+ * EmployeeProfilesAccessor — an employee's work-arrangement profile (Iteration 4).
1626
+ * Gated server-side by the `employee-profiles` scope.
1627
+ */ class EmployeeProfilesAccessor {
1628
+ constructor(transport){
1629
+ this.transport = transport;
1630
+ }
1631
+ async get(employeeId) {
1632
+ const result = await this.transport.get(`/api/v1/data/employee-profiles/employees/${employeeId}/profile`);
1633
+ if ('error' in result) return result;
1634
+ return {
1635
+ data: result.data ? transform$1(result.data) : null
1636
+ };
1637
+ }
1638
+ /** Create-or-update the profile. Requires `employee-profiles` update scope. */ async upsert(employeeId, data) {
1639
+ const result = await this.transport.put(`/api/v1/data/employee-profiles/employees/${employeeId}/profile`, toSnakeBody(data));
1640
+ if ('error' in result) return result;
1641
+ return {
1642
+ data: transform$1(result.data)
1643
+ };
1644
+ }
1645
+ }
1646
+
1647
+ function transform(raw) {
1648
+ return {
1649
+ id: raw['id'],
1650
+ employeeId: raw['employee_id'],
1651
+ reviewType: raw['review_type'],
1652
+ dueDate: raw['due_date'] ?? null,
1653
+ completedDate: raw['completed_date'] ?? null,
1654
+ status: raw['status'],
1655
+ rating: raw['rating'] ?? null,
1656
+ feedback: raw['feedback'] ?? null,
1657
+ reviewerId: raw['reviewer_id'] ?? null
1658
+ };
1659
+ }
1660
+ /**
1661
+ * EmployeeReviewsAccessor — performance reviews (Iteration 4). Gated server-side by the
1662
+ * `employee-reviews` scope; the `feedback` bucket (rating + feedback) is approval-gated.
1663
+ */ class EmployeeReviewsAccessor {
1664
+ constructor(transport){
1665
+ this.transport = transport;
1666
+ }
1667
+ async list(employeeId) {
1668
+ const result = await this.transport.get(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews`);
1669
+ if ('error' in result) return result;
1670
+ return {
1671
+ data: (result.data ?? []).map((r)=>transform(r))
1672
+ };
1673
+ }
1674
+ async create(employeeId, data) {
1675
+ const result = await this.transport.post(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews`, toSnakeBody(data));
1676
+ if ('error' in result) return result;
1677
+ return {
1678
+ data: transform(result.data)
1679
+ };
1680
+ }
1681
+ async update(employeeId, id, data) {
1682
+ const result = await this.transport.patch(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews/${id}`, toSnakeBody(data));
1683
+ if ('error' in result) return result;
1684
+ return {
1685
+ data: transform(result.data)
1686
+ };
1687
+ }
1688
+ async delete(employeeId, id) {
1689
+ const result = await this.transport.del(`/api/v1/data/employee-reviews/employees/${employeeId}/reviews/${id}`);
1587
1690
  if ('error' in result) return result;
1588
1691
  return {
1589
1692
  data: null
@@ -1757,6 +1860,8 @@ class AuthAccessor {
1757
1860
  this.calendar = new CalendarAccessor(transport);
1758
1861
  this.email = new EmailAccessor(transport);
1759
1862
  this.employeeCompensation = new EmployeeCompensationAccessor(transport);
1863
+ this.employeeProfiles = new EmployeeProfilesAccessor(transport);
1864
+ this.employeeReviews = new EmployeeReviewsAccessor(transport);
1760
1865
  this.apps = new AppsAccessor(transport);
1761
1866
  this.files = new FilesAccessor(transport);
1762
1867
  this.auth = new AuthAccessor(config.baseUrl);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@typeb-digital/nucleus-sdk",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Server-side TypeScript SDK for the Nucleus data platform",
5
5
  "type": "module",
6
6
  "engines": {