@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.
- package/README.md +144 -0
- 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.
|
|
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",
|