@riverbankcms/sdk 0.88.0 → 0.89.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 (103) hide show
  1. package/dist/{PreviewEditorSidebar-EVRS3C7T.mjs → PreviewEditorSidebar-JDR64FEC.mjs} +3 -3
  2. package/dist/{PreviewEditorUI-54WD4IGE.mjs → PreviewEditorUI-67TMJMAF.mjs} +3 -3
  3. package/dist/SdkPreviewModeRuntime-ZBEMRV7N.mjs +8 -0
  4. package/dist/_dts/api/src/accessAdmin.d.ts +7 -0
  5. package/dist/_dts/api/src/endpoints.d.ts +8 -0
  6. package/dist/_dts/api/src/index.d.ts +2 -2
  7. package/dist/_dts/api/src/siteManagementEndpoints.d.ts +5 -1
  8. package/dist/_dts/api/src/siteMembers.d.ts +6 -1
  9. package/dist/_dts/api/src/types.d.ts +1 -1
  10. package/dist/_dts/blocks/src/system/icons/cta.d.ts +3 -3
  11. package/dist/_dts/blocks/src/system/icons/index.d.ts +1 -0
  12. package/dist/_dts/blocks/src/system/icons/registry.d.ts +2 -2
  13. package/dist/_dts/blocks/src/system/icons/semantic.d.ts +3 -3
  14. package/dist/_dts/blocks/src/system/icons/svg.d.ts +72 -0
  15. package/dist/_dts/blocks/src/system/runtime/api/types.d.ts +1 -0
  16. package/dist/_dts/blocks/src/system/runtime/hooks/loadStateError.d.ts +1 -0
  17. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.d.ts +1 -1
  18. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.state.d.ts +55 -0
  19. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableSlots.state.d.ts +39 -0
  20. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.d.ts +4 -27
  21. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingFormConfig.state.d.ts +40 -0
  22. package/dist/_dts/blocks/src/system/runtime/hooks/useCalendarEvents.state.d.ts +20 -0
  23. package/dist/_dts/blocks/src/system/runtime/hooks/useEventFilters.state.d.ts +31 -0
  24. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.d.ts +3 -3
  25. package/dist/_dts/blocks/src/system/runtime/hooks/useEventPagination.state.d.ts +39 -0
  26. package/dist/_dts/blocks/src/system/runtime/nodes/events/shared/EventPaginatedListView.client.d.ts +1 -1
  27. package/dist/_dts/blocks/src/system/runtime/nodes/newsletter-form.client.state.d.ts +24 -2
  28. package/dist/_dts/blocks/src/system/runtime/nodes/shared/MagicLinkForm.state.d.ts +24 -0
  29. package/dist/_dts/blocks/src/system/runtime/shared/useWaitlistClaim.state.d.ts +35 -0
  30. package/dist/_dts/content-model/src/entry-slots/types.d.ts +54 -0
  31. package/dist/_dts/core/src/branded.d.ts +7 -0
  32. package/dist/_dts/core/src/index.d.ts +1 -0
  33. package/dist/_dts/core/src/site-route-target.d.ts +40 -0
  34. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +159 -2
  35. package/dist/_dts/media-core/src/fileDomain.d.ts +4 -0
  36. package/dist/_dts/sdk/src/client/runtimeCachePolicy.d.ts +160 -0
  37. package/dist/_dts/sdk/src/client/types.d.ts +26 -1
  38. package/dist/_dts/sdk/src/index.d.ts +3 -1
  39. package/dist/_dts/sdk/src/version.d.ts +1 -1
  40. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  41. package/dist/{chunk-YDMBIIS5.mjs → chunk-7N46MZHI.mjs} +1 -1
  42. package/dist/{chunk-7KOO7RPP.mjs → chunk-7YUAXONX.mjs} +1007 -353
  43. package/dist/{chunk-O4LVYUVH.mjs → chunk-F645A5UV.mjs} +18 -0
  44. package/dist/{chunk-ER4UIW4X.mjs → chunk-HKJQERFR.mjs} +7 -7
  45. package/dist/{chunk-K3JWH6HE.mjs → chunk-TGBJWKMP.mjs} +1 -1
  46. package/dist/{chunk-HVOBXA3Y.mjs → chunk-ZQRBLCW5.mjs} +2 -2
  47. package/dist/cli/index.mjs +668 -18
  48. package/dist/client/{accordion-PT5CGW5N.mjs → accordion-MUCVNGQ7.mjs} +2 -2
  49. package/dist/client/{bookingForm-2HLRTEYS.mjs → bookingForm-PKD6EFIE.mjs} +192 -76
  50. package/dist/client/bookings.mjs +436 -191
  51. package/dist/client/{carousel-Z2LKYSWA.mjs → carousel-3TKQSNJC.mjs} +4 -3
  52. package/dist/client/{cart-ND5IK4A6.mjs → cart-6XHSZK23.mjs} +8 -7
  53. package/dist/client/{checkout-EYUSGAY7.mjs → checkout-FVSPM6FI.mjs} +8 -7
  54. package/dist/client/chunk-6N7YRNYU.mjs +183 -0
  55. package/dist/client/{chunk-O5JNI3E4.mjs → chunk-7DH35FGA.mjs} +2 -2
  56. package/dist/client/{chunk-BAWHZ5GM.mjs → chunk-CQKKFEQD.mjs} +195 -61
  57. package/dist/client/{chunk-X7GVFB7Y.mjs → chunk-EY42X22F.mjs} +3 -3
  58. package/dist/client/{chunk-6DVPO44G.mjs → chunk-FHU6PFPM.mjs} +1 -1
  59. package/dist/client/{chunk-H4MHEXYS.mjs → chunk-LQFDYWPJ.mjs} +1 -1
  60. package/dist/client/{chunk-MHBEWDT7.mjs → chunk-RSQWWUAD.mjs} +122 -50
  61. package/dist/client/{chunk-GOFO7HRH.mjs → chunk-STJ2NCQM.mjs} +1 -1
  62. package/dist/client/{chunk-DIRW2LNG.mjs → chunk-UQFY4AHX.mjs} +272 -198
  63. package/dist/client/{chunk-WCVK4MBJ.mjs → chunk-VGLXACVK.mjs} +1 -1
  64. package/dist/client/{chunk-BL66UWGD.mjs → chunk-ZJZZA5EP.mjs} +6 -6
  65. package/dist/client/{chunk-S4G65LGR.mjs → chunk-ZT5XE7FK.mjs} +1 -1
  66. package/dist/client/client.mjs +3823 -3507
  67. package/dist/client/{courseRegistration-H3AZBUEG.mjs → courseRegistration-ATZSYDHM.mjs} +6 -6
  68. package/dist/client/{eventCalendar-FPKJGLGS.mjs → eventCalendar-6T2UGKKP.mjs} +10 -9
  69. package/dist/client/{eventCombined-QCGIZBUY.mjs → eventCombined-Q4VANXVF.mjs} +10 -9
  70. package/dist/client/{eventDetails-HIT3BJWU.mjs → eventDetails-DW37E7VW.mjs} +10 -9
  71. package/dist/client/{eventListing-R4HNWJDN.mjs → eventListing-XURTSAUW.mjs} +10 -9
  72. package/dist/client/{eventRegistration-Q7BYY5HF.mjs → eventRegistration-MRKEVAXW.mjs} +10 -9
  73. package/dist/client/{form-NI6YOG6S.mjs → form-WZZFFGMU.mjs} +3 -3
  74. package/dist/client/{headerSection-SDYGII36.mjs → headerSection-EQYVQBLM.mjs} +3 -3
  75. package/dist/client/hooks.mjs +18 -0
  76. package/dist/client/{locationMap-BDETEUQD.mjs → locationMap-MFF5VAZR.mjs} +3 -3
  77. package/dist/client/{newsletterForm-EKYIU67X.mjs → newsletterForm-JQ77UYIE.mjs} +60 -24
  78. package/dist/client/{productDetail-5UTGNN76.mjs → productDetail-25LMT3IZ.mjs} +8 -7
  79. package/dist/client/{productList-7YA5KXZQ.mjs → productList-5ABEMKUG.mjs} +8 -7
  80. package/dist/client/rendering/client.mjs +3266 -3528
  81. package/dist/client/rendering/islands.mjs +19 -19
  82. package/dist/client/rendering.mjs +3143 -3452
  83. package/dist/client/{shop-AIMUMZYC.mjs → shop-OMMQZ6YO.mjs} +8 -7
  84. package/dist/preview-next/before-render.mjs +18 -0
  85. package/dist/preview-next/client/runtime.mjs +5 -5
  86. package/dist/preview-next/middleware.mjs +18 -0
  87. package/dist/{sdk-runtime-NW472WNT.mjs → sdk-runtime-WNLBZ3ZH.mjs} +6 -6
  88. package/dist/server/components.mjs +1068 -1540
  89. package/dist/server/config-validation.mjs +18 -0
  90. package/dist/server/config.mjs +18 -0
  91. package/dist/server/data.mjs +18 -0
  92. package/dist/server/index.mjs +847 -261
  93. package/dist/server/next.mjs +1708 -1555
  94. package/dist/server/prebuild.mjs +1 -1
  95. package/dist/server/rendering/server.mjs +1068 -1540
  96. package/dist/server/rendering.mjs +1074 -1546
  97. package/dist/server/routing.mjs +314 -9
  98. package/dist/server/server.mjs +668 -25
  99. package/dist/server/theme-bridge.mjs +26 -0
  100. package/dist/styles/index.css +26 -0
  101. package/package.json +2 -1
  102. package/dist/SdkPreviewModeRuntime-ZALZDJEK.mjs +0 -8
  103. /package/dist/client/{chunk-LI2C6M5O.mjs → chunk-25W2EQUN.mjs} +0 -0
