riverbankcms 0.12.0 → 0.14.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.
@@ -48,6 +48,8 @@ const unsafeAsApiKeyId = (id) => id;
48
48
  const unsafeAsSiteRouteId = (id) => id;
49
49
  const unsafeAsPageId = (id) => id;
50
50
  const unsafeAsPageSurfaceId = (id) => id;
51
+ const unsafeAsEditLeaseToken = (id) => id;
52
+ const unsafeAsEditorClientId = (id) => id;
51
53
  const unsafeAsOccurrenceId = (id) => id;
52
54
  const unsafeAsEventOfferingId = (id) => id;
53
55
  const unsafeAsEventSeriesId = (id) => id;
@@ -120,6 +122,8 @@ const unsafeAsContentBlockId = (id) => id;
120
122
  const unsafeAsContentVersionId = (id) => id;
121
123
  const unsafeAsEntryContentHash = (value) => value;
122
124
  const unsafeAsStripeInvoiceId = (id) => id;
125
+ const unsafeAsStripeCustomerId = (id) => id;
126
+ const unsafeAsStripeSubscriptionId = (id) => id;
123
127
  const unsafeAsNewsletterSubscriberId = (id) => id;
124
128
  const unsafeAsNavigationMenuId = (id) => id;
125
129
  const unsafeAsNavigationItemId = (id) => id;
@@ -156,6 +160,8 @@ const parseApiKeyId = (value) => parseUuidBrand(value, unsafeAsApiKeyId);
156
160
  const parseSiteRouteId = (value) => parseUuidBrand(value, unsafeAsSiteRouteId);
157
161
  const parsePageId = (value) => parseUuidBrand(value, unsafeAsPageId);
158
162
  const parsePageSurfaceId = (value) => parseUuidBrand(value, unsafeAsPageSurfaceId);
163
+ const parseEditLeaseToken = (value) => parseUuidBrand(value, unsafeAsEditLeaseToken);
164
+ const parseEditorClientId = (value) => parseUuidBrand(value, unsafeAsEditorClientId);
159
165
  const parseOccurrenceId = (value) => parseUuidBrand(value, unsafeAsOccurrenceId);
160
166
  const parseEventOfferingId = (value) => parseUuidBrand(value, unsafeAsEventOfferingId);
161
167
  const parseEventAttendeeTicketLineId = (value) => parseUuidBrand(value, unsafeAsEventAttendeeTicketLineId);
@@ -223,6 +229,29 @@ function subtractDaysFromIso(isoString, dayCount) {
223
229
  return addDaysToIso(isoString, -dayCount);
224
230
  }
225
231
 
232
+ //#endregion
233
+ //#region ../core/src/html-entities.ts
234
+ const NAMED_ENTITIES = {
235
+ amp: "&",
236
+ lt: "<",
237
+ gt: ">",
238
+ quot: "\"",
239
+ apos: "'",
240
+ nbsp: "\xA0"
241
+ };
242
+ /**
243
+ * Decodes the HTML entities rendered pages commonly contain (the basic named
244
+ * set plus decimal and hex numeric references), leaving anything else as is.
245
+ * For reading text back out of server-rendered HTML, not for sanitising input.
246
+ */
247
+ function decodeHtmlEntities(text) {
248
+ return text.replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi, (entity, body) => {
249
+ if (body[0] !== "#") return NAMED_ENTITIES[body.toLowerCase()] ?? entity;
250
+ const codePoint = body[1] === "x" || body[1] === "X" ? Number.parseInt(body.slice(2), 16) : Number.parseInt(body.slice(1), 10);
251
+ return Number.isInteger(codePoint) && codePoint > 0 && codePoint <= 1114111 ? String.fromCodePoint(codePoint) : entity;
252
+ });
253
+ }
254
+
226
255
  //#endregion
227
256
  //#region ../core/src/duration.ts
