@typeb-digital/nucleus-sdk 0.1.0 → 0.2.0
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 +14 -0
- package/dist/cjs/index.cjs +291 -16
- package/dist/cjs/index.d.cts +290 -11
- package/dist/cjs/index.d.cts.map +1 -1
- package/dist/es/index.d.ts +290 -11
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +291 -16
- package/package.json +1 -1
package/dist/es/index.js
CHANGED
|
@@ -413,6 +413,30 @@ function transformJurisdiction(raw) {
|
|
|
413
413
|
if ('country' in r) out['country'] = str(r['country']);
|
|
414
414
|
return out;
|
|
415
415
|
}
|
|
416
|
+
function transformJobLevel(raw) {
|
|
417
|
+
if (!raw || typeof raw !== 'object') return {};
|
|
418
|
+
const r = raw;
|
|
419
|
+
const out = {};
|
|
420
|
+
if ('id' in r) out['id'] = r['id'];
|
|
421
|
+
if ('name' in r) out['name'] = str(r['name']);
|
|
422
|
+
if ('code' in r) out['code'] = str(r['code']);
|
|
423
|
+
if ('department_id' in r) out['departmentId'] = str(r['department_id']);
|
|
424
|
+
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
425
|
+
return out;
|
|
426
|
+
}
|
|
427
|
+
function transformSalaryBand(raw) {
|
|
428
|
+
if (!raw || typeof raw !== 'object') return {};
|
|
429
|
+
const r = raw;
|
|
430
|
+
const out = {};
|
|
431
|
+
if ('id' in r) out['id'] = r['id'];
|
|
432
|
+
if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
|
|
433
|
+
if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
|
|
434
|
+
if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
|
|
435
|
+
if ('min_salary' in r) out['minSalary'] = num(r['min_salary']);
|
|
436
|
+
if ('max_salary' in r) out['maxSalary'] = num(r['max_salary']);
|
|
437
|
+
if ('target_salary' in r) out['targetSalary'] = num(r['target_salary']);
|
|
438
|
+
return out;
|
|
439
|
+
}
|
|
416
440
|
function transformLeaveType(raw) {
|
|
417
441
|
if (!raw || typeof raw !== 'object') return {};
|
|
418
442
|
const r = raw;
|
|
@@ -564,6 +588,7 @@ class EmployeesAccessor {
|
|
|
564
588
|
if (params?.employmentStatus) query['employmentStatus'] = params.employmentStatus;
|
|
565
589
|
if (params?.page) query['page'] = params.page;
|
|
566
590
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
591
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
567
592
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
568
593
|
const result = await this.transport.getList('/api/v1/data/employees', query);
|
|
569
594
|
if ('error' in result) return result;
|
|
@@ -581,23 +606,16 @@ class EmployeesAccessor {
|
|
|
581
606
|
data: transformEmployee(result.data)
|
|
582
607
|
};
|
|
583
608
|
}
|
|
584
|
-
// No create: the platform exposes no POST route for employees.
|
|
585
|
-
/** Update an employee (managerId / timezone overrides). Requires `employees.update` scope. */ async update(id, data) {
|
|
586
|
-
const result = await this.transport.patch(`/api/v1/data/employees/${id}`, toSnakeBody(data));
|
|
587
|
-
if ('error' in result) return result;
|
|
588
|
-
return {
|
|
589
|
-
data: transformEmployee(result.data)
|
|
590
|
-
};
|
|
591
|
-
}
|
|
592
|
-
/** Soft-delete an employee. Requires `employees.delete` scope. */ async delete(id) {
|
|
593
|
-
const result = await this.transport.del(`/api/v1/data/employees/${id}`);
|
|
594
|
-
if ('error' in result) return result;
|
|
595
|
-
return {
|
|
596
|
-
data: null
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
609
|
}
|
|
600
610
|
|
|
611
|
+
function transformMember(raw) {
|
|
612
|
+
return {
|
|
613
|
+
id: raw['id'],
|
|
614
|
+
projectId: raw['project_id'],
|
|
615
|
+
employeeId: raw['employee_id'],
|
|
616
|
+
role: raw['role'] ?? null
|
|
617
|
+
};
|
|
618
|
+
}
|
|
601
619
|
class ProjectsAccessor {
|
|
602
620
|
constructor(transport){
|
|
603
621
|
this.transport = transport;
|
|
@@ -606,9 +624,11 @@ class ProjectsAccessor {
|
|
|
606
624
|
const query = {};
|
|
607
625
|
if (params?.search) query['search'] = params.search;
|
|
608
626
|
if (params?.status) query['status'] = params.status;
|
|
627
|
+
if (params?.stage) query['stage'] = params.stage;
|
|
609
628
|
if (params?.clientId) query['clientId'] = params.clientId;
|
|
610
629
|
if (params?.page) query['page'] = params.page;
|
|
611
630
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
631
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
612
632
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
613
633
|
const result = await this.transport.getList('/api/v1/data/projects', query);
|
|
614
634
|
if ('error' in result) return result;
|
|
@@ -647,6 +667,33 @@ class ProjectsAccessor {
|
|
|
647
667
|
data: null
|
|
648
668
|
};
|
|
649
669
|
}
|
|
670
|
+
// ─── Team membership (the projects `team` bucket) ──────────────────────────
|
|
671
|
+
// Membership is the project↔employee join. Reads need `projects` read on `team`;
|
|
672
|
+
// add/remove need `projects` update on `team` (re-adding restores a soft-deleted row).
|
|
673
|
+
membersBase(projectId) {
|
|
674
|
+
return `/api/v1/data/project-memberships/projects/${projectId}/members`;
|
|
675
|
+
}
|
|
676
|
+
/** List a project's team members. Requires `projects` read on the `team` bucket. */ async listMembers(projectId) {
|
|
677
|
+
const result = await this.transport.get(this.membersBase(projectId));
|
|
678
|
+
if ('error' in result) return result;
|
|
679
|
+
return {
|
|
680
|
+
data: (result.data ?? []).map((r)=>transformMember(r))
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
/** Add a team member. Requires `projects` update on the `team` bucket. */ async addMember(projectId, data) {
|
|
684
|
+
const result = await this.transport.post(this.membersBase(projectId), toSnakeBody(data));
|
|
685
|
+
if ('error' in result) return result;
|
|
686
|
+
return {
|
|
687
|
+
data: transformMember(result.data)
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
/** Remove a team member. Requires `projects` update on the `team` bucket. */ async removeMember(projectId, employeeId) {
|
|
691
|
+
const result = await this.transport.del(`${this.membersBase(projectId)}/${employeeId}`);
|
|
692
|
+
if ('error' in result) return result;
|
|
693
|
+
return {
|
|
694
|
+
data: null
|
|
695
|
+
};
|
|
696
|
+
}
|
|
650
697
|
}
|
|
651
698
|
|
|
652
699
|
class ClientsAccessor {
|
|
@@ -660,6 +707,7 @@ class ClientsAccessor {
|
|
|
660
707
|
if (params?.country) query['country'] = params.country;
|
|
661
708
|
if (params?.page) query['page'] = params.page;
|
|
662
709
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
710
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
663
711
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
664
712
|
const result = await this.transport.getList('/api/v1/data/clients', query);
|
|
665
713
|
if ('error' in result) return result;
|
|
@@ -709,6 +757,7 @@ class PartnersAccessor {
|
|
|
709
757
|
if (params?.search) query['search'] = params.search;
|
|
710
758
|
if (params?.page) query['page'] = params.page;
|
|
711
759
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
760
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
712
761
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
713
762
|
const result = await this.transport.getList('/api/v1/data/partners', query);
|
|
714
763
|
if ('error' in result) return result;
|
|
@@ -758,6 +807,7 @@ class DepartmentsAccessor {
|
|
|
758
807
|
if (params?.search) query['search'] = params.search;
|
|
759
808
|
if (params?.page) query['page'] = params.page;
|
|
760
809
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
810
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
761
811
|
const result = await this.transport.getList('/api/v1/data/departments', query);
|
|
762
812
|
if ('error' in result) return result;
|
|
763
813
|
return {
|
|
@@ -803,6 +853,7 @@ class ProjectTypesAccessor {
|
|
|
803
853
|
const query = {};
|
|
804
854
|
if (params?.page) query['page'] = params.page;
|
|
805
855
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
856
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
806
857
|
const result = await this.transport.getList('/api/v1/data/project-types', query);
|
|
807
858
|
if ('error' in result) return result;
|
|
808
859
|
return {
|
|
@@ -848,6 +899,7 @@ class CurrenciesAccessor {
|
|
|
848
899
|
const query = {};
|
|
849
900
|
if (params?.page) query['page'] = params.page;
|
|
850
901
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
902
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
851
903
|
const result = await this.transport.getList('/api/v1/data/currencies', query);
|
|
852
904
|
if ('error' in result) return result;
|
|
853
905
|
return {
|
|
@@ -897,6 +949,7 @@ class GenericRatesAccessor {
|
|
|
897
949
|
if (params?.department) query['department'] = params.department;
|
|
898
950
|
if (params?.page) query['page'] = params.page;
|
|
899
951
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
952
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
900
953
|
const result = await this.transport.getList('/api/v1/data/generic-rates', query);
|
|
901
954
|
if ('error' in result) return result;
|
|
902
955
|
return {
|
|
@@ -943,6 +996,7 @@ class JurisdictionsAccessor {
|
|
|
943
996
|
if (params?.search) query['search'] = params.search;
|
|
944
997
|
if (params?.page) query['page'] = params.page;
|
|
945
998
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
999
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
946
1000
|
const result = await this.transport.getList('/api/v1/data/jurisdictions', query);
|
|
947
1001
|
if ('error' in result) return result;
|
|
948
1002
|
return {
|
|
@@ -980,6 +1034,105 @@ class JurisdictionsAccessor {
|
|
|
980
1034
|
}
|
|
981
1035
|
}
|
|
982
1036
|
|
|
1037
|
+
/** JobLevelsAccessor — the company's career-ladder rungs (WS7). */ class JobLevelsAccessor {
|
|
1038
|
+
constructor(transport){
|
|
1039
|
+
this.transport = transport;
|
|
1040
|
+
}
|
|
1041
|
+
async list(params) {
|
|
1042
|
+
const query = {};
|
|
1043
|
+
if (params?.search) query['search'] = params.search;
|
|
1044
|
+
if (params?.departmentId) query['departmentId'] = params.departmentId;
|
|
1045
|
+
if (params?.page) query['page'] = params.page;
|
|
1046
|
+
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1047
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1048
|
+
const result = await this.transport.getList('/api/v1/data/job-levels', query);
|
|
1049
|
+
if ('error' in result) return result;
|
|
1050
|
+
return {
|
|
1051
|
+
data: result.data.map((r)=>transformJobLevel(r)),
|
|
1052
|
+
meta: result.meta
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
async getById(id) {
|
|
1056
|
+
const result = await this.transport.get(`/api/v1/data/job-levels/${id}`);
|
|
1057
|
+
if ('error' in result) return result;
|
|
1058
|
+
return {
|
|
1059
|
+
data: transformJobLevel(result.data)
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
/** Create a job level. Requires `job-levels.create` scope. */ async create(data) {
|
|
1063
|
+
const result = await this.transport.post('/api/v1/data/job-levels', toSnakeBody(data));
|
|
1064
|
+
if ('error' in result) return result;
|
|
1065
|
+
return {
|
|
1066
|
+
data: transformJobLevel(result.data)
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
/** Update a job level. Requires `job-levels.update` scope. */ async update(id, data) {
|
|
1070
|
+
const result = await this.transport.put(`/api/v1/data/job-levels/${id}`, toSnakeBody(data));
|
|
1071
|
+
if ('error' in result) return result;
|
|
1072
|
+
return {
|
|
1073
|
+
data: transformJobLevel(result.data)
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
/** Soft-delete a job level. Requires `job-levels.delete` scope. */ async delete(id) {
|
|
1077
|
+
const result = await this.transport.del(`/api/v1/data/job-levels/${id}`);
|
|
1078
|
+
if ('error' in result) return result;
|
|
1079
|
+
return {
|
|
1080
|
+
data: null
|
|
1081
|
+
};
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* SalaryBandsAccessor — per-jurisdiction pay ranges for a job level (WS7).
|
|
1087
|
+
* The `financials` bucket (min/max/target) is flagged sensitive server-side.
|
|
1088
|
+
*/ class SalaryBandsAccessor {
|
|
1089
|
+
constructor(transport){
|
|
1090
|
+
this.transport = transport;
|
|
1091
|
+
}
|
|
1092
|
+
async list(params) {
|
|
1093
|
+
const query = {};
|
|
1094
|
+
if (params?.jobLevelId) query['jobLevelId'] = params.jobLevelId;
|
|
1095
|
+
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1096
|
+
if (params?.page) query['page'] = params.page;
|
|
1097
|
+
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1098
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1099
|
+
const result = await this.transport.getList('/api/v1/data/salary-bands', query);
|
|
1100
|
+
if ('error' in result) return result;
|
|
1101
|
+
return {
|
|
1102
|
+
data: result.data.map((r)=>transformSalaryBand(r)),
|
|
1103
|
+
meta: result.meta
|
|
1104
|
+
};
|
|
1105
|
+
}
|
|
1106
|
+
async getById(id) {
|
|
1107
|
+
const result = await this.transport.get(`/api/v1/data/salary-bands/${id}`);
|
|
1108
|
+
if ('error' in result) return result;
|
|
1109
|
+
return {
|
|
1110
|
+
data: transformSalaryBand(result.data)
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
/** Create a salary band. Requires `salary-bands.create` scope. */ async create(data) {
|
|
1114
|
+
const result = await this.transport.post('/api/v1/data/salary-bands', toSnakeBody(data));
|
|
1115
|
+
if ('error' in result) return result;
|
|
1116
|
+
return {
|
|
1117
|
+
data: transformSalaryBand(result.data)
|
|
1118
|
+
};
|
|
1119
|
+
}
|
|
1120
|
+
/** Update a salary band. Requires `salary-bands.update` scope. */ async update(id, data) {
|
|
1121
|
+
const result = await this.transport.put(`/api/v1/data/salary-bands/${id}`, toSnakeBody(data));
|
|
1122
|
+
if ('error' in result) return result;
|
|
1123
|
+
return {
|
|
1124
|
+
data: transformSalaryBand(result.data)
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
/** Soft-delete a salary band. Requires `salary-bands.delete` scope. */ async delete(id) {
|
|
1128
|
+
const result = await this.transport.del(`/api/v1/data/salary-bands/${id}`);
|
|
1129
|
+
if ('error' in result) return result;
|
|
1130
|
+
return {
|
|
1131
|
+
data: null
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
983
1136
|
class LeaveTypesAccessor {
|
|
984
1137
|
constructor(transport){
|
|
985
1138
|
this.transport = transport;
|
|
@@ -989,6 +1142,7 @@ class LeaveTypesAccessor {
|
|
|
989
1142
|
if (params?.search) query['search'] = params.search;
|
|
990
1143
|
if (params?.page) query['page'] = params.page;
|
|
991
1144
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1145
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
992
1146
|
const result = await this.transport.getList('/api/v1/data/leave-types', query);
|
|
993
1147
|
if ('error' in result) return result;
|
|
994
1148
|
return {
|
|
@@ -1037,6 +1191,7 @@ class LeavesAccessor {
|
|
|
1037
1191
|
if (params?.status) query['status'] = params.status;
|
|
1038
1192
|
if (params?.page) query['page'] = params.page;
|
|
1039
1193
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1194
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1040
1195
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1041
1196
|
const result = await this.transport.getList('/api/v1/data/leaves', query);
|
|
1042
1197
|
if ('error' in result) return result;
|
|
@@ -1088,6 +1243,7 @@ class LeaveBalancesAccessor {
|
|
|
1088
1243
|
if (params?.year) query['year'] = params.year;
|
|
1089
1244
|
if (params?.page) query['page'] = params.page;
|
|
1090
1245
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1246
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1091
1247
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1092
1248
|
const result = await this.transport.getList('/api/v1/data/leave-balances', query);
|
|
1093
1249
|
if ('error' in result) return result;
|
|
@@ -1138,6 +1294,7 @@ class PoliciesAccessor {
|
|
|
1138
1294
|
if (params?.category) query['category'] = params.category;
|
|
1139
1295
|
if (params?.page) query['page'] = params.page;
|
|
1140
1296
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1297
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1141
1298
|
const result = await this.transport.getList('/api/v1/data/policies', query);
|
|
1142
1299
|
if ('error' in result) return result;
|
|
1143
1300
|
return {
|
|
@@ -1185,6 +1342,7 @@ class PolicyAcknowledgementsAccessor {
|
|
|
1185
1342
|
if (params?.employeeId) query['employeeId'] = params.employeeId;
|
|
1186
1343
|
if (params?.page) query['page'] = params.page;
|
|
1187
1344
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1345
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1188
1346
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1189
1347
|
const result = await this.transport.getList('/api/v1/data/policy-acknowledgements', query);
|
|
1190
1348
|
if ('error' in result) return result;
|
|
@@ -1233,8 +1391,10 @@ class CalendarEventsAccessor {
|
|
|
1233
1391
|
const query = {};
|
|
1234
1392
|
if (params?.search) query['search'] = params.search;
|
|
1235
1393
|
if (params?.type) query['type'] = params.type;
|
|
1394
|
+
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1236
1395
|
if (params?.page) query['page'] = params.page;
|
|
1237
1396
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1397
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1238
1398
|
const result = await this.transport.getList('/api/v1/data/calendar-events', query);
|
|
1239
1399
|
if ('error' in result) return result;
|
|
1240
1400
|
return {
|
|
@@ -1282,6 +1442,7 @@ class TimesheetsAccessor {
|
|
|
1282
1442
|
if (params?.projectId) query['projectId'] = params.projectId;
|
|
1283
1443
|
if (params?.page) query['page'] = params.page;
|
|
1284
1444
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1445
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1285
1446
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1286
1447
|
const result = await this.transport.getList('/api/v1/data/timesheets', query);
|
|
1287
1448
|
if ('error' in result) return result;
|
|
@@ -1306,6 +1467,23 @@ class TimesheetsAccessor {
|
|
|
1306
1467
|
data: transformTimesheet(result.data)
|
|
1307
1468
|
};
|
|
1308
1469
|
}
|
|
1470
|
+
/**
|
|
1471
|
+
* Bulk-create timesheet entries (partial accept). Requires `timesheets.create` scope.
|
|
1472
|
+
* Returns `{ created, rejected }` — every valid item is inserted; invalid items come back
|
|
1473
|
+
* with their input index + reason.
|
|
1474
|
+
*/ async bulkCreate(items) {
|
|
1475
|
+
const result = await this.transport.post('/api/v1/data/timesheets/bulk', {
|
|
1476
|
+
items: items.map((i)=>toSnakeBody(i))
|
|
1477
|
+
});
|
|
1478
|
+
if ('error' in result) return result;
|
|
1479
|
+
const data = result.data;
|
|
1480
|
+
return {
|
|
1481
|
+
data: {
|
|
1482
|
+
created: data.created.map((r)=>transformTimesheet(r)),
|
|
1483
|
+
rejected: data.rejected
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
}
|
|
1309
1487
|
/** Update a timesheet entry. Requires `timesheets.update` scope. */ async update(id, data) {
|
|
1310
1488
|
const result = await this.transport.put(`/api/v1/data/timesheets/${id}`, toSnakeBody(data));
|
|
1311
1489
|
if ('error' in result) return result;
|
|
@@ -1322,6 +1500,98 @@ class TimesheetsAccessor {
|
|
|
1322
1500
|
}
|
|
1323
1501
|
}
|
|
1324
1502
|
|
|
1503
|
+
/**
|
|
1504
|
+
* CalendarAccessor — read workspace users' Google Calendar events (WS3).
|
|
1505
|
+
* Requires the app's `calendar:read` scope. Not part of the bucket/CRUD scope system.
|
|
1506
|
+
*/ class CalendarAccessor {
|
|
1507
|
+
constructor(transport){
|
|
1508
|
+
this.transport = transport;
|
|
1509
|
+
}
|
|
1510
|
+
async listEvents(params) {
|
|
1511
|
+
const result = await this.transport.get('/api/v1/data/calendar/events', {
|
|
1512
|
+
employeeId: params.employeeId,
|
|
1513
|
+
timeMin: params.timeMin,
|
|
1514
|
+
timeMax: params.timeMax,
|
|
1515
|
+
q: params.q
|
|
1516
|
+
});
|
|
1517
|
+
if ('error' in result) return result;
|
|
1518
|
+
return {
|
|
1519
|
+
data: result.data
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
/**
|
|
1525
|
+
* EmailAccessor — send Nucleus-mediated email (WS5). Requires the app's `email:send` scope.
|
|
1526
|
+
* In test mode the message is marked `[SANDBOX]` and external recipients are suppressed.
|
|
1527
|
+
*/ class EmailAccessor {
|
|
1528
|
+
constructor(transport){
|
|
1529
|
+
this.transport = transport;
|
|
1530
|
+
}
|
|
1531
|
+
async send(input) {
|
|
1532
|
+
const result = await this.transport.post('/api/v1/data/comms/send', input);
|
|
1533
|
+
if ('error' in result) return result;
|
|
1534
|
+
return {
|
|
1535
|
+
data: result.data
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
function transform(raw) {
|
|
1541
|
+
return {
|
|
1542
|
+
id: raw['id'],
|
|
1543
|
+
employeeId: raw['employee_id'],
|
|
1544
|
+
hourlyCostRate: raw['hourly_cost_rate'] ?? null,
|
|
1545
|
+
monthlyCostRate: raw['monthly_cost_rate'] ?? null,
|
|
1546
|
+
hourlyBillableRate: raw['hourly_billable_rate'] ?? null,
|
|
1547
|
+
monthlyBillableRate: raw['monthly_billable_rate'] ?? null,
|
|
1548
|
+
salary: raw['salary'] ?? null,
|
|
1549
|
+
currencyCode: raw['currency_code'],
|
|
1550
|
+
effectiveFrom: raw['effective_from'],
|
|
1551
|
+
effectiveTo: raw['effective_to'] ?? null
|
|
1552
|
+
};
|
|
1553
|
+
}
|
|
1554
|
+
/**
|
|
1555
|
+
* EmployeeCompensationAccessor — read/write an employee's effective-dated compensation (WS6).
|
|
1556
|
+
* Gated server-side by the `employee-compensation` scope (buckets: `core`, `rates`, `salary`).
|
|
1557
|
+
* `create` closes the prior open record and opens a new one (Nucleus = single comp authority).
|
|
1558
|
+
*/ class EmployeeCompensationAccessor {
|
|
1559
|
+
constructor(transport){
|
|
1560
|
+
this.transport = transport;
|
|
1561
|
+
}
|
|
1562
|
+
base(employeeId) {
|
|
1563
|
+
return `/api/v1/data/employee-compensation/employees/${employeeId}/compensation`;
|
|
1564
|
+
}
|
|
1565
|
+
/** Full history, newest first. */ async list(employeeId) {
|
|
1566
|
+
const result = await this.transport.get(this.base(employeeId));
|
|
1567
|
+
if ('error' in result) return result;
|
|
1568
|
+
return {
|
|
1569
|
+
data: (result.data ?? []).map((r)=>transform(r))
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
/** The current (open) record, or null. */ async current(employeeId) {
|
|
1573
|
+
const result = await this.transport.get(`${this.base(employeeId)}/current`);
|
|
1574
|
+
if ('error' in result) return result;
|
|
1575
|
+
return {
|
|
1576
|
+
data: result.data ? transform(result.data) : null
|
|
1577
|
+
};
|
|
1578
|
+
}
|
|
1579
|
+
/** Add a new effective-dated record (closes the prior open one). */ async create(employeeId, data) {
|
|
1580
|
+
const result = await this.transport.post(this.base(employeeId), toSnakeBody(data));
|
|
1581
|
+
if ('error' in result) return result;
|
|
1582
|
+
return {
|
|
1583
|
+
data: transform(result.data)
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
/** Soft-delete a compensation record. */ async delete(employeeId, id) {
|
|
1587
|
+
const result = await this.transport.del(`${this.base(employeeId)}/${id}`);
|
|
1588
|
+
if ('error' in result) return result;
|
|
1589
|
+
return {
|
|
1590
|
+
data: null
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1325
1595
|
/**
|
|
1326
1596
|
* AppsAccessor — wraps the self-service app info endpoint (§3.8, §6).
|
|
1327
1597
|
* Calls GET /api/v1/platform/apps/me with the app token.
|
|
@@ -1476,6 +1746,8 @@ class AuthAccessor {
|
|
|
1476
1746
|
this.currencies = new CurrenciesAccessor(transport);
|
|
1477
1747
|
this.genericRates = new GenericRatesAccessor(transport);
|
|
1478
1748
|
this.jurisdictions = new JurisdictionsAccessor(transport);
|
|
1749
|
+
this.jobLevels = new JobLevelsAccessor(transport);
|
|
1750
|
+
this.salaryBands = new SalaryBandsAccessor(transport);
|
|
1479
1751
|
this.leaveTypes = new LeaveTypesAccessor(transport);
|
|
1480
1752
|
this.leaves = new LeavesAccessor(transport);
|
|
1481
1753
|
this.leaveBalances = new LeaveBalancesAccessor(transport);
|
|
@@ -1483,6 +1755,9 @@ class AuthAccessor {
|
|
|
1483
1755
|
this.policyAcknowledgements = new PolicyAcknowledgementsAccessor(transport);
|
|
1484
1756
|
this.calendarEvents = new CalendarEventsAccessor(transport);
|
|
1485
1757
|
this.timesheets = new TimesheetsAccessor(transport);
|
|
1758
|
+
this.calendar = new CalendarAccessor(transport);
|
|
1759
|
+
this.email = new EmailAccessor(transport);
|
|
1760
|
+
this.employeeCompensation = new EmployeeCompensationAccessor(transport);
|
|
1486
1761
|
this.apps = new AppsAccessor(transport);
|
|
1487
1762
|
this.files = new FilesAccessor(transport);
|
|
1488
1763
|
this.auth = new AuthAccessor(config.baseUrl);
|
|
@@ -1492,7 +1767,7 @@ class AuthAccessor {
|
|
|
1492
1767
|
/**
|
|
1493
1768
|
* Nucleus SDK — Type System
|
|
1494
1769
|
*
|
|
1495
|
-
* Bucket types are transcribed from docs/
|
|
1770
|
+
* Bucket types are transcribed from docs/ARCHITECTURE.md §7 (Bucket Definitions).
|
|
1496
1771
|
* Each bucket type contains only that bucket's fields.
|
|
1497
1772
|
* The scope-to-type inference intersects selected bucket types at compile time.
|
|
1498
1773
|
*/ // ─── Utility types ────────────────────────────────────────────────────────────
|