@typeb-digital/nucleus-sdk 0.0.6 → 0.1.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/es/index.js CHANGED
@@ -66,6 +66,44 @@ class NucleusTransport {
66
66
  return makeErrorResult('NETWORK_ERROR', String(err));
67
67
  }
68
68
  }
69
+ async put(path, body) {
70
+ try {
71
+ const envelope = await $fetch(`${this.baseUrl}${path}`, {
72
+ method: 'PUT',
73
+ headers: this.headers,
74
+ body: JSON.stringify(body)
75
+ });
76
+ if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
77
+ return {
78
+ data: envelope.data
79
+ };
80
+ } catch (err) {
81
+ if (err instanceof FetchError) {
82
+ const errBody = err.data;
83
+ return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
84
+ }
85
+ return makeErrorResult('NETWORK_ERROR', String(err));
86
+ }
87
+ }
88
+ async patch(path, body) {
89
+ try {
90
+ const envelope = await $fetch(`${this.baseUrl}${path}`, {
91
+ method: 'PATCH',
92
+ headers: this.headers,
93
+ body: JSON.stringify(body)
94
+ });
95
+ if (!envelope.success) return makeErrorResult('FORBIDDEN', envelope.error);
96
+ return {
97
+ data: envelope.data
98
+ };
99
+ } catch (err) {
100
+ if (err instanceof FetchError) {
101
+ const errBody = err.data;
102
+ return makeErrorResult(statusToCode(err.status ?? 0, errBody?.error), err.message);
103
+ }
104
+ return makeErrorResult('NETWORK_ERROR', String(err));
105
+ }
106
+ }
69
107
  async del(path, query) {
70
108
  try {
71
109
  const params = query ? Object.fromEntries(Object.entries(query).filter(([, v])=>v !== undefined)) : undefined;
@@ -122,7 +160,20 @@ class NucleusTransport {
122
160
  /**
123
161
  * Transform utilities — map snake_case Prisma API responses to camelCase SDK types.
124
162
  * Each function accepts `unknown` so it works regardless of which buckets were active.
125
- */ function str(v) {
163
+ */ /**
164
+ * Serialize a camelCase mutation input to the snake_case body the API expects.
165
+ * Shallow is sufficient — write bodies are flat. `undefined` keys are dropped;
166
+ * `null` is preserved (explicit clear).
167
+ */ function toSnakeBody(input) {
168
+ const out = {};
169
+ for (const [key, value] of Object.entries(input)){
170
+ if (value === undefined) continue;
171
+ const snake = key.replace(/[A-Z]/g, (m)=>`_${m.toLowerCase()}`);
172
+ out[snake] = value;
173
+ }
174
+ return out;
175
+ }
176
+ function str(v) {
126
177
  return typeof v === 'string' ? v : null;
127
178
  }
128
179
  function num(v) {
@@ -155,6 +206,7 @@ function transformCompensation(raw) {
155
206
  hourlyBillableRate: num(r['hourly_billable_rate']),
156
207
  monthlyCostRate: num(r['monthly_cost_rate']),
157
208
  monthlyBillableRate: num(r['monthly_billable_rate']),
209
+ salary: num(r['salary']),
158
210
  currencyCode: str(r['currency_code']) ?? 'USD',
159
211
  effectiveFrom: str(r['effective_from']) ?? ''
160
212
  };
@@ -166,6 +218,7 @@ function transformCompensationHistoryEntry(raw) {
166
218
  hourlyBillableRate: num(r['hourly_billable_rate']),
167
219
  monthlyCostRate: num(r['monthly_cost_rate']),
168
220
  monthlyBillableRate: num(r['monthly_billable_rate']),
221
+ salary: num(r['salary']),
169
222
  currencyCode: str(r['currency_code']) ?? 'USD',
170
223
  effectiveFrom: str(r['effective_from']) ?? '',
171
224
  effectiveTo: str(r['effective_to'])
@@ -185,6 +238,7 @@ function transformEmployee(raw) {
185
238
  if ('job_title' in r) out['jobTitle'] = str(r['job_title']);
186
239
  if ('department' in r) out['department'] = str(r['department']);
187
240
  if ('employment_status' in r) out['employmentStatus'] = str(r['employment_status']);
241
+ if ('employment_type' in r) out['employmentType'] = str(r['employment_type']);
188
242
  if ('is_external' in r) out['isExternal'] = bool(r['is_external']);
189
243
  // employment
190
244
  if ('start_date' in r) out['startDate'] = str(r['start_date']);
@@ -245,6 +299,11 @@ function transformProject(raw) {
245
299
  return entry;
246
300
  });
247
301
  }
302
+ // financials
303
+ if ('contract_value' in r) out['contractValue'] = num(r['contract_value']);
304
+ if ('budget' in r) out['budget'] = num(r['budget']);
305
+ if ('margin_target' in r) out['marginTarget'] = num(r['margin_target']);
306
+ if ('financials_currency' in r) out['financialsCurrency'] = str(r['financials_currency']);
248
307
  // integrations
249
308
  if ('source' in r) out['source'] = str(r['source']);
250
309
  if ('clockify_project_id' in r) out['clockifyProjectId'] = str(r['clockify_project_id']);
@@ -344,6 +403,155 @@ function transformGenericRate(raw) {
344
403
  if ('billable_rate' in r) out['billableRate'] = num(r['billable_rate']);
345
404
  return out;
346
405
  }
406
+ function transformJurisdiction(raw) {
407
+ if (!raw || typeof raw !== 'object') return {};
408
+ const r = raw;
409
+ const out = {};
410
+ if ('id' in r) out['id'] = r['id'];
411
+ if ('name' in r) out['name'] = str(r['name']);
412
+ if ('code' in r) out['code'] = str(r['code']);
413
+ if ('country' in r) out['country'] = str(r['country']);
414
+ return out;
415
+ }
416
+ function transformLeaveType(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 ('description' in r) out['description'] = str(r['description']);
423
+ if ('color' in r) out['color'] = str(r['color']);
424
+ if ('sort_order' in r) out['sortOrder'] = num(r['sort_order']) ?? 0;
425
+ return out;
426
+ }
427
+ function transformLeave(raw) {
428
+ if (!raw || typeof raw !== 'object') return {};
429
+ const r = raw;
430
+ const out = {};
431
+ // core
432
+ if ('id' in r) out['id'] = r['id'];
433
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
434
+ if ('leave_type_id' in r) out['leaveTypeId'] = str(r['leave_type_id']);
435
+ if ('start_date' in r) out['startDate'] = str(r['start_date']);
436
+ if ('end_date' in r) out['endDate'] = str(r['end_date']);
437
+ if ('days' in r) out['days'] = num(r['days']);
438
+ if ('status' in r) out['status'] = str(r['status']);
439
+ if ('source' in r) out['source'] = str(r['source']);
440
+ // details
441
+ if ('reason' in r) out['reason'] = str(r['reason']);
442
+ // expand: employee / leaveType
443
+ if ('employee' in r) {
444
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
445
+ }
446
+ if ('leave_type' in r || 'leaveType' in r) {
447
+ const lt = r['leave_type'] ?? r['leaveType'];
448
+ out['leaveType'] = lt ? transformLeaveType(lt) : null;
449
+ }
450
+ return out;
451
+ }
452
+ function transformLeaveBalance(raw) {
453
+ if (!raw || typeof raw !== 'object') return {};
454
+ const r = raw;
455
+ const out = {};
456
+ // core
457
+ if ('id' in r) out['id'] = r['id'];
458
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
459
+ if ('leave_type_id' in r) out['leaveTypeId'] = str(r['leave_type_id']);
460
+ if ('year' in r) out['year'] = num(r['year']);
461
+ if ('balance_days' in r) out['balanceDays'] = num(r['balance_days']);
462
+ // expand: employee / leaveType
463
+ if ('employee' in r) {
464
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
465
+ }
466
+ if ('leave_type' in r || 'leaveType' in r) {
467
+ const lt = r['leave_type'] ?? r['leaveType'];
468
+ out['leaveType'] = lt ? transformLeaveType(lt) : null;
469
+ }
470
+ return out;
471
+ }
472
+ function transformPolicy(raw) {
473
+ if (!raw || typeof raw !== 'object') return {};
474
+ const r = raw;
475
+ const out = {};
476
+ // core
477
+ if ('id' in r) out['id'] = r['id'];
478
+ if ('title' in r) out['title'] = str(r['title']);
479
+ if ('code' in r) out['code'] = str(r['code']);
480
+ if ('category' in r) out['category'] = str(r['category']);
481
+ if ('description' in r) out['description'] = str(r['description']);
482
+ if ('current_version' in r) out['currentVersion'] = num(r['current_version']) ?? 1;
483
+ if ('requires_acknowledgement' in r) {
484
+ out['requiresAcknowledgement'] = bool(r['requires_acknowledgement']);
485
+ }
486
+ if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
487
+ // content
488
+ if ('body' in r) out['body'] = str(r['body']);
489
+ if ('file_key' in r) out['fileKey'] = str(r['file_key']);
490
+ return out;
491
+ }
492
+ function transformPolicyAcknowledgement(raw) {
493
+ if (!raw || typeof raw !== 'object') return {};
494
+ const r = raw;
495
+ const out = {};
496
+ // core
497
+ if ('id' in r) out['id'] = r['id'];
498
+ if ('policy_id' in r) out['policyId'] = str(r['policy_id']);
499
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
500
+ if ('version' in r) out['version'] = num(r['version']);
501
+ if ('acknowledged_at' in r) out['acknowledgedAt'] = str(r['acknowledged_at']);
502
+ // expand: employee / policy
503
+ if ('employee' in r) {
504
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
505
+ }
506
+ if ('policy' in r) {
507
+ out['policy'] = r['policy'] ? transformPolicy(r['policy']) : null;
508
+ }
509
+ return out;
510
+ }
511
+ function transformCalendarEvent(raw) {
512
+ if (!raw || typeof raw !== 'object') return {};
513
+ const r = raw;
514
+ const out = {};
515
+ if ('id' in r) out['id'] = r['id'];
516
+ if ('title' in r) out['title'] = str(r['title']);
517
+ if ('description' in r) out['description'] = str(r['description']);
518
+ if ('start_date' in r) out['startDate'] = str(r['start_date']);
519
+ if ('end_date' in r) out['endDate'] = str(r['end_date']);
520
+ if ('all_day' in r) out['allDay'] = bool(r['all_day']);
521
+ if ('type' in r) out['type'] = str(r['type']);
522
+ if ('location' in r) out['location'] = str(r['location']);
523
+ if ('color' in r) out['color'] = str(r['color']);
524
+ if ('is_published' in r) out['isPublished'] = bool(r['is_published']);
525
+ return out;
526
+ }
527
+ function transformTimesheet(raw) {
528
+ if (!raw || typeof raw !== 'object') return {};
529
+ const r = raw;
530
+ const out = {};
531
+ // core
532
+ if ('id' in r) out['id'] = r['id'];
533
+ if ('employee_id' in r) out['employeeId'] = str(r['employee_id']);
534
+ if ('project_id' in r) out['projectId'] = str(r['project_id']);
535
+ if ('start_time' in r) out['startTime'] = str(r['start_time']);
536
+ if ('end_time' in r) out['endTime'] = str(r['end_time']);
537
+ if ('duration_minutes' in r) out['durationMinutes'] = num(r['duration_minutes']);
538
+ if ('billable' in r) out['billable'] = bool(r['billable']);
539
+ // details
540
+ if ('description' in r) out['description'] = str(r['description']);
541
+ if ('activity_name' in r) out['activityName'] = str(r['activity_name']);
542
+ // integrations
543
+ if ('source' in r) out['source'] = str(r['source']);
544
+ if ('kimai_id' in r) out['kimaiId'] = str(r['kimai_id']);
545
+ if ('kimai_activity_id' in r) out['kimaiActivityId'] = str(r['kimai_activity_id']);
546
+ // expand: employee / project
547
+ if ('employee' in r) {
548
+ out['employee'] = r['employee'] ? transformEmployee(r['employee']) : null;
549
+ }
550
+ if ('project' in r) {
551
+ out['project'] = r['project'] ? transformProject(r['project']) : null;
552
+ }
553
+ return out;
554
+ }
347
555
 
348
556
  class EmployeesAccessor {
349
557
  constructor(transport){
@@ -373,6 +581,21 @@ class EmployeesAccessor {
373
581
  data: transformEmployee(result.data)
374
582
  };
375
583
  }
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
+ }
376
599
  }
377
600
 
378
601
  class ProjectsAccessor {
@@ -403,6 +626,27 @@ class ProjectsAccessor {
403
626
  data: transformProject(result.data)
404
627
  };
405
628
  }
629
+ /** Create a project. Requires `projects.create` scope. */ async create(data) {
630
+ const result = await this.transport.post('/api/v1/data/projects', toSnakeBody(data));
631
+ if ('error' in result) return result;
632
+ return {
633
+ data: transformProject(result.data)
634
+ };
635
+ }
636
+ /** Update a project. Requires `projects.update` scope. */ async update(id, data) {
637
+ const result = await this.transport.put(`/api/v1/data/projects/${id}`, toSnakeBody(data));
638
+ if ('error' in result) return result;
639
+ return {
640
+ data: transformProject(result.data)
641
+ };
642
+ }
643
+ /** Soft-delete a project. Requires `projects.delete` scope. */ async delete(id) {
644
+ const result = await this.transport.del(`/api/v1/data/projects/${id}`);
645
+ if ('error' in result) return result;
646
+ return {
647
+ data: null
648
+ };
649
+ }
406
650
  }
407
651
 
408
652
  class ClientsAccessor {
@@ -433,6 +677,27 @@ class ClientsAccessor {
433
677
  data: transformClient(result.data)
434
678
  };
435
679
  }
680
+ /** Create a client. Requires `clients.create` scope. */ async create(data) {
681
+ const result = await this.transport.post('/api/v1/data/clients', toSnakeBody(data));
682
+ if ('error' in result) return result;
683
+ return {
684
+ data: transformClient(result.data)
685
+ };
686
+ }
687
+ /** Update a client. Requires `clients.update` scope. */ async update(id, data) {
688
+ const result = await this.transport.put(`/api/v1/data/clients/${id}`, toSnakeBody(data));
689
+ if ('error' in result) return result;
690
+ return {
691
+ data: transformClient(result.data)
692
+ };
693
+ }
694
+ /** Soft-delete a client. Requires `clients.delete` scope. */ async delete(id) {
695
+ const result = await this.transport.del(`/api/v1/data/clients/${id}`);
696
+ if ('error' in result) return result;
697
+ return {
698
+ data: null
699
+ };
700
+ }
436
701
  }
437
702
 
438
703
  class PartnersAccessor {
@@ -461,6 +726,27 @@ class PartnersAccessor {
461
726
  data: transformPartner(result.data)
462
727
  };
463
728
  }
729
+ /** Create a partner. Requires `partners.create` scope. */ async create(data) {
730
+ const result = await this.transport.post('/api/v1/data/partners', toSnakeBody(data));
731
+ if ('error' in result) return result;
732
+ return {
733
+ data: transformPartner(result.data)
734
+ };
735
+ }
736
+ /** Update a partner. Requires `partners.update` scope. */ async update(id, data) {
737
+ const result = await this.transport.put(`/api/v1/data/partners/${id}`, toSnakeBody(data));
738
+ if ('error' in result) return result;
739
+ return {
740
+ data: transformPartner(result.data)
741
+ };
742
+ }
743
+ /** Soft-delete a partner. Requires `partners.delete` scope. */ async delete(id) {
744
+ const result = await this.transport.del(`/api/v1/data/partners/${id}`);
745
+ if ('error' in result) return result;
746
+ return {
747
+ data: null
748
+ };
749
+ }
464
750
  }
465
751
 
466
752
  class DepartmentsAccessor {
@@ -486,6 +772,27 @@ class DepartmentsAccessor {
486
772
  data: transformDepartment(result.data)
487
773
  };
488
774
  }
775
+ /** Create a department. Requires `departments.create` scope. */ async create(data) {
776
+ const result = await this.transport.post('/api/v1/data/departments', toSnakeBody(data));
777
+ if ('error' in result) return result;
778
+ return {
779
+ data: transformDepartment(result.data)
780
+ };
781
+ }
782
+ /** Update a department. Requires `departments.update` scope. */ async update(id, data) {
783
+ const result = await this.transport.put(`/api/v1/data/departments/${id}`, toSnakeBody(data));
784
+ if ('error' in result) return result;
785
+ return {
786
+ data: transformDepartment(result.data)
787
+ };
788
+ }
789
+ /** Soft-delete a department. Requires `departments.delete` scope. */ async delete(id) {
790
+ const result = await this.transport.del(`/api/v1/data/departments/${id}`);
791
+ if ('error' in result) return result;
792
+ return {
793
+ data: null
794
+ };
795
+ }
489
796
  }