@@ -1865,6 +1865,24 @@ var ENDPOINT_DEFINITIONS = {
1865
1865
  auth: "user",
1866
1866
  responseKind: "json"
1867
1867
  },
1868
+ resendSiteInvitation: {
1869
+ path: "/sites/{siteId}/members/invitations/{invitationId}/resend",
1870
+ method: "POST",
1871
+ errors: [
1872
+ "auth:forbidden",
1873
+ "resource:not_found",
1874
+ "validation:invalid_input",
1875
+ "external:service_error",
1876
+ "server:internal_error"
1877
+ ],
1878
+ tags: [
1879
+ "site-{siteId}",
1880
+ "site-members-{siteId}",
1881
+ "site-invite-{invitationId}"
1882
+ ],
1883
+ auth: "user",
1884
+ responseKind: "json"
1885
+ },
1868
1886
  transferSiteOwnership: {
1869
1887
  path: "/sites/{siteId}/members/transfer-ownership",
1870
1888
  method: "POST",
@@ -7042,7 +7060,7 @@ var SimpleCache = class {
7042
7060
  };
7043
7061
 
7044
7062
  // src/version.ts
7045
- var SDK_VERSION = "0.88.0";
7063
+ var SDK_VERSION = "0.89.1";
7046
7064
 
7047
7065
  // src/client/error.ts
7048
7066
  var RiverbankApiError = class _RiverbankApiError extends Error {
@@ -7199,6 +7217,476 @@ function attachResilienceStatusToError(error, resilienceStatus) {
7199
7217
  return target;
7200
7218
  }
7201
7219
 
7220
+ // src/public-api/runtime.ts
7221
+ var PUBLIC_ENDPOINT_NAMES2 = [
7222
+ "getSite",
7223
+ "getContentByPath",
7224
+ "listPublishedEntries",
7225
+ "getPublishedEntryPreview",
7226
+ "getPublicFormById",
7227
+ "listPublicForms",
7228
+ "getPublicBookingServices",
7229
+ "getPublicChallenge",
7230
+ "listPublicEvents",
7231
+ "batchBlockLoaders",
7232
+ "listPublicCourses",
7233
+ "listPublicTeamMembers",
7234
+ "listPublicProducts",
7235
+ "listPublicPasses",
7236
+ "listPublicMemberships",
7237
+ "resolveEntrySubroute",
7238
+ "resolveEventOccurrence",
7239
+ "checkRedirect",
7240
+ "getRoutableContent",
7241
+ "getPublicRoutableContent",
7242
+ "getPublicSitemapRoutes"
7243
+ ];
7244
+ var API_ENDPOINTS2 = Object.freeze({
7245
+ getSite: {
7246
+ path: "/sites",
7247
+ method: "GET",
7248
+ revalidate: 900,
7249
+ tags: ["riverbank:site", "riverbank:site:id:{id}", "riverbank:site:slug:{slug}", "riverbank:site:domain:{domain}"],
7250
+ auth: "public",
7251
+ responseKind: "json"
7252
+ },
7253
+ getContentByPath: {
7254
+ path: "/sites/{siteId}/pages",
7255
+ method: "GET",
7256
+ tags: ["riverbank:site:{siteId}:routable-content"],
7257
+ auth: "public",
7258
+ responseKind: "json"
7259
+ },
7260
+ listPublishedEntries: {
7261
+ path: "/public/content/{siteId}/{type}/entries",
7262
+ method: "GET",
7263
+ revalidate: 60,
7264
+ tags: ["content-{siteId}-{type}"],
7265
+ auth: "public",
7266
+ responseKind: "json"
7267
+ },
7268
+ getPublishedEntryPreview: {
7269
+ path: "/public/content/{siteId}/{type}/{slug}/preview",
7270
+ method: "GET",
7271
+ revalidate: 60,
7272
+ tags: ["content-{siteId}-{type}-{slug}"],
7273
+ auth: "public",
7274
+ responseKind: "json"
7275
+ },
7276
+ getPublicFormById: {
7277
+ path: "/public/forms/{formId}",
7278
+ method: "GET",
7279
+ revalidate: 60,
7280
+ tags: ["riverbank:form:{formId}"],
7281
+ auth: "public",
7282
+ responseKind: "json"
7283
+ },
7284
+ listPublicForms: {
7285
+ path: "/public/sites/{siteId}/forms",
7286
+ method: "GET",
7287
+ revalidate: 60,
7288
+ tags: ["riverbank:site:{siteId}:forms"],
7289
+ auth: "public",
7290
+ responseKind: "json"
7291
+ },
7292
+ getPublicBookingServices: {
7293
+ path: "/public/bookings/services",
7294
+ method: "GET",
7295
+ revalidate: 60,
7296
+ tags: ["site-{siteId}"],
7297
+ auth: "public",
7298
+ responseKind: "json"
7299
+ },
7300
+ getPublicChallenge: {
7301
+ path: "/public/challenge",
7302
+ method: "GET",
7303
+ auth: "public",
7304
+ responseKind: "text"
7305
+ },
7306
+ listPublicEvents: {
7307
+ path: "/public/sites/{siteId}/events",
7308
+ method: "GET",
7309
+ revalidate: 60,
7310
+ tags: ["riverbank:site:{siteId}:public-events"],
7311
+ auth: "public",
7312
+ responseKind: "json"
7313
+ },
7314
+ batchBlockLoaders: {
7315
+ path: "/public/sites/{siteId}/block-loaders/batch",
7316
+ method: "POST",
7317
+ auth: "public",
7318
+ responseKind: "json"
7319
+ },
7320
+ listPublicCourses: {
7321
+ path: "/public/sites/{siteId}/courses",
7322
+ method: "GET",
7323
+ revalidate: 60,
7324
+ tags: ["riverbank:site:{siteId}:public-courses"],
7325
+ auth: "public",
7326
+ responseKind: "json"
7327
+ },
7328
+ listPublicTeamMembers: {
7329
+ path: "/public/sites/{siteId}/team-members",
7330
+ method: "GET",
7331
+ revalidate: 60,
7332
+ tags: ["riverbank:site:{siteId}:public-team-members"],
7333
+ auth: "public",
7334
+ responseKind: "json"
7335
+ },
7336
+ listPublicProducts: {
7337
+ path: "/public/sites/{siteId}/products",
7338
+ method: "GET",
7339
+ revalidate: 300,
7340
+ tags: ["riverbank:site:{siteId}:public-products"],
7341
+ auth: "public",
7342
+ responseKind: "json"
7343
+ },
7344
+ listPublicPasses: {
7345
+ path: "/public/sites/{siteId}/bookings/products/passes",
7346
+ method: "GET",
7347
+ revalidate: 300,
7348
+ tags: ["riverbank:site:{siteId}:public-passes"],
7349
+ auth: "public",
7350
+ responseKind: "json"
7351
+ },
7352
+ listPublicMemberships: {
7353
+ path: "/public/sites/{siteId}/bookings/products/memberships",
7354
+ method: "GET",
7355
+ revalidate: 300,
7356
+ tags: ["riverbank:site:{siteId}:public-memberships"],
7357
+ auth: "public",
7358
+ responseKind: "json"
7359
+ },
7360
+ resolveEntrySubroute: {
7361
+ path: "/public/sites/{siteId}/routing/subroutes/resolve",
7362
+ method: "GET",
7363
+ revalidate: 60,
7364
+ tags: ["site-{siteId}", "entry-subroute"],
7365
+ auth: "public",
7366
+ responseKind: "json"
7367
+ },
7368
+ resolveEventOccurrence: {
7369
+ path: "/public/sites/{siteId}/events/occurrences/resolve",
7370
+ method: "GET",
7371
+ revalidate: 60,
7372
+ tags: ["riverbank:site:{siteId}:public-events", "event-occurrence"],
7373
+ auth: "public",
7374
+ responseKind: "json"
7375
+ },
7376
+ checkRedirect: {
7377
+ path: "/public/content/redirect",
7378
+ method: "GET",
7379
+ revalidate: 86400,
7380
+ tags: ["redirect"],
7381
+ auth: "public",
7382
+ responseKind: "json"
7383
+ },
7384
+ getRoutableContent: {
7385
+ path: "/sites/{siteId}/routable-content",
7386
+ method: "GET",
7387
+ revalidate: 60,
7388
+ tags: ["riverbank:site:{siteId}:routable-content"],
7389
+ auth: "user",
7390
+ responseKind: "json"
7391
+ },
7392
+ getPublicRoutableContent: {
7393
+ path: "/public/sites/{siteId}/routable-content",
7394
+ method: "GET",
7395
+ revalidate: 60,
7396
+ tags: ["riverbank:site:{siteId}:routable-content"],
7397
+ auth: "public",
7398
+ responseKind: "json"
7399
+ },
7400
+ getPublicSitemapRoutes: {
7401
+ path: "/public/sites/{siteId}/sitemap",
7402
+ method: "GET",
7403
+ revalidate: 60,
7404
+ tags: ["riverbank:site:{siteId}:routable-content", "riverbank:site:{siteId}:settings"],
7405
+ auth: "public",
7406
+ responseKind: "json"
7407
+ }
7408
+ });
7409
+
7410
+ // src/client/runtimeCachePolicy.ts
7411
+ var DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION = 1;
7412
+ var DEFAULT_STALE_TTL_SEC = 24 * 60 * 60;
7413
+ var DEFAULT_MEMORY_TTL_SEC = 60;
7414
+ var RUNTIME_CACHE_DURABILITY_OVERRIDES = {
7415
+ getSite: {
7416
+ kind: "durable-public-stale",
7417
+ staleTtlSec: DEFAULT_STALE_TTL_SEC
7418
+ },
7419
+ getContentByPath: {
7420
+ kind: "durable-public-stale",
7421
+ staleTtlSec: DEFAULT_STALE_TTL_SEC
7422
+ },
7423
+ listPublishedEntries: {
7424
+ kind: "memory-only",
7425
+ reason: "durable_rollout_pending"
7426
+ },
7427
+ getPublishedEntryPreview: {
7428
+ kind: "memory-only",
7429
+ reason: "durable_rollout_pending"
7430
+ },
7431
+ getPublicFormById: {
7432
+ kind: "memory-only",
7433
+ reason: "durable_rollout_pending"
7434
+ },
7435
+ listPublicForms: {
7436
+ kind: "memory-only",
7437
+ reason: "durable_rollout_pending"
7438
+ },
7439
+ getPublicBookingServices: {
7440
+ kind: "live-only",
7441
+ reason: "safety_sensitive_booking"
7442
+ },
7443
+ getPublicChallenge: {
7444
+ kind: "live-only",
7445
+ reason: "challenge_endpoint"
7446
+ },
7447
+ listPublicEvents: {
7448
+ kind: "memory-only",
7449
+ reason: "durable_rollout_pending"
7450
+ },
7451
+ batchBlockLoaders: {
7452
+ kind: "live-only",
7453
+ reason: "opaque_batch_loader"
7454
+ },
7455
+ listPublicCourses: {
7456
+ kind: "memory-only",
7457
+ reason: "durable_rollout_pending"
7458
+ },
7459
+ listPublicTeamMembers: {
7460
+ kind: "memory-only",
7461
+ reason: "durable_rollout_pending"
7462
+ },
7463
+ listPublicProducts: {
7464
+ kind: "memory-only",
7465
+ reason: "durable_rollout_pending"
7466
+ },
7467
+ listPublicPasses: {
7468
+ kind: "live-only",
7469
+ reason: "safety_sensitive_booking"
7470
+ },
7471
+ listPublicMemberships: {
7472
+ kind: "live-only",
7473
+ reason: "safety_sensitive_booking"
7474
+ },
7475
+ resolveEntrySubroute: {
7476
+ kind: "memory-only",
7477
+ reason: "durable_rollout_pending"
7478
+ },
7479
+ resolveEventOccurrence: {
7480
+ kind: "memory-only",
7481
+ reason: "durable_rollout_pending"
7482
+ },
7483
+ checkRedirect: {
7484
+ kind: "memory-only",
7485
+ reason: "durable_rollout_pending"
7486
+ },
7487
+ getRoutableContent: {
7488
+ kind: "live-only",
7489
+ reason: "auth_required"
7490
+ },
7491
+ getPublicRoutableContent: {
7492
+ kind: "memory-only",
7493
+ reason: "durable_rollout_pending"
7494
+ },
7495
+ getPublicSitemapRoutes: {
7496
+ kind: "memory-only",
7497
+ reason: "durable_rollout_pending"
7498
+ }
7499
+ };
7500
+ var PUBLIC_ENDPOINT_NAME_SET = new Set(PUBLIC_ENDPOINT_NAMES2);
7501
+ function isPublicEndpointName(endpoint) {
7502
+ return PUBLIC_ENDPOINT_NAME_SET.has(endpoint);
7503
+ }
7504
+ function isTruthyParam(value) {
7505
+ return value === true || value === "true" || value === 1 || value === "1";
7506
+ }
7507
+ function isPreviewRequest(endpoint, params) {
7508
+ if (endpoint === "getContentByPath") {
7509
+ return isTruthyParam(params.preview);
7510
+ }
7511
+ if (endpoint === "listPublishedEntries" || endpoint === "resolveEntrySubroute" || endpoint === "resolveEventOccurrence") {
7512
+ return params.stage === "preview";
7513
+ }
7514
+ return false;
7515
+ }
7516
+ function getEndpointFreshTtlSec(endpoint) {
7517
+ return API_ENDPOINTS2[endpoint].revalidate ?? DEFAULT_MEMORY_TTL_SEC;
7518
+ }
7519
+ function assertNever(value) {
7520
+ throw new Error(`Unhandled runtime cache policy override: ${String(value)}`);
7521
+ }
7522
+ function resolveKnownEndpointPolicy(endpoint, params) {
7523
+ if (isPreviewRequest(endpoint, params)) {
7524
+ return { kind: "live-only", endpoint, reason: "preview_request" };
7525
+ }
7526
+ if (endpoint === "getSite" && isTruthyParam(params.force)) {
7527
+ return { kind: "live-only", endpoint, reason: "force_refresh" };
7528
+ }
7529
+ const override = RUNTIME_CACHE_DURABILITY_OVERRIDES[endpoint];
7530
+ if (override.kind === "live-only") {
7531
+ return { kind: "live-only", endpoint, reason: override.reason };
7532
+ }
7533
+ const endpointDefinition = API_ENDPOINTS2[endpoint];
7534
+ if (endpointDefinition.method !== "GET") {
7535
+ return { kind: "live-only", endpoint, reason: "non_get_request" };
7536
+ }
7537
+ if (endpointDefinition.auth === "user") {
7538
+ return { kind: "live-only", endpoint, reason: "auth_required" };
7539
+ }
7540
+ switch (override.kind) {
7541
+ case "durable-public-stale":
7542
+ return {
7543
+ kind: "durable-public-stale",
7544
+ endpoint,
7545
+ freshTtlSec: getEndpointFreshTtlSec(endpoint),
7546
+ staleTtlSec: override.staleTtlSec
7547
+ };
7548
+ case "memory-only":
7549
+ return {
7550
+ kind: "memory-only",
7551
+ endpoint,
7552
+ freshTtlSec: getEndpointFreshTtlSec(endpoint),
7553
+ reason: override.reason
7554
+ };
7555
+ default:
7556
+ return assertNever(override);
7557
+ }
7558
+ }
7559
+ function resolveRuntimeCachePolicy(input) {
7560
+ if (input.method && input.method.toUpperCase() !== "GET") {
7561
+ return {
7562
+ kind: "live-only",
7563
+ endpoint: input.endpoint,
7564
+ reason: "non_get_request"
7565
+ };
7566
+ }
7567
+ if (!isPublicEndpointName(input.endpoint)) {
7568
+ return {
7569
+ kind: "live-only",
7570
+ endpoint: input.endpoint,
7571
+ reason: "unknown_endpoint"
7572
+ };
7573
+ }
7574
+ return resolveKnownEndpointPolicy(input.endpoint, input.params ?? {});
7575
+ }
7576
+ function toNonEmptyString(value) {
7577
+ if (value === null || value === void 0) return null;
7578
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean") {
7579
+ return null;
7580
+ }
7581
+ const normalized = String(value).trim();
7582
+ return normalized.length > 0 ? normalized : null;
7583
+ }
7584
+ function normalizeRuntimePublicPath(value) {
7585
+ const raw = toNonEmptyString(value) ?? "/";
7586
+ const withoutQuery = raw.split(/[?#]/, 1)[0] ?? "/";
7587
+ const withLeadingSlash = withoutQuery.startsWith("/") ? withoutQuery : `/${withoutQuery}`;
7588
+ const collapsed = withLeadingSlash.replace(/\/{2,}/g, "/");
7589
+ const withoutTrailingSlash = collapsed.length > 1 ? collapsed.replace(/\/+$/g, "") : collapsed;
7590
+ return withoutTrailingSlash || "/";
7591
+ }
7592
+ function normalizeRuntimeHostname(value) {
7593
+ const trimmed = value.trim().toLowerCase();
7594
+ const url = /^[a-z][a-z0-9+.-]*:\/\//.test(trimmed) ? new URL(trimmed) : new URL(`http://${trimmed}`);
7595
+ return url.hostname.replace(/\.$/, "");
7596
+ }
7597
+ function normalizeScalar(value) {
7598
+ return value.trim().toLowerCase();
7599
+ }
7600
+ function encodeKeyPart(key, value) {
7601
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
7602
+ }
7603
+ function unsafeAsPublishedRuntimeCacheKey(value) {
7604
+ return value;
7605
+ }
7606
+ function buildPublishedRuntimeCacheKey(endpoint, normalizedParams) {
7607
+ const encodedParams = Object.entries(normalizedParams).sort(([left], [right]) => left.localeCompare(right)).map(([key, value]) => encodeKeyPart(key, value)).join(":");
7608
+ return unsafeAsPublishedRuntimeCacheKey(
7609
+ `published-runtime:v1:${endpoint}:${encodedParams}`
7610
+ );
7611
+ }
7612
+ function selectSiteRuntimeIdentity(params) {
7613
+ const slug = toNonEmptyString(params.slug);
7614
+ if (slug !== null) return { slug: normalizeScalar(slug) };
7615
+ const domain = toNonEmptyString(params.domain);
7616
+ if (domain !== null) return { domain: normalizeRuntimeHostname(domain) };
7617
+ const id = toNonEmptyString(params.id);
7618
+ if (id !== null) return { id: normalizeScalar(id) };
7619
+ return null;
7620
+ }
7621
+ function deriveGetSiteKey(params) {
7622
+ const identity = selectSiteRuntimeIdentity(params);
7623
+ if (identity === null) {
7624
+ return {
7625
+ ok: false,
7626
+ error: {
7627
+ kind: "missing_site_identity",
7628
+ acceptedParams: ["slug", "domain", "id"]
7629
+ }
7630
+ };
7631
+ }
7632
+ const normalizedParams = {
7633
+ ...identity,
7634
+ currentPath: normalizeRuntimePublicPath(params.currentPath)
7635
+ };
7636
+ return {
7637
+ ok: true,
7638
+ endpoint: "getSite",
7639
+ key: buildPublishedRuntimeCacheKey("getSite", normalizedParams),
7640
+ normalizedParams
7641
+ };
7642
+ }
7643
+ function deriveGetContentByPathKey(params) {
7644
+ const siteId = toNonEmptyString(params.siteId);
7645
+ if (siteId === null) {
7646
+ return {
7647
+ ok: false,
7648
+ error: {
7649
+ kind: "missing_required_param",
7650
+ endpoint: "getContentByPath",
7651
+ param: "siteId"
7652
+ }
7653
+ };
7654
+ }
7655
+ const normalizedParams = {
7656
+ siteId: normalizeScalar(siteId),
7657
+ path: normalizeRuntimePublicPath(params.path)
7658
+ };
7659
+ return {
7660
+ ok: true,
7661
+ endpoint: "getContentByPath",
7662
+ key: buildPublishedRuntimeCacheKey("getContentByPath", normalizedParams),
7663
+ normalizedParams
7664
+ };
7665
+ }
7666
+ var DURABLE_RUNTIME_CACHE_KEY_DERIVERS = {
7667
+ getSite: deriveGetSiteKey,
7668
+ getContentByPath: deriveGetContentByPathKey
7669
+ };
7670
+ function derivePublishedRuntimeCacheKey(input) {
7671
+ const policy = resolveRuntimeCachePolicy({
7672
+ endpoint: input.endpoint,
7673
+ method: "GET",
7674
+ params: input.params
7675
+ });
7676
+ if (policy.kind !== "durable-public-stale") {
7677
+ return {
7678
+ ok: false,
7679
+ error: { kind: "not_durable_eligible", policy }
7680
+ };
7681
+ }
7682
+ switch (input.endpoint) {
7683
+ case "getSite":
7684
+ return DURABLE_RUNTIME_CACHE_KEY_DERIVERS.getSite(input.params);
7685
+ case "getContentByPath":
7686
+ return DURABLE_RUNTIME_CACHE_KEY_DERIVERS.getContentByPath(input.params);
7687
+ }
7688
+ }
7689
+
7202
7690
  // src/client/resilience.ts
7203
7691
  var DEFAULT_RETRY_CONFIG = {
7204
7692
  maxAttempts: 3,
@@ -7508,12 +7996,57 @@ setSdkVersion(SDK_VERSION);
7508
7996
  var DEFAULT_BROWSER_TIMEOUT_MS = 5e3;
7509
7997
  var DEFAULT_SERVER_TIMEOUT_MS = 8e3;
7510
7998
  var MAX_GET_ENTRIES_BY_IDENTIFIERS_REFS = 50;
7999
+ function isDurableRuntimeCacheTier(cacheTier) {
8000
+ return cacheTier === "durable-fresh" || cacheTier === "durable-stale";
8001
+ }
8002
+ function isDegradedResilienceStatus(source, details) {
8003
+ return source === "stale" || source === "error" || isDurableRuntimeCacheTier(details.cacheTier) && details.error !== void 0;
8004
+ }
7511
8005
  function generateRequestId2() {
7512
8006
  return `req-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
7513
8007
  }
7514
8008
  function toRecord(value) {
7515
8009
  return value && typeof value === "object" && !Array.isArray(value) ? value : {};
7516
8010
  }
8011
+ function getRuntimePayloadSiteId(value) {
8012
+ const site = toRecord(value).site;
8013
+ if (!site || typeof site !== "object" || Array.isArray(site)) {
8014
+ return null;
8015
+ }
8016
+ const id = site.id;
8017
+ return typeof id === "string" && id.trim().length > 0 ? id : null;
8018
+ }
8019
+ function getRiverbankErrorInfo(error) {
8020
+ if (error instanceof RiverbankApiError) {
8021
+ return { code: error.code, message: error.message, status: error.status };
8022
+ }
8023
+ if (error instanceof Error) {
8024
+ return { message: error.message };
8025
+ }
8026
+ return { message: String(error) };
8027
+ }
8028
+ function planPublishedRuntimeCache(input) {
8029
+ const policy = resolveRuntimeCachePolicy({
8030
+ endpoint: input.endpoint,
8031
+ method: "GET",
8032
+ params: input.params
8033
+ });
8034
+ if (policy.kind !== "durable-public-stale") {
8035
+ return null;
8036
+ }
8037
+ const keyResult = derivePublishedRuntimeCacheKey(input);
8038
+ if (!keyResult.ok) {
8039
+ return null;
8040
+ }
8041
+ return {
8042
+ cacheKey: keyResult.key,
8043
+ endpoint: keyResult.endpoint,
8044
+ normalizedParams: keyResult.normalizedParams,
8045
+ freshTtlSec: policy.freshTtlSec,
8046
+ staleTtlSec: policy.staleTtlSec,
8047
+ siteId: input.siteId ?? null
8048
+ };
8049
+ }
7517
8050
  function normalizeEntryIdentifierRefs(identifiers) {
7518
8051
  const trimmed = identifiers.map((identifier) => identifier.trim()).filter((identifier) => identifier.length > 0);
7519
8052
  if (trimmed.length === 0) {
@@ -7747,6 +8280,8 @@ function createRiverbankClient(config) {
7747
8280
  source,
7748
8281
  isPreview: details.isPreview,
7749
8282
  cacheKey: details.cacheKey,
8283
+ cacheTier: details.cacheTier,
8284
+ durableCache: details.durableCache,
7750
8285
  error: details.error,
7751
8286
  staleAgeSec: details.staleAgeSec,
7752
8287
  prebuildAgeSec: details.prebuildAgeSec,
@@ -7756,7 +8291,7 @@ function createRiverbankClient(config) {
7756
8291
  };
7757
8292
  lastStatus = status;
7758
8293
  config.resilience?.onStatusChange?.(status);
7759
- const nowDegraded = source === "stale" || source === "error";
8294
+ const nowDegraded = isDegradedResilienceStatus(source, details);
7760
8295
  if (nowDegraded !== isDegraded) {
7761
8296
  isDegraded = nowDegraded;
7762
8297
  config.resilience?.onDegradedMode?.(nowDegraded, status);
@@ -7766,6 +8301,80 @@ function createRiverbankClient(config) {
7766
8301
  resilience: status
7767
8302
  };
7768
8303
  }
8304
+ async function tryPublishedRuntimeCacheFallback(plan, statusDetails, errorInfo) {
8305
+ const reader = config.publishedRuntimeCache?.read;
8306
+ if (!plan || !reader) {
8307
+ return null;
8308
+ }
8309
+ try {
8310
+ const result = await reader({
8311
+ cacheKey: plan.cacheKey,
8312
+ endpoint: plan.endpoint,
8313
+ payloadSchemaVersion: DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION
8314
+ });
8315
+ if (result.kind === "miss") {
8316
+ return {
8317
+ kind: "miss",
8318
+ diagnostic: {
8319
+ outcome: "miss",
8320
+ reason: result.reason
8321
+ }
8322
+ };
8323
+ }
8324
+ if (result.kind === "error") {
8325
+ return {
8326
+ kind: "error",
8327
+ diagnostic: {
8328
+ outcome: "error",
8329
+ error: result.error
8330
+ }
8331
+ };
8332
+ }
8333
+ return {
8334
+ kind: "hit",
8335
+ result: emitStatus(
8336
+ result.freshness === "fresh" ? "cache" : "stale",
8337
+ result.payload,
8338
+ statusDetails({
8339
+ error: errorInfo,
8340
+ staleAgeSec: result.staleAgeSec,
8341
+ cacheTier: result.freshness === "fresh" ? "durable-fresh" : "durable-stale"
8342
+ })
8343
+ )
8344
+ };
8345
+ } catch (error) {
8346
+ return {
8347
+ kind: "error",
8348
+ diagnostic: {
8349
+ outcome: "error",
8350
+ error: {
8351
+ kind: "adapter_exception",
8352
+ message: error instanceof Error ? error.message : String(error)
8353
+ }
8354
+ }
8355
+ };
8356
+ }
8357
+ }
8358
+ async function writePublishedRuntimeCache(plan, payload) {
8359
+ const writer = config.publishedRuntimeCache?.write;
8360
+ if (!plan || !writer) {
8361
+ return;
8362
+ }
8363
+ try {
8364
+ await writer({
8365
+ cacheKey: plan.cacheKey,
8366
+ endpoint: plan.endpoint,
8367
+ normalizedParams: plan.normalizedParams,
8368
+ payload,
8369
+ siteId: plan.siteId ?? getRuntimePayloadSiteId(payload),
8370
+ freshTtlSec: plan.freshTtlSec,
8371
+ staleTtlSec: plan.staleTtlSec,
8372
+ payloadSchemaVersion: DEFAULT_PUBLISHED_RUNTIME_CACHE_PAYLOAD_SCHEMA_VERSION,
8373
+ writeReason: "live_success"
8374
+ });
8375
+ } catch {
8376
+ }
8377
+ }
7769
8378
  async function resilientFetch(cacheKey, fetcher, options) {
7770
8379
  const requestId = generateRequestId2();
7771
8380
  const startTime = Date.now();
@@ -7781,7 +8390,11 @@ function createRiverbankClient(config) {
7781
8390
  if (cacheEnabled && !options.force) {
7782
8391
  const fresh = cache.getFresh(cacheKey);
7783
8392
  if (fresh !== null) {
7784
- return emitStatus("cache", fresh, statusDetails());
8393
+ return emitStatus(
8394
+ "cache",
8395
+ fresh,
8396
+ statusDetails({ cacheTier: "memory-fresh" })
8397
+ );
7785
8398
  }
7786
8399
  }
7787
8400
  if (resilienceEnabled && circuitBreaker.isOpen()) {
@@ -7793,6 +8406,7 @@ function createRiverbankClient(config) {
7793
8406
  stale.value,
7794
8407
  statusDetails({
7795
8408
  staleAgeSec: stale.staleAgeSec,
8409
+ cacheTier: "memory-stale",
7796
8410
  error: {
7797
8411
  code: "circuit_open",
7798
8412
  message: "Circuit breaker is open"
@@ -7801,6 +8415,15 @@ function createRiverbankClient(config) {
7801
8415
  );
7802
8416
  }
7803
8417
  }
8418
+ const durableFallback = allowFallbacks && !isPreview ? await tryPublishedRuntimeCacheFallback(
8419
+ options.publishedRuntimeCache,
8420
+ statusDetails,
8421
+ { code: "circuit_open", message: "Circuit breaker is open" }
8422
+ ) : null;
8423
+ const durableCache = durableFallback?.kind === "miss" || durableFallback?.kind === "error" ? durableFallback.diagnostic : void 0;
8424
+ if (durableFallback?.kind === "hit") {
8425
+ return durableFallback.result;
8426
+ }
7804
8427
  if (allowFallbacks && !isPreview && options.prebuildFallback) {
7805
8428
  const prebuildResult = options.prebuildFallback();
7806
8429
  if (prebuildResult) {
@@ -7809,6 +8432,8 @@ function createRiverbankClient(config) {
7809
8432
  prebuildResult.data,
7810
8433
  statusDetails({
7811
8434
  prebuildAgeSec: prebuildResult.prebuildAgeSec,
8435
+ cacheTier: "prebuild",
8436
+ durableCache,
7812
8437
  error: {
7813
8438
  code: "circuit_open",
7814
8439
  message: "Circuit breaker is open"
@@ -7822,6 +8447,7 @@ function createRiverbankClient(config) {
7822
8447
  "error",
7823
8448
  null,
7824
8449
  statusDetails({
8450
+ durableCache,
7825
8451
  error: { code: "circuit_open", message: "Circuit breaker is open" }
7826
8452
  })
7827
8453
  );
@@ -7862,6 +8488,9 @@ function createRiverbankClient(config) {
7862
8488
  if (cacheEnabled) {
7863
8489
  cache.set(cacheKey, data);
7864
8490
  }
8491
+ if (allowFallbacks && !isPreview) {
8492
+ await writePublishedRuntimeCache(options.publishedRuntimeCache, data);
8493
+ }
7865
8494
  return emitStatus("live", data, statusDetails());
7866
8495
  } catch (error) {
7867
8496
  if (resilienceEnabled && error instanceof Error) {
@@ -7870,44 +8499,47 @@ function createRiverbankClient(config) {
7870
8499
  if (allowFallbacks && !isPreview && staleIfError && cacheEnabled) {
7871
8500
  const stale = cache.getStale(cacheKey);
7872
8501
  if (stale) {
7873
- const errorInfo2 = error instanceof RiverbankApiError ? {
7874
- code: error.code,
7875
- message: error.message,
7876
- status: error.status
7877
- } : { message: error.message };
8502
+ const errorInfo2 = getRiverbankErrorInfo(error);
7878
8503
  return emitStatus(
7879
8504
  "stale",
7880
8505
  stale.value,
7881
8506
  statusDetails({
7882
8507
  staleAgeSec: stale.staleAgeSec,
8508
+ cacheTier: "memory-stale",
7883
8509
  error: errorInfo2
7884
8510
  })
7885
8511
  );
7886
8512
  }
7887
8513
  }
8514
+ const errorInfo = getRiverbankErrorInfo(error);
8515
+ const durableFallback = allowFallbacks && !isPreview ? await tryPublishedRuntimeCacheFallback(
8516
+ options.publishedRuntimeCache,
8517
+ statusDetails,
8518
+ errorInfo
8519
+ ) : null;
8520
+ const durableCache = durableFallback?.kind === "miss" || durableFallback?.kind === "error" ? durableFallback.diagnostic : void 0;
8521
+ if (durableFallback?.kind === "hit") {
8522
+ return durableFallback.result;
8523
+ }
7888
8524
  if (allowFallbacks && !isPreview && options.prebuildFallback) {
7889
8525
  const prebuildResult = options.prebuildFallback();
7890
8526
  if (prebuildResult) {
7891
- const errorInfo2 = error instanceof RiverbankApiError ? {
7892
- code: error.code,
7893
- message: error.message,
7894
- status: error.status
7895
- } : { message: error.message };
7896
8527
  return emitStatus(
7897
8528
  "prebuild",
7898
8529
  prebuildResult.data,
7899
8530
  statusDetails({
7900
8531
  prebuildAgeSec: prebuildResult.prebuildAgeSec,
7901
- error: errorInfo2
8532
+ cacheTier: "prebuild",
8533
+ durableCache,
8534
+ error: errorInfo
7902
8535
  })
7903
8536
  );
7904
8537
  }
7905
8538
  }
7906
- const errorInfo = error instanceof RiverbankApiError ? { code: error.code, message: error.message, status: error.status } : { message: error.message };
7907
8539
  const failure = emitStatus(
7908
8540
  "error",
7909
8541
  null,
7910
- statusDetails({ error: errorInfo })
8542
+ statusDetails({ error: errorInfo, durableCache })
7911
8543
  );
7912
8544
  throw attachResilienceStatusToError(error, failure.resilience);
7913
8545
  }
@@ -7957,8 +8589,12 @@ function createRiverbankClient(config) {
7957
8589
  );
7958
8590
  }
7959
8591
  const siteIdentifier = slug || domain || id;
7960
- const cacheKey = `site:${siteIdentifier ?? "unknown"}:${currentPath ?? ""}`;
7961
8592
  const siteId = id || slug || domain;
8593
+ const publishedRuntimeCache = planPublishedRuntimeCache({
8594
+ endpoint: "getSite",
8595
+ params: { slug, domain, id, currentPath, force }
8596
+ });
8597
+ const cacheKey = publishedRuntimeCache?.cacheKey ?? `site:${siteIdentifier ?? "unknown"}:${currentPath ?? ""}`;
7962
8598
  return resilientFetch(
7963
8599
  cacheKey,
7964
8600
  async (sig) => {
@@ -7981,13 +8617,19 @@ function createRiverbankClient(config) {
7981
8617
  {
7982
8618
  signal,
7983
8619
  force,
8620
+ publishedRuntimeCache,
7984
8621
  prebuildFallback: prebuildLoader && siteId ? () => prebuildLoader.loadSite(siteId) : void 0
7985
8622
  }
7986
8623
  );
7987
8624
  }
7988
8625
  async function getPageWithResilienceInternal(params) {
7989
8626
  const { siteId, path, preview = false, signal } = params;
7990
- const cacheKey = `page:${siteId}:${path}:${preview}`;
8627
+ const publishedRuntimeCache = planPublishedRuntimeCache({
8628
+ endpoint: "getContentByPath",
8629
+ params: { siteId, path, preview },
8630
+ siteId
8631
+ });
8632
+ const cacheKey = publishedRuntimeCache?.cacheKey ?? `page:${siteId}:${path}:${preview}`;
7991
8633
  return resilientFetch(
7992
8634
  cacheKey,
7993
8635
  async (sig) => {
@@ -8000,6 +8642,7 @@ function createRiverbankClient(config) {
8000
8642
  {
8001
8643
  preview,
8002
8644
  signal,
8645
+ publishedRuntimeCache,
8003
8646
  // Prebuild fallback only for published pages (not preview)
8004
8647
  prebuildFallback: prebuildLoader && !preview ? () => prebuildLoader.loadPage(siteId, path) : void 0
8005
8648
  }
@@ -8545,7 +9188,7 @@ function err(error) {
8545
9188
  }
8546
9189
 
8547
9190
  // ../core/src/assert-never.ts
8548
- function assertNever(value, message = "Unexpected variant") {
9191
+ function assertNever2(value, message = "Unexpected variant") {
8549
9192
  throw new Error(`${message}: ${String(value)}`);
8550
9193
  }
8551
9194
 
@@ -9964,7 +10607,7 @@ function makeBoundaryId(previousBlockId, nextBlockId) {
9964
10607
  const next = encodeURIComponent(nextBlockId);
9965
10608
  return asDesignBoundaryId(`boundary:${previous}:${next}`);
9966
10609
  }
9967
- function assertNever2(value, message = "Unhandled Theme V2 variant") {
10610
+ function assertNever3(value, message = "Unhandled Theme V2 variant") {
9968
10611
  throw new Error(`${message}: ${String(value)}`);
9969
10612
  }
9970
10613
  function brandNonEmptyString(value, label) {
@@ -16345,7 +16988,7 @@ function themedHeaderShadow(theme) {
16345
16988
  case "high":
16346
16989
  return { elevation: "lg" };
16347
16990
  default:
16348
- return assertNever2(
16991
+ return assertNever3(
16349
16992
  theme.shadow.elevation,
16350
16993
  "Unhandled theme shadow elevation"
16351
16994
  );
@@ -26800,7 +27443,7 @@ function planSiteChromePlacement(positioning) {
26800
27443
  standaloneShellClassName: "fixed left-0 right-0 top-0 z-40 w-full"
26801
27444
  };
26802
27445
  default:
26803
- return assertNever2(positioning);
27446
+ return assertNever3(positioning);
26804
27447
  }
26805
27448
  }
26806
27449
 
@@ -35411,7 +36054,7 @@ var publicProductsResponseSchema = z56.object({
35411
36054
  });
35412
36055
 
35413
36056
  // ../blocks/src/system/runtime/api/creditProducts.ts
35414
- function assertNever3(value) {
36057
+ function assertNever4(value) {
35415
36058
  throw new Error(`Unhandled credit product case: ${String(value)}`);
35416
36059
  }
35417
36060
  function useCasesFromModules(modules) {
@@ -35444,7 +36087,7 @@ function getCreditProductCreditUnit(useCase) {
35444
36087
  perCreditSuffix: "credit"
35445
36088
  };
35446
36089
  default:
35447
- return assertNever3(useCase);
36090
+ return assertNever4(useCase);
35448
36091
  }
35449
36092
  }
35450
36093
  function deriveCreditProductLabels(products, options = {}) {
@@ -39315,7 +39958,7 @@ function resolveLinkedContentEditSupport(contentType) {
39315
39958
  case "unsupported-domain-backed":
39316
39959
  return { kind: "unsupported-domain-backed", reason: metadata.reason };
39317
39960
  default:
39318
- return assertNever(metadata);
39961
+ return assertNever2(metadata);
39319
39962
  }
39320
39963
  }
39321
39964
  function contentTypeKeyToLabel(key) {