228
257
  const DURATION_UNIT_MINUTES = {
@@ -357,7 +386,7 @@ const demoInstanceStatusValues = [
357
386
  "available",
358
387
  "claimed",
359
388
  "expired",
360
- "recycling",
389
+ "showcase",
361
390
  "failed"
362
391
  ];
363
392
  const demoClaimStatusValues = [
@@ -365,7 +394,7 @@ const demoClaimStatusValues = [
365
394
  "expired",
366
395
  "released"
367
396
  ];
368
- const demoBlueprintArtifactKindValues = ["site_backup", "manual_snapshot"];
397
+ const demoBlueprintArtifactKindValues = ["recipe"];
369
398
  function narrowDemoInstanceStatus(value) {
370
399
  if (demoInstanceStatusValues.includes(value)) {
371
400
  return value;
@@ -385,6 +414,28 @@ function narrowDemoBlueprintArtifactKind(value) {
385
414
  throw new Error(`Unexpected demo blueprint artifact kind: ${value}`);
386
415
  }
387
416
 
417
+ //#endregion
418
+ //#region ../core/src/demo-warm-pool-target.ts
419
+ const DEFAULT_DEMO_WARM_POOL_TARGET = 0;
420
+ const MAX_DEMO_WARM_POOL_TARGET = 20;
421
+ function parseDemoWarmPoolTarget(value) {
422
+ if (value === undefined || value === null || value.trim() === "") {
423
+ return ok(DEFAULT_DEMO_WARM_POOL_TARGET);
424
+ }
425
+ const normalized = value.trim();
426
+ if (!/^(0|[1-9]\d*)$/u.test(normalized)) {
427
+ return err(invalidTargetError());
428
+ }
429
+ const target = Number(normalized);
430
+ return Number.isSafeInteger(target) && target <= MAX_DEMO_WARM_POOL_TARGET ? ok(target) : err(invalidTargetError());
431
+ }
432
+ function invalidTargetError() {
433
+ return {
434
+ kind: "invalid_demo_warm_pool_target",
435
+ message: "DEMO_WARM_POOL_TARGET must be a whole number from 0 to 20."
436
+ };
437
+ }
438
+
388
439
  //#endregion
389
440
  //#region ../core/src/demo-runtime.ts
390
441
  const RIVERBANK_RUNTIME_ENV_VAR = "RIVERBANK_RUNTIME_ENV";
@@ -544,6 +595,19 @@ const CURRENCY_LOCALE_BY_CODE = {
544
595
  function resolveCurrencyLocale(currencyCode, override) {
545
596
  return override ?? CURRENCY_LOCALE_BY_CODE[currencyCode] ?? "en";
546
597
  }
598
+ function fractionDigitsFor(decimals, exactFormatter) {
599
+ switch (decimals) {
600
+ case "exact": return {};
601
+ case "auto": return {
602
+ minimumFractionDigits: 0,
603
+ maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
604
+ };
605
+ case "whole": return {
606
+ minimumFractionDigits: 0,
607
+ maximumFractionDigits: 0
608
+ };
609
+ }
610
+ }
547
611
  /**
548
612
  * The single currency-amount formatter for the product: minor units in,
549
613
  * localized string out.
@@ -554,6 +618,13 @@ function resolveCurrencyLocale(currencyCode, override) {
554
618
  * own `Intl.NumberFormat`.
555
619
  */
556
620
  function formatCurrencyAmount(amountCents, currency, options) {
621
+ return formatCurrencyMajorUnits(amountCents / 100, currency, options);
622
+ }
623
+ /**
624
+ * `formatCurrencyAmount` for an amount already in MAJOR units (29.99 = £29.99),
625
+ * such as a registrar price. Prefer minor units everywhere else.
626
+ */
627
+ function formatCurrencyMajorUnits(amount, currency, options) {
557
628
  const currencyCode = currency.toUpperCase();
558
629
  const locale = resolveCurrencyLocale(currencyCode, options?.locale);
559
630
  try {
@@ -561,17 +632,13 @@ function formatCurrencyAmount(amountCents, currency, options) {
561
632
  style: "currency",
562
633
  currency: currencyCode
563
634
  });
564
- const fractionDigits = options?.decimals === "auto" ? {
565
- minimumFractionDigits: 0,
566
- maximumFractionDigits: exactFormatter.resolvedOptions().maximumFractionDigits
567
- } : {};
568
635
  return new Intl.NumberFormat(locale, {
569
636
  style: "currency",
570
637
  currency: currencyCode,
571
- ...fractionDigits
572
- }).format(amountCents / 100);
638
+ ...fractionDigitsFor(options?.decimals ?? "exact", exactFormatter)
639
+ }).format(amount);
573
640
  } catch {
574
- return `${(amountCents / 100).toFixed(2)} ${currencyCode}`;
641
+ return `${amount.toFixed(2)} ${currencyCode}`;
575
642
  }
576
643
  }
577
644
 
@@ -2446,6 +2513,18 @@ const unsafeAsEditorSiteId = (value) => value;
2446
2513
  const unsafeAsEditorPageId = (value) => value;
2447
2514
  const unsafeAsEditorEntryId = (value) => value;
2448
2515
  const unsafeAsEditorBlockId = (value) => value;
2516
+ function editorBlockCollectionOwnerKey(owner) {
2517
+ switch (owner.kind) {
2518
+ case "page": return `page:${owner.pageId}`;
2519
+ case "entry-slot": return `entry-slot:${owner.type}:${owner.entryId}:${owner.slotKey}`;
2520
+ case "surface-slot": return `surface-slot:${owner.pageSurfaceId}:${owner.slotKey}`;
2521
+ case "site-footer": return `site-footer:${owner.siteId}`;
2522
+ }
2523
+ }
2524
+ function editorBlockCollectionOwnersEqual(left, right) {
2525
+ if (left === right) return true;
2526
+ return left !== null && right !== null && editorBlockCollectionOwnerKey(left) === editorBlockCollectionOwnerKey(right);
2527
+ }
2449
2528
  const unsafeAsEditorMetadataValues = (value) => value;
2450
2529
  const unsafeAsEditorContentValues = (value) => value;
2451
2530
  const unsafeAsEditorBlockValues = (value) => value;
@@ -2470,6 +2549,151 @@ function createEditorReorderBlocksCommand(blockIds) {
2470
2549
  };
2471
2550
  }
2472
2551
 
2552
+ //#endregion
2553
+ //#region ../core/src/editor-value-sync.ts
2554
+ const unsafeAsSendId = (value) => value;
2555
+ const UNKNOWN_REVISION = { kind: "unknown" };
2556
+ function knownRevision(value) {
2557
+ return {
2558
+ kind: "known",
2559
+ value
2560
+ };
2561
+ }
2562
+ /** A pristine value at the given baseline. */
2563
+ function pristineValueSync(values, revision) {
2564
+ return {
2565
+ baseline: {
2566
+ values,
2567
+ revision
2568
+ },
2569
+ local: {
2570
+ kind: "pristine",
2571
+ request: { kind: "idle" }
2572
+ }
2573
+ };
2574
+ }
2575
+ /** What the person sees: their edits, or the baseline when there are none. */
2576
+ function displayedValues(sync) {
2577
+ return sync.local.kind === "edited" ? sync.local.values : sync.baseline.values;
2578
+ }
2579
+ /** Pristine counts as saved even with an abandoned request: nothing the person wants is unsaved. */
2580
+ function valueStatus(sync) {
2581
+ if (sync.local.kind === "pristine") return "saved";
2582
+ switch (sync.local.request.kind) {
2583
+ case "idle":
2584
+ case "abandoned": return "unsaved";
2585
+ case "in-flight": return "saving";
2586
+ case "failed": return "failed";
2587
+ default: return assertNever(sync.local.request);
2588
+ }
2589
+ }
2590
+ /** Projects the model onto the presentation sync state: unsaved and saving are both `pending`. */
2591
+ function syncStateOf(sync) {
2592
+ if (sync.local.kind === "edited" && sync.local.request.kind === "failed") {
2593
+ return {
2594
+ kind: "failed",
2595
+ error: sync.local.request.error
2596
+ };
2597
+ }
2598
+ return valueStatus(sync) === "saved" ? { kind: "baseline" } : { kind: "pending" };
2599
+ }
2600
+
2601
+ //#endregion
2602
+ //#region ../core/src/edit-lease.ts
2603
+ function parseEditLeaseScope(input) {
2604
+ switch (input.nodeType) {
2605
+ case "page": {
2606
+ const id = parsePageId(input.nodeId);
2607
+ return id.ok ? {
2608
+ nodeType: "page",
2609
+ nodeId: id.value
2610
+ } : null;
2611
+ }
2612
+ case "content_entry": {
2613
+ const id = parseContentEntryId(input.nodeId);
2614
+ return id.ok ? {
2615
+ nodeType: "content_entry",
2616
+ nodeId: id.value
2617
+ } : null;
2618
+ }
2619
+ case "page_surface": {
2620
+ const id = parsePageSurfaceId(input.nodeId);
2621
+ return id.ok ? {
2622
+ nodeType: "page_surface",
2623
+ nodeId: id.value
2624
+ } : null;
2625
+ }
2626
+ }
2627
+ }
2628
+
2629
+ //#endregion
2630
+ //#region ../core/src/block-content-identity.ts
2631
+ function readContentVersionId(value) {
2632
+ const parsed = parseContentVersionId(value);
2633
+ return parsed.ok ? parsed.value : null;
2634
+ }
2635
+ /** The one pairing of a published id with its content. */
2636
+ function readPublishedBlockPlacement(id, content$1) {
2637
+ if (id == null && content$1 == null) return null;
2638
+ const versionId = readContentVersionId(id);
2639
+ return versionId !== null && content$1 != null ? {
2640
+ kind: "published",
2641
+ id: versionId,
2642
+ content: content$1
2643
+ } : {
2644
+ kind: "incomplete",
2645
+ id: id ?? null,
2646
+ content: content$1 ?? null
2647
+ };
2648
+ }
2649
+ const NO_BLOCK_VERSIONS = {
2650
+ draftContentId: null,
2651
+ publishedPlacement: null
2652
+ };
2653
+ /** The one conversion from wire identity to editor identity. */
2654
+ function readEditorBlockVersions(wire) {
2655
+ return {
2656
+ draftContentId: readContentVersionId(wire.draftContentId),
2657
+ publishedPlacement: readPublishedBlockPlacement(wire.publishedContentId, wire.publishedContent)
2658
+ };
2659
+ }
2660
+ /** Editor identity from a render block, whose published placement is already paired. */
2661
+ function readEditorBlockVersionsFromPlacement(draftContentId, publishedPlacement) {
2662
+ return {
2663
+ draftContentId: readContentVersionId(draftContentId),
2664
+ publishedPlacement
2665
+ };
2666
+ }
2667
+ /** The published version a block can cite, if it has a complete one. */
2668
+ function publishedVersionOf(versions) {
2669
+ const placement = versions?.publishedPlacement ?? null;
2670
+ return placement?.kind === "published" ? placement : null;
2671
+ }
2672
+ /** The content version a block renders: its draft if it has one, else its published version. */
2673
+ function selectedContentVersionId(versions) {
2674
+ return versions.draftContentId ?? publishedVersionOf(versions)?.id ?? null;
2675
+ }
2676
+ /** Published content the editor treats as its dirty-state baseline. */
2677
+ function publishedContentOf(versions) {
2678
+ return publishedVersionOf(versions)?.content ?? null;
2679
+ }
2680
+ function readContentRecord(value) {
2681
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
2682
+ }
2683
+ /** A block's versions after the server acknowledges one content save. */
2684
+ function applySavedBlockContentVersion(versions, saved) {
2685
+ switch (saved.stage) {
2686
+ case "draft": return {
2687
+ ...versions,
2688
+ draftContentId: readContentVersionId(saved.contentId)
2689
+ };
2690
+ case "published": return {
2691
+ draftContentId: null,
2692
+ publishedPlacement: readPublishedBlockPlacement(saved.contentId, readContentRecord(saved.data))
2693
+ };
2694
+ }
2695
+ }
2696
+
2473
2697
  //#endregion
2474
2698
  //#region ../core/src/sensitive-collection.ts
2475
2699
  const SENSITIVE_COLLECTION_MODES = ["standard", "sensitive"];
@@ -5850,14 +6074,18 @@ function generateUniqueSlug(text, existingSlugs) {
5850
6074
 
5851
6075
  //#endregion
5852
6076
  //#region ../core/src/uuid.ts
5853
- /**
5854
- * Validates whether a string matches UUID v4 format
5855
- * Format: 8-4-4-4-12 hexadecimal digits
5856
- * Example: 550e8400-e29b-41d4-a716-446655440000
5857
- */
6077
+ /** Validate a UUID in the existing 8-4-4-4-12 hexadecimal format. */
5858
6078
  function isValidUuid(str) {
5859
6079
  return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
5860
6080
  }
6081
+ function generateUuidV4(cryptoSource = globalThis.crypto) {
6082
+ if (typeof cryptoSource.randomUUID === "function") return cryptoSource.randomUUID();
6083
+ const bytes = cryptoSource.getRandomValues(new Uint8Array(16));
6084
+ bytes[6] = (bytes[6] ?? 0) & 15 | 64;
6085
+ bytes[8] = (bytes[8] ?? 0) & 63 | 128;
6086
+ const hex = Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0"));
6087
+ return `${hex.slice(0, 4).join("")}-${hex.slice(4, 6).join("")}-${hex.slice(6, 8).join("")}-${hex.slice(8, 10).join("")}-${hex.slice(10).join("")}`;
6088
+ }
5861
6089
 
5862
6090
  //#endregion
5863
6091
  //#region ../core/src/stable-json.ts
package/dist/testing.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./sdk-event-upsert-CuDl9Gk1.mjs";
3
- import "./src-9YtMip19.mjs";
4
- import { n as syncLocalMediaForPush, r as syncLocalMediaForPull, y as writeMediaManifest } from "./local-sync-CCfQzCgJ.mjs";
2
+ import "./sdk-event-upsert-CqCQwcwu.mjs";
3
+ import "./src-CxEAuQpf.mjs";
4
+ import { n as syncLocalMediaForPush, r as syncLocalMediaForPull, y as writeMediaManifest } from "./local-sync-C-FEofmj.mjs";
5
5
 
6
6
  export { syncLocalMediaForPull, syncLocalMediaForPush, writeMediaManifest };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "riverbankcms",
3
- "version": "0.12.0",
3
+ "version": "0.14.0",
4
4
  "description": "Riverbank CMS command-line tools for SDK site developers",
5
5
  "bin": {
6
6
  "riverbankcms": "dist/cli/index.mjs"
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- import { t as loadConfigFile } from "./load-config-BhUqNoQL.mjs";
3
-
4
- export { loadConfigFile };