490
797
 
491
798
  class ProjectTypesAccessor {
@@ -510,6 +817,27 @@ class ProjectTypesAccessor {
510
817
  data: transformProjectType(result.data)
511
818
  };
512
819
  }
820
+ /** Create a project type. Requires `projectTypes.create` scope. */ async create(data) {
821
+ const result = await this.transport.post('/api/v1/data/project-types', toSnakeBody(data));
822
+ if ('error' in result) return result;
823
+ return {
824
+ data: transformProjectType(result.data)
825
+ };
826
+ }
827
+ /** Update a project type. Requires `projectTypes.update` scope. */ async update(id, data) {
828
+ const result = await this.transport.put(`/api/v1/data/project-types/${id}`, toSnakeBody(data));
829
+ if ('error' in result) return result;
830
+ return {
831
+ data: transformProjectType(result.data)
832
+ };
833
+ }
834
+ /** Soft-delete a project type. Requires `projectTypes.delete` scope. */ async delete(id) {
835
+ const result = await this.transport.del(`/api/v1/data/project-types/${id}`);
836
+ if ('error' in result) return result;
837
+ return {
838
+ data: null
839
+ };
840
+ }
513
841
  }
514
842
 
515
843
  class CurrenciesAccessor {
@@ -534,6 +862,30 @@ class CurrenciesAccessor {
534
862
  data: transformCurrency(result.data)
535
863
  };
536
864
  }
