@traiwa/cms-client 0.11.0 → 0.11.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.
Files changed (2) hide show
  1. package/README.md +144 -0
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -57,10 +57,15 @@ const { data: posts } = await cms.listContent({ type: "article", limit: 20 });
57
57
  | Method | Endpoint | Returns |
58
58
  |---|---|---|
59
59
  | `getPage(slug)` | `GET /api/public/pages/:slug` | `SitePage` (with `sections: PageSection[]`) |
60
+ | `getPageJsonLd(slug)` | `GET /api/public/pages/:slug/jsonld` | Pre-computed JSON-LD object |
60
61
  | `listPages()` | `GET /api/public/pages` | `{ data: SitePageSummary[], count: number }` |
62
+ | `getPackage(slug)` | `GET /api/public/packages/:slug` | `Package` (with `sections: PageSection[]`) |
63
+ | `getPackageJsonLd(slug)` | `GET /api/public/packages/:slug/jsonld` | Pre-computed JSON-LD object |
64
+ | `listPackages(query?)` | `GET /api/public/packages?...` | `{ data: PackageSummary[], count: number }` |
61
65
  | `getSettings()` | `GET /api/public/settings` | `SiteSettings` |
62
66
  | `getContent(slug)` | `GET /api/public/content/:slug` | `Article` |
63
67
  | `listContent(query?)` | `GET /api/public/content?...` | `{ data: Article[], count: number }` |
68
+ | `getSitemap()` | `GET /api/public/sitemap.xml` | `string` (raw XML) |
64
69
  | `listBlogs()` | `GET /api/blogs` | `Blog[]` |
65
70
  | `getBlog(id)` | `GET /api/blogs/:id` | `Blog` |
66
71
  | `getBlogBySlug(slug)` | `GET /api/blogs/slug/:slug` | `Blog` |
@@ -79,10 +84,27 @@ import type { PageSection } from "@traiwa/cms-client";
79
84
  function renderSection(section: PageSection) {
80
85
  switch (section.type) {
81
86
  case "hero": return <Hero {...section} />;
87
+ case "singleImage": return <SingleImage {...section} />;
82
88
  case "packages": return <PackageCollection {...section} />;
83
89
  case "testimonials": return <TestimonialCollection {...section} />;
84
90
  case "faq": return <FAQSection {...section} />;
85
91
  case "stats": return <StatsSection {...section} />;
92
+ case "destinations": return <Destinations {...section} />;
93
+ case "features": return <Features {...section} />;
94
+ case "checklist": return <Checklist {...section} />;
95
+ case "richText": return <RichText {...section} />;
96
+ case "enquiryForm": return <EnquiryForm {...section} />;
97
+ case "categoryGrid": return <CategoryGrid {...section} />;
98
+ case "team": return <Team {...section} />;
99
+ case "specCards": return <SpecCards {...section} />;
100
+ case "splitContent": return <SplitContent {...section} />;
101
+ case "timeline": return <Timeline {...section} />;
102
+ case "cta": return <Cta {...section} />;
103
+ case "logoGrid": return <LogoGrid {...section} />;
104
+ case "blogGrid": return <BlogGrid {...section} />;
105
+ case "itinerary": return <Itinerary {...section} />;
106
+ case "inclusions": return <Inclusions {...section} />;
107
+ case "locationMap": return <LocationMap {...section} />;
86
108
  }
87
109
  }
88
110
  ```
@@ -202,6 +224,128 @@ await admin.admin.updateBlog(post.id, { title: "Updated title" });
202
224
  await admin.admin.deleteBlog(post.id);
203
225
  ```
204
226
 
