@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/cjs/index.cjs
CHANGED
|
@@ -415,6 +415,30 @@ function transformJurisdiction(raw) {
|
|
|
415
415
|
if ('country' in r) out['country'] = str(r['country']);
|
|
416
416
|
return out;
|
|
417
417
|
}
|
|
418
|
+
function transformJobLevel(raw) {
|
|
419
|
+
if (!raw || typeof raw !== 'object') return {};
|
|
420
|
+
const r = raw;
|
|
421
|
+
const out = {};
|
|
422
|
+
if ('id' in r) out['id'] = r['id'];
|
|
423
|
+
if ('name' in r) out['name'] = str(r['name']);
|
|
424
|
+
if ('code' in r) out['code'] = str(r['code']);
|
|
425
|
+
if ('department_id' in r) out['departmentId'] = str(r['department_id']);
|
|
426
|
+
if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
|
|
427
|
+
return out;
|
|
428
|
+
}
|
|
429
|
+
function transformSalaryBand(raw) {
|
|
430
|
+
if (!raw || typeof raw !== 'object') return {};
|
|
431
|
+
const r = raw;
|
|
432
|
+
const out = {};
|
|
433
|
+
if ('id' in r) out['id'] = r['id'];
|
|
434
|
+
if ('job_level_id' in r) out['jobLevelId'] = str(r['job_level_id']);
|
|
435
|
+
if ('jurisdiction_id' in r) out['jurisdictionId'] = str(r['jurisdiction_id']);
|
|
436
|
+
if ('currency_code' in r) out['currencyCode'] = str(r['currency_code']);
|
|
437
|
+
if ('min_salary' in r) out['minSalary'] = num(r['min_salary']);
|
|
438
|
+
if ('max_salary' in r) out['maxSalary'] = num(r['max_salary']);
|
|
439
|
+
if ('target_salary' in r) out['targetSalary'] = num(r['target_salary']);
|
|
440
|
+
return out;
|
|
441
|
+
}
|
|
418
442
|
function transformLeaveType(raw) {
|
|
419
443
|
if (!raw || typeof raw !== 'object') return {};
|
|
420
444
|
const r = raw;
|
|
@@ -566,6 +590,7 @@ class EmployeesAccessor {
|
|
|
566
590
|
if (params?.employmentStatus) query['employmentStatus'] = params.employmentStatus;
|
|
567
591
|
if (params?.page) query['page'] = params.page;
|
|
568
592
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
593
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
569
594
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
570
595
|
const result = await this.transport.getList('/api/v1/data/employees', query);
|
|
571
596
|
if ('error' in result) return result;
|
|
@@ -585,6 +610,14 @@ class EmployeesAccessor {
|
|
|
585
610
|
}
|
|
586
611
|
}
|
|
587
612
|
|
|
613
|
+
function transformMember(raw) {
|
|
614
|
+
return {
|
|
615
|
+
id: raw['id'],
|
|
616
|
+
projectId: raw['project_id'],
|
|
617
|
+
employeeId: raw['employee_id'],
|
|
618
|
+
role: raw['role'] ?? null
|
|
619
|
+
};
|
|
620
|
+
}
|
|
588
621
|
class ProjectsAccessor {
|
|
589
622
|
constructor(transport){
|
|
590
623
|
this.transport = transport;
|
|
@@ -593,9 +626,11 @@ class ProjectsAccessor {
|
|
|
593
626
|
const query = {};
|
|
594
627
|
if (params?.search) query['search'] = params.search;
|
|
595
628
|
if (params?.status) query['status'] = params.status;
|
|
629
|
+
if (params?.stage) query['stage'] = params.stage;
|
|
596
630
|
if (params?.clientId) query['clientId'] = params.clientId;
|
|
597
631
|
if (params?.page) query['page'] = params.page;
|
|
598
632
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
633
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
599
634
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
600
635
|
const result = await this.transport.getList('/api/v1/data/projects', query);
|
|
601
636
|
if ('error' in result) return result;
|
|
@@ -634,6 +669,33 @@ class ProjectsAccessor {
|
|
|
634
669
|
data: null
|
|
635
670
|
};
|
|
636
671
|
}
|
|
672
|
+
// ─── Team membership (the projects `team` bucket) ──────────────────────────
|
|
673
|
+
// Membership is the project↔employee join. Reads need `projects` read on `team`;
|
|
674
|
+
// add/remove need `projects` update on `team` (re-adding restores a soft-deleted row).
|
|
675
|
+
membersBase(projectId) {
|
|
676
|
+
return `/api/v1/data/project-memberships/projects/${projectId}/members`;
|
|
677
|
+
}
|
|
678
|
+
/** List a project's team members. Requires `projects` read on the `team` bucket. */ async listMembers(projectId) {
|
|
679
|
+
const result = await this.transport.get(this.membersBase(projectId));
|
|
680
|
+
if ('error' in result) return result;
|
|
681
|
+
return {
|
|
682
|
+
data: (result.data ?? []).map((r)=>transformMember(r))
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
/** Add a team member. Requires `projects` update on the `team` bucket. */ async addMember(projectId, data) {
|
|
686
|
+
const result = await this.transport.post(this.membersBase(projectId), toSnakeBody(data));
|
|
687
|
+
if ('error' in result) return result;
|
|
688
|
+
return {
|
|
689
|
+
data: transformMember(result.data)
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
/** Remove a team member. Requires `projects` update on the `team` bucket. */ async removeMember(projectId, employeeId) {
|
|
693
|
+
const result = await this.transport.del(`${this.membersBase(projectId)}/${employeeId}`);
|
|
694
|
+
if ('error' in result) return result;
|
|
695
|
+
return {
|
|
696
|
+
data: null
|
|
697
|
+
};
|
|
698
|
+
}
|
|
637
699
|
}
|
|
638
700
|
|
|
639
701
|
class ClientsAccessor {
|
|
@@ -647,6 +709,7 @@ class ClientsAccessor {
|
|
|
647
709
|
if (params?.country) query['country'] = params.country;
|
|
648
710
|
if (params?.page) query['page'] = params.page;
|
|
649
711
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
712
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
650
713
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
651
714
|
const result = await this.transport.getList('/api/v1/data/clients', query);
|
|
652
715
|
if ('error' in result) return result;
|
|
@@ -696,6 +759,7 @@ class PartnersAccessor {
|
|
|
696
759
|
if (params?.search) query['search'] = params.search;
|
|
697
760
|
if (params?.page) query['page'] = params.page;
|
|
698
761
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
762
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
699
763
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
700
764
|
const result = await this.transport.getList('/api/v1/data/partners', query);
|
|
701
765
|
if ('error' in result) return result;
|
|
@@ -745,6 +809,7 @@ class DepartmentsAccessor {
|
|
|
745
809
|
if (params?.search) query['search'] = params.search;
|
|
746
810
|
if (params?.page) query['page'] = params.page;
|
|
747
811
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
812
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
748
813
|
const result = await this.transport.getList('/api/v1/data/departments', query);
|
|
749
814
|
if ('error' in result) return result;
|
|
750
815
|
return {
|
|
@@ -790,6 +855,7 @@ class ProjectTypesAccessor {
|
|
|
790
855
|
const query = {};
|
|
791
856
|
if (params?.page) query['page'] = params.page;
|
|
792
857
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
858
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
793
859
|
const result = await this.transport.getList('/api/v1/data/project-types', query);
|
|
794
860
|
if ('error' in result) return result;
|
|
795
861
|
return {
|
|
@@ -835,6 +901,7 @@ class CurrenciesAccessor {
|
|
|
835
901
|
const query = {};
|
|
836
902
|
if (params?.page) query['page'] = params.page;
|
|
837
903
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
904
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
838
905
|
const result = await this.transport.getList('/api/v1/data/currencies', query);
|
|
839
906
|
if ('error' in result) return result;
|
|
840
907
|
return {
|
|
@@ -884,6 +951,7 @@ class GenericRatesAccessor {
|
|
|
884
951
|
if (params?.department) query['department'] = params.department;
|
|
885
952
|
if (params?.page) query['page'] = params.page;
|
|
886
953
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
954
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
887
955
|
const result = await this.transport.getList('/api/v1/data/generic-rates', query);
|
|
888
956
|
if ('error' in result) return result;
|
|
889
957
|
return {
|
|
@@ -930,6 +998,7 @@ class JurisdictionsAccessor {
|
|
|
930
998
|
if (params?.search) query['search'] = params.search;
|
|
931
999
|
if (params?.page) query['page'] = params.page;
|
|
932
1000
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1001
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
933
1002
|
const result = await this.transport.getList('/api/v1/data/jurisdictions', query);
|
|
934
1003
|
if ('error' in result) return result;
|
|
935
1004
|
return {
|
|
@@ -967,6 +1036,105 @@ class JurisdictionsAccessor {
|
|
|
967
1036
|
}
|
|
968
1037
|
}
|
|
969
1038
|
|
|
1039
|
+
/** JobLevelsAccessor — the company's career-ladder rungs (WS7). */ class JobLevelsAccessor {
|
|
1040
|
+
constructor(transport){
|
|
1041
|
+
this.transport = transport;
|
|
1042
|
+
}
|
|
1043
|
+
async list(params) {
|
|
1044
|
+
const query = {};
|
|
1045
|
+
if (params?.search) query['search'] = params.search;
|
|
1046
|
+
if (params?.departmentId) query['departmentId'] = params.departmentId;
|
|
1047
|
+
if (params?.page) query['page'] = params.page;
|
|
1048
|
+
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1049
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1050
|
+
const result = await this.transport.getList('/api/v1/data/job-levels', query);
|
|
1051
|
+
if ('error' in result) return result;
|
|
1052
|
+
return {
|
|
1053
|
+
data: result.data.map((r)=>transformJobLevel(r)),
|
|
1054
|
+
meta: result.meta
|
|
1055
|
+
};
|
|
1056
|
+
}
|
|
1057
|
+
async getById(id) {
|
|
1058
|
+
const result = await this.transport.get(`/api/v1/data/job-levels/${id}`);
|
|
1059
|
+
if ('error' in result) return result;
|
|
1060
|
+
return {
|
|
1061
|
+
data: transformJobLevel(result.data)
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
/** Create a job level. Requires `job-levels.create` scope. */ async create(data) {
|
|
1065
|
+
const result = await this.transport.post('/api/v1/data/job-levels', toSnakeBody(data));
|
|
1066
|
+
if ('error' in result) return result;
|
|
1067
|
+
return {
|
|
1068
|
+
data: transformJobLevel(result.data)
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
/** Update a job level. Requires `job-levels.update` scope. */ async update(id, data) {
|
|
1072
|
+
const result = await this.transport.put(`/api/v1/data/job-levels/${id}`, toSnakeBody(data));
|
|
1073
|
+
if ('error' in result) return result;
|
|
1074
|
+
return {
|
|
1075
|
+
data: transformJobLevel(result.data)
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
/** Soft-delete a job level. Requires `job-levels.delete` scope. */ async delete(id) {
|
|
1079
|
+
const result = await this.transport.del(`/api/v1/data/job-levels/${id}`);
|
|
1080
|
+
if ('error' in result) return result;
|
|
1081
|
+
return {
|
|
1082
|
+
data: null
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
/**
|
|
1088
|
+
* SalaryBandsAccessor — per-jurisdiction pay ranges for a job level (WS7).
|
|
1089
|
+
* The `financials` bucket (min/max/target) is flagged sensitive server-side.
|
|
1090
|
+
*/ class SalaryBandsAccessor {
|
|
1091
|
+
constructor(transport){
|
|
1092
|
+
this.transport = transport;
|
|
1093
|
+
}
|
|
1094
|
+
async list(params) {
|
|
1095
|
+
const query = {};
|
|
1096
|
+
if (params?.jobLevelId) query['jobLevelId'] = params.jobLevelId;
|
|
1097
|
+
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1098
|
+
if (params?.page) query['page'] = params.page;
|
|
1099
|
+
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1100
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1101
|
+
const result = await this.transport.getList('/api/v1/data/salary-bands', query);
|
|
1102
|
+
if ('error' in result) return result;
|
|
1103
|
+
return {
|
|
1104
|
+
data: result.data.map((r)=>transformSalaryBand(r)),
|
|
1105
|
+
meta: result.meta
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
async getById(id) {
|
|
1109
|
+
const result = await this.transport.get(`/api/v1/data/salary-bands/${id}`);
|
|
1110
|
+
if ('error' in result) return result;
|
|
1111
|
+
return {
|
|
1112
|
+
data: transformSalaryBand(result.data)
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
/** Create a salary band. Requires `salary-bands.create` scope. */ async create(data) {
|
|
1116
|
+
const result = await this.transport.post('/api/v1/data/salary-bands', toSnakeBody(data));
|
|
1117
|
+
if ('error' in result) return result;
|
|
1118
|
+
return {
|
|
1119
|
+
data: transformSalaryBand(result.data)
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
/** Update a salary band. Requires `salary-bands.update` scope. */ async update(id, data) {
|
|
1123
|
+
const result = await this.transport.put(`/api/v1/data/salary-bands/${id}`, toSnakeBody(data));
|
|
1124
|
+
if ('error' in result) return result;
|
|
1125
|
+
return {
|
|
1126
|
+
data: transformSalaryBand(result.data)
|
|
1127
|
+
};
|
|
1128
|
+
}
|
|
1129
|
+
/** Soft-delete a salary band. Requires `salary-bands.delete` scope. */ async delete(id) {
|
|
1130
|
+
const result = await this.transport.del(`/api/v1/data/salary-bands/${id}`);
|
|
1131
|
+
if ('error' in result) return result;
|
|
1132
|
+
return {
|
|
1133
|
+
data: null
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
970
1138
|
class LeaveTypesAccessor {
|
|
971
1139
|
constructor(transport){
|
|
972
1140
|
this.transport = transport;
|
|
@@ -976,6 +1144,7 @@ class LeaveTypesAccessor {
|
|
|
976
1144
|
if (params?.search) query['search'] = params.search;
|
|
977
1145
|
if (params?.page) query['page'] = params.page;
|
|
978
1146
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1147
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
979
1148
|
const result = await this.transport.getList('/api/v1/data/leave-types', query);
|
|
980
1149
|
if ('error' in result) return result;
|
|
981
1150
|
return {
|
|
@@ -1024,6 +1193,7 @@ class LeavesAccessor {
|
|
|
1024
1193
|
if (params?.status) query['status'] = params.status;
|
|
1025
1194
|
if (params?.page) query['page'] = params.page;
|
|
1026
1195
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1196
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1027
1197
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1028
1198
|
const result = await this.transport.getList('/api/v1/data/leaves', query);
|
|
1029
1199
|
if ('error' in result) return result;
|
|
@@ -1075,6 +1245,7 @@ class LeaveBalancesAccessor {
|
|
|
1075
1245
|
if (params?.year) query['year'] = params.year;
|
|
1076
1246
|
if (params?.page) query['page'] = params.page;
|
|
1077
1247
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1248
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1078
1249
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1079
1250
|
const result = await this.transport.getList('/api/v1/data/leave-balances', query);
|
|
1080
1251
|
if ('error' in result) return result;
|
|
@@ -1125,6 +1296,7 @@ class PoliciesAccessor {
|
|
|
1125
1296
|
if (params?.category) query['category'] = params.category;
|
|
1126
1297
|
if (params?.page) query['page'] = params.page;
|
|
1127
1298
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1299
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1128
1300
|
const result = await this.transport.getList('/api/v1/data/policies', query);
|
|
1129
1301
|
if ('error' in result) return result;
|
|
1130
1302
|
return {
|
|
@@ -1172,6 +1344,7 @@ class PolicyAcknowledgementsAccessor {
|
|
|
1172
1344
|
if (params?.employeeId) query['employeeId'] = params.employeeId;
|
|
1173
1345
|
if (params?.page) query['page'] = params.page;
|
|
1174
1346
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1347
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1175
1348
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1176
1349
|
const result = await this.transport.getList('/api/v1/data/policy-acknowledgements', query);
|
|
1177
1350
|
if ('error' in result) return result;
|
|
@@ -1220,8 +1393,10 @@ class CalendarEventsAccessor {
|
|
|
1220
1393
|
const query = {};
|
|
1221
1394
|
if (params?.search) query['search'] = params.search;
|
|
1222
1395
|
if (params?.type) query['type'] = params.type;
|
|
1396
|
+
if (params?.jurisdictionId) query['jurisdictionId'] = params.jurisdictionId;
|
|
1223
1397
|
if (params?.page) query['page'] = params.page;
|
|
1224
1398
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1399
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1225
1400
|
const result = await this.transport.getList('/api/v1/data/calendar-events', query);
|
|
1226
1401
|
if ('error' in result) return result;
|
|
1227
1402
|
return {
|
|
@@ -1269,6 +1444,7 @@ class TimesheetsAccessor {
|
|
|
1269
1444
|
if (params?.projectId) query['projectId'] = params.projectId;
|
|
1270
1445
|
if (params?.page) query['page'] = params.page;
|
|
1271
1446
|
if (params?.pageSize) query['pageSize'] = params.pageSize;
|
|
1447
|
+
if (params?.updatedSince) query['updatedSince'] = params.updatedSince;
|
|
1272
1448
|
if (params?.expand?.length) query['expand'] = params.expand.join(',');
|
|
1273
1449
|
const result = await this.transport.getList('/api/v1/data/timesheets', query);
|
|
1274
1450
|
if ('error' in result) return result;
|
|
@@ -1293,6 +1469,23 @@ class TimesheetsAccessor {
|
|
|
1293
1469
|
data: transformTimesheet(result.data)
|
|
1294
1470
|
};
|
|
1295
1471
|
}
|
|
1472
|
+
/**
|
|
1473
|
+
* Bulk-create timesheet entries (partial accept). Requires `timesheets.create` scope.
|
|
1474
|
+
* Returns `{ created, rejected }` — every valid item is inserted; invalid items come back
|
|
1475
|
+
* with their input index + reason.
|
|
1476
|
+
*/ async bulkCreate(items) {
|
|
1477
|
+
const result = await this.transport.post('/api/v1/data/timesheets/bulk', {
|
|
1478
|
+
items: items.map((i)=>toSnakeBody(i))
|
|
1479
|
+
});
|
|
1480
|
+
if ('error' in result) return result;
|
|
1481
|
+
const data = result.data;
|
|
1482
|
+
return {
|
|
1483
|
+
data: {
|
|
1484
|
+
created: data.created.map((r)=>transformTimesheet(r)),
|
|
1485
|
+
rejected: data.rejected
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1296
1489
|
/** Update a timesheet entry. Requires `timesheets.update` scope. */ async update(id, data) {
|
|
1297
1490
|
const result = await this.transport.put(`/api/v1/data/timesheets/${id}`, toSnakeBody(data));
|
|
1298
1491
|
if ('error' in result) return result;
|
|
@@ -1309,6 +1502,98 @@ class TimesheetsAccessor {
|
|
|
1309
1502
|
}
|
|
1310
1503
|
}
|
|
1311
1504
|
|
|
1505
|
+
/**
|
|
1506
|
+
* CalendarAccessor — read workspace users' Google Calendar events (WS3).
|
|
1507
|
+
* Requires the app's `calendar:read` scope. Not part of the bucket/CRUD scope system.
|
|
1508
|
+
*/ class CalendarAccessor {
|
|
1509
|
+
constructor(transport){
|
|
1510
|
+
this.transport = transport;
|
|
1511
|
+
}
|
|
1512
|
+
async listEvents(params) {
|
|
1513
|
+
const result = await this.transport.get('/api/v1/data/calendar/events', {
|
|
1514
|
+
employeeId: params.employeeId,
|
|
1515
|
+
timeMin: params.timeMin,
|
|
1516
|
+
timeMax: params.timeMax,
|
|
1517
|
+
q: params.q
|
|
1518
|
+
});
|
|
1519
|
+
if ('error' in result) return result;
|
|
1520
|
+
return {
|
|
1521
|
+
data: result.data
|
|
1522
|
+
};
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* EmailAccessor — send Nucleus-mediated email (WS5). Requires the app's `email:send` scope.
|
|
1528
|
+
* In test mode the message is marked `[SANDBOX]` and external recipients are suppressed.
|
|
1529
|
+
*/ class EmailAccessor {
|
|
1530
|
+
constructor(transport){
|
|
1531
|
+
this.transport = transport;
|
|
1532
|
+
}
|
|
1533
|
+
async send(input) {
|
|
1534
|
+
const result = await this.transport.post('/api/v1/data/comms/send', input);
|
|
1535
|
+
if ('error' in result) return result;
|
|
1536
|
+
return {
|
|
1537
|
+
data: result.data
|
|
1538
|
+
};
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
function transform(raw) {
|
|
1543
|
+
return {
|
|
1544
|
+
id: raw['id'],
|
|
1545
|
+
employeeId: raw['employee_id'],
|
|
1546
|
+
hourlyCostRate: raw['hourly_cost_rate'] ?? null,
|
|
1547
|
+
monthlyCostRate: raw['monthly_cost_rate'] ?? null,
|
|
1548
|
+
hourlyBillableRate: raw['hourly_billable_rate'] ?? null,
|
|
1549
|
+
monthlyBillableRate: raw['monthly_billable_rate'] ?? null,
|
|
1550
|
+
salary: raw['salary'] ?? null,
|
|
1551
|
+
currencyCode: raw['currency_code'],
|
|
1552
|
+
effectiveFrom: raw['effective_from'],
|
|
1553
|
+
effectiveTo: raw['effective_to'] ?? null
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* EmployeeCompensationAccessor — read/write an employee's effective-dated compensation (WS6).
|
|
1558
|
+
* Gated server-side by the `employee-compensation` scope (buckets: `core`, `rates`, `salary`).
|
|
1559
|
+
* `create` closes the prior open record and opens a new one (Nucleus = single comp authority).
|
|
1560
|
+
*/ class EmployeeCompensationAccessor {
|
|
1561
|
+
constructor(transport){
|
|
1562
|
+
this.transport = transport;
|
|
1563
|
+
}
|
|
1564
|
+
base(employeeId) {
|
|
1565
|
+
return `/api/v1/data/employee-compensation/employees/${employeeId}/compensation`;
|
|
1566
|
+
}
|
|
1567
|
+
/** Full history, newest first. */ async list(employeeId) {
|
|
1568
|
+
const result = await this.transport.get(this.base(employeeId));
|
|
1569
|
+
if ('error' in result) return result;
|
|
1570
|
+
return {
|
|
1571
|
+
data: (result.data ?? []).map((r)=>transform(r))
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
/** The current (open) record, or null. */ async current(employeeId) {
|
|
1575
|
+
const result = await this.transport.get(`${this.base(employeeId)}/current`);
|
|
1576
|
+
if ('error' in result) return result;
|
|
1577
|
+
return {
|
|
1578
|
+
data: result.data ? transform(result.data) : null
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
/** Add a new effective-dated record (closes the prior open one). */ async create(employeeId, data) {
|
|
1582
|
+
const result = await this.transport.post(this.base(employeeId), toSnakeBody(data));
|
|
1583
|
+
if ('error' in result) return result;
|
|
1584
|
+
return {
|
|
1585
|
+
data: transform(result.data)
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1588
|
+
/** Soft-delete a compensation record. */ async delete(employeeId, id) {
|
|
1589
|
+
const result = await this.transport.del(`${this.base(employeeId)}/${id}`);
|
|
1590
|
+
if ('error' in result) return result;
|
|
1591
|
+
return {
|
|
1592
|
+
data: null
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1312
1597
|
/**
|
|
1313
1598
|
* AppsAccessor — wraps the self-service app info endpoint (§3.8, §6).
|
|
1314
1599
|
* Calls GET /api/v1/platform/apps/me with the app token.
|
|
@@ -1463,6 +1748,8 @@ class AuthAccessor {
|
|
|
1463
1748
|
this.currencies = new CurrenciesAccessor(transport);
|
|
1464
1749
|
this.genericRates = new GenericRatesAccessor(transport);
|
|
1465
1750
|
this.jurisdictions = new JurisdictionsAccessor(transport);
|
|
1751
|
+
this.jobLevels = new JobLevelsAccessor(transport);
|
|
1752
|
+
this.salaryBands = new SalaryBandsAccessor(transport);
|
|
1466
1753
|
this.leaveTypes = new LeaveTypesAccessor(transport);
|
|
1467
1754
|
this.leaves = new LeavesAccessor(transport);
|
|
1468
1755
|
this.leaveBalances = new LeaveBalancesAccessor(transport);
|
|
@@ -1470,6 +1757,9 @@ class AuthAccessor {
|
|
|
1470
1757
|
this.policyAcknowledgements = new PolicyAcknowledgementsAccessor(transport);
|
|
1471
1758
|
this.calendarEvents = new CalendarEventsAccessor(transport);
|
|
1472
1759
|
this.timesheets = new TimesheetsAccessor(transport);
|
|
1760
|
+
this.calendar = new CalendarAccessor(transport);
|
|
1761
|
+
this.email = new EmailAccessor(transport);
|
|
1762
|
+
this.employeeCompensation = new EmployeeCompensationAccessor(transport);
|
|
1473
1763
|
this.apps = new AppsAccessor(transport);
|
|
1474
1764
|
this.files = new FilesAccessor(transport);
|
|
1475
1765
|
this.auth = new AuthAccessor(config.baseUrl);
|
|
@@ -1479,7 +1769,7 @@ class AuthAccessor {
|
|
|
1479
1769
|
/**
|
|
1480
1770
|
* Nucleus SDK — Type System
|
|
1481
1771
|
*
|
|
1482
|
-
* Bucket types are transcribed from docs/
|
|
1772
|
+
* Bucket types are transcribed from docs/ARCHITECTURE.md §7 (Bucket Definitions).
|
|
1483
1773
|
* Each bucket type contains only that bucket's fields.
|
|
1484
1774
|
* The scope-to-type inference intersects selected bucket types at compile time.
|
|
1485
1775
|
*/ // ─── Utility types ────────────────────────────────────────────────────────────
|