865
+ /** Create a currency. Requires `currencies.create` scope. */ async create(data) {
866
+ const result = await this.transport.post('/api/v1/data/currencies', toSnakeBody(data));
867
+ if ('error' in result) return result;
868
+ return {
869
+ data: transformCurrency(result.data)
870
+ };
871
+ }
872
+ /**
873
+ * Update a currency (keyed by its ISO code; `code` itself is immutable).
874
+ * Requires `currencies.update` scope.
875
+ */ async update(code, data) {
876
+ const result = await this.transport.put(`/api/v1/data/currencies/${code}`, toSnakeBody(data));
877
+ if ('error' in result) return result;
878
+ return {
879
+ data: transformCurrency(result.data)
880
+ };
881
+ }
882
+ /** Soft-delete a currency (keyed by its ISO code). Requires `currencies.delete` scope. */ async delete(code) {
883
+ const result = await this.transport.del(`/api/v1/data/currencies/${code}`);
884
+ if ('error' in result) return result;
885
+ return {
886
+ data: null
887
+ };
888
+ }
537
889
  }
538
890
 
539
891
  class GenericRatesAccessor {
@@ -559,6 +911,415 @@ class GenericRatesAccessor {
559
911
  data: transformGenericRate(result.data)
560
912
  };
561
913
  }
