@riverbankcms/sdk 0.6.0 → 0.7.0
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 +239 -0
- package/dist/cli/index.js +22 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/client/client.js +1 -1
- package/dist/client/client.js.map +1 -1
- package/dist/client/client.mjs +1 -1
- package/dist/client/client.mjs.map +1 -1
- package/dist/server/{Layout-BClXUTsd.d.mts → Layout-B7cvis7r.d.mts} +3 -3
- package/dist/server/{Layout-UXGjXv8M.d.ts → Layout-wBtJLTVX.d.ts} +3 -3
- package/dist/server/{chunk-Z5ZA6Q4D.mjs → chunk-74XUVNOO.mjs} +5 -3
- package/dist/server/chunk-74XUVNOO.mjs.map +1 -0
- package/dist/server/{chunk-PHS2KWJX.js → chunk-7BVRA5MY.js} +7 -52
- package/dist/server/chunk-7BVRA5MY.js.map +1 -0
- package/dist/server/{chunk-SQMGHEJM.mjs → chunk-7FIJSGHU.mjs} +2 -2
- package/dist/server/{chunk-SQMGHEJM.mjs.map → chunk-7FIJSGHU.mjs.map} +1 -1
- package/dist/server/chunk-ARNCLSQT.mjs +52 -0
- package/dist/server/chunk-ARNCLSQT.mjs.map +1 -0
- package/dist/server/chunk-BNQV3PXP.js +69 -0
- package/dist/server/chunk-BNQV3PXP.js.map +1 -0
- package/dist/server/{chunk-SSS7CCRR.js → chunk-EIVISR62.js} +15 -57
- package/dist/server/chunk-EIVISR62.js.map +1 -0
- package/dist/server/{chunk-I2D7KOEA.js → chunk-JWRNMNWI.js} +5 -3
- package/dist/server/chunk-JWRNMNWI.js.map +1 -0
- package/dist/server/{chunk-EOWGKCUZ.js → chunk-P7UVAMK6.js} +2 -2
- package/dist/server/{chunk-EOWGKCUZ.js.map → chunk-P7UVAMK6.js.map} +1 -1
- package/dist/server/{chunk-2HXHFSMI.mjs → chunk-RBJFXNDM.mjs} +6 -51
- package/dist/server/chunk-RBJFXNDM.mjs.map +1 -0
- package/dist/server/chunk-SWYWZT3L.mjs +69 -0
- package/dist/server/chunk-SWYWZT3L.mjs.map +1 -0
- package/dist/server/chunk-T26N3P26.js +52 -0
- package/dist/server/chunk-T26N3P26.js.map +1 -0
- package/dist/server/{chunk-PMHLZ3FW.mjs → chunk-YXA4GAAQ.mjs} +15 -57
- package/dist/server/chunk-YXA4GAAQ.mjs.map +1 -0
- package/dist/server/{components-DppHY5oD.d.ts → components-CICSJyp_.d.ts} +1 -1
- package/dist/server/{components-BmaJxgCV.d.mts → components-CMMwDXTW.d.mts} +1 -1
- package/dist/server/components.d.mts +2 -2
- package/dist/server/components.d.ts +2 -2
- package/dist/server/components.js +5 -3
- package/dist/server/components.js.map +1 -1
- package/dist/server/components.mjs +5 -3
- package/dist/server/index-BTwWvSBu.d.ts +130 -0
- package/dist/server/index-DI_qlYx3.d.mts +130 -0
- package/dist/server/index.js +2 -2
- package/dist/server/index.mjs +1 -1
- package/dist/server/{loadContent-BS-3wesN.d.mts → loadContent-C-YYUKQa.d.mts} +10 -2
- package/dist/server/{loadContent-Buvmudee.d.ts → loadContent-DmgpFcFC.d.ts} +10 -2
- package/dist/server/metadata.d.mts +8 -135
- package/dist/server/metadata.d.ts +8 -135
- package/dist/server/metadata.js +5 -65
- package/dist/server/metadata.js.map +1 -1
- package/dist/server/metadata.mjs +4 -64
- package/dist/server/metadata.mjs.map +1 -1
- package/dist/server/navigation.d.mts +80 -145
- package/dist/server/navigation.d.ts +80 -145
- package/dist/server/navigation.js +2 -10
- package/dist/server/navigation.js.map +1 -1
- package/dist/server/navigation.mjs +7 -15
- package/dist/server/next.d.mts +274 -0
- package/dist/server/next.d.ts +274 -0
- package/dist/server/next.js +150 -0
- package/dist/server/next.js.map +1 -0
- package/dist/server/next.mjs +150 -0
- package/dist/server/next.mjs.map +1 -0
- package/dist/server/rendering/server.d.mts +1 -1
- package/dist/server/rendering/server.d.ts +1 -1
- package/dist/server/rendering/server.js +5 -3
- package/dist/server/rendering/server.js.map +1 -1
- package/dist/server/rendering/server.mjs +5 -3
- package/dist/server/rendering.d.mts +4 -4
- package/dist/server/rendering.d.ts +4 -4
- package/dist/server/rendering.js +6 -4
- package/dist/server/rendering.js.map +1 -1
- package/dist/server/rendering.mjs +6 -4
- package/dist/server/server.d.mts +1 -1
- package/dist/server/server.d.ts +1 -1
- package/dist/server/server.js +3 -3
- package/dist/server/server.mjs +2 -2
- package/package.json +13 -1
- package/dist/server/chunk-2HXHFSMI.mjs.map +0 -1
- package/dist/server/chunk-I2D7KOEA.js.map +0 -1
- package/dist/server/chunk-PHS2KWJX.js.map +0 -1
- package/dist/server/chunk-PMHLZ3FW.mjs.map +0 -1
- package/dist/server/chunk-SSS7CCRR.js.map +0 -1
- package/dist/server/chunk-Z5ZA6Q4D.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -458,6 +458,245 @@ import { usePage, Page } from '@riverbankcms/sdk/client';
|
|
|
458
458
|
|
|
459
459
|
The `/client` subpath exports React hooks that require client-side React features (useState, useEffect). The main entry point only exports server-safe code.
|
|
460
460
|
|
|
461
|
+
## Navigation
|
|
462
|
+
|
|
463
|
+
The SDK provides navigation utilities for transforming CMS navigation data into render-ready structures. All navigation functions return nested structures that support both direct links and dropdown menus.
|
|
464
|
+
|
|
465
|
+
### Navigation Types
|
|
466
|
+
|
|
467
|
+
Navigation items are discriminated unions using a `kind` field:
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
import type {
|
|
471
|
+
NavItem, // NavLink | NavDropdown
|
|
472
|
+
NavLink, // Direct link with href
|
|
473
|
+
NavDropdown, // Dropdown container with children
|
|
474
|
+
} from '@riverbankcms/sdk/navigation';
|
|
475
|
+
|
|
476
|
+
// NavLink - a direct navigation link
|
|
477
|
+
type NavLink = {
|
|
478
|
+
kind: 'link';
|
|
479
|
+
id: string;
|
|
480
|
+
label: string;
|
|
481
|
+
href: string;
|
|
482
|
+
isExternal: boolean;
|
|
483
|
+
};
|
|
484
|
+
|
|
485
|
+
// NavDropdown - a dropdown menu container
|
|
486
|
+
type NavDropdown = {
|
|
487
|
+
kind: 'dropdown';
|
|
488
|
+
id: string;
|
|
489
|
+
label: string;
|
|
490
|
+
children: NavLink[]; // Max 1 level of nesting
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
// NavItem - either a link or dropdown
|
|
494
|
+
type NavItem = NavLink | NavDropdown;
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
### Type Guards
|
|
498
|
+
|
|
499
|
+
Use the provided type guards for safe type narrowing:
|
|
500
|
+
|
|
501
|
+
```typescript
|
|
502
|
+
import { isNavLink, isNavDropdown } from '@riverbankcms/sdk/navigation';
|
|
503
|
+
|
|
504
|
+
const items = getPrimaryNavItems(siteData.navigation);
|
|
505
|
+
|
|
506
|
+
items.forEach(item => {
|
|
507
|
+
if (isNavLink(item)) {
|
|
508
|
+
// TypeScript knows this is NavLink
|
|
509
|
+
console.log(item.href);
|
|
510
|
+
} else if (isNavDropdown(item)) {
|
|
511
|
+
// TypeScript knows this is NavDropdown
|
|
512
|
+
console.log(`${item.label} has ${item.children.length} children`);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Or use the `kind` discriminator directly:
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
items.forEach(item => {
|
|
521
|
+
if (item.kind === 'link') {
|
|
522
|
+
console.log(item.href);
|
|
523
|
+
} else {
|
|
524
|
+
// item.kind === 'dropdown'
|
|
525
|
+
console.log(item.children);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Navigation Helper Functions
|
|
531
|
+
|
|
532
|
+
```typescript
|
|
533
|
+
import {
|
|
534
|
+
getPrimaryNavItems,
|
|
535
|
+
getNavItemsBySlug,
|
|
536
|
+
getPrimaryNavigation,
|
|
537
|
+
getNavigationBySlug,
|
|
538
|
+
transformToNavItems,
|
|
539
|
+
} from '@riverbankcms/sdk/navigation';
|
|
540
|
+
|
|
541
|
+
// Get nav items from the primary menu (marked isPrimary, or first menu)
|
|
542
|
+
const headerNav = getPrimaryNavItems(siteData.navigation);
|
|
543
|
+
|
|
544
|
+
// Get nav items from a specific menu by name/slug
|
|
545
|
+
const footerNav = getNavItemsBySlug(siteData.navigation, 'footer');
|
|
546
|
+
|
|
547
|
+
// Get the raw menu object (for accessing menu metadata)
|
|
548
|
+
const primaryMenu = getPrimaryNavigation(siteData.navigation);
|
|
549
|
+
const footerMenu = getNavigationBySlug(siteData.navigation, 'footer');
|
|
550
|
+
|
|
551
|
+
// Transform a menu object to nav items
|
|
552
|
+
const items = transformToNavItems(primaryMenu);
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Building Menu and Logo
|
|
556
|
+
|
|
557
|
+
For rendering, use `buildMenu` and `buildLogo` which resolve all hrefs from the route map:
|
|
558
|
+
|
|
559
|
+
```typescript
|
|
560
|
+
import type { Menu, Logo } from '@riverbankcms/sdk/navigation';
|
|
561
|
+
import { buildMenu, buildLogo } from '@riverbankcms/sdk/navigation';
|
|
562
|
+
|
|
563
|
+
// Build menu with pre-resolved hrefs from route map
|
|
564
|
+
const menu = buildMenu(siteData.navigation, siteData.routes);
|
|
565
|
+
|
|
566
|
+
// menu.items is NavItem[] (links and dropdowns)
|
|
567
|
+
// menu.ctaItem is NavLink | null (CTA is always a link, never dropdown)
|
|
568
|
+
|
|
569
|
+
const logo = buildLogo(siteData.layout.logo, siteData.site.title);
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
### Rendering Navigation with Dropdowns
|
|
573
|
+
|
|
574
|
+
```tsx
|
|
575
|
+
import { getPrimaryNavItems, isNavLink, isNavDropdown } from '@riverbankcms/sdk/navigation';
|
|
576
|
+
|
|
577
|
+
function Header({ navigation }) {
|
|
578
|
+
const items = getPrimaryNavItems(navigation);
|
|
579
|
+
|
|
580
|
+
return (
|
|
581
|
+
<nav>
|
|
582
|
+
{items.map(item => {
|
|
583
|
+
if (isNavLink(item)) {
|
|
584
|
+
return (
|
|
585
|
+
<a
|
|
586
|
+
key={item.id}
|
|
587
|
+
href={item.href}
|
|
588
|
+
target={item.isExternal ? '_blank' : undefined}
|
|
589
|
+
rel={item.isExternal ? 'noopener noreferrer' : undefined}
|
|
590
|
+
>
|
|
591
|
+
{item.label}
|
|
592
|
+
</a>
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// Dropdown
|
|
597
|
+
return (
|
|
598
|
+
<div key={item.id} className="dropdown">
|
|
599
|
+
<button>{item.label}</button>
|
|
600
|
+
<div className="dropdown-menu">
|
|
601
|
+
{item.children.map(child => (
|
|
602
|
+
<a
|
|
603
|
+
key={child.id}
|
|
604
|
+
href={child.href}
|
|
605
|
+
target={child.isExternal ? '_blank' : undefined}
|
|
606
|
+
>
|
|
607
|
+
{child.label}
|
|
608
|
+
</a>
|
|
609
|
+
))}
|
|
610
|
+
</div>
|
|
611
|
+
</div>
|
|
612
|
+
);
|
|
613
|
+
})}
|
|
614
|
+
</nav>
|
|
615
|
+
);
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Rendering Menu in Components
|
|
620
|
+
|
|
621
|
+
```tsx
|
|
622
|
+
import { buildMenu, buildLogo } from '@riverbankcms/sdk/navigation';
|
|
623
|
+
|
|
624
|
+
function SiteHeader({ siteData }) {
|
|
625
|
+
const menu = buildMenu(siteData.navigation, siteData.routes);
|
|
626
|
+
const logo = buildLogo(siteData.layout.logo, siteData.site.title);
|
|
627
|
+
|
|
628
|
+
return (
|
|
629
|
+
<header>
|
|
630
|
+
{logo && <img src={logo.src} alt={logo.alt} />}
|
|
631
|
+
|
|
632
|
+
<nav>
|
|
633
|
+
{menu.items.map(item => {
|
|
634
|
+
if (item.kind === 'link') {
|
|
635
|
+
return <a key={item.id} href={item.href}>{item.label}</a>;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
return (
|
|
639
|
+
<div key={item.id} className="dropdown">
|
|
640
|
+
<span>{item.label}</span>
|
|
641
|
+
<ul>
|
|
642
|
+
{item.children.map(child => (
|
|
643
|
+
<li key={child.id}>
|
|
644
|
+
<a href={child.href}>{child.label}</a>
|
|
645
|
+
</li>
|
|
646
|
+
))}
|
|
647
|
+
</ul>
|
|
648
|
+
</div>
|
|
649
|
+
);
|
|
650
|
+
})}
|
|
651
|
+
</nav>
|
|
652
|
+
|
|
653
|
+
{menu.ctaItem && (
|
|
654
|
+
<a href={menu.ctaItem.href} className="cta-button">
|
|
655
|
+
{menu.ctaItem.label}
|
|
656
|
+
</a>
|
|
657
|
+
)}
|
|
658
|
+
</header>
|
|
659
|
+
);
|
|
660
|
+
}
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
### Navigation Exports
|
|
664
|
+
|
|
665
|
+
```typescript
|
|
666
|
+
import {
|
|
667
|
+
// Helper functions
|
|
668
|
+
getPrimaryNavItems,
|
|
669
|
+
getNavItemsBySlug,
|
|
670
|
+
getPrimaryNavigation,
|
|
671
|
+
getNavigationBySlug,
|
|
672
|
+
transformToNavItems,
|
|
673
|
+
buildMenu,
|
|
674
|
+
buildLogo,
|
|
675
|
+
buildMenuViewModel,
|
|
676
|
+
buildLogoViewModel,
|
|
677
|
+
|
|
678
|
+
// Type guards
|
|
679
|
+
isNavLink,
|
|
680
|
+
isNavDropdown,
|
|
681
|
+
|
|
682
|
+
// Types
|
|
683
|
+
type NavItem,
|
|
684
|
+
type NavLink,
|
|
685
|
+
type NavDropdown,
|
|
686
|
+
type Menu,
|
|
687
|
+
type Logo,
|
|
688
|
+
type MenuViewModel,
|
|
689
|
+
type MenuLinkViewModel,
|
|
690
|
+
type MenuCtaViewModel,
|
|
691
|
+
type LogoViewModel,
|
|
692
|
+
type LogoSource,
|
|
693
|
+
type LinkValue,
|
|
694
|
+
type InternalLinkValue,
|
|
695
|
+
type ExternalLinkValue,
|
|
696
|
+
type CustomLinkValue,
|
|
697
|
+
} from '@riverbankcms/sdk/navigation';
|
|
698
|
+
```
|
|
699
|
+
|
|
461
700
|
## Layout Component
|
|
462
701
|
|
|
463
702
|
The `Layout` component renders the site header, footer, and wraps your page content. Use this when you want consistent site chrome across all pages.
|
package/dist/cli/index.js
CHANGED
|
@@ -7227,6 +7227,23 @@ ${contentType} (updated):`);
|
|
|
7227
7227
|
}
|
|
7228
7228
|
|
|
7229
7229
|
// src/cli/sync/executor.ts
|
|
7230
|
+
function hasFieldErrors(details) {
|
|
7231
|
+
if (typeof details !== "object" || details === null || !("fieldErrors" in details)) {
|
|
7232
|
+
return false;
|
|
7233
|
+
}
|
|
7234
|
+
const fieldErrors = details.fieldErrors;
|
|
7235
|
+
return Array.isArray(fieldErrors) && fieldErrors.length > 0;
|
|
7236
|
+
}
|
|
7237
|
+
function formatApiError(error) {
|
|
7238
|
+
if (!(error instanceof ManagementApiError)) {
|
|
7239
|
+
return error instanceof Error ? error.message : String(error);
|
|
7240
|
+
}
|
|
7241
|
+
let message = error.message;
|
|
7242
|
+
if (hasFieldErrors(error.details)) {
|
|
7243
|
+
message += "\n" + error.details.fieldErrors.map((fe) => ` ${fe.field} (${fe.code}): ${fe.message}`).join("\n");
|
|
7244
|
+
}
|
|
7245
|
+
return message;
|
|
7246
|
+
}
|
|
7230
7247
|
function createEmptyResult() {
|
|
7231
7248
|
return {
|
|
7232
7249
|
entries: { created: 0, updated: 0, failed: 0 },
|
|
@@ -7266,7 +7283,7 @@ async function syncEntries(client, diff, local, options, result) {
|
|
|
7266
7283
|
result.errors.push({
|
|
7267
7284
|
resource: "entry",
|
|
7268
7285
|
identifier: `${contentType}/${entryDiff.identifier}`,
|
|
7269
|
-
error:
|
|
7286
|
+
error: formatApiError(error)
|
|
7270
7287
|
});
|
|
7271
7288
|
}
|
|
7272
7289
|
}
|
|
@@ -7310,7 +7327,7 @@ async function syncPages(client, diff, local, options, result) {
|
|
|
7310
7327
|
result.errors.push({
|
|
7311
7328
|
resource: "page",
|
|
7312
7329
|
identifier: pageDiff.identifier,
|
|
7313
|
-
error:
|
|
7330
|
+
error: formatApiError(error)
|
|
7314
7331
|
});
|
|
7315
7332
|
}
|
|
7316
7333
|
}
|
|
@@ -7342,7 +7359,7 @@ async function syncBlocks(client, pageIdentifier, blockDiffs, localBlocks, optio
|
|
|
7342
7359
|
result.errors.push({
|
|
7343
7360
|
resource: "block",
|
|
7344
7361
|
identifier: `${pageIdentifier}/${blockDiff.identifier}`,
|
|
7345
|
-
error:
|
|
7362
|
+
error: formatApiError(error)
|
|
7346
7363
|
});
|
|
7347
7364
|
}
|
|
7348
7365
|
}
|
|
@@ -7380,7 +7397,7 @@ async function syncNavigation(client, diff, local, options, result) {
|
|
|
7380
7397
|
result.errors.push({
|
|
7381
7398
|
resource: "navigation",
|
|
7382
7399
|
identifier: navDiff.name,
|
|
7383
|
-
error:
|
|
7400
|
+
error: formatApiError(error)
|
|
7384
7401
|
});
|
|
7385
7402
|
}
|
|
7386
7403
|
}
|
|
@@ -7399,7 +7416,7 @@ async function syncSettings(client, diff, local, options, result) {
|
|
|
7399
7416
|
result.errors.push({
|
|
7400
7417
|
resource: "settings",
|
|
7401
7418
|
identifier: "site",
|
|
7402
|
-
error:
|
|
7419
|
+
error: formatApiError(error)
|
|
7403
7420
|
});
|
|
7404
7421
|
}
|
|
7405
7422
|
}
|