@axcode/axcloud-sdk 0.1.0 → 0.1.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.
- package/README.md +30 -1
- package/dist/index.d.mts +6 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +97 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +97 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,35 @@ SDK for building websites with AxCloud CMS and member management.
|
|
|
8
8
|
npm install @axcode/axcloud-sdk
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
### Version Tags
|
|
12
|
+
|
|
13
|
+
The SDK is published with two tags for different environments:
|
|
14
|
+
|
|
15
|
+
| Tag | Purpose | Stability | Install |
|
|
16
|
+
|-----|---------|-----------|---------|
|
|
17
|
+
| `latest` | Production | Stable, tested | `npm install @axcode/axcloud-sdk` |
|
|
18
|
+
| `next` | Development/Staging | Preview, may have breaking changes | `npm install @axcode/axcloud-sdk@next` |
|
|
19
|
+
|
|
20
|
+
**Recommended setup:**
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
// Production project (package.json)
|
|
24
|
+
{
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@axcode/axcloud-sdk": "^0.1.0"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Development/Staging project (package.json)
|
|
31
|
+
{
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@axcode/axcloud-sdk": "next"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This allows you to test new SDK features in your staging environment before they reach production.
|
|
39
|
+
|
|
11
40
|
## Quick Start
|
|
12
41
|
|
|
13
42
|
### 1. Wrap your app with AxCloudProvider
|
|
@@ -20,7 +49,7 @@ function App() {
|
|
|
20
49
|
<AxCloudProvider
|
|
21
50
|
orgId="org_ba81807b" // Your organization ID
|
|
22
51
|
apiUrl="https://api.axcloud.app"
|
|
23
|
-
apiKey="
|
|
52
|
+
apiKey="pk_live_..." // Public API key from Settings → API Keys
|
|
24
53
|
auth0={{
|
|
25
54
|
domain: "auth.axcloud.app",
|
|
26
55
|
clientId: "your-client-id",
|
package/dist/index.d.mts
CHANGED
|
@@ -37,6 +37,11 @@ declare class AxCloudClient {
|
|
|
37
37
|
* Build URL with query parameters
|
|
38
38
|
*/
|
|
39
39
|
private buildUrl;
|
|
40
|
+
/**
|
|
41
|
+
* API key should only be sent to public endpoints.
|
|
42
|
+
* This avoids leaking public keys to authenticated/internal routes.
|
|
43
|
+
*/
|
|
44
|
+
private shouldAttachApiKey;
|
|
40
45
|
/**
|
|
41
46
|
* Make an authenticated request
|
|
42
47
|
*/
|
|
@@ -761,7 +766,7 @@ declare function useOrg(): {
|
|
|
761
766
|
* @example
|
|
762
767
|
* // With pagination
|
|
763
768
|
* ```tsx
|
|
764
|
-
* const { data, hasMore,
|
|
769
|
+
* const { data, hasMore, refetch } = useNews({
|
|
765
770
|
* pageSize: 10,
|
|
766
771
|
* status: 'published'
|
|
767
772
|
* })
|
package/dist/index.d.ts
CHANGED
|
@@ -37,6 +37,11 @@ declare class AxCloudClient {
|
|
|
37
37
|
* Build URL with query parameters
|
|
38
38
|
*/
|
|
39
39
|
private buildUrl;
|
|
40
|
+
/**
|
|
41
|
+
* API key should only be sent to public endpoints.
|
|
42
|
+
* This avoids leaking public keys to authenticated/internal routes.
|
|
43
|
+
*/
|
|
44
|
+
private shouldAttachApiKey;
|
|
40
45
|
/**
|
|
41
46
|
* Make an authenticated request
|
|
42
47
|
*/
|
|
@@ -761,7 +766,7 @@ declare function useOrg(): {
|
|
|
761
766
|
* @example
|
|
762
767
|
* // With pagination
|
|
763
768
|
* ```tsx
|
|
764
|
-
* const { data, hasMore,
|
|
769
|
+
* const { data, hasMore, refetch } = useNews({
|
|
765
770
|
* pageSize: 10,
|
|
766
771
|
* status: 'published'
|
|
767
772
|
* })
|
package/dist/index.js
CHANGED
|
@@ -118,6 +118,14 @@ var AxCloudClient = class {
|
|
|
118
118
|
}
|
|
119
119
|
return url.toString();
|
|
120
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* API key should only be sent to public endpoints.
|
|
123
|
+
* This avoids leaking public keys to authenticated/internal routes.
|
|
124
|
+
*/
|
|
125
|
+
shouldAttachApiKey(path) {
|
|
126
|
+
const normalized = path.startsWith("/") ? path : `/${path}`;
|
|
127
|
+
return normalized.startsWith("/public/") || normalized.startsWith("/api/public/") || normalized.startsWith("/content/public/");
|
|
128
|
+
}
|
|
121
129
|
/**
|
|
122
130
|
* Make an authenticated request
|
|
123
131
|
*/
|
|
@@ -130,7 +138,7 @@ var AxCloudClient = class {
|
|
|
130
138
|
const customHeadersRecord = customHeaders;
|
|
131
139
|
Object.assign(headers, customHeadersRecord);
|
|
132
140
|
}
|
|
133
|
-
if (this.apiKey) {
|
|
141
|
+
if (this.apiKey && this.shouldAttachApiKey(path)) {
|
|
134
142
|
headers["x-api-key"] = this.apiKey;
|
|
135
143
|
}
|
|
136
144
|
if (this.getAccessToken) {
|
|
@@ -249,30 +257,55 @@ function userHasAllPermissions(user, permissions) {
|
|
|
249
257
|
|
|
250
258
|
// src/core/forms.ts
|
|
251
259
|
async function submitForm(apiUrl, submission) {
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
260
|
+
const baseUrl = apiUrl.replace(/\/$/, "");
|
|
261
|
+
try {
|
|
262
|
+
const response = await fetch(`${baseUrl}/public/submit`, {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: {
|
|
265
|
+
"Content-Type": "application/json"
|
|
266
|
+
},
|
|
267
|
+
body: JSON.stringify({
|
|
268
|
+
api_key: submission.apiKey,
|
|
269
|
+
site: submission.site,
|
|
270
|
+
form_type: submission.formType,
|
|
271
|
+
email: submission.email,
|
|
272
|
+
data: submission.data || {}
|
|
273
|
+
})
|
|
274
|
+
});
|
|
275
|
+
if (!response.ok) {
|
|
276
|
+
const error = await response.json().catch(() => ({ message: "Form submission failed" }));
|
|
277
|
+
throw new Error(error.message || "Form submission failed");
|
|
278
|
+
}
|
|
279
|
+
const result = await response.json();
|
|
280
|
+
return {
|
|
281
|
+
success: result.success,
|
|
282
|
+
message: result.message,
|
|
283
|
+
submissionId: result.submission_id
|
|
284
|
+
};
|
|
285
|
+
} catch (primaryError) {
|
|
286
|
+
try {
|
|
287
|
+
const notifyResponse = await fetch(`${baseUrl}/public/notify`, {
|
|
288
|
+
method: "POST",
|
|
289
|
+
headers: { "Content-Type": "application/json" },
|
|
290
|
+
body: JSON.stringify({
|
|
291
|
+
api_key: submission.apiKey,
|
|
292
|
+
site: submission.site,
|
|
293
|
+
form_type: submission.formType,
|
|
294
|
+
email: submission.email
|
|
295
|
+
})
|
|
296
|
+
});
|
|
297
|
+
if (notifyResponse.ok) {
|
|
298
|
+
const result = await notifyResponse.json();
|
|
299
|
+
return {
|
|
300
|
+
success: true,
|
|
301
|
+
message: result.message || "Thanks! We'll notify you when we launch.",
|
|
302
|
+
submissionId: "fallback"
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
} catch {
|
|
306
|
+
}
|
|
307
|
+
throw primaryError;
|
|
269
308
|
}
|
|
270
|
-
const result = await response.json();
|
|
271
|
-
return {
|
|
272
|
-
success: result.success,
|
|
273
|
-
message: result.message,
|
|
274
|
-
submissionId: result.submission_id
|
|
275
|
-
};
|
|
276
309
|
}
|
|
277
310
|
function createFormHelper(config) {
|
|
278
311
|
return {
|
|
@@ -572,8 +605,8 @@ function useUser() {
|
|
|
572
605
|
};
|
|
573
606
|
}
|
|
574
607
|
function useOrg() {
|
|
575
|
-
const { client, orgId, stage,
|
|
576
|
-
const usePublicEndpoint =
|
|
608
|
+
const { client, orgId, stage, isPublicMode } = useAxCloudContext();
|
|
609
|
+
const usePublicEndpoint = isPublicMode;
|
|
577
610
|
const query = reactQuery.useQuery({
|
|
578
611
|
queryKey: ["axcloud", "organization", orgId, stage, usePublicEndpoint],
|
|
579
612
|
queryFn: async () => {
|
|
@@ -632,7 +665,20 @@ function useNews(options = {}) {
|
|
|
632
665
|
} = options;
|
|
633
666
|
const usePublicEndpoint = isPublicMode || publicOnly;
|
|
634
667
|
const query = reactQuery.useQuery({
|
|
635
|
-
queryKey: [
|
|
668
|
+
queryKey: [
|
|
669
|
+
"axcloud",
|
|
670
|
+
"news",
|
|
671
|
+
orgId,
|
|
672
|
+
usePublicEndpoint,
|
|
673
|
+
page,
|
|
674
|
+
pageSize,
|
|
675
|
+
status,
|
|
676
|
+
visibility,
|
|
677
|
+
sectionId,
|
|
678
|
+
search,
|
|
679
|
+
sortBy,
|
|
680
|
+
sortOrder
|
|
681
|
+
],
|
|
636
682
|
queryFn: async () => {
|
|
637
683
|
const endpoint = usePublicEndpoint ? `/content/public/${orgId}/news` : `/content/members/${orgId}/news`;
|
|
638
684
|
return client.get(endpoint, {
|
|
@@ -663,6 +709,7 @@ var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
|
|
|
663
709
|
function useContent(contentType, options = {}) {
|
|
664
710
|
const { client, orgId, isPublicMode } = useAxCloudContext();
|
|
665
711
|
const {
|
|
712
|
+
publicOnly = false,
|
|
666
713
|
page = 1,
|
|
667
714
|
pageSize = 20,
|
|
668
715
|
status = "published",
|
|
@@ -673,9 +720,24 @@ function useContent(contentType, options = {}) {
|
|
|
673
720
|
sortOrder = "desc"
|
|
674
721
|
} = options;
|
|
675
722
|
const query = reactQuery.useQuery({
|
|
676
|
-
queryKey: [
|
|
723
|
+
queryKey: [
|
|
724
|
+
"axcloud",
|
|
725
|
+
"content",
|
|
726
|
+
orgId,
|
|
727
|
+
contentType,
|
|
728
|
+
isPublicMode,
|
|
729
|
+
publicOnly,
|
|
730
|
+
page,
|
|
731
|
+
pageSize,
|
|
732
|
+
status,
|
|
733
|
+
visibility,
|
|
734
|
+
sectionId,
|
|
735
|
+
search,
|
|
736
|
+
sortBy,
|
|
737
|
+
sortOrder
|
|
738
|
+
],
|
|
677
739
|
queryFn: async () => {
|
|
678
|
-
const useMemberEndpoint = !isPublicMode && MEMBER_ENDPOINT_TYPES.includes(contentType);
|
|
740
|
+
const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
|
|
679
741
|
const endpoint = useMemberEndpoint ? `/content/members/${orgId}/${contentType}` : `/content/public/${orgId}/${contentType}`;
|
|
680
742
|
return client.get(endpoint, {
|
|
681
743
|
page,
|
|
@@ -781,7 +843,7 @@ function useForms(options = {}) {
|
|
|
781
843
|
const { client, stage } = useAxCloudContext();
|
|
782
844
|
const { formType, status, limit = 50, cursor } = options;
|
|
783
845
|
const query = reactQuery.useQuery({
|
|
784
|
-
queryKey: ["axcloud", "forms", "submissions", stage,
|
|
846
|
+
queryKey: ["axcloud", "forms", "submissions", stage, formType, status, limit, cursor],
|
|
785
847
|
queryFn: async () => {
|
|
786
848
|
const params = { limit };
|
|
787
849
|
if (formType) params.form_type = formType;
|
|
@@ -842,13 +904,13 @@ function useUpdateFormSubmission() {
|
|
|
842
904
|
}
|
|
843
905
|
var LINKED_ACCOUNTS_QUERY_KEY = ["axcloud", "linked-accounts"];
|
|
844
906
|
function useLinkedAccounts() {
|
|
907
|
+
const { client, stage } = useAxCloudContext();
|
|
845
908
|
const { isAuthenticated } = useAuth();
|
|
846
909
|
const queryClient = reactQuery.useQueryClient();
|
|
847
910
|
const query = reactQuery.useQuery({
|
|
848
|
-
queryKey: LINKED_ACCOUNTS_QUERY_KEY,
|
|
911
|
+
queryKey: [...LINKED_ACCOUNTS_QUERY_KEY, stage],
|
|
849
912
|
queryFn: async () => {
|
|
850
|
-
|
|
851
|
-
return client.get("/api/users/me/identities");
|
|
913
|
+
return client.get(`/${stage}/api/users/me/identities`);
|
|
852
914
|
},
|
|
853
915
|
enabled: isAuthenticated,
|
|
854
916
|
staleTime: 1e3 * 60 * 5
|
|
@@ -856,9 +918,8 @@ function useLinkedAccounts() {
|
|
|
856
918
|
});
|
|
857
919
|
const linkMutation = reactQuery.useMutation({
|
|
858
920
|
mutationFn: async (provider) => {
|
|
859
|
-
const client = getClient();
|
|
860
921
|
const response = await client.post(
|
|
861
|
-
|
|
922
|
+
`/${stage}/api/users/me/identities/${provider}/link`,
|
|
862
923
|
{}
|
|
863
924
|
);
|
|
864
925
|
if (response.authorization_url) {
|
|
@@ -872,9 +933,8 @@ function useLinkedAccounts() {
|
|
|
872
933
|
});
|
|
873
934
|
const unlinkMutation = reactQuery.useMutation({
|
|
874
935
|
mutationFn: async (provider) => {
|
|
875
|
-
const client = getClient();
|
|
876
936
|
return client.delete(
|
|
877
|
-
|
|
937
|
+
`/${stage}/api/users/me/identities/${provider}`
|
|
878
938
|
);
|
|
879
939
|
},
|
|
880
940
|
onSuccess: () => {
|