@codingfactory/socialkit-vue 0.7.8 → 0.7.11

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.
@@ -319,6 +319,29 @@ function buildActorContext(circle) {
319
319
  managementSections,
320
320
  };
321
321
  }
322
+ function resolveBootstrapActorRole(actorCapabilities, fallbackRole) {
323
+ if (actorCapabilities === null) {
324
+ return fallbackRole;
325
+ }
326
+ const displayRole = readString(actorCapabilities.display_role);
327
+ if (isCircleRole(displayRole)) {
328
+ return displayRole;
329
+ }
330
+ const moderationLevel = readString(actorCapabilities.moderation_level);
331
+ if (isCircleRole(moderationLevel)) {
332
+ return moderationLevel;
333
+ }
334
+ return fallbackRole;
335
+ }
336
+ function circleUserRole(circle) {
337
+ if (circle === null || circle === undefined) {
338
+ return null;
339
+ }
340
+ return isCircleRole(circle.user_role) ? circle.user_role : null;
341
+ }
342
+ function hasValue(value) {
343
+ return value !== undefined && value !== null;
344
+ }
322
345
  function normalizeCollectionResponse(payload, normalizeItem) {
323
346
  const data = readRecord(payload, 'data') ?? (isRecord(payload) ? payload : null);
324
347
  const dataItems = readArray(payload, 'data');
@@ -353,6 +376,11 @@ function normalizeInlineCollection(items, normalizeItem) {
353
376
  meta: createEmptyPagination().meta,
354
377
  };
355
378
  }