227
+ ### Packages
228
+
229
+ Package detail pages share the exact same section model as site pages (`sections: PageSection[]`) — anything that works for `page.sections` works for `pkg.sections` too.
230
+
231
+ Reads are public (no token needed); writes require an admin token.
232
+
233
+ ```ts
234
+ const cms = createClient({ baseUrl: "https://cms.example.com" });
235
+
236
+ // Detail page — only `status: published` packages resolve
237
+ const pkg = await cms.getPackage("munnar-honeymoon-tour");
238
+
239
+ // Pre-computed JSON-LD for the detail page's <script type="application/ld+json">
240
+ const jsonLd = await cms.getPackageJsonLd("munnar-honeymoon-tour");
241
+
242
+ // Related packages — same category, current package excluded
243
+ const { data: related } = await cms.listPackages({
244
+ category: pkg.category,
245
+ exclude: pkg.slug,
246
+ limit: 4,
247
+ });
248
+ ```
249
+
250
+ ```ts
251
+ const admin = createClient({
252
+ baseUrl: "https://cms.example.com",
253
+ token: process.env.CMS_ADMIN_TOKEN!,
254
+ });
255
+
256
+ const all = await admin.admin.listPackages(); // every status, full sections
257
+ const created = await admin.admin.createPackage({
258
+ title: "Munnar Honeymoon Tour",
259
+ price: "₹24,999",
260
+ image: "/api/media/file/munnar-hero.jpg",
261
+ category: "honeymoon",
262
+ });
263
+ await admin.admin.updatePackage(created.id, { status: "published" });
264
+ const copy = await admin.admin.duplicatePackage(created.id); // "(Copy)", draft, new slug
265
+ await admin.admin.deletePackage(copy.id);
266
+
267
+ // One-off, idempotent migration: link legacy hand-typed `packages`-block cards
268
+ // (from before the Package collection existed) to a real Package doc, creating
269
+ // one from the card's own fields when no match exists yet. Safe to re-run —
270
+ // already-linked cards are left untouched.
271
+ const result = await admin.admin.backfillPackageLinks();
272
+ ```
273
+
274
+ ### Site Pages (admin)
275
+
276
+ Public reads use `getPage` / `listPages` / `getPageJsonLd` (see the Methods table above). Writes require an admin token.
277
+
278
+ ```ts
279
+ const admin = createClient({
280
+ baseUrl: "https://cms.example.com",
281
+ token: process.env.CMS_ADMIN_TOKEN!,
282
+ });
283
+
284
+ const all = await admin.admin.listPages(); // every status, full sections
285
+ const page = await admin.admin.createPage({ title: "New Destination", sections: [] });
286
+ await admin.admin.updatePage(page.id, { status: "published" });
287
+ const copy = await admin.admin.duplicatePage(page.id); // "(Copy)", draft, new slug
288
+ await admin.admin.deletePage(copy.id);
289
+ ```
290
+
291
+ ### Block Types & Custom Blocks
292
+
293
+ Two separate admin-only registries that back the page builder:
294
+
295
+ - **Block types** (`admin.*BlockType*`) — which section `kind`s are enabled and how they're labeled in the builder UI.
296
+ - **Custom blocks** (`admin.*Block`, no "Type") — reusable, pre-filled section presets an author can drop onto any page.
297
+
298
+ ```ts
299
+ const admin = createClient({
300
+ baseUrl: "https://cms.example.com",
301
+ token: process.env.CMS_ADMIN_TOKEN!,
302
+ });
303
+
304
+ // Block types
305
+ const types = await admin.admin.listBlockTypes();
306
+ await admin.admin.createBlockType({ label: "Itinerary", kind: "itinerary" });
307
+ await admin.admin.updateBlockType("itinerary", { label: "Trip Itinerary", enabled: true });
308
+ await admin.admin.deleteBlockType("itinerary"); // disables it
309
+
310
+ // Custom block presets
311
+ const presets = await admin.admin.listBlocks();
312
+ const preset = await admin.admin.createBlock({
313
+ name: "Standard FAQ",
314
+ section: { type: "faq", kind: "faq", title: "FAQ", items: [] },
315
+ });
316
+ await admin.admin.updateBlock(preset.id, { description: "Default FAQ shell" });
317
+ await admin.admin.deleteBlock(preset.id);
318
+ ```
319
+
320
+ ### AI / SEO proxy
321
+
322
+ Admin-only helpers that proxy to the AxoraConsole LLM and validate structured data before publish.
323
+
324
+ ```ts
325
+ const admin = createClient({
326
+ baseUrl: "https://cms.example.com",
327
+ token: process.env.CMS_ADMIN_TOKEN!,
328
+ });
329
+
330
+ const translated = await admin.admin.translate({
331
+ text: "Book your Munnar honeymoon package today.",
332
+ target_language: "hi",
333
+ });
334
+
335
+ const summary = await admin.admin.summarize({
336
+ text: longArticleBody,
337
+ style: "bullets",
338
+ max_bullets: 5,
339
+ });
340
+
341
+ // Validate JSON-LD (single object or array) against Google Rich Results rules
342
+ // before writing it into PageSEO.schemas.
343
+ const report = await admin.admin.validateJsonLd(jsonLdPayload);
344
+ if (report.overall === "fail") {
345
+ console.error(report.results.filter((r) => r.status === "fail"));
346
+ }
347
+ ```
348
+
205
349
  ### Contact / Enquiry forms
206
350
 
207
351
  `sendEmail` accepts either the package-enquiry shape (`ContactFormData`) or the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@traiwa/cms-client",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Tiny typed client for the FlexCMS / Traiwa Page Builder API. Fetch pages, list published slugs, and load site settings in any TypeScript/JavaScript app.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",