914
+ /** Create a generic rate. Requires `genericRates.create` scope. */ async create(data) {
915
+ const result = await this.transport.post('/api/v1/data/generic-rates', toSnakeBody(data));
916
+ if ('error' in result) return result;
917
+ return {
918
+ data: transformGenericRate(result.data)
919
+ };
920
+ }
921
+ /** Update a generic rate. Requires `genericRates.update` scope. */ async update(id, data) {
922
+ const result = await this.transport.put(`/api/v1/data/generic-rates/${id}`, toSnakeBody(data));
923
+ if ('error' in result) return result;
924
+ return {
925
+ data: transformGenericRate(result.data)
926
+ };
927
+ }
928
+ /** Soft-delete a generic rate. Requires `genericRates.delete` scope. */ async delete(id) {
929
+ const result = await this.transport.del(`/api/v1/data/generic-rates/${id}`);
930
+ if ('error' in result) return result;
931
+ return {
932
+ data: null
933
+ };
934
+ }
935
+ }
936
+
937
+ class JurisdictionsAccessor {
938
+ constructor(transport){
939
+ this.transport = transport;
940
+ }
941
+ async list(params) {
942
+ const query = {};
943
+ if (params?.search) query['search'] = params.search;
944
+ if (params?.page) query['page'] = params.page;
945
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
946
+ const result = await this.transport.getList('/api/v1/data/jurisdictions', query);
947
+ if ('error' in result) return result;
948
+ return {
949
+ data: result.data.map((r)=>transformJurisdiction(r)),
950
+ meta: result.meta
951
+ };
952
+ }
953
+ async getById(id) {
954
+ const result = await this.transport.get(`/api/v1/data/jurisdictions/${id}`);
955
+ if ('error' in result) return result;
956
+ return {
957
+ data: transformJurisdiction(result.data)
958
+ };
959
+ }
960
+ /** Create a jurisdiction. Requires `jurisdictions.create` scope. */ async create(data) {
961
+ const result = await this.transport.post('/api/v1/data/jurisdictions', toSnakeBody(data));
962
+ if ('error' in result) return result;
963
+ return {
964
+ data: transformJurisdiction(result.data)
965
+ };
966
+ }
967
+ /** Update a jurisdiction. Requires `jurisdictions.update` scope. */ async update(id, data) {
968
+ const result = await this.transport.put(`/api/v1/data/jurisdictions/${id}`, toSnakeBody(data));
969
+ if ('error' in result) return result;
970
+ return {
971
+ data: transformJurisdiction(result.data)
972
+ };
973
+ }
974
+ /** Soft-delete a jurisdiction. Requires `jurisdictions.delete` scope. */ async delete(id) {
975
+ const result = await this.transport.del(`/api/v1/data/jurisdictions/${id}`);
976
+ if ('error' in result) return result;
977
+ return {
978
+ data: null
979
+ };
980
+ }
981
+ }
982
+
983
+ class LeaveTypesAccessor {
984
+ constructor(transport){
985
+ this.transport = transport;
986
+ }
987
+ async list(params) {
988
+ const query = {};
989
+ if (params?.search) query['search'] = params.search;
990
+ if (params?.page) query['page'] = params.page;
991
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
992
+ const result = await this.transport.getList('/api/v1/data/leave-types', query);
993
+ if ('error' in result) return result;
994
+ return {
995
+ data: result.data.map((r)=>transformLeaveType(r)),
996
+ meta: result.meta
997
+ };
998
+ }
999
+ async getById(id) {
1000
+ const result = await this.transport.get(`/api/v1/data/leave-types/${id}`);
1001
+ if ('error' in result) return result;
1002
+ return {
1003
+ data: transformLeaveType(result.data)
1004
+ };
1005
+ }
1006
+ /** Create a leave type. Requires `leaveTypes.create` scope. */ async create(data) {
1007
+ const result = await this.transport.post('/api/v1/data/leave-types', toSnakeBody(data));
1008
+ if ('error' in result) return result;
1009
+ return {
1010
+ data: transformLeaveType(result.data)
1011
+ };
1012
+ }
1013
+ /** Update a leave type. Requires `leaveTypes.update` scope. */ async update(id, data) {
1014
+ const result = await this.transport.put(`/api/v1/data/leave-types/${id}`, toSnakeBody(data));
1015
+ if ('error' in result) return result;
1016
+ return {
1017
+ data: transformLeaveType(result.data)
1018
+ };
1019
+ }
1020
+ /** Soft-delete a leave type. Requires `leaveTypes.delete` scope. */ async delete(id) {
1021
+ const result = await this.transport.del(`/api/v1/data/leave-types/${id}`);
1022
+ if ('error' in result) return result;
1023
+ return {
1024
+ data: null
1025
+ };
1026
+ }
1027
+ }
1028
+
1029
+ class LeavesAccessor {
1030
+ constructor(transport){
1031
+ this.transport = transport;
1032
+ }
1033
+ async list(params) {
1034
+ const query = {};
1035
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1036
+ if (params?.leaveTypeId) query['leaveTypeId'] = params.leaveTypeId;
1037
+ if (params?.status) query['status'] = params.status;
1038
+ if (params?.page) query['page'] = params.page;
1039
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1040
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1041
+ const result = await this.transport.getList('/api/v1/data/leaves', query);
1042
+ if ('error' in result) return result;
1043
+ return {
1044
+ data: result.data.map((r)=>transformLeave(r)),
1045
+ meta: result.meta
1046
+ };
1047
+ }
1048
+ async getById(id, options) {
1049
+ const query = {};
1050
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1051
+ const result = await this.transport.get(`/api/v1/data/leaves/${id}`, query);
1052
+ if ('error' in result) return result;
1053
+ return {
1054
+ data: transformLeave(result.data)
1055
+ };
1056
+ }
1057
+ /** Create a leave record. Requires `leaves.create` scope. */ async create(data) {
1058
+ const result = await this.transport.post('/api/v1/data/leaves', toSnakeBody(data));
1059
+ if ('error' in result) return result;
1060
+ return {
1061
+ data: transformLeave(result.data)
1062
+ };
1063
+ }
1064
+ /** Update a leave record. Requires `leaves.update` scope. */ async update(id, data) {
1065
+ const result = await this.transport.put(`/api/v1/data/leaves/${id}`, toSnakeBody(data));
1066
+ if ('error' in result) return result;
1067
+ return {
1068
+ data: transformLeave(result.data)
1069
+ };
1070
+ }
1071
+ /** Soft-delete a leave record. Requires `leaves.delete` scope. */ async delete(id) {
1072
+ const result = await this.transport.del(`/api/v1/data/leaves/${id}`);
1073
+ if ('error' in result) return result;
1074
+ return {
1075
+ data: null
1076
+ };
1077
+ }
1078
+ }
1079
+
1080
+ class LeaveBalancesAccessor {
1081
+ constructor(transport){
1082
+ this.transport = transport;
1083
+ }
1084
+ async list(params) {
1085
+ const query = {};
1086
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1087
+ if (params?.leaveTypeId) query['leaveTypeId'] = params.leaveTypeId;
1088
+ if (params?.year) query['year'] = params.year;
1089
+ if (params?.page) query['page'] = params.page;
1090
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1091
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1092
+ const result = await this.transport.getList('/api/v1/data/leave-balances', query);
1093
+ if ('error' in result) return result;
1094
+ return {
1095
+ data: result.data.map((r)=>transformLeaveBalance(r)),
1096
+ meta: result.meta
1097
+ };
1098
+ }
1099
+ async getById(id, options) {
1100
+ const query = {};
1101
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1102
+ const result = await this.transport.get(`/api/v1/data/leave-balances/${id}`, query);
1103
+ if ('error' in result) return result;
1104
+ return {
1105
+ data: transformLeaveBalance(result.data)
1106
+ };
1107
+ }
1108
+ /** Create a leave balance. Requires `leaveBalances.create` scope. */ async create(data) {
1109
+ const result = await this.transport.post('/api/v1/data/leave-balances', toSnakeBody(data));
1110
+ if ('error' in result) return result;
1111
+ return {
1112
+ data: transformLeaveBalance(result.data)
1113
+ };
1114
+ }
1115
+ /** Update a leave balance. Requires `leaveBalances.update` scope. */ async update(id, data) {
1116
+ const result = await this.transport.put(`/api/v1/data/leave-balances/${id}`, toSnakeBody(data));
1117
+ if ('error' in result) return result;
1118
+ return {
1119
+ data: transformLeaveBalance(result.data)
1120
+ };
1121
+ }
1122
+ /** Soft-delete a leave balance. Requires `leaveBalances.delete` scope. */ async delete(id) {
1123
+ const result = await this.transport.del(`/api/v1/data/leave-balances/${id}`);
1124
+ if ('error' in result) return result;
1125
+ return {
1126
+ data: null
1127
+ };
1128
+ }
1129
+ }
1130
+
1131
+ class PoliciesAccessor {
1132
+ constructor(transport){
1133
+ this.transport = transport;
1134
+ }
1135
+ async list(params) {
1136
+ const query = {};
1137
+ if (params?.search) query['search'] = params.search;
1138
+ if (params?.category) query['category'] = params.category;
1139
+ if (params?.page) query['page'] = params.page;
1140
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1141
+ const result = await this.transport.getList('/api/v1/data/policies', query);
1142
+ if ('error' in result) return result;
1143
+ return {
1144
+ data: result.data.map((r)=>transformPolicy(r)),
1145
+ meta: result.meta
1146
+ };
1147
+ }
1148
+ async getById(id) {
1149
+ const result = await this.transport.get(`/api/v1/data/policies/${id}`);
1150
+ if ('error' in result) return result;
1151
+ return {
1152
+ data: transformPolicy(result.data)
1153
+ };
1154
+ }
1155
+ /** Create a policy. Requires `policies.create` scope. */ async create(data) {
1156
+ const result = await this.transport.post('/api/v1/data/policies', toSnakeBody(data));
1157
+ if ('error' in result) return result;
1158
+ return {
1159
+ data: transformPolicy(result.data)
1160
+ };
1161
+ }
1162
+ /** Update a policy. Requires `policies.update` scope. */ async update(id, data) {
1163
+ const result = await this.transport.put(`/api/v1/data/policies/${id}`, toSnakeBody(data));
1164
+ if ('error' in result) return result;
1165
+ return {
1166
+ data: transformPolicy(result.data)
1167
+ };
1168
+ }
1169
+ /** Soft-delete a policy. Requires `policies.delete` scope. */ async delete(id) {
1170
+ const result = await this.transport.del(`/api/v1/data/policies/${id}`);
1171
+ if ('error' in result) return result;
1172
+ return {
1173
+ data: null
1174
+ };
1175
+ }
1176
+ }
1177
+
1178
+ class PolicyAcknowledgementsAccessor {
1179
+ constructor(transport){
1180
+ this.transport = transport;
1181
+ }
1182
+ async list(params) {
1183
+ const query = {};
1184
+ if (params?.policyId) query['policyId'] = params.policyId;
1185
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1186
+ if (params?.page) query['page'] = params.page;
1187
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1188
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1189
+ const result = await this.transport.getList('/api/v1/data/policy-acknowledgements', query);
1190
+ if ('error' in result) return result;
1191
+ return {
1192
+ data: result.data.map((r)=>transformPolicyAcknowledgement(r)),
1193
+ meta: result.meta
1194
+ };
1195
+ }
1196
+ async getById(id, options) {
1197
+ const query = {};
1198
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1199
+ const result = await this.transport.get(`/api/v1/data/policy-acknowledgements/${id}`, query);
1200
+ if ('error' in result) return result;
1201
+ return {
1202
+ data: transformPolicyAcknowledgement(result.data)
1203
+ };
1204
+ }
1205
+ /** Create a policy acknowledgement. Requires `policyAcknowledgements.create` scope. */ async create(data) {
1206
+ const result = await this.transport.post('/api/v1/data/policy-acknowledgements', toSnakeBody(data));
1207
+ if ('error' in result) return result;
1208
+ return {
1209
+ data: transformPolicyAcknowledgement(result.data)
1210
+ };
1211
+ }
1212
+ /** Update a policy acknowledgement. Requires `policyAcknowledgements.update` scope. */ async update(id, data) {
1213
+ const result = await this.transport.put(`/api/v1/data/policy-acknowledgements/${id}`, toSnakeBody(data));
1214
+ if ('error' in result) return result;
1215
+ return {
1216
+ data: transformPolicyAcknowledgement(result.data)
1217
+ };
1218
+ }
1219
+ /** Soft-delete a policy acknowledgement. Requires `policyAcknowledgements.delete` scope. */ async delete(id) {
1220
+ const result = await this.transport.del(`/api/v1/data/policy-acknowledgements/${id}`);
1221
+ if ('error' in result) return result;
1222
+ return {
1223
+ data: null
1224
+ };
1225
+ }
1226
+ }
1227
+
1228
+ class CalendarEventsAccessor {
1229
+ constructor(transport){
1230
+ this.transport = transport;
1231
+ }
1232
+ async list(params) {
1233
+ const query = {};
1234
+ if (params?.search) query['search'] = params.search;
1235
+ if (params?.type) query['type'] = params.type;
1236
+ if (params?.page) query['page'] = params.page;
1237
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1238
+ const result = await this.transport.getList('/api/v1/data/calendar-events', query);
1239
+ if ('error' in result) return result;
1240
+ return {
1241
+ data: result.data.map((r)=>transformCalendarEvent(r)),
1242
+ meta: result.meta
1243
+ };
1244
+ }
1245
+ async getById(id) {
1246
+ const result = await this.transport.get(`/api/v1/data/calendar-events/${id}`);
1247
+ if ('error' in result) return result;
1248
+ return {
1249
+ data: transformCalendarEvent(result.data)
1250
+ };
1251
+ }
1252
+ /** Create a calendar event. Requires `calendarEvents.create` scope. */ async create(data) {
1253
+ const result = await this.transport.post('/api/v1/data/calendar-events', toSnakeBody(data));
1254
+ if ('error' in result) return result;
1255
+ return {
1256
+ data: transformCalendarEvent(result.data)
1257
+ };
1258
+ }
1259
+ /** Update a calendar event. Requires `calendarEvents.update` scope. */ async update(id, data) {
1260
+ const result = await this.transport.put(`/api/v1/data/calendar-events/${id}`, toSnakeBody(data));
1261
+ if ('error' in result) return result;
1262
+ return {
1263
+ data: transformCalendarEvent(result.data)
1264
+ };
1265
+ }
1266
+ /** Soft-delete a calendar event. Requires `calendarEvents.delete` scope. */ async delete(id) {
1267
+ const result = await this.transport.del(`/api/v1/data/calendar-events/${id}`);
1268
+ if ('error' in result) return result;
1269
+ return {
1270
+ data: null
1271
+ };
1272
+ }
1273
+ }
1274
+
1275
+ class TimesheetsAccessor {
1276
+ constructor(transport){
1277
+ this.transport = transport;
1278
+ }
1279
+ async list(params) {
1280
+ const query = {};
1281
+ if (params?.employeeId) query['employeeId'] = params.employeeId;
1282
+ if (params?.projectId) query['projectId'] = params.projectId;
1283
+ if (params?.page) query['page'] = params.page;
1284
+ if (params?.pageSize) query['pageSize'] = params.pageSize;
1285
+ if (params?.expand?.length) query['expand'] = params.expand.join(',');
1286
+ const result = await this.transport.getList('/api/v1/data/timesheets', query);
1287
+ if ('error' in result) return result;
1288
+ return {
1289
+ data: result.data.map((r)=>transformTimesheet(r)),
1290
+ meta: result.meta
1291
+ };
1292
+ }
1293
+ async getById(id, options) {
1294
+ const query = {};
1295
+ if (options?.expand?.length) query['expand'] = options.expand.join(',');
1296
+ const result = await this.transport.get(`/api/v1/data/timesheets/${id}`, query);
1297
+ if ('error' in result) return result;
1298
+ return {
1299
+ data: transformTimesheet(result.data)
1300
+ };
1301
+ }
1302
+ /** Create a timesheet entry. Requires `timesheets.create` scope. */ async create(data) {
1303
+ const result = await this.transport.post('/api/v1/data/timesheets', toSnakeBody(data));
1304
+ if ('error' in result) return result;
1305
+ return {
1306
+ data: transformTimesheet(result.data)
1307
+ };
1308
+ }
1309
+ /** Update a timesheet entry. Requires `timesheets.update` scope. */ async update(id, data) {
1310
+ const result = await this.transport.put(`/api/v1/data/timesheets/${id}`, toSnakeBody(data));
1311
+ if ('error' in result) return result;
1312
+ return {
1313
+ data: transformTimesheet(result.data)
1314
+ };
1315
+ }
1316
+ /** Soft-delete a timesheet entry. Requires `timesheets.delete` scope. */ async delete(id) {
1317
+ const result = await this.transport.del(`/api/v1/data/timesheets/${id}`);
1318
+ if ('error' in result) return result;
1319
+ return {
1320
+ data: null
1321
+ };
1322
+ }
562
1323
  }
