@typeb-digital/nucleus-sdk 0.1.1 → 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/dist/cjs/index.cjs +291 -1
- package/dist/cjs/index.d.cts +285 -2
- package/dist/cjs/index.d.cts.map +1 -1
- package/dist/es/index.d.ts +285 -2
- package/dist/es/index.d.ts.map +1 -1
- package/dist/es/index.js +291 -1
- 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;
|
|
@@ -583,6 +608,14 @@ class EmployeesAccessor {
|
|
|
583
608
|
}
|
|
584
609
|
}
|
|
585
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
|
+
}
|
|
586
619
|
class ProjectsAccessor {
|
|
587
620
|
constructor(transport){
|
|
588
621
|
this.transport = transport;
|
|
@@ -591,9 +624,11 @@ class ProjectsAccessor {
|
|
|
591
624
|
const query = {};
|
|
592
625
|
if (params?.search) query['search'] = params.search;
|
|
593
626
|
if (params?.status) query['status'] = params.status;
|
|
627
|
+
if (params?.stage) query['stage'] = params.stage;
|
|
594
628
|
if (params?.clientId) query['clientId'] = params.clientId;
|
|
595
629
|
if (params?.page) query['page'] = params.page;
|
|
596
630
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
631
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
597
632
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
598
633
|
const result = await this.transport.getList('/api/v1/data/projects', query);
|
|
599
634
|
if ('error' in result) return result;
|
|
@@ -632,6 +667,33 @@ class ProjectsAccessor {
|
|
|
632
667
|
data: null
|
|
633
668
|
};
|
|
634
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
|
+
}
|
|
635
697
|
}
|
|
636
698
|
|
|
637
699
|
class ClientsAccessor {
|
|
@@ -645,6 +707,7 @@ class ClientsAccessor {
|
|
|
645
707
|
if (params?.country) query['country'] = params.country;
|
|
646
708
|
if (params?.page) query['page'] = params.page;
|
|
647
709
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
710
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
648
711
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
649
712
|
const result = await this.transport.getList('/api/v1/data/clients', query);
|
|
650
713
|
if ('error' in result) return result;
|
|
@@ -694,6 +757,7 @@ class PartnersAccessor {
|
|
|
694
757
|
if (params?.search) query['search'] = params.search;
|
|
695
758
|
if (params?.page) query['page'] = params.page;
|
|
696
759
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
760
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
697
761
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
698
762
|
const result = await this.transport.getList('/api/v1/data/partners', query);
|
|
699
763
|
if ('error' in result) return result;
|
|
@@ -743,6 +807,7 @@ class DepartmentsAccessor {
|
|
|
743
807
|
if (params?.search) query['search'] = params.search;
|
|
744
808
|
if (params?.page) query['page'] = params.page;
|
|
745
809
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
810
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
746
811
|
const result = await this.transport.getList('/api/v1/data/departments', query);
|
|
747
812
|
if ('error' in result) return result;
|
|
748
813
|
return {
|
|
@@ -788,6 +853,7 @@ class ProjectTypesAccessor {
|
|
|
788
853
|
const query = {};
|
|
789
854
|
if (params?.page) query['page'] = params.page;
|
|
790
855
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
856
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
791
857
|
const result = await this.transport.getList('/api/v1/data/project-types', query);
|
|
792
858
|
if ('error' in result) return result;
|
|
793
859
|
return {
|
|
@@ -833,6 +899,7 @@ class CurrenciesAccessor {
|
|
|
833
899
|
const query = {};
|
|
834
900
|
if (params?.page) query['page'] = params.page;
|
|
835
901
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
902
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
836
903
|
const result = await this.transport.getList('/api/v1/data/currencies', query);
|
|
837
904
|
if ('error' in result) return result;
|
|
838
905
|
return {
|
|
@@ -882,6 +949,7 @@ class GenericRatesAccessor {
|
|
|
882
949
|
if (params?.department) query['department'] = params.department;
|
|
883
950
|
if (params?.page) query['page'] = params.page;
|
|
884
951
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
952
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
885
953
|
const result = await this.transport.getList('/api/v1/data/generic-rates', query);
|
|
886
954
|
if ('error' in result) return result;
|
|
887
955
|
return {
|
|
@@ -928,6 +996,7 @@ class JurisdictionsAccessor {
|
|
|
928
996
|
if (params?.search) query['search'] = params.search;
|
|
929
997
|
if (params?.page) query['page'] = params.page;
|
|
930
998
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
999
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
931
1000
|
const result = await this.transport.getList('/api/v1/data/jurisdictions', query);
|
|
932
1001
|
if ('error' in result) return result;
|
|
933
1002
|
return {
|
|
@@ -965,6 +1034,105 @@ class JurisdictionsAccessor {
|
|
|
965
1034
|
}
|
|
966
1035
|
}
|
|
967
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
|
+
|
|
968
1136
|
class LeaveTypesAccessor {
|
|
969
1137
|
constructor(transport){
|
|
970
1138
|
this.transport = transport;
|
|
@@ -974,6 +1142,7 @@ class LeaveTypesAccessor {
|
|
|
974
1142
|
if (params?.search) query['search'] = params.search;
|
|
975
1143
|
if (params?.page) query['page'] = params.page;
|
|
976
1144
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1145
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
977
1146
|
const result = await this.transport.getList('/api/v1/data/leave-types', query);
|
|
978
1147
|
if ('error' in result) return result;
|
|
979
1148
|
return {
|
|
@@ -1022,6 +1191,7 @@ class LeavesAccessor {
|
|
|
1022
1191
|
if (params?.status) query['status'] = params.status;
|
|
1023
1192
|
if (params?.page) query['page'] = params.page;
|
|
1024
1193
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1194
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1025
1195
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1026
1196
|
const result = await this.transport.getList('/api/v1/data/leaves', query);
|
|
1027
1197
|
if ('error' in result) return result;
|
|
@@ -1073,6 +1243,7 @@ class LeaveBalancesAccessor {
|
|
|
1073
1243
|
if (params?.year) query['year'] = params.year;
|
|
1074
1244
|
if (params?.page) query['page'] = params.page;
|
|
1075
1245
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1246
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1076
1247
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1077
1248
|
const result = await this.transport.getList('/api/v1/data/leave-balances', query);
|
|
1078
1249
|
if ('error' in result) return result;
|
|
@@ -1123,6 +1294,7 @@ class PoliciesAccessor {
|
|
|
1123
1294
|
if (params?.category) query['category'] = params.category;
|
|
1124
1295
|
if (params?.page) query['page'] = params.page;
|
|
1125
1296
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1297
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1126
1298
|
const result = await this.transport.getList('/api/v1/data/policies', query);
|
|
1127
1299
|
if ('error' in result) return result;
|
|
1128
1300
|
return {
|
|
@@ -1170,6 +1342,7 @@ class PolicyAcknowledgementsAccessor {
|
|
|
1170
1342
|
if (params?.employeeId) query['employeeId'] = params.employeeId;
|
|
1171
1343
|
if (params?.page) query['page'] = params.page;
|
|
1172
1344
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1345
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1173
1346
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1174
1347
|
const result = await this.transport.getList('/api/v1/data/policy-acknowledgements', query);
|
|
1175
1348
|
if ('error' in result) return result;
|
|
@@ -1218,8 +1391,10 @@ class CalendarEventsAccessor {
|
|
|
1218
1391
|
const query = {};
|
|
1219
1392
|
if (params?.search) query['search'] = params.search;
|
|
1220
1393
|
if (params?.type) query['type'] = params.type;
|
|
1394
|
+
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1221
1395
|
if (params?.page) query['page'] = params.page;
|
|
1222
1396
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1397
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1223
1398
|
const result = await this.transport.getList('/api/v1/data/calendar-events', query);
|
|
1224
1399
|
if ('error' in result) return result;
|
|
1225
1400
|
return {
|
|
@@ -1267,6 +1442,7 @@ class TimesheetsAccessor {
|
|
|
1267
1442
|
if (params?.projectId) query['projectId'] = params.projectId;
|
|
1268
1443
|
if (params?.page) query['page'] = params.page;
|
|
1269
1444
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1445
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1270
1446
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1271
1447
|
const result = await this.transport.getList('/api/v1/data/timesheets', query);
|
|
1272
1448
|
if ('error' in result) return result;
|
|
@@ -1291,6 +1467,23 @@ class TimesheetsAccessor {
|
|
|
1291
1467
|
data: transformTimesheet(result.data)
|
|
1292
1468
|
};
|
|
1293
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
|
+
}
|
|
1294
1487
|
/** Update a timesheet entry. Requires `timesheets.update` scope. */ async update(id, data) {
|
|
1295
1488
|
const result = await this.transport.put(`/api/v1/data/timesheets/${id}`, toSnakeBody(data));
|
|
1296
1489
|
if ('error' in result) return result;
|
|
@@ -1307,6 +1500,98 @@ class TimesheetsAccessor {
|
|
|
1307
1500
|
}
|
|
1308
1501
|
}
|
|
1309
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
|
+
|
|
1310
1595
|
/**
|
|
1311
1596
|
* AppsAccessor — wraps the self-service app info endpoint (§3.8, §6).
|
|
1312
1597
|
* Calls GET /api/v1/platform/apps/me with the app token.
|
|
@@ -1461,6 +1746,8 @@ class AuthAccessor {
|
|
|
1461
1746
|
this.currencies = new CurrenciesAccessor(transport);
|
|
1462
1747
|
this.genericRates = new GenericRatesAccessor(transport);
|
|
1463
1748
|
this.jurisdictions = new JurisdictionsAccessor(transport);
|
|
1749
|
+
this.jobLevels = new JobLevelsAccessor(transport);
|
|
1750
|
+
this.salaryBands = new SalaryBandsAccessor(transport);
|
|
1464
1751
|
this.leaveTypes = new LeaveTypesAccessor(transport);
|
|
1465
1752
|
this.leaves = new LeavesAccessor(transport);
|
|
1466
1753
|
this.leaveBalances = new LeaveBalancesAccessor(transport);
|
|
@@ -1468,6 +1755,9 @@ class AuthAccessor {
|
|
|
1468
1755
|
this.policyAcknowledgements = new PolicyAcknowledgementsAccessor(transport);
|
|
1469
1756
|
this.calendarEvents = new CalendarEventsAccessor(transport);
|
|
1470
1757
|
this.timesheets = new TimesheetsAccessor(transport);
|
|
1758
|
+
this.calendar = new CalendarAccessor(transport);
|
|
1759
|
+
this.email = new EmailAccessor(transport);
|
|
1760
|
+
this.employeeCompensation = new EmployeeCompensationAccessor(transport);
|
|
1471
1761
|
this.apps = new AppsAccessor(transport);
|
|
1472
1762
|
this.files = new FilesAccessor(transport);
|
|
1473
1763
|
this.auth = new AuthAccessor(config.baseUrl);
|
|
@@ -1477,7 +1767,7 @@ class AuthAccessor {
|
|
|
1477
1767
|
/**
|
|
1478
1768
|
* Nucleus SDK — Type System
|
|
1479
1769
|
*
|
|
1480
|
-
* Bucket types are transcribed from docs/
|
|
1770
|
+
* Bucket types are transcribed from docs/ARCHITECTURE.md §7 (Bucket Definitions).
|
|
1481
1771
|
* Each bucket type contains only that bucket's fields.
|
|
1482
1772
|
* The scope-to-type inference intersects selected bucket types at compile time.
|
|
1483
1773
|
*/ // ─── Utility types ────────────────────────────────────────────────────────────
|