riverbankcms 0.17.0 → 0.17.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.
@@ -141,7 +141,6 @@ const unsafeAsDemoLifecycleAuditEventId = (id) => id;
141
141
  const unsafeAsDemoRuntimeId = (id) => id;
142
142
  const unsafeAsDemoCapability = (value) => value;
143
143
  const unsafeAsDemoPaymentFlowId = (id) => id;
144
- const unsafeAsDemoClaimTtlHours = (value) => value;
145
144
  const unsafeAsGiftingOfferId = (id) => id;
146
145
  const unsafeAsGiftingInstrumentId = (id) => id;
147
146
  const unsafeAsBookingRequirementId = (id) => id;
@@ -392,6 +391,7 @@ const demoInstanceStatusValues = [
392
391
  "failed"
393
392
  ];
394
393
  const demoClaimStatusValues = [
394
+ "preparing",
395
395
  "active",
396
396
  "expired",
397
397
  "released"
@@ -418,7 +418,7 @@ function narrowDemoBlueprintArtifactKind(value) {
418
418
 
419
419
  //#endregion
420
420
  //#region ../core/src/demo-warm-pool-target.ts
421
- const DEFAULT_DEMO_WARM_POOL_TARGET = 0;
421
+ const DEFAULT_DEMO_WARM_POOL_TARGET = 1;
422
422
  const MAX_DEMO_WARM_POOL_TARGET = 20;
423
423
  function parseDemoWarmPoolTarget(value) {
424
424
  if (value === undefined || value === null || value.trim() === "") {
@@ -1441,6 +1441,25 @@ function isRecord$9(value) {
1441
1441
  return typeof value === "object" && value !== null && !Array.isArray(value);
1442
1442
  }
1443
1443
 
1444
+ //#endregion
1445
+ //#region ../core/src/ticket-quantity.ts
1446
+ function toPositiveTicketQuantity(value) {
1447
+ if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {
1448
+ return err("invalid_quantity");
1449
+ }
1450
+ return ok(value);
1451
+ }
1452
+ /**
1453
+ * The places a booking holds: the sum of its ticket lines' quantities. The one
1454
+ * derivation for selections, persisted lines and a booking outcome's lines;
1455
+ * null when the total is not a positive whole number.
1456
+ */
1457
+ function deriveTotalTicketQuantity(lines) {
1458
+ const total = lines.reduce((sum, line) => sum + line.quantity, 0);
1459
+ const parsed = toPositiveTicketQuantity(total);
1460
+ return parsed.ok ? parsed.value : null;
1461
+ }
1462
+
1444
1463
  //#endregion
1445
1464
  //#region ../core/src/booking-flexible-balance.ts
1446
1465
  const DEFAULT_FLEXIBLE_BALANCE_STRIPE_MINIMUM_CHARGE_CENTS = 50;
@@ -3941,9 +3960,190 @@ function parseBrevoConfirmationTemplateId(value) {
3941
3960
  return parsePositiveInteger(value);
3942
3961
  }
3943
3962
 
3963
+ //#endregion
3964
+ //#region ../core/src/mailing-list-targeting.ts
3965
+ const DEFAULT_MAILING_LIST_TARGETING = { mode: "default" };
3966
+ function sameMailingListPlacementTargeting(left, right) {
3967
+ if (left.mode !== right.mode) return false;
3968
+ if (left.mode === "default" || right.mode === "default") return true;
3969
+ if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
3970
+ if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
3971
+ return sameIds(mailingListTargetingChoiceIds(left), mailingListTargetingChoiceIds(right));
3972
+ }
3973
+ function mailingListTargetingChoiceIds(targeting) {
3974
+ switch (targeting.provider) {
3975
+ case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
3976
+ case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
3977
+ case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
3978
+ }
3979
+ }
3980
+ function sameIds(left, right) {
3981
+ const leftIds = new Set(left);
3982
+ const rightIds = new Set(right);
3983
+ return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
3984
+ }
3985
+ function resolveMailingListTarget(input) {
3986
+ if (input.targeting.mode === "default") {
3987
+ if (input.visitorSelection !== undefined) {
3988
+ return err({ tag: "visitor_selection_not_allowed" });
3989
+ }
3990
+ return ok(resolveDefaultTarget(input.setup));
3991
+ }
3992
+ if (input.targeting.provider !== input.setup.provider) {
3993
+ return err({
3994
+ tag: "targeting_provider_mismatch",
3995
+ setupProvider: input.setup.provider,
3996
+ targetingProvider: input.targeting.provider
3997
+ });
3998
+ }
3999
+ return resolveCustomTarget(input.targeting, input.visitorSelection);
4000
+ }
4001
+ function resolveDefaultTarget(setup) {
4002
+ switch (setup.provider) {
4003
+ case "native": return {
4004
+ provider: "native",
4005
+ topicIds: [setup.defaultTopicId]
4006
+ };
4007
+ case "brevo": return {
4008
+ provider: "brevo",
4009
+ listIds: [setup.defaultListId]
4010
+ };
4011
+ case "mailchimp": return {
4012
+ provider: "mailchimp",
4013
+ audienceId: setup.defaultAudienceId,
4014
+ interestIds: []
4015
+ };
4016
+ }
4017
+ }
4018
+ function resolveCustomTarget(targeting, visitorSelection) {
4019
+ switch (targeting.provider) {
4020
+ case "native": return resolveNativeTarget(targeting, visitorSelection);
4021
+ case "brevo": return resolveBrevoTarget(targeting, visitorSelection);
4022
+ case "mailchimp": return resolveMailchimpTarget(targeting, visitorSelection);
4023
+ }
4024
+ }
4025
+ function resolveNativeTarget(targeting, selection) {
4026
+ if (targeting.selection.tag === "fixed") {
4027
+ return selection === undefined ? ok({
4028
+ provider: "native",
4029
+ topicIds: targeting.selection.topicIds
4030
+ }) : err({ tag: "visitor_selection_not_allowed" });
4031
+ }
4032
+ if (selection === undefined) {
4033
+ return targeting.selection.offeredTopicIds.length === 1 ? ok({
4034
+ provider: "native",
4035
+ topicIds: targeting.selection.offeredTopicIds
4036
+ }) : err({ tag: "visitor_selection_required" });
4037
+ }
4038
+ if (selection.provider !== "native") {
4039
+ return err({ tag: "visitor_selection_provider_mismatch" });
4040
+ }
4041
+ const selected = selectedNonEmptySubset(selection.topicIds, targeting.selection.offeredTopicIds);
4042
+ return selected.ok ? ok({
4043
+ provider: "native",
4044
+ topicIds: selected.value
4045
+ }) : err({ tag: "visitor_selection_outside_offer" });
4046
+ }
4047
+ function resolveBrevoTarget(targeting, selection) {
4048
+ if (targeting.selection.tag === "fixed") {
4049
+ return selection === undefined ? ok({
4050
+ provider: "brevo",
4051
+ listIds: targeting.selection.listIds
4052
+ }) : err({ tag: "visitor_selection_not_allowed" });
4053
+ }
4054
+ if (selection === undefined) {
4055
+ return targeting.selection.offeredListIds.length === 1 ? ok({
4056
+ provider: "brevo",
4057
+ listIds: targeting.selection.offeredListIds
4058
+ }) : err({ tag: "visitor_selection_required" });
4059
+ }
4060
+ if (selection.provider !== "brevo") {
4061
+ return err({ tag: "visitor_selection_provider_mismatch" });
4062
+ }
4063
+ const selected = selectedNonEmptySubset(selection.listIds, targeting.selection.offeredListIds);
4064
+ return selected.ok ? ok({
4065
+ provider: "brevo",
4066
+ listIds: selected.value
4067
+ }) : err({ tag: "visitor_selection_outside_offer" });
4068
+ }
4069
+ function resolveMailchimpTarget(targeting, selection) {
4070
+ if (targeting.selection.tag === "fixed") {
4071
+ return selection === undefined ? ok({
4072
+ provider: "mailchimp",
4073
+ audienceId: targeting.audienceId,
4074
+ interestIds: targeting.selection.interestIds
4075
+ }) : err({ tag: "visitor_selection_not_allowed" });
4076
+ }
4077
+ if (selection === undefined) {
4078
+ return targeting.selection.offeredInterestIds.length === 1 ? ok({
4079
+ provider: "mailchimp",
4080
+ audienceId: targeting.audienceId,
4081
+ interestIds: targeting.selection.offeredInterestIds
4082
+ }) : err({ tag: "visitor_selection_required" });
4083
+ }
4084
+ if (selection.provider !== "mailchimp") {
4085
+ return err({ tag: "visitor_selection_provider_mismatch" });
4086
+ }
4087
+ const subset = selectedNonEmptySubset(selection.interestIds, targeting.selection.offeredInterestIds);
4088
+ return subset.ok ? ok({
4089
+ provider: "mailchimp",
4090
+ audienceId: targeting.audienceId,
4091
+ interestIds: subset.value
4092
+ }) : err({ tag: "visitor_selection_outside_offer" });
4093
+ }
4094
+ function selectedNonEmptySubset(selected, offered) {
4095
+ const normalized = [...new Set(selected)];
4096
+ const [first, ...rest] = normalized;
4097
+ if (first === undefined || normalized.some((item) => !offered.includes(item))) {
4098
+ return err("invalid_selection");
4099
+ }
4100
+ return ok([first, ...rest]);
4101
+ }
4102
+ function planMailingListChoicePresentation(targeting) {
4103
+ if (targeting.mode === "default" || targeting.selection.tag === "fixed") {
4104
+ return { tag: "hidden" };
4105
+ }
4106
+ switch (targeting.provider) {
4107
+ case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
4108
+ tag: "automatic",
4109
+ selection: {
4110
+ provider: "native",
4111
+ topicIds: targeting.selection.offeredTopicIds
4112
+ }
4113
+ } : {
4114
+ tag: "visitor_choice",
4115
+ provider: "native",
4116
+ optionCount: targeting.selection.offeredTopicIds.length
4117
+ };
4118
+ case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
4119
+ tag: "automatic",
4120
+ selection: {
4121
+ provider: "brevo",
4122
+ listIds: targeting.selection.offeredListIds
4123
+ }
4124
+ } : {
4125
+ tag: "visitor_choice",
4126
+ provider: "brevo",
4127
+ optionCount: targeting.selection.offeredListIds.length
4128
+ };
4129
+ case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
4130
+ tag: "automatic",
4131
+ selection: {
4132
+ provider: "mailchimp",
4133
+ interestIds: targeting.selection.offeredInterestIds
4134
+ }
4135
+ } : {
4136
+ tag: "visitor_choice",
4137
+ provider: "mailchimp",
4138
+ optionCount: targeting.selection.offeredInterestIds.length
4139
+ };
4140
+ }
4141
+ }
4142
+
3944
4143
  //#endregion
3945
4144
  //#region ../core/src/mailing-list-targeting-parser.ts
3946
4145
  function parseMailingListPlacementTargeting(value) {
4146
+ if (value == null) return ok(DEFAULT_MAILING_LIST_TARGETING);
3947
4147
  if (!isRecord$6(value)) return targetingError("shape");
3948
4148
  if (value.mode === "default") return ok({ mode: "default" });
3949
4149
  if (value.mode !== "custom") return targetingError("mode");
@@ -4069,25 +4269,15 @@ function parseNonEmptyUniqueIds(value, parseId) {
4069
4269
  }
4070
4270
  function parseUniqueIds(value, parseId) {
4071
4271
  if (!Array.isArray(value)) return targetingError("targets");
4072
- const parsed = [];
4073
- for (const item of value) {
4272
+ return Array.from(value).reduce((parsed, item) => {
4273
+ if (!parsed.ok) return parsed;
4074
4274
  const id = parseId(item);
4075
- if (id === null) return targetingError("targets");
4076
- if (parsed.includes(id)) return targetingError("duplicate_target");
4077
- parsed.push(id);
4078
- }
4079
- return ok(parsed);
4275
+ return id === null ? targetingError("targets") : parsed.value.includes(id) ? targetingError("duplicate_target") : ok([...parsed.value, id]);
4276
+ }, ok([]));
4080
4277
  }
4081
4278
  function parseVisitorIds(value, parseId) {
4082
- if (!Array.isArray(value) || value.length === 0) return null;
4083
- const parsed = [];
4084
- for (const item of value) {
4085
- const id = parseId(item);
4086
- if (id === null) return null;
4087
- if (parsed.includes(id)) return null;
4088
- parsed.push(id);
4089
- }
4090
- return parsed;
4279
+ const parsed = parseNonEmptyUniqueIds(value, parseId);
4280
+ return parsed.ok ? parsed.value : null;
4091
4281
  }
4092
4282
  function isRecord$6(value) {
4093
4283
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -5088,183 +5278,102 @@ function setupError(field) {
5088
5278
  }
5089
5279
 
5090
5280
  //#endregion
5091
- //#region ../core/src/mailing-list-targeting.ts
5092
- function sameMailingListPlacementTargeting(left, right) {
5093
- if (left.mode !== right.mode) return false;
5094
- if (left.mode === "default" || right.mode === "default") return true;
5095
- if (left.provider !== right.provider || left.selection.tag !== right.selection.tag) return false;
5096
- if (left.provider === "mailchimp" && (right.provider !== "mailchimp" || left.audienceId !== right.audienceId)) return false;
5097
- return sameIds(targetingSelectionIds(left), targetingSelectionIds(right));
5098
- }
5099
- function targetingSelectionIds(targeting) {
5100
- switch (targeting.provider) {
5101
- case "native": return targeting.selection.tag === "fixed" ? targeting.selection.topicIds : targeting.selection.offeredTopicIds;
5102
- case "brevo": return targeting.selection.tag === "fixed" ? targeting.selection.listIds : targeting.selection.offeredListIds;
5103
- case "mailchimp": return targeting.selection.tag === "fixed" ? targeting.selection.interestIds : targeting.selection.offeredInterestIds;
5281
+ //#region ../core/src/mailing-list-targeting-availability.ts
5282
+ function resolveMailingListDefaultDestination(provider) {
5283
+ switch (provider.provider) {
5284
+ case "native": return provider.topics.find((item) => item.id === provider.defaultTopicId) ?? null;
5285
+ case "brevo": return provider.lists.find((item) => item.id === provider.defaultListId) ?? null;
5286
+ case "mailchimp": return provider.audiences.find((item) => item.id === provider.defaultAudienceId) ?? null;
5104
5287
  }
5105
5288
  }
5106
- function sameIds(left, right) {
5107
- const leftIds = new Set(left);
5108
- const rightIds = new Set(right);
5109
- return leftIds.size === left.length && rightIds.size === right.length && leftIds.size === rightIds.size && [...leftIds].every((id) => rightIds.has(id));
5110
- }
5111
- function resolveMailingListTarget(input) {
5112
- if (input.targeting.mode === "default") {
5113
- if (input.visitorSelection !== undefined) {
5114
- return err({ tag: "visitor_selection_not_allowed" });
5289
+ function assessMailingListTargeting(context, targeting) {
5290
+ if (context?.tag !== "configured") return {
5291
+ tag: "unavailable",
5292
+ reason: "setup_missing",
5293
+ targeting
5294
+ };
5295
+ const catalog = context.provider;
5296
+ if (targeting.mode === "custom") return assessCustomTargeting(catalog, targeting);
5297
+ const destination = resolveMailingListDefaultDestination(catalog);
5298
+ return destination === null ? {
5299
+ tag: "unavailable",
5300
+ reason: "default_missing",
5301
+ targeting
5302
+ } : {
5303
+ tag: "available",
5304
+ value: {
5305
+ mode: "default",
5306
+ targeting,
5307
+ provider: catalog.provider,
5308
+ destination
5115
5309
  }
5116
- return ok(resolveDefaultTarget(input.setup));
5117
- }
5118
- if (input.targeting.provider !== input.setup.provider) {
5119
- return err({
5120
- tag: "targeting_provider_mismatch",
5121
- setupProvider: input.setup.provider,
5122
- targetingProvider: input.targeting.provider
5123
- });
5124
- }
5125
- return resolveCustomTarget(input.targeting, input.visitorSelection);
5126
- }
5127
- function resolveDefaultTarget(setup) {
5128
- switch (setup.provider) {
5129
- case "native": return {
5130
- provider: "native",
5131
- topicIds: [setup.defaultTopicId]
5132
- };
5133
- case "brevo": return {
5134
- provider: "brevo",
5135
- listIds: [setup.defaultListId]
5136
- };
5137
- case "mailchimp": return {
5138
- provider: "mailchimp",
5139
- audienceId: setup.defaultAudienceId,
5140
- interestIds: []
5141
- };
5142
- }
5143
- }
5144
- function resolveCustomTarget(targeting, visitorSelection) {
5145
- switch (targeting.provider) {
5146
- case "native": return resolveNativeTarget(targeting, visitorSelection);
5147
- case "brevo": return resolveBrevoTarget(targeting, visitorSelection);
5148
- case "mailchimp": return resolveMailchimpTarget(targeting, visitorSelection);
5149
- }
5150
- }
5151
- function resolveNativeTarget(targeting, selection) {
5152
- if (targeting.selection.tag === "fixed") {
5153
- return selection === undefined ? ok({
5154
- provider: "native",
5155
- topicIds: targeting.selection.topicIds
5156
- }) : err({ tag: "visitor_selection_not_allowed" });
5157
- }
5158
- if (selection === undefined) {
5159
- return targeting.selection.offeredTopicIds.length === 1 ? ok({
5160
- provider: "native",
5161
- topicIds: targeting.selection.offeredTopicIds
5162
- }) : err({ tag: "visitor_selection_required" });
5163
- }
5164
- if (selection.provider !== "native") {
5165
- return err({ tag: "visitor_selection_provider_mismatch" });
5166
- }
5167
- const selected = selectedNonEmptySubset(selection.topicIds, targeting.selection.offeredTopicIds);
5168
- return selected.ok ? ok({
5169
- provider: "native",
5170
- topicIds: selected.value
5171
- }) : err({ tag: "visitor_selection_outside_offer" });
5172
- }
5173
- function resolveBrevoTarget(targeting, selection) {
5174
- if (targeting.selection.tag === "fixed") {
5175
- return selection === undefined ? ok({
5176
- provider: "brevo",
5177
- listIds: targeting.selection.listIds
5178
- }) : err({ tag: "visitor_selection_not_allowed" });
5179
- }
5180
- if (selection === undefined) {
5181
- return targeting.selection.offeredListIds.length === 1 ? ok({
5182
- provider: "brevo",
5183
- listIds: targeting.selection.offeredListIds
5184
- }) : err({ tag: "visitor_selection_required" });
5185
- }
5186
- if (selection.provider !== "brevo") {
5187
- return err({ tag: "visitor_selection_provider_mismatch" });
5188
- }
5189
- const selected = selectedNonEmptySubset(selection.listIds, targeting.selection.offeredListIds);
5190
- return selected.ok ? ok({
5191
- provider: "brevo",
5192
- listIds: selected.value
5193
- }) : err({ tag: "visitor_selection_outside_offer" });
5194
- }
5195
- function resolveMailchimpTarget(targeting, selection) {
5196
- if (targeting.selection.tag === "fixed") {
5197
- return selection === undefined ? ok({
5198
- provider: "mailchimp",
5199
- audienceId: targeting.audienceId,
5200
- interestIds: targeting.selection.interestIds
5201
- }) : err({ tag: "visitor_selection_not_allowed" });
5202
- }
5203
- if (selection === undefined) {
5204
- return targeting.selection.offeredInterestIds.length === 1 ? ok({
5205
- provider: "mailchimp",
5206
- audienceId: targeting.audienceId,
5207
- interestIds: targeting.selection.offeredInterestIds
5208
- }) : err({ tag: "visitor_selection_required" });
5209
- }
5210
- if (selection.provider !== "mailchimp") {
5211
- return err({ tag: "visitor_selection_provider_mismatch" });
5212
- }
5213
- const subset = selectedNonEmptySubset(selection.interestIds, targeting.selection.offeredInterestIds);
5214
- return subset.ok ? ok({
5215
- provider: "mailchimp",
5216
- audienceId: targeting.audienceId,
5217
- interestIds: subset.value
5218
- }) : err({ tag: "visitor_selection_outside_offer" });
5219
- }
5220
- function selectedNonEmptySubset(selected, offered) {
5221
- const normalized = [...new Set(selected)];
5222
- const [first, ...rest] = normalized;
5223
- if (first === undefined || normalized.some((item) => !offered.includes(item))) {
5224
- return err("invalid_selection");
5225
- }
5226
- return ok([first, ...rest]);
5310
+ };
5227
5311
  }
5228
- function planMailingListChoicePresentation(targeting) {
5229
- if (targeting.mode === "default" || targeting.selection.tag === "fixed") {
5230
- return { tag: "hidden" };
5231
- }
5312
+ function assessCustomTargeting(catalog, targeting) {
5232
5313
  switch (targeting.provider) {
5233
- case "native": return targeting.selection.offeredTopicIds.length === 1 ? {
5234
- tag: "automatic",
5235
- selection: {
5236
- provider: "native",
5237
- topicIds: targeting.selection.offeredTopicIds
5238
- }
5239
- } : {
5240
- tag: "visitor_choice",
5314
+ case "native": return catalog.provider === "native" ? assessMatchedChoices({
5241
5315
  provider: "native",
5242
- optionCount: targeting.selection.offeredTopicIds.length
5316
+ catalog,
5317
+ targeting
5318
+ }, catalog.topics) : {
5319
+ tag: "unavailable",
5320
+ reason: "provider_mismatch",
5321
+ targeting
5243
5322
  };
5244
- case "brevo": return targeting.selection.offeredListIds.length === 1 ? {
5245
- tag: "automatic",
5246
- selection: {
5247
- provider: "brevo",
5248
- listIds: targeting.selection.offeredListIds
5249
- }
5250
- } : {
5251
- tag: "visitor_choice",
5323
+ case "brevo": return catalog.provider === "brevo" ? assessMatchedChoices({
5252
5324
  provider: "brevo",
5253
- optionCount: targeting.selection.offeredListIds.length
5325
+ catalog,
5326
+ targeting
5327
+ }, catalog.lists) : {
5328
+ tag: "unavailable",
5329
+ reason: "provider_mismatch",
5330
+ targeting
5254
5331
  };
5255
- case "mailchimp": return targeting.selection.offeredInterestIds.length === 1 ? {
5256
- tag: "automatic",
5257
- selection: {
5332
+ case "mailchimp": {
5333
+ if (catalog.provider !== "mailchimp") return {
5334
+ tag: "unavailable",
5335
+ reason: "provider_mismatch",
5336
+ targeting
5337
+ };
5338
+ const audience = catalog.audiences.find((item) => item.id === targeting.audienceId);
5339
+ return audience === undefined ? {
5340
+ tag: "unavailable",
5341
+ reason: "audience_missing",
5342
+ value: {
5343
+ mode: "custom",
5344
+ provider: "mailchimp",
5345
+ catalog,
5346
+ targeting
5347
+ }
5348
+ } : assessMatchedChoices({
5258
5349
  provider: "mailchimp",
5259
- interestIds: targeting.selection.offeredInterestIds
5260
- }
5261
- } : {
5262
- tag: "visitor_choice",
5263
- provider: "mailchimp",
5264
- optionCount: targeting.selection.offeredInterestIds.length
5265
- };
5350
+ catalog,
5351
+ targeting,
5352
+ audience
5353
+ }, audience.interests);
5354
+ }
5266
5355
  }
5267
5356
  }
5357
+ function assessMatchedChoices(matched, choices) {
5358
+ const selected = new Set(mailingListTargetingChoiceIds(matched.targeting));
5359
+ const available = new Set(choices.map((item) => item.id));
5360
+ const missingIds = [...selected].filter((id) => !available.has(id));
5361
+ const value = {
5362
+ mode: "custom",
5363
+ ...matched,
5364
+ choices,
5365
+ selectedChoices: choices.filter((item) => selected.has(item.id))
5366
+ };
5367
+ return missingIds.length > 0 ? {
5368
+ tag: "unavailable",
5369
+ reason: "choices_missing",
5370
+ missingIds,
5371
+ value
5372
+ } : {
5373
+ tag: "available",
5374
+ value
5375
+ };
5376
+ }
5268
5377
 
5269
5378
  //#endregion
5270
5379
  //#region ../core/src/mailing-list-runtime.ts
@@ -5357,59 +5466,47 @@ function parseBrevoRuntimeProvider(value) {
5357
5466
  function parseMailchimpRuntimeProvider(value) {
5358
5467
  if (!Array.isArray(value.audiences)) return null;
5359
5468
  const defaultAudienceId = parseMailchimpAudienceId(value.defaultAudienceId);
5360
- if (defaultAudienceId === null) return null;
5361
- const audiences = [];
5362
- for (const audience of value.audiences) {
5363
- if (!isRecord$1(audience)) return null;
5364
- const id = parseMailchimpAudienceId(audience.id);
5365
- const name = parseName(audience.name);
5366
- if (id === null || name === null || !Array.isArray(audience.interests)) {
5367
- return null;
5368
- }
5369
- const interests = parseMailchimpInterests(audience.interests);
5370
- if (interests === null) return null;
5371
- audiences.push({
5372
- id,
5373
- name,
5374
- interests
5375
- });
5376
- }
5377
- return {
5469
+ const audiences = Array.from(value.audiences, parseMailchimpAudience);
5470
+ return defaultAudienceId !== null && audiences.every((audience) => audience !== null) ? {
5378
5471
  provider: "mailchimp",
5379
5472
  defaultAudienceId,
5380
5473
  audiences
5381
- };
5474
+ } : null;
5382
5475
  }
5383
- function parseMailchimpInterests(value) {
5384
- const interests = [];
5385
- for (const interest of value) {
5386
- if (!isRecord$1(interest)) return null;
5387
- const id = parseMailchimpInterestId(interest.id);
5388
- const name = parseName(interest.name);
5389
- const categoryName = parseName(interest.categoryName);
5390
- if (id === null || name === null || categoryName === null) return null;
5391
- interests.push({
5392
- id,
5393
- name,
5394
- categoryName
5395
- });
5396
- }
5397
- return interests;
5476
+ function parseMailchimpAudience(value) {
5477
+ if (!isRecord$1(value) || !Array.isArray(value.interests)) return null;
5478
+ const id = parseMailchimpAudienceId(value.id);
5479
+ const name = parseName(value.name);
5480
+ const interests = Array.from(value.interests, parseMailchimpInterest);
5481
+ return id !== null && name !== null && interests.every((interest) => interest !== null) ? {
5482
+ id,
5483
+ name,
5484
+ interests
5485
+ } : null;
5486
+ }
5487
+ function parseMailchimpInterest(value) {
5488
+ if (!isRecord$1(value)) return null;
5489
+ const id = parseMailchimpInterestId(value.id);
5490
+ const name = parseName(value.name);
5491
+ const categoryName = parseName(value.categoryName);
5492
+ return id !== null && name !== null && categoryName !== null ? {
5493
+ id,
5494
+ name,
5495
+ categoryName
5496
+ } : null;
5398
5497
  }
5399
5498
  function parseNamedItems(value, parseId) {
5400
5499
  if (!Array.isArray(value)) return null;
5401
- const items = [];
5402
- for (const item of value) {
5500
+ const items = Array.from(value, (item) => {
5403
5501
  if (!isRecord$1(item)) return null;
5404
5502
  const id = parseId(item.id);
5405
5503
  const name = parseName(item.name);
5406
- if (id === null || name === null) return null;
5407
- items.push({
5504
+ return id !== null && name !== null ? {
5408
5505
  id,
5409
5506
  name
5410
- });
5411
- }
5412
- return items;
5507
+ } : null;
5508
+ });
5509
+ return items.every((item) => item !== null) ? items : null;
5413
5510
  }
5414
5511
  function parseName(value) {
5415
5512
  if (typeof value !== "string") return null;
@@ -7428,4 +7525,4 @@ function mergeBag(stored, patch, options) {
7428
7525
  }
7429
7526
 
7430
7527
  //#endregion
7431
- export { parseBookingTimeZone as $, unsafeAsEventOfferingId as $t, footerNavigationLayouts as A, parseCurrencyCode as At, buildBookingUtcDateWindow as B, parsePageId as Bt, parseMailingListContentVersionId as C, isNonNegativeWholeCents as Ct, sameMailingListPlacementTargeting as D, unsafeAsNonNegativeCents as Dt, planMailingListChoicePresentation as E, toNonNegativeCents as Et, assertAllowedPublicUrl as F, parseDatedOfferingCapacityHoldAuditRef as Ft, formatLocalScheduleTime as G, unsafeAsBookingRequirementId as Gt, formatBookingDateParts as H, parseSiteId as Ht, isPresent as I, parseDatedOfferingCapacityHoldId as It, getLocalScheduleTime as J, unsafeAsDeclaredMimeType as Jt, getBookingLocalDateKey as K, unsafeAsBookingSessionId as Kt, normalizeLocationAddressText as L, parseEventSeriesId as Lt, parseMailingListPlacementTargeting as M, formatDurationUnitLabel as Mt, isCanonicalRichTextDoc as N, parseApiKeyId as Nt, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as O, unsafeAsPositiveCents as Ot, parsePublicContactDetails as P, parseCustomerId as Pt, toScheduledBookingDateTime as Q, unsafeAsEventInstanceId as Qt, toLocationCoordinates as R, parseMediaAssetId as Rt, parseMailingListBlockId as S, mapNonEmptyArray as St, parseMailingListRuntimeContext as T, toCents as Tt, formatBookingTime as U, parseUserId as Ut, formatBookingDate as V, parseRetiredCourseId as Vt, formatLocalScheduleDate as W, unsafeAsAppointmentResourceId as Wt, toBookingTimeZone as X, unsafeAsDetectedMimeType as Xt, parseUtcIsoDateTimeString as Y, unsafeAsDemoCapability as Yt, toScheduledBookingDateRange as Z, unsafeAsEntitlementId as Zt, createSecret as _, unsafeAsUploadSessionId as _n, publicEventPricingDisplay as _t, parseVerticalId as a, unsafeAsPassId as an, clampConfiguredAmount as at, stableJsonStringify as b, ok as bn, resolvePricingOptionsPriceDisplay as bt, DEFAULT_EVENT_TYPE_PRESETS as c, unsafeAsPricingOptionId as cn, omitZeroAmountFutureRows as ct, SURFACE_EVENT_PRESET_VALUES as d, unsafeAsSiteFontId as dn, resolveFlexibleBalanceInitialPaymentCents as dt, unsafeAsEventSeriesId as en, validateBookingPaymentOptionKinds as et, WHOLE_SERIES_EVENT_PRESET_VALUES as f, unsafeAsSiteId as fn, parseEventPageSurfaceSubject as ft, resolveWholeSeriesBookingPhase as g, unsafeAsStoragePath as gn, publicEventPricingCurrency as gt, orderedLiveRunSessions as h, unsafeAsStorageBucketName as hn, isPublicEventPricingOptionDisplayable as ht, canonicalizeConfiguredBookingVerticalConfig as i, unsafeAsOriginalFilename as in, addIntervalPreservingMonthAnchor as it, parseFooterCompositionV1 as j, assertNever as jt, parseMailingListProviderScope as k, formatCurrencyAmount as kt, EVENT_PRESET_VALUES as l, unsafeAsProductId as ln, splitAmountWithRemainderInFirst as lt, CANCELLED_SESSION_STATUS as m, unsafeAsStaffMemberId as mn, formatEventPricing as mt, NAVIGATION_LOCATIONS as n, unsafeAsMediaAssetId as nn, isSettleableFlexibleBalanceContractStatus as nt, parseVerticalPresetId as o, unsafeAsPositiveByteCount as on, getBookingInstalmentDepositRefundability as ot, publicReadFreshnessSeconds as p, unsafeAsSiteScopedStoragePath as pn, formatBookingPriceDisplay as pt, getLocalScheduleDate as q, unsafeAsCheckoutLineId as qt, areConfiguredBookingVerticalConfigsEqual as r, unsafeAsOccurrenceId as rn, isSettleableOrderInstalmentPlanStatus as rt, resolveSiteVerticalBookingConfig as s, unsafeAsPositiveSeconds as sn, getBookingInstalmentProtectedDepositAmountCents as st, resolveEventCatalogue as t, unsafeAsFileChecksumSha256 as tn, isLiveOrderInstalmentPlanStatus as tt, ORDINARY_EVENT_PRESET_VALUES as u, unsafeAsSafeDownloadFilename as un, resolveFlexibleBalanceDueAt as ut, exposeSecret as v, unsafeAsUserId as vn, publicEventPricingType as vt, parseMailingListSignedSourceToken as w, parseNonNegativeCents as wt, buildMailingListSignupBlockSourceRef as x, fromArray as xt, parseManagementKey as y, err as yn, resolveExactOrFreePriceDisplay as yt, selectCategoryView as z, parseMembershipId as zt };
7528
+ export { toBookingTimeZone as $, unsafeAsCheckoutLineId as $t, footerNavigationLayouts as A, parsePositiveCents as At, normalizeLocationAddressText as B, parseCustomerId as Bt, parseMailingListBlockId as C, unsafeAsUploadSessionId as Cn, publicEventPricingType as Ct, assessMailingListTargeting as D, mapNonEmptyArray as Dt, parseMailingListRuntimeContext as E, ok as En, fromArray as Et, sameMailingListPlacementTargeting as F, formatCurrencyAmount as Ft, formatBookingDateParts as G, parseMembershipId as Gt, selectCategoryView as H, parseDatedOfferingCapacityHoldId as Ht, isCanonicalRichTextDoc as I, parseCurrencyCode as It, formatLocalScheduleTime as J, parseSiteId as Jt, formatBookingTime as K, parsePageId as Kt, parsePublicContactDetails as L, assertNever as Lt, parseMailingListPlacementTargeting as M, toNonNegativeCents as Mt, DEFAULT_MAILING_LIST_TARGETING as N, unsafeAsNonNegativeCents as Nt, DEFAULT_MAILING_LIST_SUCCESS_MESSAGE as O, isNonNegativeWholeCents as Ot, planMailingListChoicePresentation as P, unsafeAsPositiveCents as Pt, parseUtcIsoDateTimeString as Q, unsafeAsBookingSessionId as Qt, assertAllowedPublicUrl as R, formatDurationUnitLabel as Rt, buildMailingListSignupBlockSourceRef as S, unsafeAsStoragePath as Sn, publicEventPricingOptions as St, parseMailingListSignedSourceToken as T, err as Tn, resolvePricingOptionsPriceDisplay as Tt, buildBookingUtcDateWindow as U, parseEventSeriesId as Ut, toLocationCoordinates as V, parseDatedOfferingCapacityHoldAuditRef as Vt, formatBookingDate as W, parseMediaAssetId as Wt, getLocalScheduleDate as X, unsafeAsAppointmentResourceId as Xt, getBookingLocalDateKey as Y, parseUserId as Yt, getLocalScheduleTime as Z, unsafeAsBookingRequirementId as Zt, resolveWholeSeriesBookingPhase as _, unsafeAsSiteFontId as _n, formatBookingPriceDisplay as _t, canonicalizeConfiguredBookingVerticalConfig as a, unsafeAsEventOfferingId as an, isSettleableFlexibleBalanceContractStatus as at, parseManagementKey as b, unsafeAsStaffMemberId as bn, publicEventPricingCurrency as bt, resolveSiteVerticalBookingConfig as c, unsafeAsMediaAssetId as cn, clampConfiguredAmount as ct, ORDINARY_EVENT_PRESET_VALUES as d, unsafeAsPassId as dn, getBookingInstalmentProtectedDepositAmountCents as dt, unsafeAsDeclaredMimeType as en, toScheduledBookingDateRange as et, SURFACE_EVENT_PRESET_VALUES as f, unsafeAsPositiveByteCount as fn, omitZeroAmountFutureRows as ft, orderedLiveRunSessions as g, unsafeAsSafeDownloadFilename as gn, parseEventPageSurfaceSubject as gt, CANCELLED_SESSION_STATUS as h, unsafeAsProductId as hn, resolveFlexibleBalanceInitialPaymentCents as ht, areConfiguredBookingVerticalConfigsEqual as i, unsafeAsEventInstanceId as in, isLiveOrderInstalmentPlanStatus as it, parseFooterCompositionV1 as j, toCents as jt, parseMailingListProviderScope as k, parseNonNegativeCents as kt, DEFAULT_EVENT_TYPE_PRESETS as l, unsafeAsOccurrenceId as ln, getBookingInstalmentDepositRefundability as lt, publicReadFreshnessSeconds as m, unsafeAsPricingOptionId as mn, resolveFlexibleBalanceDueAt as mt, EVENT_PRESET_VOCABULARY as n, unsafeAsDetectedMimeType as nn, parseBookingTimeZone as nt, parseVerticalId as o, unsafeAsEventSeriesId as on, isSettleableOrderInstalmentPlanStatus as ot, WHOLE_SERIES_EVENT_PRESET_VALUES as p, unsafeAsPositiveSeconds as pn, splitAmountWithRemainderInFirst as pt, formatLocalScheduleDate as q, parseRetiredCourseId as qt, NAVIGATION_LOCATIONS as r, unsafeAsEntitlementId as rn, validateBookingPaymentOptionKinds as rt, parseVerticalPresetId as s, unsafeAsFileChecksumSha256 as sn, addIntervalPreservingMonthAnchor as st, resolveEventCatalogue as t, unsafeAsDemoCapability as tn, toScheduledBookingDateTime as tt, EVENT_PRESET_VALUES as u, unsafeAsOriginalFilename as un, getBookingInstalmentPlanIntervalCount as ut, createSecret as v, unsafeAsSiteId as vn, formatEventPricing as vt, parseMailingListContentVersionId as w, unsafeAsUserId as wn, resolveExactOrFreePriceDisplay as wt, stableJsonStringify as x, unsafeAsStorageBucketName as xn, publicEventPricingDisplay as xt, exposeSecret as y, unsafeAsSiteScopedStoragePath as yn, isPublicEventPricingOptionDisplayable as yt, isPresent as z, parseApiKeyId as zt };
package/dist/testing.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import "./sdk-event-upsert-BfdOApMM.mjs";
3
- import "./src-DwdPY0Os.mjs";
4
- import { n as syncLocalMediaForPush, r as syncLocalMediaForPull, y as writeMediaManifest } from "./local-sync-Cnqnhvry.mjs";
2
+ import "./sdk-event-upsert-JKXlp2Ct.mjs";
3
+ import "./src-JsJh7WAb.mjs";
4
+ import { n as syncLocalMediaForPush, r as syncLocalMediaForPull, y as writeMediaManifest } from "./local-sync-C0m2pobl.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.17.0",
3
+ "version": "0.17.1",
4
4
  "description": "Riverbank CMS command-line tools for SDK site developers",
5
5
  "bin": {
6
6
  "riverbankcms": "dist/cli/index.mjs"