@typeb-digital/nucleus-sdk 0.1.1 → 0.2.1

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