563
1324
 
564
1325
  /**
@@ -693,9 +1454,9 @@ class AuthAccessor {
693
1454
  * export const nucleus = new NucleusClient({
694
1455
  * token: process.env.NUCLEUS_TOKEN!,
695
1456
  * scopes: {
696
- * employees: ['identity', 'employment'],
697
- * projects: ['core'],
698
- * clients: ['identity'],
1457
+ * employees: { read: ['identity', 'employment'], update: ['contact'] },
1458
+ * projects: { read: ['core'] },
1459
+ * leaves: { read: ['core'], create: ['core'], delete: true },
699
1460
  * },
700
1461
  * });
701
1462
  * ```
@@ -714,6 +1475,14 @@ class AuthAccessor {
714
1475
  this.projectTypes = new ProjectTypesAccessor(transport);
715
1476
  this.currencies = new CurrenciesAccessor(transport);
716
1477
  this.genericRates = new GenericRatesAccessor(transport);
1478
+ this.jurisdictions = new JurisdictionsAccessor(transport);
1479
+ this.leaveTypes = new LeaveTypesAccessor(transport);
1480
+ this.leaves = new LeavesAccessor(transport);
1481
+ this.leaveBalances = new LeaveBalancesAccessor(transport);
1482
+ this.policies = new PoliciesAccessor(transport);
1483
+ this.policyAcknowledgements = new PolicyAcknowledgementsAccessor(transport);
1484
+ this.calendarEvents = new CalendarEventsAccessor(transport);
1485
+ this.timesheets = new TimesheetsAccessor(transport);
717
1486
  this.apps = new AppsAccessor(transport);
718
1487
  this.files = new FilesAccessor(transport);
719
1488
  this.auth = new AuthAccessor(config.baseUrl);