@axcode/axcloud-sdk 0.1.4 → 0.1.5

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/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ # AxCloud SDK License
2
+
3
+ Copyright (c) 2026 Axcode AB. All rights reserved.
4
+
5
+ This package is proprietary software owned by Axcode AB.
6
+
7
+ Use, copying, modification, distribution, or sublicensing of this package is only permitted under a separate written agreement with Axcode AB.
8
+
9
+ No open source license is granted.
package/README.md CHANGED
@@ -87,6 +87,21 @@ function NewsPage() {
87
87
 
88
88
  > **Content visibility:** When the user is authenticated, `useNews`, `useContent('pages')`, and `useContent('events')` automatically fetch **public + internal + members-only** content based on the user's organization membership. For anonymous users, only public content is returned.
89
89
 
90
+ Pages can be stored once in AxCloud with translations and requested per language:
91
+
92
+ ```tsx
93
+ import { useContentItem } from '@axcode/axcloud-sdk'
94
+
95
+ function AboutPage({ locale }: { locale: 'sv' | 'en' }) {
96
+ const { data: page } = useContentItem('pages', 'about-us', {
97
+ lang: locale,
98
+ publicOnly: true,
99
+ })
100
+
101
+ return <h1>{page?.title}</h1>
102
+ }
103
+ ```
104
+
90
105
  ### 3. Add authentication
91
106
 
92
107
  ```tsx
@@ -254,11 +269,14 @@ interface ContentQueryOptions {
254
269
  page?: number // Page number (default: 1)
255
270
  pageSize?: number // Items per page (default: 20)
256
271
  status?: 'draft' | 'published' | 'archived'
257
- visibility?: 'public' | 'members' | 'section'
272
+ visibility?: 'draft' | 'published' | 'archived'
273
+ audience?: 'public' | 'internal' | 'members' | 'section'
258
274
  sectionId?: string // Filter by specific section
259
275
  search?: string // Search in title/content
260
276
  sortBy?: string // Sort field (default: 'createdAt')
261
277
  sortOrder?: 'asc' | 'desc'
278
+ lang?: string // Return translated title/slug/blocks when available
279
+ publicOnly?: boolean // Force public endpoint even when authenticated
262
280
  }
263
281
  ```
264
282
 
package/dist/index.d.mts CHANGED
@@ -197,21 +197,66 @@ interface Membership {
197
197
  expiresAt?: string;
198
198
  metadata?: Record<string, unknown>;
199
199
  }
200
+ interface ContentBlock {
201
+ id: string;
202
+ type: string;
203
+ content?: string;
204
+ url?: string;
205
+ alt?: string;
206
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
207
+ items?: unknown[];
208
+ language?: string;
209
+ caption?: string;
210
+ attributes?: Record<string, unknown>;
211
+ ordered?: boolean;
212
+ author?: string;
213
+ }
214
+ interface ContentTranslation {
215
+ title: string;
216
+ slug: string;
217
+ description?: string;
218
+ blocks: ContentBlock[];
219
+ metaTitle?: string;
220
+ metaDescription?: string;
221
+ keywords?: string[];
222
+ }
223
+ type ContentPublicationState = 'draft' | 'published' | 'archived';
224
+ type ContentAudience = 'public' | 'internal' | 'members' | 'section';
200
225
  interface ContentItem {
201
226
  id: string;
202
227
  organizationId: string;
203
228
  type: string;
204
229
  title: string;
205
230
  slug: string;
206
- content: string;
231
+ /** Legacy string content. New AxCloud content uses `blocks`. */
232
+ content?: string;
233
+ description?: string;
234
+ blocks?: ContentBlock[];
207
235
  excerpt?: string;
208
236
  author?: {
209
237
  id: string;
210
238
  name: string;
211
239
  };
212
- status: 'draft' | 'published' | 'archived';
213
- visibility: 'public' | 'members' | 'section';
240
+ status?: ContentPublicationState;
241
+ visibility?: ContentPublicationState;
242
+ audience?: ContentAudience;
214
243
  sectionId?: string;
244
+ tags?: string[];
245
+ lang?: string;
246
+ featuredImage?: string;
247
+ metaTitle?: string;
248
+ metaDescription?: string;
249
+ keywords?: string[];
250
+ translations?: Record<string, ContentTranslation>;
251
+ currentLanguage?: string;
252
+ availableLanguages?: string[];
253
+ seo?: {
254
+ canonical: string;
255
+ hreflang: Array<{
256
+ lang: string;
257
+ href: string;
258
+ }>;
259
+ };
215
260
  publishedAt?: string;
216
261
  createdAt: string;
217
262
  updatedAt: string;
@@ -253,12 +298,15 @@ interface AxCloudConfig {
253
298
  interface ContentQueryOptions {
254
299
  page?: number;
255
300
  pageSize?: number;
256
- status?: 'draft' | 'published' | 'archived';
257
- visibility?: 'public' | 'members' | 'section';
301
+ status?: ContentPublicationState;
302
+ visibility?: ContentPublicationState;
303
+ audience?: ContentAudience;
258
304
  sectionId?: string;
259
305
  search?: string;
260
306
  sortBy?: string;
261
307
  sortOrder?: 'asc' | 'desc';
308
+ /** Return the requested translation when content has language variants. */
309
+ lang?: string;
262
310
  /** Force public endpoint even when authenticated (for public pages) */
263
311
  publicOnly?: boolean;
264
312
  }
@@ -685,7 +733,7 @@ interface PublicOrganization {
685
733
  *
686
734
  * Automatically uses the appropriate endpoint:
687
735
  * - With API key (public): `/content/public/{orgId}/org`
688
- * - With JWT auth: `/{stage}/api/organizations/{orgId}`
736
+ * - With JWT auth: `/orgs/api/organizations/{orgId}`
689
737
  *
690
738
  * @example
691
739
  * ```tsx
@@ -817,6 +865,8 @@ declare function useContent<T extends ContentItem = ContentItem>(contentType: st
817
865
  interface ContentItemOptions {
818
866
  /** Force public endpoint even when authenticated */
819
867
  publicOnly?: boolean;
868
+ /** Return the requested translation when content has language variants. */
869
+ lang?: string;
820
870
  }
821
871
  /**
822
872
  * useContentItem - Fetch a single content item by ID or slug
@@ -833,7 +883,7 @@ interface ContentItemOptions {
833
883
  * @example
834
884
  * ```tsx
835
885
  * // Fetch a page by slug
836
- * const { data: page } = useContentItem('pages', 'about-us')
886
+ * const { data: page } = useContentItem('pages', 'about-us', { lang: 'sv' })
837
887
  *
838
888
  * // Force public endpoint
839
889
  * const { data: page } = useContentItem('pages', 'about-us', { publicOnly: true })
package/dist/index.d.ts CHANGED
@@ -197,21 +197,66 @@ interface Membership {
197
197
  expiresAt?: string;
198
198
  metadata?: Record<string, unknown>;
199
199
  }
200
+ interface ContentBlock {
201
+ id: string;
202
+ type: string;
203
+ content?: string;
204
+ url?: string;
205
+ alt?: string;
206
+ level?: 1 | 2 | 3 | 4 | 5 | 6;
207
+ items?: unknown[];
208
+ language?: string;
209
+ caption?: string;
210
+ attributes?: Record<string, unknown>;
211
+ ordered?: boolean;
212
+ author?: string;
213
+ }
214
+ interface ContentTranslation {
215
+ title: string;
216
+ slug: string;
217
+ description?: string;
218
+ blocks: ContentBlock[];
219
+ metaTitle?: string;
220
+ metaDescription?: string;
221
+ keywords?: string[];
222
+ }
223
+ type ContentPublicationState = 'draft' | 'published' | 'archived';
224
+ type ContentAudience = 'public' | 'internal' | 'members' | 'section';
200
225
  interface ContentItem {
201
226
  id: string;
202
227
  organizationId: string;
203
228
  type: string;
204
229
  title: string;
205
230
  slug: string;
206
- content: string;
231
+ /** Legacy string content. New AxCloud content uses `blocks`. */
232
+ content?: string;
233
+ description?: string;
234
+ blocks?: ContentBlock[];
207
235
  excerpt?: string;
208
236
  author?: {
209
237
  id: string;
210
238
  name: string;
211
239
  };
212
- status: 'draft' | 'published' | 'archived';
213
- visibility: 'public' | 'members' | 'section';
240
+ status?: ContentPublicationState;
241
+ visibility?: ContentPublicationState;
242
+ audience?: ContentAudience;
214
243
  sectionId?: string;
244
+ tags?: string[];
245
+ lang?: string;
246
+ featuredImage?: string;
247
+ metaTitle?: string;
248
+ metaDescription?: string;
249
+ keywords?: string[];
250
+ translations?: Record<string, ContentTranslation>;
251
+ currentLanguage?: string;
252
+ availableLanguages?: string[];
253
+ seo?: {
254
+ canonical: string;
255
+ hreflang: Array<{
256
+ lang: string;
257
+ href: string;
258
+ }>;
259
+ };
215
260
  publishedAt?: string;
216
261
  createdAt: string;
217
262
  updatedAt: string;
@@ -253,12 +298,15 @@ interface AxCloudConfig {
253
298
  interface ContentQueryOptions {
254
299
  page?: number;
255
300
  pageSize?: number;
256
- status?: 'draft' | 'published' | 'archived';
257
- visibility?: 'public' | 'members' | 'section';
301
+ status?: ContentPublicationState;
302
+ visibility?: ContentPublicationState;
303
+ audience?: ContentAudience;
258
304
  sectionId?: string;
259
305
  search?: string;
260
306
  sortBy?: string;
261
307
  sortOrder?: 'asc' | 'desc';
308
+ /** Return the requested translation when content has language variants. */
309
+ lang?: string;
262
310
  /** Force public endpoint even when authenticated (for public pages) */
263
311
  publicOnly?: boolean;
264
312
  }
@@ -685,7 +733,7 @@ interface PublicOrganization {
685
733
  *
686
734
  * Automatically uses the appropriate endpoint:
687
735
  * - With API key (public): `/content/public/{orgId}/org`
688
- * - With JWT auth: `/{stage}/api/organizations/{orgId}`
736
+ * - With JWT auth: `/orgs/api/organizations/{orgId}`
689
737
  *
690
738
  * @example
691
739
  * ```tsx
@@ -817,6 +865,8 @@ declare function useContent<T extends ContentItem = ContentItem>(contentType: st
817
865
  interface ContentItemOptions {
818
866
  /** Force public endpoint even when authenticated */
819
867
  publicOnly?: boolean;
868
+ /** Return the requested translation when content has language variants. */
869
+ lang?: string;
820
870
  }
821
871
  /**
822
872
  * useContentItem - Fetch a single content item by ID or slug
@@ -833,7 +883,7 @@ interface ContentItemOptions {
833
883
  * @example
834
884
  * ```tsx
835
885
  * // Fetch a page by slug
836
- * const { data: page } = useContentItem('pages', 'about-us')
886
+ * const { data: page } = useContentItem('pages', 'about-us', { lang: 'sv' })
837
887
  *
838
888
  * // Force public endpoint
839
889
  * const { data: page } = useContentItem('pages', 'about-us', { publicOnly: true })
package/dist/index.js CHANGED
@@ -706,6 +706,7 @@ function useNews(options = {}) {
706
706
  };
707
707
  }
708
708
  var MEMBER_ENDPOINT_TYPES = ["news", "pages", "events"];
709
+ var PAGE_CONTENT_TYPES = ["page", "pages"];
709
710
  function useContent(contentType, options = {}) {
710
711
  const { client, orgId, isPublicMode } = useAxCloudContext();
711
712
  const {
@@ -717,7 +718,8 @@ function useContent(contentType, options = {}) {
717
718
  sectionId,
718
719
  search,
719
720
  sortBy = "createdAt",
720
- sortOrder = "desc"
721
+ sortOrder = "desc",
722
+ lang
721
723
  } = options;
722
724
  const query = reactQuery.useQuery({
723
725
  queryKey: [
@@ -734,7 +736,8 @@ function useContent(contentType, options = {}) {
734
736
  sectionId,
735
737
  search,
736
738
  sortBy,
737
- sortOrder
739
+ sortOrder,
740
+ lang
738
741
  ],
739
742
  queryFn: async () => {
740
743
  const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
@@ -747,7 +750,8 @@ function useContent(contentType, options = {}) {
747
750
  sectionId,
748
751
  search,
749
752
  sortBy,
750
- sortOrder
753
+ sortOrder,
754
+ lang
751
755
  });
752
756
  },
753
757
  staleTime: 1e3 * 60 * 5
@@ -765,13 +769,15 @@ function useContent(contentType, options = {}) {
765
769
  }
766
770
  function useContentItem(contentType, idOrSlug, options = {}) {
767
771
  const { client, orgId, isPublicMode } = useAxCloudContext();
768
- const { publicOnly = false } = options;
769
- const useMemberEndpoint = !isPublicMode && !publicOnly && MEMBER_ENDPOINT_TYPES.includes(contentType);
772
+ const { publicOnly = false, lang } = options;
773
+ const useMemberEndpoint = !isPublicMode && !publicOnly && (MEMBER_ENDPOINT_TYPES.includes(contentType) || PAGE_CONTENT_TYPES.includes(contentType));
770
774
  const query = reactQuery.useQuery({
771
- queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint],
775
+ queryKey: ["axcloud", "content", orgId, contentType, idOrSlug, useMemberEndpoint, lang],
772
776
  queryFn: async () => {
773
777
  const basePath = useMemberEndpoint ? "members" : "public";
774
- return client.get(`/content/${basePath}/${orgId}/${contentType}/${idOrSlug}`);
778
+ const encodedIdOrSlug = encodeURIComponent(idOrSlug);
779
+ const endpoint = PAGE_CONTENT_TYPES.includes(contentType) ? `/content/${basePath}/${orgId}/page/${encodedIdOrSlug}` : `/content/${basePath}/${orgId}/${contentType}/${encodedIdOrSlug}`;
780
+ return lang ? client.get(endpoint, { lang }) : client.get(endpoint);
775
781
  },
776
782
  enabled: !!idOrSlug,
777
783
  staleTime: 1e3 * 60 * 5
@@ -800,7 +806,7 @@ function useMySection(options = {}) {
800
806
  `/orgs/api/organizations/${orgId}/sections/${sectionId}`,
801
807
  { includeMembers: includeMembers ? "true" : void 0 }
802
808
  );
803
- return "success" in response && response.data ? response.data : response;
809
+ return "success" in response && response.success === true && response.data ? response.data : response;
804
810
  },
805
811
  enabled: isAuthenticated && !isUserLoading && !!sectionId,
806
812
  staleTime: 1e3 * 60 * 5
@@ -827,7 +833,7 @@ function useSections() {
827
833
  queryKey: ["axcloud", "sections", orgId, stage],
828
834
  queryFn: async () => {
829
835
  const response = await client.get(`/orgs/api/organizations/${orgId}/sections`);
830
- return "success" in response && response.data ? response.data : response;
836
+ return "success" in response && response.success === true && response.data ? response.data : response;
831
837
  },
832
838
  staleTime: 1e3 * 60 * 10
833
839
  // 10 minutes