379
+ function normalizeBootstrapRoleCollection(value) {
380
+ return Array.isArray(value)
381
+ ? normalizeInlineCollection(value, normalizeRoleDefinition)
382
+ : normalizeCollectionResponse(value ?? {}, normalizeRoleDefinition);
383
+ }
356
384
  function normalizeCircle(value) {
357
385
  if (!isRecord(value)) {
358
386
  return null;
@@ -1008,6 +1036,56 @@ class CirclesService {
1008
1036
  const matchedCircle = items.find((item) => isCircleWithSlug(item) && item.slug.toLowerCase() === normalizedSlug);
1009
1037
  return matchedCircle ? normalizeCircle(matchedCircle) : null;
1010
1038
  }
1039
+ normalizeModerationReportSubmissionInput(subjectOrInput, category, notes) {
1040
+ if (typeof subjectOrInput !== 'string') {
1041
+ return subjectOrInput;
1042
+ }
1043
+ const input = {
1044
+ category: category ?? '',
1045
+ subject_user_id: subjectOrInput,
1046
+ subject_type: 'user',
1047
+ subject_id: subjectOrInput,
1048
+ };
1049
+ if (typeof notes === 'string') {
1050
+ input.notes = notes;
1051
+ }
1052
+ return input;
1053
+ }
1054
+ buildModerationReportPayload(input) {
1055
+ const category = this.sanitizeInput(input.category);
1056
+ if (category.length === 0) {
1057
+ throw new Error('Moderation report category is required.');
1058
+ }
1059
+ const subjectUserId = typeof input.subject_user_id === 'string' && input.subject_user_id.trim().length > 0
1060
+ ? this.sanitizeInput(input.subject_user_id)
1061
+ : null;
1062
+ const subjectType = input.subject_type ?? (subjectUserId !== null ? 'user' : undefined);
1063
+ const derivedSubjectId = typeof input.subject_id === 'string' && input.subject_id.trim().length > 0
1064
+ ? this.sanitizeInput(input.subject_id)
1065
+ : subjectType === 'user'
1066
+ ? subjectUserId
1067
+ : null;
1068
+ if (subjectType !== undefined && derivedSubjectId === null) {
1069
+ throw new Error('Moderation report subject_id is required when subject_type is provided.');
1070
+ }
1071
+ if (subjectType === undefined && subjectUserId === null) {
1072
+ throw new Error('Moderation report subject details are required.');
1073
+ }
1074
+ const payload = {
1075
+ category,
1076
+ };
1077
+ if (subjectUserId !== null) {
1078
+ payload.subject_user_id = subjectUserId;
1079
+ }
1080
+ if (subjectType !== undefined && derivedSubjectId !== null) {
1081
+ payload.subject_type = subjectType;
1082
+ payload.subject_id = derivedSubjectId;
1083
+ }
1084
+ if (typeof input.notes === 'string' && input.notes.trim().length > 0) {
1085
+ payload.notes = this.sanitizeInput(input.notes);
1086
+ }
1087
+ return payload;
1088
+ }
1011
1089
  async list(cursor, filters) {
1012
1090
  try {
1013
1091
  const params = {
@@ -1490,15 +1568,9 @@ class CirclesService {
1490
1568
  return await this.handleError(error);
1491
1569
  }
1492
1570
  }
1493
- async reportMember(circleId, subjectUserId, category, notes) {
1571
+ async submitModerationReport(circleId, input) {
1494
1572
  try {
1495
- const payload = {
1496
- subject_user_id: subjectUserId,
1497
- category: this.sanitizeInput(category),
1498
- };
1499
- if (typeof notes === 'string' && notes.trim().length > 0) {
1500
- payload.notes = this.sanitizeInput(notes);
1501
- }
1573
+ const payload = this.buildModerationReportPayload(input);
1502
1574
  const response = await this.client.post(`${this.baseURL}/${circleId}/moderation/reports`, payload);
1503
1575
  const data = readRecord(response.data, 'data') ?? {};
1504
1576
  const reportId = readString(data.report_id);
@@ -1519,6 +1591,9 @@ class CirclesService {
1519
1591
  return await this.handleError(error);
1520
1592
  }
1521
1593
  }
1594
+ async reportMember(circleId, subjectOrInput, category, notes) {
1595
+ return await this.submitModerationReport(circleId, this.normalizeModerationReportSubmissionInput(subjectOrInput, category, notes));
1596
+ }
1522
1597
  async listModerationReports(circleId, cursor, status) {
1523
1598
  try {
1524
1599
  const params = {};
@@ -1686,6 +1761,10 @@ class CirclesService {
1686
1761
  async getManagementBootstrap(circleId) {
1687
1762
  const identifier = this.sanitizeInput(circleId);
1688
1763
  let resolvedCircle = null;
1764
+ let bootstrapPermissionCatalog = createEmptyPagination().data;
1765
+ let bootstrapManagementSections = [];
1766
+ let bootstrapCounts = createEmptyManagementCounts();
1767
+ let hasBootstrapCounts = false;
1689
1768
  const bootstrapIdentifier = this.isUuid(identifier)
1690
1769
  ? identifier
1691
1770
  : await (async () => {
@@ -1696,12 +1775,24 @@ class CirclesService {
1696
1775
  const response = await this.client.get(`${this.baseURL}/${bootstrapIdentifier}/management/bootstrap`);
1697
1776
  const data = readRecord(response.data, 'data');
1698
1777
  const bootstrapCircle = data?.circle;
1699
- const bootstrapManagementSections = normalizeManagementSections(data?.management_sections);
1778
+ const bootstrapActorCapabilities = readRecord(data, 'actor_capabilities');
1779
+ bootstrapManagementSections = normalizeManagementSections(data?.management_sections);
1780
+ bootstrapPermissionCatalog = Array.isArray(data?.permission_catalog)
1781
+ ? data.permission_catalog
1782
+ .map((entry) => normalizePermissionCatalogEntry(entry))
1783
+ .filter((entry) => entry !== null)
1784
+ : [];
1785
+ hasBootstrapCounts = hasValue(data?.counts);
1786
+ bootstrapCounts = normalizeManagementCounts(data?.counts);
1700
1787
  const directCircle = normalizeCircle(bootstrapCircle ?? data);
1788
+ const directCircleRole = circleUserRole(directCircle);
1789
+ const fallbackRole = directCircleRole ?? circleUserRole(resolvedCircle);
1790
+ const bootstrapActorRole = resolveBootstrapActorRole(bootstrapActorCapabilities, fallbackRole);
1701
1791
  const mergedCircleSource = directCircle === null
1702
1792
  ? {
1703
1793
  ...(resolvedCircle ?? await this.get(bootstrapIdentifier)),
1704
1794
  ...(bootstrapCircle ?? {}),
1795
+ ...(bootstrapActorRole !== null ? { user_role: bootstrapActorRole } : {}),
1705
1796
  actor_capabilities: data?.actor_capabilities,
1706
1797
  management_sections: bootstrapManagementSections.length > 0
1707
1798
  ? bootstrapManagementSections
@@ -1709,6 +1800,7 @@ class CirclesService {
1709
1800
  }
1710
1801
  : {
1711
1802
  ...directCircle,
1803
+ ...(bootstrapActorRole !== null ? { user_role: bootstrapActorRole } : {}),
1712
1804
  actor_capabilities: data?.actor_capabilities ?? directCircle.actor_capabilities,
1713
1805
  management_sections: bootstrapManagementSections.length > 0
1714
1806
  ? bootstrapManagementSections
@@ -1716,36 +1808,98 @@ class CirclesService {
1716
1808
  };
1717
1809
  const circle = normalizeCircle(mergedCircleSource);
1718
1810
  if (circle !== null) {
1719
- const bootstrapHasCollections = data?.members !== undefined && data?.members !== null;
1720
- if (bootstrapHasCollections) {
1721
- const actor = circle.actor ?? buildActorContext(circle);
1811
+ const actor = circle.actor ?? buildActorContext(circle);
1812
+ if (!actor.capabilities.canViewManagement) {
1722
1813
  return {
1723
1814
  circle,
1724
1815
  actor,
1725
1816
  management_sections: bootstrapManagementSections.length > 0
1726
1817
  ? bootstrapManagementSections
1727
1818
  : actor.managementSections,
1728
- members: normalizeCollectionResponse(data?.members ?? {}, normalizeCircleMember),
1729
- requests: normalizeCollectionResponse(data?.requests ?? {}, normalizeJoinRequest),
1730
- roles: Array.isArray(data?.roles)
1731
- ? normalizeInlineCollection(data.roles, normalizeRoleDefinition)
1732
- : normalizeCollectionResponse(data?.roles ?? {}, normalizeRoleDefinition),
1733
- counts: normalizeManagementCounts(data?.counts),
1734
- permission_catalog: Array.isArray(data?.permission_catalog)
1735
- ? data.permission_catalog
1736
- .map((entry) => normalizePermissionCatalogEntry(entry))
1737
- .filter((entry) => entry !== null)
1738
- : [],
1739
- reports: normalizeCollectionResponse(data?.reports ?? {}, normalizeModerationReport),
1740
- bans: normalizeCollectionResponse(data?.bans ?? {}, normalizeBanRecord),
1741
- mutes: normalizeCollectionResponse(data?.mutes ?? {}, normalizeMuteRecord),
1742
- audit: normalizeCollectionResponse(data?.audit ?? {}, normalizeAuditLogEntry),
1743
- automod: normalizeCollectionResponse(data?.automod ?? {}, normalizeAutomodRule),
1819
+ members: createEmptyPagination(),
1820
+ requests: createEmptyPagination(),
1821
+ roles: createEmptyPagination(),
1822
+ counts: createEmptyManagementCounts(),
1823
+ permission_catalog: [],
1824
+ reports: createEmptyPagination(),
1825
+ bans: createEmptyPagination(),
1826
+ mutes: createEmptyPagination(),
1827
+ audit: createEmptyPagination(),
1828
+ automod: createEmptyPagination(),
1744
1829
  };
1745
1830
  }
1746
- // Bootstrap returned circle + counts but no collection data arrays.
1747
- // Save the circle so the individual-fetch fallback path below can use it.
1748
- resolvedCircle = circle;
1831
+ const caps = actor.capabilities;
1832
+ const emptyJoinRequests = createEmptyPagination();
1833
+ const emptyRoles = createEmptyPagination();
1834
+ const emptyReports = createEmptyPagination();
1835
+ const emptyBans = createEmptyPagination();
1836
+ const emptyMutes = createEmptyPagination();
1837
+ const emptyAudit = createEmptyPagination();
1838
+ const emptyAutomod = createEmptyPagination();
1839
+ const members = hasValue(data?.members)
1840
+ ? normalizeCollectionResponse(data?.members ?? {}, normalizeCircleMember)
1841
+ : await this.getMembers(circle.id);
1842
+ const requests = hasValue(data?.requests)
1843
+ ? normalizeCollectionResponse(data?.requests ?? {}, normalizeJoinRequest)
1844
+ : caps.canReviewRequests
1845
+ ? await this.listJoinRequests(circle.id, null, 'pending')
1846
+ : emptyJoinRequests;
1847
+ const roles = hasValue(data?.roles)
1848
+ ? normalizeBootstrapRoleCollection(data?.roles)
1849
+ : caps.canManageRoles
1850
+ ? await this.listRoles(circle.id)
1851
+ : emptyRoles;
1852
+ const reports = hasValue(data?.reports)
1853
+ ? normalizeCollectionResponse(data?.reports ?? {}, normalizeModerationReport)
1854
+ : caps.canManageReports
1855
+ ? await this.listModerationReports(circle.id, null, 'pending')
1856
+ : emptyReports;
1857
+ const bans = hasValue(data?.bans)
1858
+ ? normalizeCollectionResponse(data?.bans ?? {}, normalizeBanRecord)
1859
+ : caps.canManageBans
1860
+ ? await this.listBans(circle.id)
1861
+ : emptyBans;
1862
+ const mutes = hasValue(data?.mutes)
1863
+ ? normalizeCollectionResponse(data?.mutes ?? {}, normalizeMuteRecord)
1864
+ : caps.canManageMutes
1865
+ ? await this.listMutes(circle.id)
1866
+ : emptyMutes;
1867
+ const audit = hasValue(data?.audit)
1868
+ ? normalizeCollectionResponse(data?.audit ?? {}, normalizeAuditLogEntry)
1869
+ : caps.canViewAuditLog
1870
+ ? await this.getModerationAuditLog(circle.id)
1871
+ : emptyAudit;
1872
+ const automod = hasValue(data?.automod)
1873
+ ? normalizeCollectionResponse(data?.automod ?? {}, normalizeAutomodRule)
1874
+ : caps.canManageAutomod
1875
+ ? await this.listAutomodRules(circle.id)
1876
+ : emptyAutomod;
1877
+ return {
1878
+ circle,
1879
+ actor,
1880
+ management_sections: bootstrapManagementSections.length > 0
1881
+ ? bootstrapManagementSections
1882
+ : actor.managementSections,
1883
+ members,
1884
+ requests,
1885
+ roles,
1886
+ counts: hasBootstrapCounts
1887
+ ? bootstrapCounts
1888
+ : {
1889
+ members: circle.member_count ?? members.data.length,
1890
+ requests_pending: requests.data.length,
1891
+ reports_pending: reports.data.length,
1892
+ roles: roles.data.length,
1893
+ bans_active: bans.data.length,
1894
+ mutes_active: mutes.data.length,
1895
+ },
1896
+ permission_catalog: bootstrapPermissionCatalog,
1897
+ reports,
1898
+ bans,
1899
+ mutes,
1900
+ audit,
1901
+ automod,
1902
+ };
1749
1903
  }
1750
1904
  }
1751
1905
  catch (error) {
@@ -1764,7 +1918,7 @@ class CirclesService {
1764
1918
  requests: createEmptyPagination(),
1765
1919
  roles: createEmptyPagination(),
1766
1920
  counts: createEmptyManagementCounts(),
1767
- permission_catalog: [],
1921
+ permission_catalog: bootstrapPermissionCatalog,
1768
1922
  reports: createEmptyPagination(),
1769
1923
  bans: createEmptyPagination(),
1770
1924
  mutes: createEmptyPagination(),
@@ -1819,7 +1973,7 @@ class CirclesService {
1819
1973
  bans_active: bans.data.length,
1820
1974
  mutes_active: mutes.data.length,
1821
1975
  },
1822
- permission_catalog: [],
1976
+ permission_catalog: bootstrapPermissionCatalog,
1823
1977
  reports,
1824
1978
  bans,
1825
1979
  mutes,