@cmssy/react 3.0.0 → 4.0.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/dist/index.cjs +176 -211
- package/dist/index.d.cts +30 -4
- package/dist/index.d.ts +30 -4
- package/dist/index.js +176 -212
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -342,6 +342,108 @@ function parseEditorMessage(data, origin, expectedOrigin) {
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
+
// src/data/http.ts
|
|
346
|
+
var CmssyRequestError = class extends Error {
|
|
347
|
+
status;
|
|
348
|
+
constructor(message, status) {
|
|
349
|
+
super(message);
|
|
350
|
+
this.name = "CmssyRequestError";
|
|
351
|
+
this.status = status;
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
var DEFAULT_RETRY_STATUSES = [429, 503];
|
|
355
|
+
function retryAfterMs(response) {
|
|
356
|
+
const raw = response.headers?.get("retry-after");
|
|
357
|
+
if (!raw) return null;
|
|
358
|
+
const seconds = Number(raw);
|
|
359
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
360
|
+
const date = Date.parse(raw);
|
|
361
|
+
if (Number.isFinite(date)) return Math.max(0, date - Date.now());
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
function sleep(ms, signal) {
|
|
365
|
+
return new Promise((resolve, reject) => {
|
|
366
|
+
if (signal?.aborted) {
|
|
367
|
+
reject(new Error("cmssy: request aborted"));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const timer = setTimeout(() => {
|
|
371
|
+
signal?.removeEventListener("abort", onAbort);
|
|
372
|
+
resolve();
|
|
373
|
+
}, ms);
|
|
374
|
+
function onAbort() {
|
|
375
|
+
clearTimeout(timer);
|
|
376
|
+
reject(new Error("cmssy: request aborted"));
|
|
377
|
+
}
|
|
378
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
async function fetchWithRetry(doFetch, url, init, retry) {
|
|
382
|
+
if (retry === false || retry === void 0) {
|
|
383
|
+
return doFetch(url, init);
|
|
384
|
+
}
|
|
385
|
+
const maxRetries = retry.maxRetries ?? 3;
|
|
386
|
+
const baseDelayMs = retry.baseDelayMs ?? 300;
|
|
387
|
+
const maxDelayMs = retry.maxDelayMs ?? 3e3;
|
|
388
|
+
const retryStatuses = retry.retryStatuses ?? DEFAULT_RETRY_STATUSES;
|
|
389
|
+
let response = await doFetch(url, init);
|
|
390
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
391
|
+
if (response.ok || !retryStatuses.includes(response.status)) {
|
|
392
|
+
return response;
|
|
393
|
+
}
|
|
394
|
+
const backoff = baseDelayMs * 2 ** attempt;
|
|
395
|
+
const wait = Math.min(retryAfterMs(response) ?? backoff, maxDelayMs);
|
|
396
|
+
await sleep(wait, init.signal);
|
|
397
|
+
response = await doFetch(url, init);
|
|
398
|
+
}
|
|
399
|
+
return response;
|
|
400
|
+
}
|
|
401
|
+
async function postGraphql(url, query, variables, options) {
|
|
402
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
403
|
+
if (typeof doFetch !== "function") {
|
|
404
|
+
throw new Error(
|
|
405
|
+
"cmssy: no fetch implementation available - pass options.fetch"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const response = await fetchWithRetry(
|
|
409
|
+
doFetch,
|
|
410
|
+
url,
|
|
411
|
+
{
|
|
412
|
+
method: "POST",
|
|
413
|
+
headers: { "content-type": "application/json", ...options.headers },
|
|
414
|
+
body: JSON.stringify({ query, variables }),
|
|
415
|
+
signal: options.signal
|
|
416
|
+
},
|
|
417
|
+
options.retry
|
|
418
|
+
);
|
|
419
|
+
if (!response.ok) {
|
|
420
|
+
let detail = "";
|
|
421
|
+
try {
|
|
422
|
+
const body = await response.json();
|
|
423
|
+
if (body.errors && body.errors.length > 0) {
|
|
424
|
+
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
425
|
+
}
|
|
426
|
+
} catch {
|
|
427
|
+
detail = "";
|
|
428
|
+
}
|
|
429
|
+
throw new CmssyRequestError(
|
|
430
|
+
`cmssy: ${options.label} failed (${response.status})${detail}`,
|
|
431
|
+
response.status
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
let json;
|
|
435
|
+
try {
|
|
436
|
+
json = await response.json();
|
|
437
|
+
} catch {
|
|
438
|
+
throw new Error(`cmssy: invalid JSON response from the ${options.label}`);
|
|
439
|
+
}
|
|
440
|
+
if (json.errors && json.errors.length > 0) {
|
|
441
|
+
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
442
|
+
throw new Error(`cmssy: ${options.label} error - ${message}`);
|
|
443
|
+
}
|
|
444
|
+
return json.data;
|
|
445
|
+
}
|
|
446
|
+
|
|
345
447
|
// src/content/content-client.ts
|
|
346
448
|
var DEFAULT_CMSSY_API_URL = "https://api.cmssy.io/graphql";
|
|
347
449
|
function resolveApiUrl(apiUrl) {
|
|
@@ -433,251 +535,113 @@ function normalizeSlug(path) {
|
|
|
433
535
|
}
|
|
434
536
|
async function fetchPage(config, path, options = {}) {
|
|
435
537
|
const slug = normalizeSlug(path);
|
|
436
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
437
|
-
if (typeof doFetch !== "function") {
|
|
438
|
-
throw new Error(
|
|
439
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
440
|
-
);
|
|
441
|
-
}
|
|
442
538
|
const trimmedSecret = options.previewSecret?.trim();
|
|
443
539
|
const previewSecret = trimmedSecret ? trimmedSecret : null;
|
|
444
540
|
const devToken = options.devToken?.trim();
|
|
445
541
|
const devPreview = Boolean(options.devPreview && devToken);
|
|
446
|
-
const headers = {
|
|
447
|
-
"content-type": "application/json"
|
|
448
|
-
};
|
|
542
|
+
const headers = {};
|
|
449
543
|
if (devPreview && devToken) {
|
|
450
544
|
headers["authorization"] = `Bearer ${devToken}`;
|
|
451
545
|
if (options.workspaceId) {
|
|
452
546
|
headers["x-workspace-id"] = options.workspaceId;
|
|
453
547
|
}
|
|
454
548
|
}
|
|
455
|
-
const
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
let detail = "";
|
|
471
|
-
try {
|
|
472
|
-
const body = await response.json();
|
|
473
|
-
if (body.errors && body.errors.length > 0) {
|
|
474
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
475
|
-
}
|
|
476
|
-
} catch {
|
|
477
|
-
detail = "";
|
|
549
|
+
const data = await postGraphql(
|
|
550
|
+
resolvePublicUrl(config),
|
|
551
|
+
devPreview ? PUBLIC_PAGE_DEV_QUERY : PUBLIC_PAGE_QUERY,
|
|
552
|
+
{
|
|
553
|
+
workspaceSlug: config.workspaceSlug,
|
|
554
|
+
slug,
|
|
555
|
+
previewSecret,
|
|
556
|
+
...devPreview ? { devPreview: true } : {}
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
fetch: options.fetch,
|
|
560
|
+
signal: options.signal,
|
|
561
|
+
headers,
|
|
562
|
+
retry: options.retry ?? {},
|
|
563
|
+
label: "page fetch"
|
|
478
564
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
let json;
|
|
482
|
-
try {
|
|
483
|
-
json = await response.json();
|
|
484
|
-
} catch {
|
|
485
|
-
throw new Error("cmssy: invalid JSON response from the page query");
|
|
486
|
-
}
|
|
487
|
-
if (json.errors && json.errors.length > 0) {
|
|
488
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
489
|
-
throw new Error(`cmssy: page fetch error - ${message}`);
|
|
490
|
-
}
|
|
491
|
-
const page = json.data?.public?.page?.get;
|
|
565
|
+
);
|
|
566
|
+
const page = data?.public?.page?.get;
|
|
492
567
|
if (!page) return null;
|
|
493
568
|
const draft = previewSecret !== null || devPreview;
|
|
494
569
|
const blocks = (draft ? page.blocks : page.publishedBlocks) ?? [];
|
|
495
570
|
return { id: page.id, blocks };
|
|
496
571
|
}
|
|
497
572
|
async function fetchPageById(config, pageId, options = {}) {
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
body: JSON.stringify({
|
|
508
|
-
query: PUBLIC_PAGE_BY_ID_QUERY,
|
|
509
|
-
variables: { workspaceSlug: config.workspaceSlug, pageId }
|
|
510
|
-
}),
|
|
511
|
-
signal: options.signal
|
|
512
|
-
});
|
|
513
|
-
if (!response.ok) {
|
|
514
|
-
let detail = "";
|
|
515
|
-
try {
|
|
516
|
-
const body = await response.json();
|
|
517
|
-
if (body.errors && body.errors.length > 0) {
|
|
518
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
519
|
-
}
|
|
520
|
-
} catch {
|
|
521
|
-
detail = "";
|
|
573
|
+
const data = await postGraphql(
|
|
574
|
+
resolvePublicUrl(config),
|
|
575
|
+
PUBLIC_PAGE_BY_ID_QUERY,
|
|
576
|
+
{ workspaceSlug: config.workspaceSlug, pageId },
|
|
577
|
+
{
|
|
578
|
+
fetch: options.fetch,
|
|
579
|
+
signal: options.signal,
|
|
580
|
+
retry: options.retry ?? {},
|
|
581
|
+
label: "page-by-id fetch"
|
|
522
582
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
);
|
|
526
|
-
}
|
|
527
|
-
let json;
|
|
528
|
-
try {
|
|
529
|
-
json = await response.json();
|
|
530
|
-
} catch {
|
|
531
|
-
throw new Error("cmssy: invalid JSON response from the page-by-id query");
|
|
532
|
-
}
|
|
533
|
-
if (json.errors && json.errors.length > 0) {
|
|
534
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
535
|
-
throw new Error(`cmssy: page-by-id fetch error - ${message}`);
|
|
536
|
-
}
|
|
537
|
-
const page = json.data?.public?.page?.getById;
|
|
583
|
+
);
|
|
584
|
+
const page = data?.public?.page?.getById;
|
|
538
585
|
if (!page) return null;
|
|
539
586
|
return { id: page.id, blocks: page.publishedBlocks ?? [] };
|
|
540
587
|
}
|
|
541
588
|
async function fetchPages(config, options = {}) {
|
|
542
|
-
const
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}),
|
|
555
|
-
signal: options.signal
|
|
556
|
-
});
|
|
557
|
-
if (!response.ok) {
|
|
558
|
-
throw new Error(`cmssy: pages fetch failed (${response.status})`);
|
|
559
|
-
}
|
|
560
|
-
let json;
|
|
561
|
-
try {
|
|
562
|
-
json = await response.json();
|
|
563
|
-
} catch {
|
|
564
|
-
throw new Error("cmssy: invalid JSON response from the pages query");
|
|
565
|
-
}
|
|
566
|
-
if (json.errors && json.errors.length > 0) {
|
|
567
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
568
|
-
throw new Error(`cmssy: pages fetch error - ${message}`);
|
|
569
|
-
}
|
|
570
|
-
return json.data?.public?.page?.list ?? [];
|
|
589
|
+
const data = await postGraphql(
|
|
590
|
+
resolvePublicUrl(config),
|
|
591
|
+
PUBLIC_PAGES_QUERY,
|
|
592
|
+
{ workspaceSlug: config.workspaceSlug },
|
|
593
|
+
{
|
|
594
|
+
fetch: options.fetch,
|
|
595
|
+
signal: options.signal,
|
|
596
|
+
retry: options.retry ?? {},
|
|
597
|
+
label: "pages fetch"
|
|
598
|
+
}
|
|
599
|
+
);
|
|
600
|
+
return data?.public?.page?.list ?? [];
|
|
571
601
|
}
|
|
572
602
|
async function fetchPageMeta(config, path, options = {}) {
|
|
573
603
|
const slug = normalizeSlug(path);
|
|
574
|
-
const
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
}),
|
|
587
|
-
signal: options.signal
|
|
588
|
-
});
|
|
589
|
-
if (!response.ok) {
|
|
590
|
-
throw new Error(`cmssy: page meta fetch failed (${response.status})`);
|
|
591
|
-
}
|
|
592
|
-
let json;
|
|
593
|
-
try {
|
|
594
|
-
json = await response.json();
|
|
595
|
-
} catch {
|
|
596
|
-
throw new Error("cmssy: invalid JSON response from the page meta query");
|
|
597
|
-
}
|
|
598
|
-
if (json.errors && json.errors.length > 0) {
|
|
599
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
600
|
-
throw new Error(`cmssy: page meta fetch error - ${message}`);
|
|
601
|
-
}
|
|
602
|
-
return json.data?.public?.page?.get ?? null;
|
|
604
|
+
const data = await postGraphql(
|
|
605
|
+
resolvePublicUrl(config),
|
|
606
|
+
PUBLIC_PAGE_META_QUERY,
|
|
607
|
+
{ workspaceSlug: config.workspaceSlug, slug },
|
|
608
|
+
{
|
|
609
|
+
fetch: options.fetch,
|
|
610
|
+
signal: options.signal,
|
|
611
|
+
retry: options.retry ?? {},
|
|
612
|
+
label: "page meta fetch"
|
|
613
|
+
}
|
|
614
|
+
);
|
|
615
|
+
return data?.public?.page?.get ?? null;
|
|
603
616
|
}
|
|
604
617
|
async function fetchLayouts(config, path, options = {}) {
|
|
605
618
|
const pageSlug = normalizeSlug(path);
|
|
606
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
607
|
-
if (typeof doFetch !== "function") {
|
|
608
|
-
throw new Error(
|
|
609
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
619
|
const trimmedSecret = options.previewSecret?.trim();
|
|
613
620
|
const previewSecret = trimmedSecret ? trimmedSecret : null;
|
|
614
|
-
const
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
});
|
|
627
|
-
if (!response.ok) {
|
|
628
|
-
throw new Error(`cmssy: layouts fetch failed (${response.status})`);
|
|
629
|
-
}
|
|
630
|
-
let json;
|
|
631
|
-
try {
|
|
632
|
-
json = await response.json();
|
|
633
|
-
} catch {
|
|
634
|
-
throw new Error("cmssy: invalid JSON response from the layouts query");
|
|
635
|
-
}
|
|
636
|
-
if (json.errors && json.errors.length > 0) {
|
|
637
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
638
|
-
throw new Error(`cmssy: layouts fetch error - ${message}`);
|
|
639
|
-
}
|
|
640
|
-
return json.data?.public?.page?.layouts ?? [];
|
|
621
|
+
const data = await postGraphql(
|
|
622
|
+
resolvePublicUrl(config),
|
|
623
|
+
PUBLIC_PAGE_LAYOUTS_QUERY,
|
|
624
|
+
{ workspaceSlug: config.workspaceSlug, pageSlug, previewSecret },
|
|
625
|
+
{
|
|
626
|
+
fetch: options.fetch,
|
|
627
|
+
signal: options.signal,
|
|
628
|
+
retry: options.retry ?? {},
|
|
629
|
+
label: "layouts fetch"
|
|
630
|
+
}
|
|
631
|
+
);
|
|
632
|
+
return data?.public?.page?.layouts ?? [];
|
|
641
633
|
}
|
|
642
634
|
|
|
643
635
|
// src/data/graphql-request.ts
|
|
644
636
|
async function graphqlRequest(config, query, variables, options = {}, label = "request") {
|
|
645
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
646
|
-
if (typeof doFetch !== "function") {
|
|
647
|
-
throw new Error(
|
|
648
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
637
|
const url = options.public ? resolvePublicUrl(config) : resolveApiUrl(config.apiUrl);
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
638
|
+
return postGraphql(url, query, variables, {
|
|
639
|
+
fetch: options.fetch,
|
|
640
|
+
signal: options.signal,
|
|
641
|
+
headers: options.headers,
|
|
642
|
+
retry: options.retry,
|
|
643
|
+
label
|
|
657
644
|
});
|
|
658
|
-
if (!response.ok) {
|
|
659
|
-
let detail = "";
|
|
660
|
-
try {
|
|
661
|
-
const body = await response.json();
|
|
662
|
-
if (body.errors && body.errors.length > 0) {
|
|
663
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
664
|
-
}
|
|
665
|
-
} catch {
|
|
666
|
-
detail = "";
|
|
667
|
-
}
|
|
668
|
-
throw new Error(`cmssy: ${label} failed (${response.status})${detail}`);
|
|
669
|
-
}
|
|
670
|
-
let json;
|
|
671
|
-
try {
|
|
672
|
-
json = await response.json();
|
|
673
|
-
} catch {
|
|
674
|
-
throw new Error(`cmssy: invalid JSON response from the ${label}`);
|
|
675
|
-
}
|
|
676
|
-
if (json.errors && json.errors.length > 0) {
|
|
677
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
678
|
-
throw new Error(`cmssy: ${label} error - ${message}`);
|
|
679
|
-
}
|
|
680
|
-
return json.data;
|
|
681
645
|
}
|
|
682
646
|
|
|
683
647
|
// src/data/queries.ts
|
|
@@ -759,7 +723,7 @@ async function fetchSiteConfig(config, options = {}) {
|
|
|
759
723
|
config,
|
|
760
724
|
SITE_CONFIG_QUERY,
|
|
761
725
|
{ workspaceSlug: config.workspaceSlug },
|
|
762
|
-
{ ...options, public: true },
|
|
726
|
+
{ ...options, public: true, retry: options.retry ?? {} },
|
|
763
727
|
"site config query"
|
|
764
728
|
);
|
|
765
729
|
return data.public?.siteConfig ?? null;
|
|
@@ -875,7 +839,7 @@ async function resolveSiteLocales(config, options) {
|
|
|
875
839
|
config,
|
|
876
840
|
SITE_CONFIG_QUERY,
|
|
877
841
|
{ workspaceSlug: config.workspaceSlug },
|
|
878
|
-
{ ...options, public: true },
|
|
842
|
+
{ ...options, public: true, retry: options?.retry ?? {} },
|
|
879
843
|
"site config"
|
|
880
844
|
);
|
|
881
845
|
const siteConfig = data.public?.siteConfig ?? null;
|
|
@@ -985,6 +949,7 @@ Object.defineProperty(exports, "evaluateFieldConditionGroup", {
|
|
|
985
949
|
get: function () { return types.evaluateFieldConditionGroup; }
|
|
986
950
|
});
|
|
987
951
|
exports.CmssyBlock = CmssyBlock;
|
|
952
|
+
exports.CmssyRequestError = CmssyRequestError;
|
|
988
953
|
exports.CmssyServerLayout = CmssyServerLayout;
|
|
989
954
|
exports.CmssyServerPage = CmssyServerPage;
|
|
990
955
|
exports.DEFAULT_CMSSY_API_URL = DEFAULT_CMSSY_API_URL;
|
package/dist/index.d.cts
CHANGED
|
@@ -5,6 +5,22 @@ export { b as blocksToMeta, c as blocksToSchemas, d as buildBlockMap, e as defin
|
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
import 'react';
|
|
7
7
|
|
|
8
|
+
/** HTTP-level failure from the cmssy API, with a machine-readable status. */
|
|
9
|
+
declare class CmssyRequestError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
constructor(message: string, status: number);
|
|
12
|
+
}
|
|
13
|
+
interface RetryPolicy {
|
|
14
|
+
/** Additional attempts after the first request (default 3). */
|
|
15
|
+
maxRetries?: number;
|
|
16
|
+
/** Exponential backoff base in ms: base * 2^attempt (default 300). */
|
|
17
|
+
baseDelayMs?: number;
|
|
18
|
+
/** Upper bound for any single wait, including Retry-After (default 3000). */
|
|
19
|
+
maxDelayMs?: number;
|
|
20
|
+
/** HTTP statuses that trigger a retry (default [429, 503]). */
|
|
21
|
+
retryStatuses?: number[];
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* The cmssy cloud GraphQL delivery endpoint. It is the same for every workspace,
|
|
10
26
|
* so consumers never need to set it - `apiUrl` defaults to this. Self-hosted /
|
|
@@ -23,6 +39,9 @@ interface FetchLikeResponse {
|
|
|
23
39
|
ok: boolean;
|
|
24
40
|
status: number;
|
|
25
41
|
json: () => Promise<unknown>;
|
|
42
|
+
headers?: {
|
|
43
|
+
get: (name: string) => string | null;
|
|
44
|
+
};
|
|
26
45
|
}
|
|
27
46
|
type FetchLike = (url: string, init: {
|
|
28
47
|
method: string;
|
|
@@ -37,12 +56,13 @@ interface FetchPageOptions {
|
|
|
37
56
|
workspaceId?: string;
|
|
38
57
|
fetch?: FetchLike;
|
|
39
58
|
signal?: AbortSignal;
|
|
59
|
+
retry?: RetryPolicy | false;
|
|
40
60
|
}
|
|
41
61
|
declare function normalizeSlug(path: string | string[] | undefined): string;
|
|
42
62
|
declare function fetchPage(config: CmssyClientConfig, path: string | string[] | undefined, options?: FetchPageOptions): Promise<CmssyPageData | null>;
|
|
43
|
-
declare function fetchPageById(config: CmssyClientConfig, pageId: string, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageData | null>;
|
|
44
|
-
declare function fetchPages(config: CmssyClientConfig, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageSummary[]>;
|
|
45
|
-
declare function fetchPageMeta(config: CmssyClientConfig, path: string | string[] | undefined, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageMeta | null>;
|
|
63
|
+
declare function fetchPageById(config: CmssyClientConfig, pageId: string, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageData | null>;
|
|
64
|
+
declare function fetchPages(config: CmssyClientConfig, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageSummary[]>;
|
|
65
|
+
declare function fetchPageMeta(config: CmssyClientConfig, path: string | string[] | undefined, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageMeta | null>;
|
|
46
66
|
declare function fetchLayouts(config: CmssyClientConfig, path: string | string[] | undefined, options?: FetchPageOptions): Promise<CmssyLayoutGroup[]>;
|
|
47
67
|
|
|
48
68
|
declare const SITE_CONFIG_QUERY = "query PublicSiteConfig($workspaceSlug: String!) {\n public {\n siteConfig(workspaceSlug: $workspaceSlug) {\n id\n workspaceId\n siteName\n defaultLanguage\n enabledLanguages\n enabledFeatures\n notFoundPageId\n previewUrl\n branding {\n brandName\n logoUrl\n faviconUrl\n ogImageUrl\n }\n }\n }\n}";
|
|
@@ -220,6 +240,12 @@ interface GraphqlRequestOptions {
|
|
|
220
240
|
* resolves the workspace from the URL rather than a global slug lookup.
|
|
221
241
|
*/
|
|
222
242
|
public?: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* Retry transient HTTP failures (429/503, honoring Retry-After). Off by
|
|
245
|
+
* default: this function also carries mutations (auth, cart, checkout),
|
|
246
|
+
* which must never be blind-retried. Read-only callers opt in with `{}`.
|
|
247
|
+
*/
|
|
248
|
+
retry?: RetryPolicy | false;
|
|
223
249
|
}
|
|
224
250
|
declare function graphqlRequest<T>(config: CmssyClientConfig, query: string, variables: Record<string, unknown>, options?: GraphqlRequestOptions, label?: string): Promise<T>;
|
|
225
251
|
|
|
@@ -282,4 +308,4 @@ interface UnknownBlockProps {
|
|
|
282
308
|
}
|
|
283
309
|
declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
|
|
284
310
|
|
|
285
|
-
export { type AppToEditorMessage, BlockDefinition, BlockMap, type BoundsMessage, type ClickMessage, CmssyBlock, type CmssyBlockProps, type CmssyClient, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, DEFAULT_CMSSY_API_URL, type EditorToAppMessage, FORM_QUERY, type FetchLike, type FetchLikeResponse, type FetchPageOptions, type GraphqlRequestOptions, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, type ParentReadyMessage, type PatchMessage, type PostTarget, type QueryScopedOptions, type ReadyMessage, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, type SelectMessage, UnknownBlock, type UnknownBlockProps, buildBlockContext, buildLocaleSwitchHref, collectFormIds, createCmssyClient, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|
|
311
|
+
export { type AppToEditorMessage, BlockDefinition, BlockMap, type BoundsMessage, type ClickMessage, CmssyBlock, type CmssyBlockProps, type CmssyClient, CmssyRequestError, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, DEFAULT_CMSSY_API_URL, type EditorToAppMessage, FORM_QUERY, type FetchLike, type FetchLikeResponse, type FetchPageOptions, type GraphqlRequestOptions, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, type ParentReadyMessage, type PatchMessage, type PostTarget, type QueryScopedOptions, type ReadyMessage, type RetryPolicy, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, type SelectMessage, UnknownBlock, type UnknownBlockProps, buildBlockContext, buildLocaleSwitchHref, collectFormIds, createCmssyClient, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,22 @@ export { b as blocksToMeta, c as blocksToSchemas, d as buildBlockMap, e as defin
|
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
import 'react';
|
|
7
7
|
|
|
8
|
+
/** HTTP-level failure from the cmssy API, with a machine-readable status. */
|
|
9
|
+
declare class CmssyRequestError extends Error {
|
|
10
|
+
readonly status: number;
|
|
11
|
+
constructor(message: string, status: number);
|
|
12
|
+
}
|
|
13
|
+
interface RetryPolicy {
|
|
14
|
+
/** Additional attempts after the first request (default 3). */
|
|
15
|
+
maxRetries?: number;
|
|
16
|
+
/** Exponential backoff base in ms: base * 2^attempt (default 300). */
|
|
17
|
+
baseDelayMs?: number;
|
|
18
|
+
/** Upper bound for any single wait, including Retry-After (default 3000). */
|
|
19
|
+
maxDelayMs?: number;
|
|
20
|
+
/** HTTP statuses that trigger a retry (default [429, 503]). */
|
|
21
|
+
retryStatuses?: number[];
|
|
22
|
+
}
|
|
23
|
+
|
|
8
24
|
/**
|
|
9
25
|
* The cmssy cloud GraphQL delivery endpoint. It is the same for every workspace,
|
|
10
26
|
* so consumers never need to set it - `apiUrl` defaults to this. Self-hosted /
|
|
@@ -23,6 +39,9 @@ interface FetchLikeResponse {
|
|
|
23
39
|
ok: boolean;
|
|
24
40
|
status: number;
|
|
25
41
|
json: () => Promise<unknown>;
|
|
42
|
+
headers?: {
|
|
43
|
+
get: (name: string) => string | null;
|
|
44
|
+
};
|
|
26
45
|
}
|
|
27
46
|
type FetchLike = (url: string, init: {
|
|
28
47
|
method: string;
|
|
@@ -37,12 +56,13 @@ interface FetchPageOptions {
|
|
|
37
56
|
workspaceId?: string;
|
|
38
57
|
fetch?: FetchLike;
|
|
39
58
|
signal?: AbortSignal;
|
|
59
|
+
retry?: RetryPolicy | false;
|
|
40
60
|
}
|
|
41
61
|
declare function normalizeSlug(path: string | string[] | undefined): string;
|
|
42
62
|
declare function fetchPage(config: CmssyClientConfig, path: string | string[] | undefined, options?: FetchPageOptions): Promise<CmssyPageData | null>;
|
|
43
|
-
declare function fetchPageById(config: CmssyClientConfig, pageId: string, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageData | null>;
|
|
44
|
-
declare function fetchPages(config: CmssyClientConfig, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageSummary[]>;
|
|
45
|
-
declare function fetchPageMeta(config: CmssyClientConfig, path: string | string[] | undefined, options?: Pick<FetchPageOptions, "fetch" | "signal">): Promise<CmssyPageMeta | null>;
|
|
63
|
+
declare function fetchPageById(config: CmssyClientConfig, pageId: string, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageData | null>;
|
|
64
|
+
declare function fetchPages(config: CmssyClientConfig, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageSummary[]>;
|
|
65
|
+
declare function fetchPageMeta(config: CmssyClientConfig, path: string | string[] | undefined, options?: Pick<FetchPageOptions, "fetch" | "signal" | "retry">): Promise<CmssyPageMeta | null>;
|
|
46
66
|
declare function fetchLayouts(config: CmssyClientConfig, path: string | string[] | undefined, options?: FetchPageOptions): Promise<CmssyLayoutGroup[]>;
|
|
47
67
|
|
|
48
68
|
declare const SITE_CONFIG_QUERY = "query PublicSiteConfig($workspaceSlug: String!) {\n public {\n siteConfig(workspaceSlug: $workspaceSlug) {\n id\n workspaceId\n siteName\n defaultLanguage\n enabledLanguages\n enabledFeatures\n notFoundPageId\n previewUrl\n branding {\n brandName\n logoUrl\n faviconUrl\n ogImageUrl\n }\n }\n }\n}";
|
|
@@ -220,6 +240,12 @@ interface GraphqlRequestOptions {
|
|
|
220
240
|
* resolves the workspace from the URL rather than a global slug lookup.
|
|
221
241
|
*/
|
|
222
242
|
public?: boolean;
|
|
243
|
+
/**
|
|
244
|
+
* Retry transient HTTP failures (429/503, honoring Retry-After). Off by
|
|
245
|
+
* default: this function also carries mutations (auth, cart, checkout),
|
|
246
|
+
* which must never be blind-retried. Read-only callers opt in with `{}`.
|
|
247
|
+
*/
|
|
248
|
+
retry?: RetryPolicy | false;
|
|
223
249
|
}
|
|
224
250
|
declare function graphqlRequest<T>(config: CmssyClientConfig, query: string, variables: Record<string, unknown>, options?: GraphqlRequestOptions, label?: string): Promise<T>;
|
|
225
251
|
|
|
@@ -282,4 +308,4 @@ interface UnknownBlockProps {
|
|
|
282
308
|
}
|
|
283
309
|
declare function UnknownBlock({ type }: UnknownBlockProps): react_jsx_runtime.JSX.Element;
|
|
284
310
|
|
|
285
|
-
export { type AppToEditorMessage, BlockDefinition, BlockMap, type BoundsMessage, type ClickMessage, CmssyBlock, type CmssyBlockProps, type CmssyClient, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, DEFAULT_CMSSY_API_URL, type EditorToAppMessage, FORM_QUERY, type FetchLike, type FetchLikeResponse, type FetchPageOptions, type GraphqlRequestOptions, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, type ParentReadyMessage, type PatchMessage, type PostTarget, type QueryScopedOptions, type ReadyMessage, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, type SelectMessage, UnknownBlock, type UnknownBlockProps, buildBlockContext, buildLocaleSwitchHref, collectFormIds, createCmssyClient, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|
|
311
|
+
export { type AppToEditorMessage, BlockDefinition, BlockMap, type BoundsMessage, type ClickMessage, CmssyBlock, type CmssyBlockProps, type CmssyClient, CmssyRequestError, CmssyServerLayout, type CmssyServerLayoutProps, CmssyServerPage, type CmssyServerPageProps, DEFAULT_CMSSY_API_URL, type EditorToAppMessage, FORM_QUERY, type FetchLike, type FetchLikeResponse, type FetchPageOptions, type GraphqlRequestOptions, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, type ParentReadyMessage, type PatchMessage, type PostTarget, type QueryScopedOptions, type ReadyMessage, type RetryPolicy, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, type SelectMessage, UnknownBlock, type UnknownBlockProps, buildBlockContext, buildLocaleSwitchHref, collectFormIds, createCmssyClient, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|
package/dist/index.js
CHANGED
|
@@ -340,6 +340,108 @@ function parseEditorMessage(data, origin, expectedOrigin) {
|
|
|
340
340
|
}
|
|
341
341
|
}
|
|
342
342
|
|
|
343
|
+
// src/data/http.ts
|
|
344
|
+
var CmssyRequestError = class extends Error {
|
|
345
|
+
status;
|
|
346
|
+
constructor(message, status) {
|
|
347
|
+
super(message);
|
|
348
|
+
this.name = "CmssyRequestError";
|
|
349
|
+
this.status = status;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
var DEFAULT_RETRY_STATUSES = [429, 503];
|
|
353
|
+
function retryAfterMs(response) {
|
|
354
|
+
const raw = response.headers?.get("retry-after");
|
|
355
|
+
if (!raw) return null;
|
|
356
|
+
const seconds = Number(raw);
|
|
357
|
+
if (Number.isFinite(seconds)) return Math.max(0, seconds * 1e3);
|
|
358
|
+
const date = Date.parse(raw);
|
|
359
|
+
if (Number.isFinite(date)) return Math.max(0, date - Date.now());
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
function sleep(ms, signal) {
|
|
363
|
+
return new Promise((resolve, reject) => {
|
|
364
|
+
if (signal?.aborted) {
|
|
365
|
+
reject(new Error("cmssy: request aborted"));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const timer = setTimeout(() => {
|
|
369
|
+
signal?.removeEventListener("abort", onAbort);
|
|
370
|
+
resolve();
|
|
371
|
+
}, ms);
|
|
372
|
+
function onAbort() {
|
|
373
|
+
clearTimeout(timer);
|
|
374
|
+
reject(new Error("cmssy: request aborted"));
|
|
375
|
+
}
|
|
376
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
async function fetchWithRetry(doFetch, url, init, retry) {
|
|
380
|
+
if (retry === false || retry === void 0) {
|
|
381
|
+
return doFetch(url, init);
|
|
382
|
+
}
|
|
383
|
+
const maxRetries = retry.maxRetries ?? 3;
|
|
384
|
+
const baseDelayMs = retry.baseDelayMs ?? 300;
|
|
385
|
+
const maxDelayMs = retry.maxDelayMs ?? 3e3;
|
|
386
|
+
const retryStatuses = retry.retryStatuses ?? DEFAULT_RETRY_STATUSES;
|
|
387
|
+
let response = await doFetch(url, init);
|
|
388
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
389
|
+
if (response.ok || !retryStatuses.includes(response.status)) {
|
|
390
|
+
return response;
|
|
391
|
+
}
|
|
392
|
+
const backoff = baseDelayMs * 2 ** attempt;
|
|
393
|
+
const wait = Math.min(retryAfterMs(response) ?? backoff, maxDelayMs);
|
|
394
|
+
await sleep(wait, init.signal);
|
|
395
|
+
response = await doFetch(url, init);
|
|
396
|
+
}
|
|
397
|
+
return response;
|
|
398
|
+
}
|
|
399
|
+
async function postGraphql(url, query, variables, options) {
|
|
400
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
401
|
+
if (typeof doFetch !== "function") {
|
|
402
|
+
throw new Error(
|
|
403
|
+
"cmssy: no fetch implementation available - pass options.fetch"
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
const response = await fetchWithRetry(
|
|
407
|
+
doFetch,
|
|
408
|
+
url,
|
|
409
|
+
{
|
|
410
|
+
method: "POST",
|
|
411
|
+
headers: { "content-type": "application/json", ...options.headers },
|
|
412
|
+
body: JSON.stringify({ query, variables }),
|
|
413
|
+
signal: options.signal
|
|
414
|
+
},
|
|
415
|
+
options.retry
|
|
416
|
+
);
|
|
417
|
+
if (!response.ok) {
|
|
418
|
+
let detail = "";
|
|
419
|
+
try {
|
|
420
|
+
const body = await response.json();
|
|
421
|
+
if (body.errors && body.errors.length > 0) {
|
|
422
|
+
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
423
|
+
}
|
|
424
|
+
} catch {
|
|
425
|
+
detail = "";
|
|
426
|
+
}
|
|
427
|
+
throw new CmssyRequestError(
|
|
428
|
+
`cmssy: ${options.label} failed (${response.status})${detail}`,
|
|
429
|
+
response.status
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
let json;
|
|
433
|
+
try {
|
|
434
|
+
json = await response.json();
|
|
435
|
+
} catch {
|
|
436
|
+
throw new Error(`cmssy: invalid JSON response from the ${options.label}`);
|
|
437
|
+
}
|
|
438
|
+
if (json.errors && json.errors.length > 0) {
|
|
439
|
+
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
440
|
+
throw new Error(`cmssy: ${options.label} error - ${message}`);
|
|
441
|
+
}
|
|
442
|
+
return json.data;
|
|
443
|
+
}
|
|
444
|
+
|
|
343
445
|
// src/content/content-client.ts
|
|
344
446
|
var DEFAULT_CMSSY_API_URL = "https://api.cmssy.io/graphql";
|
|
345
447
|
function resolveApiUrl(apiUrl) {
|
|
@@ -431,251 +533,113 @@ function normalizeSlug(path) {
|
|
|
431
533
|
}
|
|
432
534
|
async function fetchPage(config, path, options = {}) {
|
|
433
535
|
const slug = normalizeSlug(path);
|
|
434
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
435
|
-
if (typeof doFetch !== "function") {
|
|
436
|
-
throw new Error(
|
|
437
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
536
|
const trimmedSecret = options.previewSecret?.trim();
|
|
441
537
|
const previewSecret = trimmedSecret ? trimmedSecret : null;
|
|
442
538
|
const devToken = options.devToken?.trim();
|
|
443
539
|
const devPreview = Boolean(options.devPreview && devToken);
|
|
444
|
-
const headers = {
|
|
445
|
-
"content-type": "application/json"
|
|
446
|
-
};
|
|
540
|
+
const headers = {};
|
|
447
541
|
if (devPreview && devToken) {
|
|
448
542
|
headers["authorization"] = `Bearer ${devToken}`;
|
|
449
543
|
if (options.workspaceId) {
|
|
450
544
|
headers["x-workspace-id"] = options.workspaceId;
|
|
451
545
|
}
|
|
452
546
|
}
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
let detail = "";
|
|
469
|
-
try {
|
|
470
|
-
const body = await response.json();
|
|
471
|
-
if (body.errors && body.errors.length > 0) {
|
|
472
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
473
|
-
}
|
|
474
|
-
} catch {
|
|
475
|
-
detail = "";
|
|
547
|
+
const data = await postGraphql(
|
|
548
|
+
resolvePublicUrl(config),
|
|
549
|
+
devPreview ? PUBLIC_PAGE_DEV_QUERY : PUBLIC_PAGE_QUERY,
|
|
550
|
+
{
|
|
551
|
+
workspaceSlug: config.workspaceSlug,
|
|
552
|
+
slug,
|
|
553
|
+
previewSecret,
|
|
554
|
+
...devPreview ? { devPreview: true } : {}
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
fetch: options.fetch,
|
|
558
|
+
signal: options.signal,
|
|
559
|
+
headers,
|
|
560
|
+
retry: options.retry ?? {},
|
|
561
|
+
label: "page fetch"
|
|
476
562
|
}
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
let json;
|
|
480
|
-
try {
|
|
481
|
-
json = await response.json();
|
|
482
|
-
} catch {
|
|
483
|
-
throw new Error("cmssy: invalid JSON response from the page query");
|
|
484
|
-
}
|
|
485
|
-
if (json.errors && json.errors.length > 0) {
|
|
486
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
487
|
-
throw new Error(`cmssy: page fetch error - ${message}`);
|
|
488
|
-
}
|
|
489
|
-
const page = json.data?.public?.page?.get;
|
|
563
|
+
);
|
|
564
|
+
const page = data?.public?.page?.get;
|
|
490
565
|
if (!page) return null;
|
|
491
566
|
const draft = previewSecret !== null || devPreview;
|
|
492
567
|
const blocks = (draft ? page.blocks : page.publishedBlocks) ?? [];
|
|
493
568
|
return { id: page.id, blocks };
|
|
494
569
|
}
|
|
495
570
|
async function fetchPageById(config, pageId, options = {}) {
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
body: JSON.stringify({
|
|
506
|
-
query: PUBLIC_PAGE_BY_ID_QUERY,
|
|
507
|
-
variables: { workspaceSlug: config.workspaceSlug, pageId }
|
|
508
|
-
}),
|
|
509
|
-
signal: options.signal
|
|
510
|
-
});
|
|
511
|
-
if (!response.ok) {
|
|
512
|
-
let detail = "";
|
|
513
|
-
try {
|
|
514
|
-
const body = await response.json();
|
|
515
|
-
if (body.errors && body.errors.length > 0) {
|
|
516
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
517
|
-
}
|
|
518
|
-
} catch {
|
|
519
|
-
detail = "";
|
|
571
|
+
const data = await postGraphql(
|
|
572
|
+
resolvePublicUrl(config),
|
|
573
|
+
PUBLIC_PAGE_BY_ID_QUERY,
|
|
574
|
+
{ workspaceSlug: config.workspaceSlug, pageId },
|
|
575
|
+
{
|
|
576
|
+
fetch: options.fetch,
|
|
577
|
+
signal: options.signal,
|
|
578
|
+
retry: options.retry ?? {},
|
|
579
|
+
label: "page-by-id fetch"
|
|
520
580
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
);
|
|
524
|
-
}
|
|
525
|
-
let json;
|
|
526
|
-
try {
|
|
527
|
-
json = await response.json();
|
|
528
|
-
} catch {
|
|
529
|
-
throw new Error("cmssy: invalid JSON response from the page-by-id query");
|
|
530
|
-
}
|
|
531
|
-
if (json.errors && json.errors.length > 0) {
|
|
532
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
533
|
-
throw new Error(`cmssy: page-by-id fetch error - ${message}`);
|
|
534
|
-
}
|
|
535
|
-
const page = json.data?.public?.page?.getById;
|
|
581
|
+
);
|
|
582
|
+
const page = data?.public?.page?.getById;
|
|
536
583
|
if (!page) return null;
|
|
537
584
|
return { id: page.id, blocks: page.publishedBlocks ?? [] };
|
|
538
585
|
}
|
|
539
586
|
async function fetchPages(config, options = {}) {
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
}),
|
|
553
|
-
signal: options.signal
|
|
554
|
-
});
|
|
555
|
-
if (!response.ok) {
|
|
556
|
-
throw new Error(`cmssy: pages fetch failed (${response.status})`);
|
|
557
|
-
}
|
|
558
|
-
let json;
|
|
559
|
-
try {
|
|
560
|
-
json = await response.json();
|
|
561
|
-
} catch {
|
|
562
|
-
throw new Error("cmssy: invalid JSON response from the pages query");
|
|
563
|
-
}
|
|
564
|
-
if (json.errors && json.errors.length > 0) {
|
|
565
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
566
|
-
throw new Error(`cmssy: pages fetch error - ${message}`);
|
|
567
|
-
}
|
|
568
|
-
return json.data?.public?.page?.list ?? [];
|
|
587
|
+
const data = await postGraphql(
|
|
588
|
+
resolvePublicUrl(config),
|
|
589
|
+
PUBLIC_PAGES_QUERY,
|
|
590
|
+
{ workspaceSlug: config.workspaceSlug },
|
|
591
|
+
{
|
|
592
|
+
fetch: options.fetch,
|
|
593
|
+
signal: options.signal,
|
|
594
|
+
retry: options.retry ?? {},
|
|
595
|
+
label: "pages fetch"
|
|
596
|
+
}
|
|
597
|
+
);
|
|
598
|
+
return data?.public?.page?.list ?? [];
|
|
569
599
|
}
|
|
570
600
|
async function fetchPageMeta(config, path, options = {}) {
|
|
571
601
|
const slug = normalizeSlug(path);
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
}),
|
|
585
|
-
signal: options.signal
|
|
586
|
-
});
|
|
587
|
-
if (!response.ok) {
|
|
588
|
-
throw new Error(`cmssy: page meta fetch failed (${response.status})`);
|
|
589
|
-
}
|
|
590
|
-
let json;
|
|
591
|
-
try {
|
|
592
|
-
json = await response.json();
|
|
593
|
-
} catch {
|
|
594
|
-
throw new Error("cmssy: invalid JSON response from the page meta query");
|
|
595
|
-
}
|
|
596
|
-
if (json.errors && json.errors.length > 0) {
|
|
597
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
598
|
-
throw new Error(`cmssy: page meta fetch error - ${message}`);
|
|
599
|
-
}
|
|
600
|
-
return json.data?.public?.page?.get ?? null;
|
|
602
|
+
const data = await postGraphql(
|
|
603
|
+
resolvePublicUrl(config),
|
|
604
|
+
PUBLIC_PAGE_META_QUERY,
|
|
605
|
+
{ workspaceSlug: config.workspaceSlug, slug },
|
|
606
|
+
{
|
|
607
|
+
fetch: options.fetch,
|
|
608
|
+
signal: options.signal,
|
|
609
|
+
retry: options.retry ?? {},
|
|
610
|
+
label: "page meta fetch"
|
|
611
|
+
}
|
|
612
|
+
);
|
|
613
|
+
return data?.public?.page?.get ?? null;
|
|
601
614
|
}
|
|
602
615
|
async function fetchLayouts(config, path, options = {}) {
|
|
603
616
|
const pageSlug = normalizeSlug(path);
|
|
604
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
605
|
-
if (typeof doFetch !== "function") {
|
|
606
|
-
throw new Error(
|
|
607
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
617
|
const trimmedSecret = options.previewSecret?.trim();
|
|
611
618
|
const previewSecret = trimmedSecret ? trimmedSecret : null;
|
|
612
|
-
const
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
});
|
|
625
|
-
if (!response.ok) {
|
|
626
|
-
throw new Error(`cmssy: layouts fetch failed (${response.status})`);
|
|
627
|
-
}
|
|
628
|
-
let json;
|
|
629
|
-
try {
|
|
630
|
-
json = await response.json();
|
|
631
|
-
} catch {
|
|
632
|
-
throw new Error("cmssy: invalid JSON response from the layouts query");
|
|
633
|
-
}
|
|
634
|
-
if (json.errors && json.errors.length > 0) {
|
|
635
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
636
|
-
throw new Error(`cmssy: layouts fetch error - ${message}`);
|
|
637
|
-
}
|
|
638
|
-
return json.data?.public?.page?.layouts ?? [];
|
|
619
|
+
const data = await postGraphql(
|
|
620
|
+
resolvePublicUrl(config),
|
|
621
|
+
PUBLIC_PAGE_LAYOUTS_QUERY,
|
|
622
|
+
{ workspaceSlug: config.workspaceSlug, pageSlug, previewSecret },
|
|
623
|
+
{
|
|
624
|
+
fetch: options.fetch,
|
|
625
|
+
signal: options.signal,
|
|
626
|
+
retry: options.retry ?? {},
|
|
627
|
+
label: "layouts fetch"
|
|
628
|
+
}
|
|
629
|
+
);
|
|
630
|
+
return data?.public?.page?.layouts ?? [];
|
|
639
631
|
}
|
|
640
632
|
|
|
641
633
|
// src/data/graphql-request.ts
|
|
642
634
|
async function graphqlRequest(config, query, variables, options = {}, label = "request") {
|
|
643
|
-
const doFetch = options.fetch ?? globalThis.fetch;
|
|
644
|
-
if (typeof doFetch !== "function") {
|
|
645
|
-
throw new Error(
|
|
646
|
-
"cmssy: no fetch implementation available - pass options.fetch"
|
|
647
|
-
);
|
|
648
|
-
}
|
|
649
635
|
const url = options.public ? resolvePublicUrl(config) : resolveApiUrl(config.apiUrl);
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
636
|
+
return postGraphql(url, query, variables, {
|
|
637
|
+
fetch: options.fetch,
|
|
638
|
+
signal: options.signal,
|
|
639
|
+
headers: options.headers,
|
|
640
|
+
retry: options.retry,
|
|
641
|
+
label
|
|
655
642
|
});
|
|
656
|
-
if (!response.ok) {
|
|
657
|
-
let detail = "";
|
|
658
|
-
try {
|
|
659
|
-
const body = await response.json();
|
|
660
|
-
if (body.errors && body.errors.length > 0) {
|
|
661
|
-
detail = ` - ${body.errors.map((error) => error.message ?? "GraphQL error").join("; ")}`;
|
|
662
|
-
}
|
|
663
|
-
} catch {
|
|
664
|
-
detail = "";
|
|
665
|
-
}
|
|
666
|
-
throw new Error(`cmssy: ${label} failed (${response.status})${detail}`);
|
|
667
|
-
}
|
|
668
|
-
let json;
|
|
669
|
-
try {
|
|
670
|
-
json = await response.json();
|
|
671
|
-
} catch {
|
|
672
|
-
throw new Error(`cmssy: invalid JSON response from the ${label}`);
|
|
673
|
-
}
|
|
674
|
-
if (json.errors && json.errors.length > 0) {
|
|
675
|
-
const message = json.errors.map((error) => error.message ?? "GraphQL error").join("; ");
|
|
676
|
-
throw new Error(`cmssy: ${label} error - ${message}`);
|
|
677
|
-
}
|
|
678
|
-
return json.data;
|
|
679
643
|
}
|
|
680
644
|
|
|
681
645
|
// src/data/queries.ts
|
|
@@ -757,7 +721,7 @@ async function fetchSiteConfig(config, options = {}) {
|
|
|
757
721
|
config,
|
|
758
722
|
SITE_CONFIG_QUERY,
|
|
759
723
|
{ workspaceSlug: config.workspaceSlug },
|
|
760
|
-
{ ...options, public: true },
|
|
724
|
+
{ ...options, public: true, retry: options.retry ?? {} },
|
|
761
725
|
"site config query"
|
|
762
726
|
);
|
|
763
727
|
return data.public?.siteConfig ?? null;
|
|
@@ -873,7 +837,7 @@ async function resolveSiteLocales(config, options) {
|
|
|
873
837
|
config,
|
|
874
838
|
SITE_CONFIG_QUERY,
|
|
875
839
|
{ workspaceSlug: config.workspaceSlug },
|
|
876
|
-
{ ...options, public: true },
|
|
840
|
+
{ ...options, public: true, retry: options?.retry ?? {} },
|
|
877
841
|
"site config"
|
|
878
842
|
);
|
|
879
843
|
const siteConfig = data.public?.siteConfig ?? null;
|
|
@@ -978,4 +942,4 @@ function CmssyBlock({
|
|
|
978
942
|
);
|
|
979
943
|
}
|
|
980
944
|
|
|
981
|
-
export { CmssyBlock, CmssyServerLayout, CmssyServerPage, DEFAULT_CMSSY_API_URL, FORM_QUERY, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, UnknownBlock, blocksToMeta, blocksToSchemas, buildBlockContext, buildBlockMap, buildLocaleSwitchHref, collectFormIds, createCmssyClient, defineBlock, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|
|
945
|
+
export { CmssyBlock, CmssyRequestError, CmssyServerLayout, CmssyServerPage, DEFAULT_CMSSY_API_URL, FORM_QUERY, MODEL_DEFINITIONS_QUERY, MODEL_RECORDS_QUERY, PROTOCOL_VERSION, SITE_CONFIG_QUERY, SUBMIT_FORM_MUTATION, UnknownBlock, blocksToMeta, blocksToSchemas, buildBlockContext, buildBlockMap, buildLocaleSwitchHref, collectFormIds, createCmssyClient, defineBlock, fetchLayouts, fetchPage, fetchPageById, fetchPageMeta, fetchPages, fetchSiteConfig, fields, getBlockContentForLanguage, graphqlRequest, isProtocolCompatible, localizeHref, localizeHtmlLinks, normalizeOrigin, normalizeSlug, parseEditorMessage, postToEditor, resolveApiUrl, resolveForms, resolvePublicUrl, resolveSiteLocales, resolveWorkspaceId, splitLocaleFromPath };
|