@axcode/axcloud-sdk 0.1.7-dev.bf490b9 → 0.2.0-dev.03fb26c
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/README.md +102 -48
- package/dist/index.d.mts +141 -97
- package/dist/index.d.ts +141 -97
- package/dist/index.js +392 -141
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +394 -144
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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:
|
|
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
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
1242
|
+
queryKey,
|
|
1040
1243
|
queryFn: async () => {
|
|
1041
|
-
|
|
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?.
|
|
1252
|
+
const userOrgIds = userData?.allOrgIds ?? [];
|
|
1049
1253
|
const isSuperAdmin = userData?.isSuperAdmin === true;
|
|
1050
|
-
const
|
|
1051
|
-
const
|
|
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
|
|
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
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
"
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
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
|
-
|
|
1176
|
-
|
|
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
|
|
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
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
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:
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
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:
|
|
1229
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
1471
|
+
const access = getContentAccessState(context, publicOnly);
|
|
1472
|
+
const deliveryScope = access.mode === "member" ? "members" : "public";
|
|
1241
1473
|
const query = reactQuery.useQuery({
|
|
1242
|
-
queryKey: [
|
|
1243
|
-
|
|
1244
|
-
|
|
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 =
|
|
1489
|
+
const endpoint = `/content/${deliveryScope}/${orgId}/items/${detailType}/${encodedIdOrSlug}`;
|
|
1247
1490
|
return lang ? client.get(endpoint, { lang }) : client.get(endpoint);
|
|
1248
1491
|
},
|
|
1249
|
-
enabled:
|
|
1250
|
-
staleTime:
|
|
1251
|
-
|
|
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("
|
|
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 {
|
|
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
|
|
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;
|