@axcode/axcloud-sdk 0.1.7-dev.bf490b9 → 0.2.0-dev.1e6c3d5

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/index.js CHANGED
@@ -20,7 +20,7 @@ var AxCloudError = class _AxCloudError extends Error {
20
20
  }
21
21
  static fromResponse(status, body) {
22
22
  const details = typeof body === "object" ? body : void 0;
23
- const message = details?.message;
23
+ const message = (typeof details?.message === "string" ? details.message : void 0) || (typeof details?.error === "string" ? details.error : void 0);
24
24
  switch (status) {
25
25
  case 401:
26
26
  return new _AxCloudError(
@@ -346,7 +346,7 @@ function getContentSlotMap(content) {
346
346
  for (const block of content?.blocks || []) {
347
347
  const slot = getBlockSlot(block);
348
348
  if (!slot) continue;
349
- fields[slot] = blockToSlotValue(block);
349
+ if (!(slot in fields)) fields[slot] = blockToSlotValue(block);
350
350
  }
351
351
  return fields;
352
352
  }
@@ -355,11 +355,13 @@ function createContentSlotReader(content) {
355
355
  const value = (key, fallback) => {
356
356
  return key in fields ? fields[key] : fallback;
357
357
  };
358
+ const unsafeHtml = (key, fallback = "") => stringifySlotValue(value(key, fallback));
358
359
  return {
359
360
  fields,
360
361
  value,
361
362
  text: (key, fallback = "") => stringifySlotValue(value(key, fallback)),
362
- html: (key, fallback = "") => stringifySlotValue(value(key, fallback)),
363
+ html: unsafeHtml,
364
+ unsafeHtml,
363
365
  list: (key, fallback = []) => slotValueToList(value(key, fallback)),
364
366
  image: (key, fallback) => slotValueToImage(value(key, fallback))
365
367
  };
@@ -755,25 +757,74 @@ function useAnalyticsRuntime(config) {
755
757
  function useAnalytics() {
756
758
  return useAxCloudContext().analytics;
757
759
  }
758
- var defaultQueryClient = new reactQuery.QueryClient({
759
- defaultOptions: {
760
- queries: {
761
- staleTime: 1e3 * 60 * 5,
762
- // 5 minutes
763
- gcTime: 1e3 * 60 * 30,
764
- // 30 minutes (garbage collection)
765
- retry: 2,
766
- refetchOnWindowFocus: false
767
- }
760
+
761
+ // src/react/auth/auth0Invitation.ts
762
+ var AUTH0_INVITATION_PATTERN = /^[A-Za-z0-9_-]{1,2048}$/;
763
+ function readAuth0InvitationAuthorizationParams(configuredOrganization, search = typeof window === "undefined" ? "" : window.location.search) {
764
+ if (!configuredOrganization || !search) return {};
765
+ const params = new URLSearchParams(search);
766
+ const invitation = params.get("invitation")?.trim();
767
+ const organization = params.get("organization")?.trim();
768
+ if (organization !== configuredOrganization || !invitation || !AUTH0_INVITATION_PATTERN.test(invitation)) {
769
+ return {};
768
770
  }
769
- });
771
+ return { invitation };
772
+ }
773
+ function createDefaultQueryClient() {
774
+ return new reactQuery.QueryClient({
775
+ defaultOptions: {
776
+ queries: {
777
+ staleTime: 1e3 * 60,
778
+ gcTime: 1e3 * 60 * 30,
779
+ retry: (failureCount, error) => {
780
+ if (isAxCloudError(error) && error.status >= 400 && error.status < 500) {
781
+ return false;
782
+ }
783
+ return failureCount < 2;
784
+ },
785
+ refetchOnWindowFocus: true
786
+ }
787
+ }
788
+ });
789
+ }
790
+ var queryClientAxCloudOwners = /* @__PURE__ */ new WeakMap();
791
+ function createQueryClientOwnerSignature(config, subject) {
792
+ return JSON.stringify([
793
+ subject === null ? "public" : "authenticated",
794
+ subject,
795
+ config.orgId,
796
+ config.stage,
797
+ config.apiUrl,
798
+ config.apiKey ?? null,
799
+ config.auth0.domain,
800
+ config.auth0.clientId,
801
+ config.auth0.audience ?? null,
802
+ config.auth0.organization ?? null,
803
+ config.auth0.connection ?? null
804
+ ]);
805
+ }
770
806
  function AxCloudInnerProvider({
771
807
  children,
772
808
  config,
809
+ queryClient,
773
810
  timeout
774
811
  }) {
775
- const { getAccessTokenSilently, isAuthenticated } = auth0React.useAuth0();
812
+ const { getAccessTokenSilently, isAuthenticated, isLoading, user } = auth0React.useAuth0();
776
813
  const analytics = useAnalyticsRuntime(config);
814
+ const [, setOwnerGeneration] = react.useState(0);
815
+ const currentSubject = isLoading ? void 0 : isAuthenticated ? user?.sub : null;
816
+ const currentOwnerSignature = currentSubject === void 0 ? void 0 : createQueryClientOwnerSignature(config, currentSubject);
817
+ const hasKnownOwner = queryClientAxCloudOwners.has(queryClient);
818
+ const ownerNeedsActivation = currentOwnerSignature !== void 0 && (!hasKnownOwner || queryClientAxCloudOwners.get(queryClient) !== currentOwnerSignature);
819
+ const clearContentCache = react.useCallback(() => {
820
+ queryClient.removeQueries({ queryKey: ["axcloud"] });
821
+ }, [queryClient]);
822
+ react.useLayoutEffect(() => {
823
+ if (currentOwnerSignature === void 0 || !ownerNeedsActivation) return;
824
+ clearContentCache();
825
+ queryClientAxCloudOwners.set(queryClient, currentOwnerSignature);
826
+ setOwnerGeneration((generation) => generation + 1);
827
+ }, [clearContentCache, currentOwnerSignature, ownerNeedsActivation, queryClient]);
777
828
  const tokenGetterRef = react.useRef(async () => void 0);
778
829
  tokenGetterRef.current = isAuthenticated ? async () => {
779
830
  try {
@@ -803,12 +854,17 @@ function AxCloudInnerProvider({
803
854
  client,
804
855
  orgId: config.orgId,
805
856
  stage: config.stage,
806
- isPublicMode: Boolean(config.apiKey) && !isAuthenticated,
857
+ isPublicMode: !isAuthenticated,
858
+ isAuthLoading: isLoading,
859
+ isAuthenticated,
860
+ authSubject: isAuthenticated ? user?.sub : void 0,
861
+ clearContentCache,
807
862
  analytics
808
863
  }),
809
- [config, client, isAuthenticated, analytics]
864
+ [config, client, isAuthenticated, isLoading, user?.sub, clearContentCache, analytics]
810
865
  );
811
- return /* @__PURE__ */ jsxRuntime.jsx(AxCloudContext.Provider, { value: contextValue, children });
866
+ const identityReady = currentOwnerSignature !== void 0 && !ownerNeedsActivation;
867
+ return /* @__PURE__ */ jsxRuntime.jsx(AxCloudContext.Provider, { value: contextValue, children: identityReady ? children : null });
812
868
  }
813
869
  function AxCloudProvider({
814
870
  children,
@@ -818,9 +874,12 @@ function AxCloudProvider({
818
874
  apiKey,
819
875
  analytics,
820
876
  auth0,
821
- queryClient = defaultQueryClient,
877
+ queryClient: providedQueryClient,
822
878
  timeout
823
879
  }) {
880
+ const [ownedQueryClient] = react.useState(createDefaultQueryClient);
881
+ const queryClient = providedQueryClient || ownedQueryClient;
882
+ const invitationAuthorizationParams = readAuth0InvitationAuthorizationParams(auth0.organization);
824
883
  const config = react.useMemo(
825
884
  () => ({
826
885
  orgId,
@@ -840,14 +899,15 @@ function AxCloudProvider({
840
899
  authorizationParams: {
841
900
  redirect_uri: auth0.redirectUri,
842
901
  audience: auth0.audience,
843
- ...auth0.organization ? { organization: auth0.organization } : {}
902
+ ...auth0.organization ? { organization: auth0.organization } : {},
903
+ ...invitationAuthorizationParams
844
904
  },
845
- children: /* @__PURE__ */ jsxRuntime.jsx(AxCloudInnerProvider, { config, timeout, children })
905
+ children: /* @__PURE__ */ jsxRuntime.jsx(AxCloudInnerProvider, { config, queryClient, timeout, children })
846
906
  }
847
907
  ) });
848
908
  }
849
909
  function useAuth() {
850
- const { config, client } = useAxCloudContext();
910
+ const { config, client, clearContentCache } = useAxCloudContext();
851
911
  const {
852
912
  isAuthenticated,
853
913
  isLoading,
@@ -860,13 +920,17 @@ function useAuth() {
860
920
  } = auth0React.useAuth0();
861
921
  const login = react.useCallback(
862
922
  (options) => {
923
+ const invitationAuthorizationParams = readAuth0InvitationAuthorizationParams(
924
+ config.auth0.organization
925
+ );
863
926
  return loginWithRedirect({
864
927
  appState: {
865
928
  returnTo: options?.returnTo || window.location.pathname
866
929
  },
867
930
  ...config.auth0.organization ? {
868
931
  authorizationParams: {
869
- organization: config.auth0.organization
932
+ organization: config.auth0.organization,
933
+ ...invitationAuthorizationParams
870
934
  }
871
935
  } : {}
872
936
  });
@@ -875,13 +939,14 @@ function useAuth() {
875
939
  );
876
940
  const logout = react.useCallback(
877
941
  (options) => {
942
+ clearContentCache?.();
878
943
  return auth0Logout({
879
944
  logoutParams: {
880
945
  returnTo: options?.returnTo || window.location.origin
881
946
  }
882
947
  });
883
948
  },
884
- [auth0Logout]
949
+ [auth0Logout, clearContentCache]
885
950
  );
886
951
  const getAccessToken = react.useCallback(async () => {
887
952
  try {
@@ -1032,24 +1097,167 @@ function useAuth() {
1032
1097
  requestPasswordReset
1033
1098
  };
1034
1099
  }
1100
+ var currentUserQueryKey = (stage, orgId, subject) => ["axcloud", "user", "me", stage, orgId, subject];
1101
+ function asRecord(value) {
1102
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
1103
+ }
1104
+ function asString(value) {
1105
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
1106
+ }
1107
+ function asStringArray(value) {
1108
+ if (!Array.isArray(value)) return [];
1109
+ return Array.from(new Set(value.map(asString).filter((item) => item !== null)));
1110
+ }
1111
+ function normalizeMembershipSections(rawMembership) {
1112
+ const sections = /* @__PURE__ */ new Map();
1113
+ const addSection = (idValue, nameValue, roleValue) => {
1114
+ const id = asString(idValue);
1115
+ if (!id) return;
1116
+ const existing = sections.get(id);
1117
+ sections.set(id, {
1118
+ id,
1119
+ name: asString(nameValue) || existing?.name || id,
1120
+ role: asString(roleValue) || existing?.role || "member"
1121
+ });
1122
+ };
1123
+ const directSections = rawMembership.sections;
1124
+ if (Array.isArray(directSections)) {
1125
+ for (const rawSection of directSections) {
1126
+ if (typeof rawSection === "string") {
1127
+ addSection(rawSection);
1128
+ continue;
1129
+ }
1130
+ const section = asRecord(rawSection);
1131
+ addSection(
1132
+ section.id ?? section.sectionId ?? section.section_id,
1133
+ section.name ?? section.sectionName ?? section.section_name,
1134
+ section.role
1135
+ );
1136
+ }
1137
+ }
1138
+ const sectionMemberships = asRecord(
1139
+ rawMembership.sectionMemberships ?? rawMembership.section_memberships
1140
+ );
1141
+ for (const [sectionId, rawSectionMembership] of Object.entries(sectionMemberships)) {
1142
+ const sectionMembership = asRecord(rawSectionMembership);
1143
+ addSection(
1144
+ sectionId,
1145
+ sectionMembership.name ?? sectionMembership.sectionName ?? sectionMembership.section_name,
1146
+ sectionMembership.role
1147
+ );
1148
+ }
1149
+ for (const sectionId of asStringArray(rawMembership.sectionIds ?? rawMembership.section_ids)) {
1150
+ addSection(sectionId);
1151
+ }
1152
+ const primarySectionId = asString(rawMembership.sectionId ?? rawMembership.section_id);
1153
+ if (primarySectionId) addSection(primarySectionId);
1154
+ const normalized = Array.from(sections.values());
1155
+ if (!primarySectionId) return normalized;
1156
+ return normalized.sort((left, right) => {
1157
+ if (left.id === primarySectionId) return -1;
1158
+ if (right.id === primarySectionId) return 1;
1159
+ return 0;
1160
+ });
1161
+ }
1162
+ function normalizeMembership(rawValue) {
1163
+ const raw = asRecord(rawValue);
1164
+ const role = asString(raw.role) || "member";
1165
+ const roles = asStringArray(raw.roles);
1166
+ const sections = normalizeMembershipSections(raw);
1167
+ const sectionId = asString(raw.sectionId ?? raw.section_id) || sections[0]?.id || null;
1168
+ const joinedAt = asString(raw.joinedAt ?? raw.joined_at);
1169
+ return {
1170
+ role,
1171
+ roles: roles.length > 0 ? roles : [role],
1172
+ title: asString(raw.title),
1173
+ status: asString(raw.status),
1174
+ joinedAt,
1175
+ memberSince: asString(raw.memberSince ?? raw.member_since) || joinedAt,
1176
+ sectionId,
1177
+ sectionIds: sections.map((section) => section.id),
1178
+ sections
1179
+ };
1180
+ }
1181
+ function normalizeCurrentUserResponse(raw, configuredOrgId) {
1182
+ const rawMemberships = asRecord(
1183
+ raw.organizationMemberships ?? raw.organization_memberships
1184
+ );
1185
+ const organizationMemberships = Object.fromEntries(
1186
+ Object.entries(rawMemberships).map(([organizationId2, membership]) => [
1187
+ organizationId2,
1188
+ normalizeMembership(membership)
1189
+ ])
1190
+ );
1191
+ const allOrgIds = Array.from(
1192
+ /* @__PURE__ */ new Set([
1193
+ ...asStringArray(raw.allOrgIds ?? raw.all_org_ids),
1194
+ ...Object.keys(organizationMemberships)
1195
+ ])
1196
+ );
1197
+ const effectiveOrganizationId = asString(
1198
+ raw.effectiveOrganizationId ?? raw.effective_org_id
1199
+ );
1200
+ const primaryOrganizationId = asString(
1201
+ raw.organizationId ?? raw.primary_org_id ?? raw.org_id
1202
+ );
1203
+ const organizationId = effectiveOrganizationId || primaryOrganizationId || (organizationMemberships[configuredOrgId] ? configuredOrgId : null) || allOrgIds[0] || configuredOrgId;
1204
+ const configuredMembership = organizationMemberships[configuredOrgId];
1205
+ const firstName = asString(raw.firstName ?? raw.first_name ?? raw.given_name) || "";
1206
+ const lastName = asString(raw.lastName ?? raw.last_name ?? raw.family_name) || "";
1207
+ const email = asString(raw.email) || "";
1208
+ const createdAt = asString(raw.createdAt ?? raw.created_at) || "";
1209
+ const updatedAt = asString(raw.updatedAt ?? raw.updated_at) || createdAt;
1210
+ const role = configuredMembership?.role || asString(raw.role) || "member";
1211
+ const sectionId = configuredMembership?.sectionId || asString(raw.sectionId ?? raw.section_id);
1212
+ const permissions = asStringArray(raw.permissions ?? raw.effective_permissions);
1213
+ const metadata = asRecord(raw.metadata);
1214
+ return {
1215
+ id: asString(raw.id ?? raw.userId ?? raw.user_id ?? raw.sub) || "",
1216
+ email,
1217
+ name: asString(raw.name) || [firstName, lastName].filter(Boolean).join(" ") || email,
1218
+ firstName,
1219
+ lastName,
1220
+ title: configuredMembership?.title ?? asString(raw.title),
1221
+ phone: asString(raw.phone ?? raw.phoneNumber ?? raw.phone_number),
1222
+ address: asString(raw.address ?? raw.location),
1223
+ avatar: asString(raw.avatar ?? raw.avatarUrl ?? raw.avatar_url ?? raw.picture) || void 0,
1224
+ organizationId,
1225
+ ...sectionId ? { sectionId } : {},
1226
+ role,
1227
+ permissions,
1228
+ ...Object.keys(metadata).length > 0 ? { metadata } : {},
1229
+ createdAt,
1230
+ updatedAt,
1231
+ allOrgIds,
1232
+ organizationMemberships,
1233
+ effectiveOrganizationId,
1234
+ isSuperAdmin: raw.isSuperAdmin === true || raw.is_super_admin === true || asString(raw.global_role) === "super_admin" || role === "super_admin"
1235
+ };
1236
+ }
1035
1237
  function useUser() {
1036
1238
  const { isAuthenticated, isLoading: isAuthLoading, user: auth0User } = auth0React.useAuth0();
1037
1239
  const { client, stage, orgId } = useAxCloudContext();
1240
+ const queryKey = currentUserQueryKey(stage, orgId, auth0User?.sub);
1038
1241
  const query = reactQuery.useQuery({
1039
- queryKey: ["axcloud", "user", "me", stage, orgId, auth0User?.sub],
1242
+ queryKey,
1040
1243
  queryFn: async () => {
1041
- return client.get("/api/users/me");
1244
+ const response = await client.get("/api/users/me");
1245
+ return normalizeCurrentUserResponse(response, orgId);
1042
1246
  },
1043
1247
  enabled: isAuthenticated && !isAuthLoading,
1044
1248
  staleTime: 1e3 * 60 * 5
1045
1249
  // 5 minutes
1046
1250
  });
1047
1251
  const userData = query.data;
1048
- const userOrgIds = userData?.all_org_ids ?? [];
1252
+ const userOrgIds = userData?.allOrgIds ?? [];
1049
1253
  const isSuperAdmin = userData?.isSuperAdmin === true;
1050
- const hasOrgAccess = userOrgIds.includes(orgId);
1051
- const orgMembership = userData?.organization_memberships?.[orgId];
1254
+ const orgMembership = userData?.organizationMemberships?.[orgId];
1255
+ const hasOrgAccess = userOrgIds.includes(orgId) && orgMembership?.status?.trim().toLowerCase() === "active";
1052
1256
  const roleInOrg = orgMembership?.role ?? null;
1257
+ const sectionId = orgMembership?.sectionId ?? userData?.sectionId ?? null;
1258
+ const sections = orgMembership?.sections?.length ? orgMembership.sections : sectionId ? [{ id: sectionId, name: sectionId, role: roleInOrg ?? "member" }] : [];
1259
+ const section = sections.find((item) => item.id === sectionId) ?? sections[0] ?? null;
1260
+ const memberSince = orgMembership?.memberSince ?? null;
1053
1261
  return {
1054
1262
  user: query.data ?? null,
1055
1263
  isLoading: isAuthLoading || query.isLoading,
@@ -1059,15 +1267,35 @@ function useUser() {
1059
1267
  // Organization access
1060
1268
  hasOrgAccess,
1061
1269
  roleInOrg,
1270
+ organizationMembership: orgMembership ?? null,
1271
+ title: orgMembership?.title ?? query.data?.title ?? null,
1272
+ section,
1273
+ sections,
1274
+ sectionIds: orgMembership?.sectionIds?.length ? orgMembership.sectionIds : sectionId ? [sectionId] : [],
1275
+ joinedAt: orgMembership?.joinedAt ?? null,
1276
+ memberSince,
1062
1277
  // Convenience properties
1063
1278
  isAuthenticated,
1064
- role: query.data?.role ?? null,
1279
+ role: roleInOrg ?? query.data?.role ?? null,
1065
1280
  organizationId: query.data?.organizationId ?? null,
1066
- sectionId: query.data?.sectionId ?? null,
1281
+ sectionId,
1067
1282
  permissions: query.data?.permissions ?? [],
1068
1283
  isSuperAdmin
1069
1284
  };
1070
1285
  }
1286
+ function useUpdateMyProfile() {
1287
+ const { client, stage } = useAxCloudContext();
1288
+ const queryClient = reactQuery.useQueryClient();
1289
+ return reactQuery.useMutation({
1290
+ mutationFn: (updates) => client.patch("/api/users/me/profile", updates),
1291
+ onSuccess: async () => {
1292
+ await queryClient.invalidateQueries({
1293
+ queryKey: ["axcloud", "user", "me", stage],
1294
+ exact: false
1295
+ });
1296
+ }
1297
+ });
1298
+ }
1071
1299
  function useOrg() {
1072
1300
  const { client, orgId, stage, isPublicMode } = useAxCloudContext();
1073
1301
  const usePublicEndpoint = isPublicMode;
@@ -1114,152 +1342,169 @@ function useOrg() {
1114
1342
  modules
1115
1343
  };
1116
1344
  }
1117
- function useNews(options = {}) {
1118
- const { client, orgId, isPublicMode } = useAxCloudContext();
1119
- const {
1120
- page = 1,
1121
- pageSize = 20,
1122
- status = "published",
1123
- visibility,
1124
- sectionId,
1125
- search,
1126
- sortBy = "publishedAt",
1127
- sortOrder = "desc",
1128
- lang,
1129
- publicOnly = false
1130
- } = options;
1131
- const usePublicEndpoint = isPublicMode || publicOnly;
1132
- const query = reactQuery.useQuery({
1133
- queryKey: [
1134
- "axcloud",
1135
- "news",
1136
- orgId,
1137
- usePublicEndpoint,
1138
- page,
1139
- pageSize,
1140
- status,
1141
- visibility,
1142
- sectionId,
1143
- search,
1144
- sortBy,
1145
- sortOrder,
1146
- lang
1147
- ],
1148
- queryFn: async () => {
1149
- const endpoint = usePublicEndpoint ? `/content/public/${orgId}/news` : `/content/members/${orgId}/news`;
1150
- return client.get(endpoint, {
1151
- page,
1152
- pageSize,
1153
- status,
1154
- visibility,
1155
- sectionId,
1156
- search,
1157
- sortBy,
1158
- sortOrder,
1159
- lang
1160
- });
1161
- },
1162
- staleTime: 1e3 * 60 * 5
1163
- // 5 minutes
1164
- });
1165
- return {
1166
- data: query.data?.items ?? [],
1167
- total: query.data?.total ?? 0,
1168
- hasMore: query.data?.hasMore ?? false,
1169
- isLoading: query.isLoading,
1170
- isError: query.isError,
1171
- error: query.error,
1172
- refetch: query.refetch
1173
- };
1345
+
1346
+ // src/react/contentQueryPolicy.ts
1347
+ var CONTENT_STALE_TIME_MS = 6e4;
1348
+ function shouldRetryContentRequest(failureCount, error) {
1349
+ if (isAxCloudError(error) && error.status >= 400 && error.status < 500) {
1350
+ return false;
1351
+ }
1352
+ return failureCount < 2;
1353
+ }
1354
+ function normalizeContentCollectionType(contentType) {
1355
+ switch (contentType.toLowerCase()) {
1356
+ case "news":
1357
+ return "news";
1358
+ case "page":
1359
+ case "pages":
1360
+ return "pages";
1361
+ case "event":
1362
+ case "events":
1363
+ return "events";
1364
+ default:
1365
+ throw new Error(`Unsupported AxCloud content collection type: ${contentType}`);
1366
+ }
1367
+ }
1368
+ function normalizeContentDetailType(contentType) {
1369
+ switch (contentType.toLowerCase()) {
1370
+ case "news":
1371
+ return "news";
1372
+ case "page":
1373
+ case "pages":
1374
+ return "page";
1375
+ case "event":
1376
+ case "events":
1377
+ return "event";
1378
+ default:
1379
+ throw new Error(`Unsupported AxCloud content detail type: ${contentType}`);
1380
+ }
1174
1381
  }
1175
- var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
1176
- var PAGE_CONTENT_TYPES = ["page", "pages"];
1382
+ function getContentAccessState(context, publicOnly) {
1383
+ if (publicOnly) {
1384
+ return { mode: "public", enabled: true, subject: "anonymous" };
1385
+ }
1386
+ const isLoading = context.isAuthLoading ?? false;
1387
+ if (isLoading) {
1388
+ return { mode: "pending", enabled: false, subject: "auth-loading" };
1389
+ }
1390
+ const hasExplicitAuthState = typeof context.isAuthenticated === "boolean";
1391
+ const isAuthenticated = context.isAuthenticated ?? !context.isPublicMode;
1392
+ if (!isAuthenticated) {
1393
+ return { mode: "public", enabled: true, subject: "anonymous" };
1394
+ }
1395
+ if (hasExplicitAuthState && !context.authSubject) {
1396
+ return { mode: "pending", enabled: false, subject: "auth-subject-pending" };
1397
+ }
1398
+ const subject = context.authSubject || "legacy-authenticated-session";
1399
+ return { mode: "member", enabled: Boolean(subject), subject };
1400
+ }
1401
+
1402
+ // src/react/hooks/useContent.ts
1177
1403
  function useContent(contentType, options = {}) {
1178
- const { client, orgId, isPublicMode } = useAxCloudContext();
1404
+ const context = useAxCloudContext();
1405
+ const { client, config, orgId, stage } = context;
1406
+ const collectionType = normalizeContentCollectionType(contentType);
1179
1407
  const {
1180
1408
  publicOnly = false,
1181
1409
  page = 1,
1182
1410
  pageSize = 20,
1183
- status = "published",
1184
- visibility,
1185
- sectionId,
1186
1411
  search,
1187
- sortBy = "createdAt",
1412
+ sortBy = collectionType === "news" ? "publishedAt" : "createdAt",
1188
1413
  sortOrder = "desc",
1414
+ tags,
1189
1415
  lang
1190
1416
  } = options;
1417
+ const access = getContentAccessState(context, publicOnly);
1418
+ const deliveryScope = access.mode === "member" ? "members" : "public";
1419
+ const params = {
1420
+ page,
1421
+ pageSize,
1422
+ search,
1423
+ sort: sortBy,
1424
+ order: sortOrder,
1425
+ tags: tags?.length ? tags.join(",") : void 0,
1426
+ lang
1427
+ };
1191
1428
  const query = reactQuery.useQuery({
1192
1429
  queryKey: [
1193
1430
  "axcloud",
1194
1431
  "content",
1432
+ "collection",
1433
+ stage,
1434
+ config.apiUrl,
1195
1435
  orgId,
1196
- contentType,
1197
- isPublicMode,
1198
- publicOnly,
1199
- page,
1200
- pageSize,
1201
- status,
1202
- visibility,
1203
- sectionId,
1204
- search,
1205
- sortBy,
1206
- sortOrder,
1207
- lang
1436
+ access.mode,
1437
+ access.subject,
1438
+ collectionType,
1439
+ params
1208
1440
  ],
1209
- queryFn: async () => {
1210
- const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
1211
- const endpoint = useMemberEndpoint ? `/content/members/${orgId}/${contentType}` : `/content/public/${orgId}/${contentType}`;
1212
- return client.get(endpoint, {
1213
- page,
1214
- pageSize,
1215
- status,
1216
- visibility,
1217
- sectionId,
1218
- search,
1219
- sortBy,
1220
- sortOrder,
1221
- lang
1222
- });
1223
- },
1224
- staleTime: 1e3 * 60 * 5
1225
- // 5 minutes
1441
+ queryFn: () => client.get(
1442
+ `/content/${deliveryScope}/${orgId}/${collectionType}`,
1443
+ params
1444
+ ),
1445
+ enabled: access.enabled,
1446
+ staleTime: CONTENT_STALE_TIME_MS,
1447
+ refetchOnWindowFocus: true,
1448
+ retry: shouldRetryContentRequest
1226
1449
  });
1450
+ const items = query.data?.items ?? [];
1227
1451
  return {
1228
- data: query.data?.items ?? [],
1229
- total: query.data?.total ?? 0,
1452
+ data: items,
1453
+ count: query.data?.count ?? items.length,
1454
+ total: query.data?.total ?? items.length,
1455
+ page: query.data?.page ?? page,
1456
+ pageSize: query.data?.pageSize ?? pageSize,
1230
1457
  hasMore: query.data?.hasMore ?? false,
1231
- isLoading: query.isLoading,
1458
+ nextCursor: query.data?.nextCursor,
1459
+ isLoading: access.mode === "pending" || query.isLoading,
1460
+ isFetching: query.isFetching,
1232
1461
  isError: query.isError,
1233
1462
  error: query.error,
1234
1463
  refetch: query.refetch
1235
1464
  };
1236
1465
  }
1237
1466
  function useContentItem(contentType, idOrSlug, options = {}) {
1238
- const { client, orgId, isPublicMode } = useAxCloudContext();
1467
+ const context = useAxCloudContext();
1468
+ const { client, config, orgId, stage } = context;
1469
+ const detailType = normalizeContentDetailType(contentType);
1239
1470
  const { publicOnly = false, lang } = options;
1240
- const useMemberEndpoint = !isPublicMode && !publicOnly && (MEMBER_ENDPOINT_TYPES.includes(contentType) || PAGE_CONTENT_TYPES.includes(contentType));
1471
+ const access = getContentAccessState(context, publicOnly);
1472
+ const deliveryScope = access.mode === "member" ? "members" : "public";
1241
1473
  const query = reactQuery.useQuery({
1242
- queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint, lang],
1243
- queryFn: async () => {
1244
- const basePath = useMemberEndpoint ? "members" : "public";
1474
+ queryKey: [
1475
+ "axcloud",
1476
+ "content",
1477
+ "item",
1478
+ stage,
1479
+ config.apiUrl,
1480
+ orgId,
1481
+ access.mode,
1482
+ access.subject,
1483
+ detailType,
1484
+ idOrSlug,
1485
+ lang
1486
+ ],
1487
+ queryFn: () => {
1245
1488
  const encodedIdOrSlug = encodeURIComponent(idOrSlug);
1246
- const endpoint = PAGE_CONTENT_TYPES.includes(contentType) ? `/content/${basePath}/${orgId}/page/${encodedIdOrSlug}` : `/content/${basePath}/${orgId}/${contentType}/${encodedIdOrSlug}`;
1489
+ const endpoint = `/content/${deliveryScope}/${orgId}/items/${detailType}/${encodedIdOrSlug}`;
1247
1490
  return lang ? client.get(endpoint, { lang }) : client.get(endpoint);
1248
1491
  },
1249
- enabled: !!idOrSlug,
1250
- staleTime: 1e3 * 60 * 5
1251
- // 5 minutes
1492
+ enabled: access.enabled && Boolean(idOrSlug),
1493
+ staleTime: CONTENT_STALE_TIME_MS,
1494
+ refetchOnWindowFocus: true,
1495
+ retry: shouldRetryContentRequest
1252
1496
  });
1253
1497
  return {
1254
1498
  data: query.data ?? null,
1255
- isLoading: query.isLoading,
1499
+ isLoading: access.mode === "pending" || query.isLoading,
1500
+ isFetching: query.isFetching,
1256
1501
  isError: query.isError,
1257
1502
  error: query.error,
1258
1503
  refetch: query.refetch
1259
1504
  };
1260
1505
  }
1261
1506
  function usePageContent(slug, options = {}) {
1262
- const state = useContentItem("pages", slug, options);
1507
+ const state = useContentItem("page", slug, options);
1263
1508
  const reader = react.useMemo(() => createContentSlotReader(state.data), [state.data]);
1264
1509
  return {
1265
1510
  ...state,
@@ -1267,6 +1512,11 @@ function usePageContent(slug, options = {}) {
1267
1512
  ...reader
1268
1513
  };
1269
1514
  }
1515
+
1516
+ // src/react/hooks/useNews.ts
1517
+ function useNews(options = {}) {
1518
+ return useContent("news", options);
1519
+ }
1270
1520
  function useMySection(options = {}) {
1271
1521
  const { includeMembers = true } = options;
1272
1522
  const { isAuthenticated } = auth0React.useAuth0();
@@ -1905,7 +2155,7 @@ function ProtectedRoute({
1905
2155
  returnTo
1906
2156
  }) {
1907
2157
  const { isAuthenticated, isLoading: isAuthLoading, login } = useAuth();
1908
- const { user, role, isLoading: isUserLoading } = useUser();
2158
+ const { role, isLoading: isUserLoading } = useUser();
1909
2159
  const isLoading = isAuthLoading || isAuthenticated && isUserLoading;
1910
2160
  if (isLoading) {
1911
2161
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultLoadingComponent, {}) });
@@ -1917,9 +2167,9 @@ function ProtectedRoute({
1917
2167
  }
1918
2168
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: unauthenticatedComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultUnauthenticatedComponent, {}) });
1919
2169
  }
1920
- if (roles && role) {
2170
+ if (roles) {
1921
2171
  const requiredRoles = Array.isArray(roles) ? roles : [roles];
1922
- const hasRequiredRole = requiredRoles.includes(role);
2172
+ const hasRequiredRole = role !== null && role !== void 0 && requiredRoles.includes(role);
1923
2173
  if (!hasRequiredRole) {
1924
2174
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: unauthorizedComponent ?? /* @__PURE__ */ jsxRuntime.jsx(DefaultUnauthorizedComponent, {}) });
1925
2175
  }
@@ -2155,6 +2405,7 @@ exports.usePageContent = usePageContent;
2155
2405
  exports.useSections = useSections;
2156
2406
  exports.useSubmitBarnsportInterest = useSubmitBarnsportInterest;
2157
2407
  exports.useUpdateFormSubmission = useUpdateFormSubmission;
2408
+ exports.useUpdateMyProfile = useUpdateMyProfile;
2158
2409
  exports.useUser = useUser;
2159
2410
  exports.userHasAllPermissions = userHasAllPermissions;
2160
2411
  exports.userHasAnyPermission = userHasAnyPermission;