@fanfare-io/fanfare-sdk-core 0.17.0 → 0.19.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.
@@ -1 +1 @@
1
- import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as i}from"../core/errors.js";import{buildGrantPaymentAffordance as e}from"../experiences/sequence-driver.js";import{isGrantPendingWin as n}from"./auction-status.js";import{isUnresolvedAuctionConsumer as s}from"./auction.sequence.js";function o(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function a(t){return new u(t)}function r(e){const{distribution:n,consumer:a,grant:r,settlement:c,selection:u,outcome:d}=e;if(!n)return{phase:"unavailable"};const m=function(t){if("auction"!==t.type)throw i.validationError("Auction driver received a non-auction distribution");return t}(n),h=a&&"auction"===a.mechanism?function(t){const{mechanism:i,...e}=t;return e}(a):l(n);if(r)return"completed"===d?.type?p(m,h,d):r.expiresAt&&Date.now()>new Date(r.expiresAt).getTime()?"open"===m.lifecycle?{phase:"enterable",mechanism:"auction",distribution:m,consumer:l(m)}:p(m,h,{type:"expired"}):c&&u?{phase:"granted",mechanism:"auction",distribution:m,consumer:h,grant:r,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===m.lifecycle){if("not_bid"===h.status&&m.result===t.FLOOR_UNSOLD&&o(d))return p(m,h,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===a?.mechanism&&!d)return p(m,h,{type:"lost"})}const b=d??function(t){return"lost"===t.status?{type:"lost"}:void 0}(h);return b?p(m,h,b):"settling"===m.lifecycle?{phase:"settling",mechanism:"auction",distribution:m,consumer:h}:s(h)?{phase:"participating",mechanism:"auction",distribution:m,consumer:h}:"scheduled"===m.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:m}:"open"===m.lifecycle?{phase:"enterable",mechanism:"auction",distribution:m,consumer:h}:p(m,h,{type:"closed"})}function c(t,i,e){return t&&"auction"===t.mechanism&&i?"won"===i.type?{...t,status:"won"}:!e?.finalize&&"not_bid"===t.status&&o(i)?t:{...t,status:"lost"}:t}class u{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return r(t)}buildView(t,n){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const s=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("Auction driver received a non-auction sequence");return t}(t);switch(s.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:s.distribution,startsAt:s.distribution.startsAt??s.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"auction",distribution:s.distribution,consumer:s.consumer,display$:n.displayAtom,loadSelectionOptions:n.loadSelectionOptions,bid:t=>this.bid(t)};case"participating":return{phase:"participating",mechanism:"auction",consumer:s.consumer,display$:n.displayAtom,loadSelectionOptions:n.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:s.distribution,consumer:s.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",distribution:s.distribution,consumer:s.consumer,grant:s.grant},{settlement:i}=s,o=s.selection;if("awaiting_assignment"===o.status)return{...t,settlement:i,selection:o};if("required"===o.status)return{...t,settlement:i,selection:o,select:n.select,loadSelectionOptions:n.loadSelectionOptions};if("internal"===i.processor&&"at_end"===i.mode){const a=e(i,s.pendingAction,n);return a?{...t,settlement:i,selection:o,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim(),payment:a}:{...t,settlement:i,selection:o,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}}return"external"===i.processor?{...t,settlement:i,selection:o,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",consumer:s.consumer,outcome:s.outcome}}}startMonitoring(t){this.activeMonitorId=t.participation.id,this.deps.auctions.startMonitoring(t.participation.id,{displayAtom:t.displayAtom},t.onUpdate,t.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.auctions.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async bid(t){await this.deps.runSerializedOperation(async()=>{const i=this.currentAuctionSequenceForBid(),e=i.consumer.distributionId??i.consumer.id??i.distribution.id,s=i.consumer.selection,o="auction"===i.distribution.details?.type?i.distribution.details:void 0;d(t,o?.auctionType);const a=await this.deps.auctions.bid(e,t),c=this.deps.getCurrentSequence(),u=c&&("enterable"===c.phase||"participating"===c.phase||"settling"===c.phase)&&"mechanism"in c&&"auction"===c.mechanism&&c.distribution.id===e;if("won"===a.status||"lost"===a.status)return void(u&&("won"===a.status&&a.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:a.admissionGrant}):"lost"===a.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):n(a)||this.deps.applyMonitorUpdate({type:"resync"})));if(!u)return;const l=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(a.status);void 0!==l&&this.deps.commit(r({distribution:i.distribution,consumer:{..."participating"===i.phase?i.consumer:{},mechanism:"auction",status:l,id:e,distributionId:e,...s?{selection:s}:{},currentBid:a.amount,highestBid:a.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("No auction is available to bid on");return t}}function d(t,e){if("dutch"!==e){if(void 0===t.amount)throw i.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw i.validationError("A Dutch auction clinches at the current price; omit the bid amount")}function l(t){return{status:"not_bid",distributionId:t.id}}function p(t,i,e){return{phase:"ended",mechanism:"auction",distribution:t,consumer:i,outcome:{...e,distributionType:e.distributionType??t.type,distributionId:e.distributionId??t.id,at:e.at??/* @__PURE__ */(new Date).toISOString()}}}export{d as assertBidInputMatchesMechanism,a as createAuctionDriver,o as isUpgradeableGenericLoss,r as projectAuctionSequence,c as withAuctionTerminalConsumer};
1
+ import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as i}from"../core/errors.js";import{selectionModeFields as e,buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{isGrantPendingWin as s}from"./auction-status.js";import{isUnresolvedAuctionConsumer as o}from"./auction.sequence.js";function a(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function r(t){return new d(t)}function c(n){const s=function(e){const{distribution:n,consumer:s,grant:r,settlement:c,selection:u,outcome:d}=e;if(!n)return{phase:"unavailable"};const l=function(t){if("auction"!==t.type)throw i.validationError("Auction driver received a non-auction distribution");return t}(n),h=s&&"auction"===s.mechanism?function(t){const{mechanism:i,...e}=t;return e}(s):p(n);if(r)return"completed"===d?.type?m(l,h,d):r.expiresAt&&Date.now()>new Date(r.expiresAt).getTime()?"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:p(l)}:m(l,h,{type:"expired"}):c&&u?{phase:"granted",mechanism:"auction",distribution:l,consumer:h,grant:r,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===l.lifecycle){if("not_bid"===h.status&&l.result===t.FLOOR_UNSOLD&&a(d))return m(l,h,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===s?.mechanism&&!d)return m(l,h,{type:"lost"})}const b=d??function(t){return"lost"===t.status?{type:"lost"}:void 0}(h);if(b)return m(l,h,b);if("settling"===l.lifecycle)return{phase:"settling",mechanism:"auction",distribution:l,consumer:h};if(o(h))return{phase:"participating",mechanism:"auction",distribution:l,consumer:h};if("scheduled"===l.lifecycle)return{phase:"scheduled",mechanism:"auction",distribution:l};if("open"===l.lifecycle)return{phase:"enterable",mechanism:"auction",distribution:l,consumer:h};return m(l,h,{type:"closed"})}(n);return"unavailable"===s.phase?s:{...s,...e(n)}}function u(t,i,e){return t&&"auction"===t.mechanism&&i?"won"===i.type?{...t,status:"won"}:!e?.finalize&&"not_bid"===t.status&&a(i)?t:{...t,status:"lost"}:t}class d{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return c(t)}buildView(t,s){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const o=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("Auction driver received a non-auction sequence");return t}(t);switch(o.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",...e(o),distribution:o.distribution,startsAt:o.distribution.startsAt??o.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"participating":return{phase:"participating",mechanism:"auction",...e(o),consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer,grant:o.grant},{settlement:i}=o,a=o.selection;if("awaiting_assignment"===a.status)return{...t,settlement:i,selection:a};if("required"===a.status)return{...t,settlement:i,selection:a,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===i.processor&&"at_end"===i.mode){const e=n(i,o.pendingAction,s);return e?{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:e}:{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return"external"===i.processor?{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",...e(o),consumer:o.consumer,outcome:o.outcome}}}startMonitoring(t){this.activeMonitorId=t.participation.id,this.deps.auctions.startMonitoring(t.participation.id,{displayAtom:t.displayAtom},t.onUpdate,t.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.auctions.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async bid(t){await this.deps.runSerializedOperation(async()=>{const i=this.currentAuctionSequenceForBid(),e=i.consumer.distributionId??i.consumer.id??i.distribution.id,n=i.consumer.selection,o="auction"===i.distribution.details?.type?i.distribution.details:void 0;l(t,o?.auctionType);const a=await this.deps.auctions.bid(e,t),r=this.deps.getCurrentSequence(),u=r&&("enterable"===r.phase||"participating"===r.phase||"settling"===r.phase)&&"mechanism"in r&&"auction"===r.mechanism&&r.distribution.id===e;if("won"===a.status||"lost"===a.status)return void(u&&("won"===a.status&&a.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:a.admissionGrant}):"lost"===a.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):s(a)||this.deps.applyMonitorUpdate({type:"resync"})));if(!u)return;const d=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(a.status);void 0!==d&&this.deps.commit(c({distribution:i.distribution,consumer:{..."participating"===i.phase?i.consumer:{},mechanism:"auction",status:d,id:e,distributionId:e,...n?{selection:n}:{},currentBid:a.amount,highestBid:a.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("No auction is available to bid on");return t}}function l(t,e){if("dutch"!==e){if(void 0===t.amount)throw i.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw i.validationError("A Dutch auction clinches at the current price; omit the bid amount")}function p(t){return{status:"not_bid",distributionId:t.id}}function m(t,i,e){return{phase:"ended",mechanism:"auction",distribution:t,consumer:i,outcome:{...e,distributionType:e.distributionType??t.type,distributionId:e.distributionId??t.id,at:e.at??/* @__PURE__ */(new Date).toISOString()}}}export{l as assertBidInputMatchesMechanism,r as createAuctionDriver,a as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionTerminalConsumer};
@@ -1,5 +1,5 @@
1
1
  import { AdmissionGrant, AuctionConsumerStatus, GrantedSettlement, SequenceOutcome } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
2
- import { GrantedSelection } from '@fanfare-io/fanfare-sdk-contracts/selection';
2
+ import { GrantedSelection, SelectionMode } from '@fanfare-io/fanfare-sdk-contracts/selection';
3
3
  import { ReadableAtom } from 'nanostores';
4
4
  import { AuctionDisplayState } from '../experiences/distribution-monitor.types';
5
5
  import { DistributionSummary } from '../experiences/journey.types';
@@ -52,6 +52,7 @@ export type AuctionSequence = AuctionScheduled | AuctionEnterable | AuctionParti
52
52
  export interface AuctionScheduled {
53
53
  /** Mechanism discriminator for auction narrowing. */
54
54
  mechanism: "auction";
55
+ selectionMode?: SelectionMode;
55
56
  /** Phase discriminator; scheduled auctions cannot be bid on yet. */
56
57
  phase: "scheduled";
57
58
  /** Auction distribution facts from the journey projector. */
@@ -65,6 +66,7 @@ export interface AuctionScheduled {
65
66
  export interface AuctionEnterable {
66
67
  /** Mechanism discriminator for auction narrowing. */
67
68
  mechanism: "auction";
69
+ selectionMode?: SelectionMode;
68
70
  /** Phase discriminator; `bid()` is legal on the matching view. */
69
71
  phase: "enterable";
70
72
  /** Open auction distribution facts from the journey projector. */
@@ -80,6 +82,7 @@ export interface AuctionEnterable {
80
82
  export interface AuctionParticipating {
81
83
  /** Mechanism discriminator for auction narrowing. */
82
84
  mechanism: "auction";
85
+ selectionMode?: SelectionMode;
83
86
  /** Phase discriminator; auction display and bidding are live. */
84
87
  phase: "participating";
85
88
  /** Auction distribution facts from the journey projector. */
@@ -95,6 +98,7 @@ export interface AuctionParticipating {
95
98
  export interface AuctionSettling {
96
99
  /** Mechanism discriminator for auction narrowing. */
97
100
  mechanism: "auction";
101
+ selectionMode?: SelectionMode;
98
102
  /** Phase discriminator; no consumer action is legal while settling. */
99
103
  phase: "settling";
100
104
  /** Settling auction distribution facts from the journey projector. */
@@ -110,6 +114,7 @@ export interface AuctionSettling {
110
114
  export interface AuctionGranted {
111
115
  /** Mechanism discriminator for auction narrowing. */
112
116
  mechanism: "auction";
117
+ selectionMode?: SelectionMode;
113
118
  /** Phase discriminator; `claim()` is legal on the matching view. */
114
119
  phase: "granted";
115
120
  /** Auction distribution facts from the journey projector. */
@@ -135,6 +140,7 @@ export interface AuctionGranted {
135
140
  export interface AuctionEnded {
136
141
  /** Mechanism discriminator for auction narrowing. */
137
142
  mechanism: "auction";
143
+ selectionMode?: SelectionMode;
138
144
  /** Phase discriminator; no auction actions are legal after this phase. */
139
145
  phase: "ended";
140
146
  /** Auction distribution facts from the journey projector. */
@@ -162,6 +168,7 @@ export interface AuctionScheduledView {
162
168
  phase: "scheduled";
163
169
  /** Mechanism discriminator for auction rendering. */
164
170
  mechanism: "auction";
171
+ selectionMode?: SelectionMode;
165
172
  /** Auction distribution facts from the journey projector. */
166
173
  distribution: DistributionSummary & {
167
174
  type: "auction";
@@ -177,6 +184,7 @@ export interface AuctionEnterableView {
177
184
  phase: "enterable";
178
185
  /** Mechanism discriminator for auction rendering. */
179
186
  mechanism: "auction";
187
+ selectionMode?: SelectionMode;
180
188
  /** Open auction distribution facts from the journey projector. */
181
189
  distribution: DistributionSummary & {
182
190
  type: "auction";
@@ -208,6 +216,7 @@ export interface AuctionParticipatingView {
208
216
  phase: "participating";
209
217
  /** Mechanism discriminator for auction rendering. */
210
218
  mechanism: "auction";
219
+ selectionMode?: SelectionMode;
211
220
  /** Consumer auction participation facts. */
212
221
  consumer: AuctionSequenceConsumerState;
213
222
  /** Live auction display facts: the price model, currency, and close time. */
@@ -234,6 +243,7 @@ export interface AuctionSettlingView {
234
243
  phase: "settling";
235
244
  /** Mechanism discriminator for auction rendering. */
236
245
  mechanism: "auction";
246
+ selectionMode?: SelectionMode;
237
247
  /** Settling auction distribution facts from the journey projector. */
238
248
  distribution: DistributionSummary & {
239
249
  type: "auction";
@@ -249,6 +259,7 @@ interface AuctionGrantedViewBase {
249
259
  phase: "granted";
250
260
  /** Mechanism discriminator for auction rendering. */
251
261
  mechanism: "auction";
262
+ selectionMode?: SelectionMode;
252
263
  /** Auction distribution facts from the journey projector. */
253
264
  distribution: DistributionSummary & {
254
265
  type: "auction";
@@ -317,6 +328,7 @@ export interface AuctionEndedView {
317
328
  phase: "ended";
318
329
  /** Mechanism discriminator for auction rendering. */
319
330
  mechanism: "auction";
331
+ selectionMode?: SelectionMode;
320
332
  /** Consumer auction facts at the terminal outcome. */
321
333
  consumer: AuctionSequenceConsumerState;
322
334
  /** Server-derived terminal outcome for the auction participation. */
@@ -328,6 +340,7 @@ export interface AuctionGrantedAwaitingAssignmentView {
328
340
  phase: "granted";
329
341
  /** Mechanism discriminator. */
330
342
  mechanism: "auction";
343
+ selectionMode?: SelectionMode;
331
344
  /** Distribution associated with this grant. */
332
345
  distribution: DistributionSummary & {
333
346
  type: "auction";
@@ -349,6 +362,7 @@ export interface AuctionGrantedSelectionRequiredView {
349
362
  phase: "granted";
350
363
  /** Mechanism discriminator. */
351
364
  mechanism: "auction";
365
+ selectionMode?: SelectionMode;
352
366
  /** Distribution associated with this grant. */
353
367
  distribution: DistributionSummary & {
354
368
  type: "auction";
@@ -1 +1 @@
1
- import{classify as r}from"./error-disposition.js";import{FanfareError as e,ErrorCodes as o}from"./errors.js";const t={[o.OTP_INVALID]:"auth.invalidCode",[o.OTP_EXPIRED]:"auth.codeExpired",[o.INVALID_SESSION]:"common.sessionExpired",[o.INVALID_REFRESH_TOKEN]:"common.sessionExpired",[o.SERVICE_UNAVAILABLE]:"error.overloadedGeneric",[o.TIMEOUT]:"error.overloadedGeneric",[o.NETWORK_ERROR]:"error.overloadedGeneric",[o.FEATURE_DISABLED]:"error.featureDisabled",[o.NO_ACCESS]:"widget.noAccess.message",[o.FORBIDDEN]:"error.forbidden",[o.DISTRIBUTION_NOT_OPEN]:"error.notOpen",[o.DISTRIBUTION_DEACTIVATED]:"error.deactivated",[o.ALREADY_BOOKED]:"appointment.error.alreadyBooked",[o.ACTIVE_BOOKING_EXISTS]:"appointment.error.activeBookingExists",[o.SLOT_NOT_AVAILABLE]:"appointment.error.slotNotAvailable",[o.SLOT_EXPIRED]:"appointment.error.slotExpired",[o.SLOT_OUT_OF_WINDOW]:"appointment.error.slotOutOfWindow",[o.CANNOT_CANCEL_ONGOING_OR_PAST]:"appointment.error.cannotCancel",[o.NEW_SLOT_FULL]:"appointment.error.newSlotFull",[o.BOOKING_COMPLETED]:"appointment.error.bookingCompleted",[o.NO_EXISTING_BOOKING]:"appointment.error.noExistingBooking",[o.INVALID_SLOT]:"appointment.error.invalidSlot"},i=/* @__PURE__ */new Set([o.DISTRIBUTION_DEACTIVATED,o.DISTRIBUTION_CLOSED,o.DISTRIBUTION_ORDER_LIMIT,o.SOLD_OUT,o.CHECKOUT_MISCONFIGURED]);function n(r){return"INLINE"===r||"STEP_RESET"===r?"error.inlineGeneric":"error.description"}function s(e,s){const{disposition:E}=r(e.code,e.status,e.action),I="number"==typeof e.retryAfter&&Number.isFinite(e.retryAfter)?e.retryAfter:void 0,d=function(r,e,i){return r===o.RATE_LIMITED?i?"error.rateLimited":"error.rateLimitedGeneric":r===o.OVERLOADED?i?"error.overloaded":"error.overloadedGeneric":t[r]??n(e)}(e.code,E,void 0!==I);let O=s(d,void 0!==I?{values:{seconds:I}}:void 0);O.includes("{{")&&(O=s(n(E)));const a="PANEL"===E?s("error.title"):void 0;return{code:e.code,title:a,description:O,disposition:E,retryAfter:e.retryAfter,support:e.support,allowRetry:!i.has(e.code)}}function E(r){if(r instanceof e)return r;const t=r instanceof Error?r.message:String(r);return new e(t,o.INTERNAL_ERROR)}function I(r){return{code:r.code,status:r.status,requestId:r.requestId,correlationId:r.correlationId,details:r.details,issues:r.issues}}export{E as ensureFanfareError,I as toDebug,s as toDisplay};
1
+ import{classify as e}from"./error-disposition.js";import{FanfareError as r,ErrorCodes as o}from"./errors.js";const t={[o.OTP_INVALID]:"auth.invalidCode",[o.OTP_EXPIRED]:"auth.codeExpired",[o.INVALID_SESSION]:"common.sessionExpired",[o.INVALID_REFRESH_TOKEN]:"common.sessionExpired",[o.SERVICE_UNAVAILABLE]:"error.overloadedGeneric",[o.TIMEOUT]:"error.overloadedGeneric",[o.NETWORK_ERROR]:"error.overloadedGeneric",[o.FEATURE_DISABLED]:"error.featureDisabled",[o.NO_ACCESS]:"widget.noAccess.message",[o.FORBIDDEN]:"error.forbidden",[o.DISTRIBUTION_NOT_OPEN]:"error.notOpen",[o.DISTRIBUTION_DEACTIVATED]:"error.deactivated",[o.ALREADY_BOOKED]:"appointment.error.alreadyBooked",[o.ACTIVE_BOOKING_EXISTS]:"appointment.error.activeBookingExists",[o.SLOT_NOT_AVAILABLE]:"appointment.error.slotNotAvailable",[o.SLOT_EXPIRED]:"appointment.error.slotExpired",[o.SLOT_OUT_OF_WINDOW]:"appointment.error.slotOutOfWindow",[o.CANNOT_CANCEL_ONGOING_OR_PAST]:"appointment.error.cannotCancel",[o.NEW_SLOT_FULL]:"appointment.error.newSlotFull",[o.BOOKING_COMPLETED]:"appointment.error.bookingCompleted",[o.NO_EXISTING_BOOKING]:"appointment.error.noExistingBooking",[o.INVALID_SLOT]:"appointment.error.invalidSlot",[o.SELECTION_REQUIRED]:"selection.error.required",[o.SELECTION_INVALID_CHOICE]:"selection.error.invalidChoice",[o.SELECTION_NOT_REQUIRED]:"selection.error.notRequired",[o.SELECTION_LOCKED]:"selection.locked.final",[o.SELECTION_MISMATCH]:"selection.error.mismatch",[o.SELECTION_UNAVAILABLE]:"selection.error.unavailable",[o.SELECTION_LIMIT_REACHED]:"selection.error.limitReached",[o.SELECTION_ASSIGNMENT_PENDING]:"selection.error.assignmentPending",[o.ADMISSION_SELECTION_UNRESOLVED]:"selection.error.admissionUnresolved",[o.SOLD_OUT]:"selection.error.soldOut",[o.STOCK_UNSEEDED]:"selection.error.unseeded"},i=/* @__PURE__ */new Set([o.DISTRIBUTION_DEACTIVATED,o.DISTRIBUTION_CLOSED,o.DISTRIBUTION_ORDER_LIMIT,o.SOLD_OUT,o.CHECKOUT_MISCONFIGURED]);function n(e){return"INLINE"===e||"STEP_RESET"===e?"error.inlineGeneric":"error.description"}function E(r,E){const{disposition:s}=e(r.code,r.status,r.action),I="number"==typeof r.retryAfter&&Number.isFinite(r.retryAfter)?r.retryAfter:void 0,O=function(e,r,i){return e===o.RATE_LIMITED?i?"error.rateLimited":"error.rateLimitedGeneric":e===o.OVERLOADED?i?"error.overloaded":"error.overloadedGeneric":t[e]??n(r)}(r.code,s,void 0!==I);let d=E(O,void 0!==I?{values:{seconds:I}}:void 0);d.includes("{{")&&(d=E(n(s)));const T="PANEL"===s?E("error.title"):void 0;return{code:r.code,title:T,description:d,disposition:s,retryAfter:r.retryAfter,support:r.support,allowRetry:!i.has(r.code)}}function s(e){if(e instanceof r)return e;const t=e instanceof Error?e.message:String(e);return new r(t,o.INTERNAL_ERROR)}function I(e){return{code:e.code,status:e.status,requestId:e.requestId,correlationId:e.correlationId,details:e.details,issues:e.issues}}export{s as ensureFanfareError,I as toDebug,E as toDisplay};
@@ -1 +1 @@
1
- import{DrawConsumerStatuses as e}from"@fanfare-io/fanfare-sdk-contracts/consumer-me";import{createError as t}from"../core/errors.js";import{buildGrantPaymentAffordance as i}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as n,checkoutViewFields as s,isEntryActionRequired as r,canReenter as o,isPreAuthMisconfigured as a}from"../payment/checkout-contract.js";import{isClaimableSettlement as d}from"../payment/settlement.js";import{isUnresolvedDrawConsumer as c}from"./draw.sequence.js";import{drawSelectionFromResponse as u}from"./types.js";function p(e){return a(n(e.details))}function l(e){return o(e.distribution.lifecycle,n(e.distribution.details))}function m(e){return new f(e)}const h=new Set(e);function w(e){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:a,outcome:d}=e;if(!i)return{phase:"unavailable"};const u=function(e){if("draw"!==e.type)throw t.validationError("Draw driver received a non-draw distribution");return e}(i),l=n&&"draw"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):y(i);if(s)return"completed"===d?.type?v(u,l,d,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===u.lifecycle?p(u)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:u,consumer:y(u)}:v(u,l,{type:"expired"}):o&&a?{phase:"granted",mechanism:"draw",distribution:u,consumer:l,grant:s,settlement:o,selection:a}:{phase:"unavailable"};if(!function(e){return h.has(e.status)}(l))return{phase:"unavailable",reason:"unrecognized_standing"};if(!d&&"draw"===n?.mechanism&&"closed"===u.lifecycle)return v(u,l,{type:"lost"});const m=d??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:void 0}(l);return m?v(u,l,m,r):"settling"===u.lifecycle?{phase:"settling",mechanism:"draw",distribution:u,consumer:l}:c(l)?{phase:"participating",mechanism:"draw",distribution:u,consumer:l}:"scheduled"===u.lifecycle?{phase:"scheduled",mechanism:"draw",distribution:u}:"open"===u.lifecycle?p(u)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:u,consumer:l}:v(u,l,{type:"closed"})}function b(e,t){return e&&"draw"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:"won"===t.type?{...e,status:"won"}:{...e,status:"not_entered"}:e}class f{constructor(e){this.deps=e,this.mechanism="draw",this.settlementCanStartWhileActive=!0}project(e){return w(e)}buildView(e,n){if("unavailable"===e.phase)return{phase:"unavailable",reason:e.reason};const s=function(e){if(!("mechanism"in e)||"draw"!==e.mechanism)throw t.validationError("Draw driver received a non-draw sequence");return e}(e);switch(s.phase){case"scheduled":return{phase:"scheduled",mechanism:"draw",distribution:s.distribution,startsAt:s.distribution.startsAt??s.distribution.opensAt};case"enterable":return this.buildEnterableView(s,n);case"participating":return{phase:"participating",mechanism:"draw",consumer:s.consumer,display$:n.displayAtom,loadSelectionOptions:n.loadSelectionOptions,select:n.select,leave:()=>this.leave()};case"settling":return{phase:"settling",mechanism:"draw",distribution:s.distribution,consumer:s.consumer};case"granted":{const e={phase:"granted",mechanism:"draw",distribution:s.distribution,consumer:s.consumer,grant:s.grant},{settlement:t}=s,r=s.selection;if("awaiting_assignment"===r.status)return{...e,settlement:t,selection:r};if("required"===r.status)return{...e,settlement:t,selection:r,select:n.select,loadSelectionOptions:n.loadSelectionOptions};if("internal"===t.processor&&"at_end"===t.mode){const o=i(t,s.pendingAction,n);return o?{...e,settlement:t,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim(),payment:o}:{...e,settlement:t,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}}return d(t)?{...e,settlement:t,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}:{...e,settlement:t,selection:r}}case"ended":return this.buildEndedView(s)}}buildEnterableView(e,t){const i=n(e.distribution.details),r=s(i);return"pre_auth"===r.checkoutMode?{phase:"enterable",mechanism:"draw",...r,distribution:e.distribution,consumer:e.consumer,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{},loadSelectionOptions:t.loadSelectionOptions,enter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{phase:"enterable",mechanism:"draw",...r,distribution:e.distribution,consumer:e.consumer,loadSelectionOptions:t.loadSelectionOptions,enter:e=>this.enter({selection:e})}}buildEndedView(e){const t={phase:"ended",mechanism:"draw",consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!l(e))return t;const i=n(e.distribution.details),r=s(i);return"pre_auth"===r.checkoutMode?{...t,...r,reenter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{...t,...r,reenter:e=>this.enter({selection:e})}}startMonitoring(e){this.activeMonitorId=e.participation.id;const t=this.deps.getCurrentSequence(),i=t&&("participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"draw"===t.mechanism&&"draw"===t.distribution.details?.type?t.distribution.details.drawTime:void 0;this.deps.draws.startMonitoring(e.participation.id,{displayAtom:e.displayAtom,drawTime:i,phase:"settling"===t?.phase?"settling":"participating"},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.draws.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const i=this.currentDrawSequence("enterable","No open draw to enter"),s=i.distribution,o=n(s.details),a=e?.paymentInput;if("pre_auth"===o.mode&&!a)throw t.validationError("Payment input is required for pre-auth distributions");const d=e?.selection?await this.deps.draws.enter(s.id,void 0,void 0,a,e.selection):a?await this.deps.draws.enter(s.id,void 0,void 0,a):await this.deps.draws.enter(s.id,void 0);if(r(d))return this.deps.commit({...i,pendingAction:d.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:s.id,processor:d.nextAction.processor});const c=function(e){if("ENTERED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("WON"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("LEFT"===e.status)return{type:"ended",outcome:{type:"left"}};return{type:"ended",outcome:{type:"DENIED"===e.status?"denied":"lost",reason:"reason"in e?e.reason:void 0}}}(d);if(c)return void this.deps.applyMonitorUpdate(c);const p=u(d),l={...(m=s.id,{mechanism:"draw",status:"entered",id:m,distributionId:m}),...p?{selection:p}:{}};var m;this.deps.ensureDisplayAtom({id:s.id,type:"draw"}),this.deps.commit(w({distribution:s,consumer:l})),this.deps.emitEvent("sequence_change","success","user","Entered draw",{distributionId:s.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentDrawSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;await this.deps.draws.leave(t),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"draw"})}currentDrawSequence(e,i="Not participating in a draw"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"draw"!==n.mechanism)throw t.validationError(i);if("enterable"===e&&"ended"===n.phase&&l(n))return{phase:"enterable",mechanism:"draw",distribution:n.distribution,consumer:y(n.distribution)};if(n.phase!==e)throw t.validationError(i);return n}}function y(e){return{status:"not_entered",distributionId:e.id}}function v(e,t,i,n){return{phase:"ended",mechanism:"draw",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}export{m as createDrawDriver,w as projectDrawSequence,b as withDrawTerminalConsumer};
1
+ import{DrawConsumerStatuses as e}from"@fanfare-io/fanfare-sdk-contracts/consumer-me";import{createError as t}from"../core/errors.js";import{selectionModeFields as i,buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as s,checkoutViewFields as r,isEntryActionRequired as o,canReenter as a,isPreAuthMisconfigured as d}from"../payment/checkout-contract.js";import{isClaimableSettlement as c}from"../payment/settlement.js";import{isUnresolvedDrawConsumer as u}from"./draw.sequence.js";import{drawSelectionFromResponse as p}from"./types.js";function l(e){return d(s(e.details))}function m(e){return a(e.distribution.lifecycle,s(e.distribution.details))}function h(e){return new y(e)}const w=new Set(e);function f(e){const n=function(e){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:a,outcome:d}=e;if(!i)return{phase:"unavailable"};const c=function(e){if("draw"!==e.type)throw t.validationError("Draw driver received a non-draw distribution");return e}(i),p=n&&"draw"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):v(i);if(s)return"completed"===d?.type?g(c,p,d,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===c.lifecycle?l(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:v(c)}:g(c,p,{type:"expired"}):o&&a?{phase:"granted",mechanism:"draw",distribution:c,consumer:p,grant:s,settlement:o,selection:a}:{phase:"unavailable"};if(!function(e){return w.has(e.status)}(p))return{phase:"unavailable",reason:"unrecognized_standing"};if(!d&&"draw"===n?.mechanism&&"closed"===c.lifecycle)return g(c,p,{type:"lost"});const m=d??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:void 0}(p);if(m)return g(c,p,m,r);if("settling"===c.lifecycle)return{phase:"settling",mechanism:"draw",distribution:c,consumer:p};if(u(p))return{phase:"participating",mechanism:"draw",distribution:c,consumer:p};if("scheduled"===c.lifecycle)return{phase:"scheduled",mechanism:"draw",distribution:c};if("open"===c.lifecycle)return l(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:p};return g(c,p,{type:"closed"})}(e);return"unavailable"===n.phase?n:{...n,...i(e)}}function b(e,t){return e&&"draw"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:"won"===t.type?{...e,status:"won"}:{...e,status:"not_entered"}:e}class y{constructor(e){this.deps=e,this.mechanism="draw",this.settlementCanStartWhileActive=!0}project(e){return f(e)}buildView(e,s){if("unavailable"===e.phase)return{phase:"unavailable",reason:e.reason};const r=function(e){if(!("mechanism"in e)||"draw"!==e.mechanism)throw t.validationError("Draw driver received a non-draw sequence");return e}(e);switch(r.phase){case"scheduled":return{phase:"scheduled",mechanism:"draw",...i(r),distribution:r.distribution,startsAt:r.distribution.startsAt??r.distribution.opensAt};case"enterable":return this.buildEnterableView(r,s);case"participating":return{phase:"participating",mechanism:"draw",...i(r),consumer:r.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,select:s.select,leave:()=>this.leave()};case"settling":return{phase:"settling",mechanism:"draw",...i(r),distribution:r.distribution,consumer:r.consumer};case"granted":{const e={phase:"granted",mechanism:"draw",...i(r),distribution:r.distribution,consumer:r.consumer,grant:r.grant},{settlement:t}=r,o=r.selection;if("awaiting_assignment"===o.status)return{...e,settlement:t,selection:o};if("required"===o.status)return{...e,settlement:t,selection:o,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===t.processor&&"at_end"===t.mode){const i=n(t,r.pendingAction,s);return i?{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:i}:{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return c(t)?{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{...e,settlement:t,selection:o}}case"ended":return this.buildEndedView(r)}}buildEnterableView(e,t){const n=s(e.distribution.details),o=r(n);return"pre_auth"===o.checkoutMode?{phase:"enterable",mechanism:"draw",...i(e),...o,distribution:e.distribution,consumer:e.consumer,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{},loadSelectionOptions:t.loadSelectionOptions,enter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{phase:"enterable",mechanism:"draw",...i(e),...o,distribution:e.distribution,consumer:e.consumer,loadSelectionOptions:t.loadSelectionOptions,enter:e=>this.enter({selection:e})}}buildEndedView(e){const t={phase:"ended",mechanism:"draw",...i(e),consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!m(e))return t;const n=s(e.distribution.details),o=r(n);return"pre_auth"===o.checkoutMode?{...t,...o,reenter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{...t,...o,reenter:e=>this.enter({selection:e})}}startMonitoring(e){this.activeMonitorId=e.participation.id;const t=this.deps.getCurrentSequence(),i=t&&("participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"draw"===t.mechanism&&"draw"===t.distribution.details?.type?t.distribution.details.drawTime:void 0;this.deps.draws.startMonitoring(e.participation.id,{displayAtom:e.displayAtom,drawTime:i,phase:"settling"===t?.phase?"settling":"participating"},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.draws.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const i=this.currentDrawSequence("enterable","No open draw to enter"),n=i.distribution,r=s(n.details),a=e?.paymentInput;if("pre_auth"===r.mode&&!a)throw t.validationError("Payment input is required for pre-auth distributions");const d=e?.selection?await this.deps.draws.enter(n.id,void 0,void 0,a,e.selection):a?await this.deps.draws.enter(n.id,void 0,void 0,a):await this.deps.draws.enter(n.id,void 0);if(o(d))return this.deps.commit({...i,pendingAction:d.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:n.id,processor:d.nextAction.processor});const c=function(e){if("ENTERED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("WON"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("LEFT"===e.status)return{type:"ended",outcome:{type:"left"}};return{type:"ended",outcome:{type:"DENIED"===e.status?"denied":"lost",reason:"reason"in e?e.reason:void 0}}}(d);if(c)return void this.deps.applyMonitorUpdate(c);const u=p(d),l={...(m=n.id,{mechanism:"draw",status:"entered",id:m,distributionId:m}),...u?{selection:u}:{}};var m;this.deps.ensureDisplayAtom({id:n.id,type:"draw"}),this.deps.commit(f({distribution:n,consumer:l})),this.deps.emitEvent("sequence_change","success","user","Entered draw",{distributionId:n.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentDrawSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;await this.deps.draws.leave(t),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"draw"})}currentDrawSequence(e,i="Not participating in a draw"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"draw"!==n.mechanism)throw t.validationError(i);if("enterable"===e&&"ended"===n.phase&&m(n))return{phase:"enterable",mechanism:"draw",distribution:n.distribution,consumer:v(n.distribution)};if(n.phase!==e)throw t.validationError(i);return n}}function v(e){return{status:"not_entered",distributionId:e.id}}function g(e,t,i,n){return{phase:"ended",mechanism:"draw",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}export{h as createDrawDriver,f as projectDrawSequence,b as withDrawTerminalConsumer};
@@ -1,5 +1,5 @@
1
1
  import { AdmissionGrant, DrawConsumerStatus, GrantedSettlement, SequenceOutcome } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
2
- import { GrantedSelection } from '@fanfare-io/fanfare-sdk-contracts/selection';
2
+ import { GrantedSelection, SelectionMode } from '@fanfare-io/fanfare-sdk-contracts/selection';
3
3
  import { ReadableAtom } from 'nanostores';
4
4
  import { DrawDisplayState } from '../experiences/distribution-monitor.types';
5
5
  import { DistributionSummary } from '../experiences/journey.types';
@@ -48,6 +48,7 @@ export type DrawSequence = DrawScheduled | DrawEnterable | DrawParticipating | D
48
48
  export interface DrawScheduled {
49
49
  /** Mechanism discriminator for draw narrowing. */
50
50
  mechanism: "draw";
51
+ selectionMode?: SelectionMode;
51
52
  /** Phase discriminator; scheduled draws cannot be entered yet. */
52
53
  phase: "scheduled";
53
54
  /** Draw distribution facts from the journey projector. */
@@ -61,6 +62,7 @@ export interface DrawScheduled {
61
62
  export interface DrawEnterable {
62
63
  /** Mechanism discriminator for draw narrowing. */
63
64
  mechanism: "draw";
65
+ selectionMode?: SelectionMode;
64
66
  /** Phase discriminator; `enter()` is legal on the matching view. */
65
67
  phase: "enterable";
66
68
  /** Open draw distribution facts from the journey projector. */
@@ -87,6 +89,7 @@ export interface DrawEnterable {
87
89
  export interface DrawParticipating {
88
90
  /** Mechanism discriminator for draw narrowing. */
89
91
  mechanism: "draw";
92
+ selectionMode?: SelectionMode;
90
93
  /** Phase discriminator; the draw display is live while participating. */
91
94
  phase: "participating";
92
95
  /** Draw distribution facts from the journey projector. */
@@ -102,6 +105,7 @@ export interface DrawParticipating {
102
105
  export interface DrawSettling {
103
106
  /** Mechanism discriminator for draw narrowing. */
104
107
  mechanism: "draw";
108
+ selectionMode?: SelectionMode;
105
109
  /** Phase discriminator; no consumer action is legal while settling. */
106
110
  phase: "settling";
107
111
  /** Settling draw distribution facts from the journey projector. */
@@ -117,6 +121,7 @@ export interface DrawSettling {
117
121
  export interface DrawGranted {
118
122
  /** Mechanism discriminator for draw narrowing. */
119
123
  mechanism: "draw";
124
+ selectionMode?: SelectionMode;
120
125
  /** Phase discriminator; `claim()` is legal on the matching view. */
121
126
  phase: "granted";
122
127
  /** Draw distribution facts from the journey projector. */
@@ -143,6 +148,7 @@ export interface DrawGranted {
143
148
  export interface DrawEnded {
144
149
  /** Mechanism discriminator for draw narrowing. */
145
150
  mechanism: "draw";
151
+ selectionMode?: SelectionMode;
146
152
  /** Phase discriminator; no draw actions are legal after this phase. */
147
153
  phase: "ended";
148
154
  /** Draw distribution facts from the journey projector. */
@@ -172,6 +178,7 @@ export interface DrawScheduledView {
172
178
  phase: "scheduled";
173
179
  /** Mechanism discriminator for draw rendering. */
174
180
  mechanism: "draw";
181
+ selectionMode?: SelectionMode;
175
182
  /** Draw distribution facts from the journey projector. */
176
183
  distribution: DistributionSummary & {
177
184
  type: "draw";
@@ -193,6 +200,7 @@ export type DrawEnterableView = {
193
200
  phase: "enterable";
194
201
  /** Mechanism discriminator for draw rendering. */
195
202
  mechanism: "draw";
203
+ selectionMode?: SelectionMode;
196
204
  /** Money moves after the win; entry places no hold. */
197
205
  checkoutMode: "at_end";
198
206
  /** Open draw distribution facts from the journey projector. */
@@ -216,6 +224,7 @@ export type DrawEnterableView = {
216
224
  phase: "enterable";
217
225
  /** Mechanism discriminator for draw rendering. */
218
226
  mechanism: "draw";
227
+ selectionMode?: SelectionMode;
219
228
  /** Fanfare places a payment authorization hold at entry and captures it on win. */
220
229
  checkoutMode: "pre_auth";
221
230
  /** Open draw distribution facts from the journey projector. */
@@ -258,6 +267,7 @@ export interface DrawParticipatingView {
258
267
  phase: "participating";
259
268
  /** Mechanism discriminator for draw rendering. */
260
269
  mechanism: "draw";
270
+ selectionMode?: SelectionMode;
261
271
  /** Consumer draw participation facts. */
262
272
  consumer: DrawSequenceConsumerState;
263
273
  /** Live draw display facts, such as participant counts and draw timing. */
@@ -282,6 +292,7 @@ export interface DrawSettlingView {
282
292
  phase: "settling";
283
293
  /** Mechanism discriminator for draw rendering. */
284
294
  mechanism: "draw";
295
+ selectionMode?: SelectionMode;
285
296
  /** Settling draw distribution facts from the journey projector. */
286
297
  distribution: DistributionSummary & {
287
298
  type: "draw";
@@ -295,6 +306,7 @@ interface DrawGrantedViewBase {
295
306
  phase: "granted";
296
307
  /** Mechanism discriminator for draw rendering. */
297
308
  mechanism: "draw";
309
+ selectionMode?: SelectionMode;
298
310
  /** Draw distribution facts from the journey projector. */
299
311
  distribution: DistributionSummary & {
300
312
  type: "draw";
@@ -375,6 +387,7 @@ export type DrawEndedView = {
375
387
  phase: "ended";
376
388
  /** Mechanism discriminator for draw rendering. */
377
389
  mechanism: "draw";
390
+ selectionMode?: SelectionMode;
378
391
  /** Consumer draw facts at the terminal outcome. */
379
392
  consumer: DrawSequenceConsumerState;
380
393
  /** Server-derived terminal outcome for the draw participation. */
@@ -390,6 +403,7 @@ export type DrawEndedView = {
390
403
  phase: "ended";
391
404
  /** Mechanism discriminator for draw rendering. */
392
405
  mechanism: "draw";
406
+ selectionMode?: SelectionMode;
393
407
  /** Consumer draw facts at the terminal outcome. */
394
408
  consumer: DrawSequenceConsumerState;
395
409
  /** Server-derived terminal outcome for the draw participation. */
@@ -411,6 +425,7 @@ export type DrawEndedView = {
411
425
  phase: "ended";
412
426
  /** Mechanism discriminator for draw rendering. */
413
427
  mechanism: "draw";
428
+ selectionMode?: SelectionMode;
414
429
  /** Consumer draw facts at the terminal outcome. */
415
430
  consumer: DrawSequenceConsumerState;
416
431
  /** Server-derived terminal outcome for the draw participation. */
@@ -445,6 +460,7 @@ export interface DrawGrantedAwaitingAssignmentView {
445
460
  phase: "granted";
446
461
  /** Mechanism discriminator. */
447
462
  mechanism: "draw";
463
+ selectionMode?: SelectionMode;
448
464
  /** Distribution associated with this grant. */
449
465
  distribution: DistributionSummary & {
450
466
  type: "draw";
@@ -466,6 +482,7 @@ export interface DrawGrantedSelectionRequiredView {
466
482
  phase: "granted";
467
483
  /** Mechanism discriminator. */
468
484
  mechanism: "draw";
485
+ selectionMode?: SelectionMode;
469
486
  /** Distribution associated with this grant. */
470
487
  distribution: DistributionSummary & {
471
488
  type: "draw";
@@ -1 +1 @@
1
- import{AuthenticationRoutingGateV1Schema as e,AccessCodeRoutingGateV1Schema as t,BotCheckRoutingGateV1Schema as i}from"@fanfare-io/fanfare-sdk-contracts/routing";import{GrantedSelectionSchema as s,SelectionChoiceSchema as r}from"@fanfare-io/fanfare-sdk-contracts/selection";import{atom as n,computed as o}from"nanostores";import*as a from"valibot";import{createAppointmentDriver as c,withAppointmentTerminalConsumer as d}from"../appointments/appointment.driver.js";import{createAuctionDriver as u,isUpgradeableGenericLoss as h,withAuctionTerminalConsumer as l}from"../auctions/auction.driver.js";import{createError as p,isFanfareError as m,ErrorCodes as g}from"../core/errors.js";import{createLogger as y}from"../core/logger.js";import{generateId as f}from"../core/utils.js";import{createDrawDriver as b,withDrawTerminalConsumer as S}from"../draws/draw.driver.js";import{createQueueDriver as I,withQueueTerminalConsumer as v}from"../queues/queue.driver.js";import{clearExperienceContext as A,clearSequenceContext as q,resolveCapabilityOptions as w,bindDistributionContext as k,bindWaitlist as C,upsertSequenceToken as x,peekSequenceToken as j,getSequenceTokenExpiryMs as T}from"../state/capability-token-registry.js";import{getEventBus as D}from"../state/events.js";import{getSDKStore as E}from"../state/store.js";import{createTimedReleaseDriver as R,withTimedReleaseTerminalConsumer as O}from"../timed-releases/timed-release.driver.js";import{NoSequenceAvailableError as M}from"./experience.module.js";import{buildJourneyView as G}from"./journey-view.js";import{createInitialSnapshot as F,getSequencePhase as _,normalizeSequenceState as P,buildSnapshot as H,getSequenceId as N,getConsumer as z,getWaitlistAttachment as U,getDistribution as B,getOutcome as L,getGrant as J,getSequenceState as W,getCheckout as Q,isPreEntryJourney as V,getGates as $,isRoutedState as K,getAdmissionGrantExpiresAt as X,getParticipation as Y,validateSequenceState as Z}from"./journey.machine.js";import{isUnresolvedSettlementConsumer as ee}from"./settlement.js";const te="Cannot commit a stale sequence transition",ie="Cannot commit a sequence transition before routing",se=3e4,re=/* @__PURE__ */new Set([g.RATE_LIMITED,g.OVERLOADED,g.SERVICE_UNAVAILABLE,g.TIMEOUT,g.NETWORK_ERROR]),ne=[2e3,5e3,1e4],oe=3*ne.length,ae=[2e3,5e3,1e4];function ce(e,t){if("scheduled"!==e?.lifecycle||!e.opensAt)return!1;const i=Date.parse(e.opensAt);return Number.isFinite(i)&&i<=t}function de(e){const t=Y(e);if(t)return t;if(!K(e))return;const i=e.sequence;return"enterable"===i.phase&&"mechanism"in i&&"auction"===i.mechanism?{id:i.distribution.id,type:"auction"}:void 0}function ue(e,t){return"routing"!==e.journeyStage&&("routed"!==e.journeyStage||e.sequenceId!==t||"granted"===e.sequence.phase&&"awaiting_assignment"!==e.sequence.selection.status||"ended"===e.sequence.phase)}class he{constructor(e,t){this.experienceId=e,this.sdk=t,this.store=E(),this.routingSession=this.store.session,this.logger=y(),this.activeMonitor=null,this.selfCheckStartedAtMs=0,this.selfCheckAttempts=0,this.selfCheckTotalAttempts=0,this.consecutiveRefreshFailures=0,this.checkoutStarted=!1,this.displayAtom=null,this.destroyed=!1,this.operationQueue=Promise.resolve(),this.lastClearedSequenceId=null,this.restoredSnapshotNeedsPersist=!1,this.EVENT_BUFFER_LIMIT=20;const i=this.restoreFromStore(),s=i??F(this.experienceId),r=i?de(i):void 0,a=_(s);!r||"participating"!==a&&"enterable"!==a||this.ensureDisplayAtom(r),this.stateAtom=n(s),this.state=this.stateAtom,this.sequenceDrivers=this.createSequenceDrivers(),this.view$=o(this.stateAtom,e=>this.buildView(e)),this.events$=o(this.stateAtom,e=>e.events),this.latestEvent$=o(this.stateAtom,e=>{if(!e.events.length)return null;const t=e.lastSeenEventId??"",i=e.events.filter(e=>e.id>t);return i.length?i[i.length-1]:null}),i?(this.restoredSnapshotNeedsPersist&&this.persist(),this.rearmTimersIfNeeded()):this.persist()}getExperienceId(){return this.experienceId}async start(e){await this.runSerializedOperation(async()=>{e?.reset&&(this.clearRoutedRuntimeState(),this.setSnapshot(F(this.experienceId))),"accessCode"in(e??{})&&this.patchJourneyBase({accessCode:e?.accessCode??null}),await this.routeAndLoadDistribution(this.stateAtom.get().accessCode)})}async reroute(e={}){await this.runSerializedOperation(async()=>{"accessCode"in e&&this.patchJourneyBase({accessCode:e.accessCode??null}),await this.routeAndLoadDistribution(e.accessCode??this.stateAtom.get().accessCode)})}async submitAccessCode(e){return await this.runSerializedOperation(async()=>{const t=this.stateAtom.get();if("routed"!==t.journeyStage){await this.routeAndLoadDistribution(e,{transient:!0});const t=this.stateAtom.get();return"routed"!==t.journeyStage?"gated"===t.journeyStage?{outcome:"gated"}:{outcome:"unchanged"}:(this.patchJourneyBase({accessCode:e}),{outcome:"advanced",sequenceId:t.sequenceId})}const i=t.sequenceId,s=t.accessCode,r=new Set(t.offers.map(e=>e.sequence.id));await this.routeAndLoadDistribution(e,{transient:!0});let n=this.stateAtom.get();return"routed"===n.journeyStage&&n.sequenceId===i?{outcome:"unchanged"}:"routed"===n.journeyStage&&r.has(n.sequenceId)?(this.patchJourneyBase({accessCode:e}),{outcome:"advanced",sequenceId:n.sequenceId}):("string"==typeof s&&s!==e&&(await this.routeAndLoadDistribution(s,{carryFrom:t,transient:!0}),n=this.stateAtom.get()),"gated"===n.journeyStage?{outcome:"gated"}:{outcome:"unchanged"})})}async retry(){await this.runSerializedOperation(()=>this.routeAndLoadDistribution(this.stateAtom.get().accessCode))}destroy(){this.destroyed||(this.destroyed=!0,this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.stopPolling(),A(this.experienceId),this.store.removeJourney(this.experienceId),this.stateAtom.set(F(this.experienceId)))}async resumeFromMe(e){const t=e.active.journeys.find(e=>e.experienceId===this.experienceId&&"routed"===e.journeyStage);if(!t||"routed"!==t.journeyStage)return!1;const i=this.stateAtom.get(),s=P({sequence:Ue(t.sequence)}),r="granted"===s.phase&&!("routed"===i.journeyStage&&i.sequenceId===t.sequenceId&&"granted"===i.sequence.phase),n=H({base:this.baseFromSnapshot(i),journeyStage:"routed",sequenceId:t.sequenceId,offers:this.normalizeOffers(t.offers),sequence:s,waitlist:this.buildWaitlistAttachmentFromMe(e,t.sequenceId)});this.setSnapshot(n),"routed"===i.journeyStage&&i.sequenceId!==t.sequenceId&&q(this.experienceId,i.sequenceId);try{await this.reroute()}catch{}return"granted"!==s.phase&&"ended"!==s.phase||(this.stopRuntimeMonitoring(!0),this.resetDistributionSelfCheck()),r&&"granted"===s.phase&&(this.clearGrantExpiryTimer(),this.checkoutStarted=!1),this.rearmTimersIfNeeded(),r&&"granted"===s.phase&&"granted"===_(this.stateAtom.get())&&(this.emitEvent("sequence_change","success","user","Grant issued",{grant:s.grant.token}),D().emit("journey:granted",{experienceId:this.experienceId,sequenceId:t.sequenceId,grant:s.grant.token,distributionType:s.grant.distributionType})),!0}async refreshDistribution(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get();try{const t=N(e);if(!t)throw p.validationError("Cannot refresh distribution before routing to a sequence");const i=await this.sdk.experiences.getCurrentDistributions(t,w({experienceId:this.experienceId,sequenceId:t})),s=this.stateAtom.get();if(N(s)!==t)return;const r=z(s),n=this.buildDistributionSummary(i,t,{consumer:r,settlingDistributionId:"routed"===s.journeyStage&&"settling"===s.sequence.phase?s.sequence.distribution.id:void 0}),o=this.buildWaitlistAttachmentFromContext(i,U(s)),a=B(s);n&&k({experienceId:this.experienceId,sequenceId:t,distributionContext:n}),o&&C({waitlistId:o.waitlistId,experienceId:this.experienceId,sequenceId:t});const c=this.deriveTerminalOutcomeForClosedDistribution(r,n,L(s)),d=this.withTerminalConsumer(r,c),u=!n&&"routed"===s.journeyStage&&("granted"===s.sequence.phase||"ended"===s.sequence.phase)?s.sequence:this.projectSequenceState({distribution:n,consumer:d,grant:J(s),settlement:Le(s),selection:Je(s),checkout:Be(s),outcome:c});this.commit(u,{waitlist:o,lastSyncedAt:Date.now(),degraded:!1}),this.emitIfDistributionChanged(a,n),"granted"===u.phase||"ended"===u.phase?this.resetDistributionSelfCheck():this.evaluateDistributionSelfCheck(n)}catch(t){const i=this.stateAtom.get();if(N(i)===N(e)&&"routed"===i.journeyStage&&this.isQuietableDegradationError(t))throw this.markDegraded(),this.markErrorQuietable(t);throw t}})}async joinWaitlistAttachment(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get(),t=W(e),i=B(e),s=U(e)?.waitlistId;if("scheduled"!==t?.phase||!i||!s)throw p.validationError("Waitlist is not available for this sequence");const r=await this.sdk.waitlists.enter(s);this.commit(t,{waitlist:{waitlistId:s,status:"waitlisted",entryId:r.id}}),this.emitEvent("sequence_change","info","user","Entered waitlist",{waitlistId:s})})}async exitWaitlistAttachment(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get(),t=W(e),i=B(e),s=U(e)?.waitlistId;"scheduled"===t?.phase&&i&&s&&(await this.sdk.waitlists.leave(s),this.commit(t,{waitlist:{waitlistId:s,status:"not_waitlisted"}}),this.emitEvent("sequence_change","info","user","Left waitlist",{waitlistId:s}))})}async loadSelectionOptions(){const e=N(this.stateAtom.get());if(!e)throw p.validationError("No sequence is available to load selection options");return this.sdk.selections.loadOptions(e,w({experienceId:this.experienceId,sequenceId:e}))}async select(e){await this.runSerializedOperation(async()=>{const t=this.stateAtom.get();if("routed"!==t.journeyStage)throw p.validationError("No sequence is available to select against");const i=t.sequence;if(!("participating"===i.phase&&"draw"===i.mechanism||"granted"===i.phase&&"timed_release"!==i.mechanism))throw p.validationError("Selection is not available in the current phase");const s=t.sequenceId,r=await this.sdk.selections.select(s,e,w({experienceId:this.experienceId,sequenceId:s})),n=this.stateAtom.get();if("routed"!==n.journeyStage||n.sequenceId!==s)return;const o=n.sequence;if("participating"===i.phase){if("participating"!==o.phase||"draw"!==o.mechanism||o.distribution.id!==i.distribution.id||o.consumer.id!==i.consumer.id)return;if("recorded"!==r.status)return;this.commit({...o,consumer:{...o.consumer,selection:{productId:r.productId,variantId:r.variantId}}});const e=this.displayAtom?.get();"draw"===e?.type&&this.displayAtom?.set({...e,selectionAvailability:void 0})}else{if("granted"!==o.phase||o.mechanism!==i.mechanism||o.grant.token!==i.grant.token)return;if("recorded"===r.status)return;this.commit({...o,selection:r})}})}claim(){const e=this.stateAtom.get();if("routed"===e.journeyStage&&"granted"===e.sequence.phase&&"resolved"!==e.sequence.selection.status)throw p.validationError("Selection must be resolved before claiming the grant");const t=J(e);if(!t)throw p.validationError("No grant is available to claim");return this.checkoutStarted=!0,this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.emitEvent("sequence_change","success","user","Grant claimed",{distributionType:t.distributionType,distributionId:t.distributionId,sequenceId:t.sequenceId}),D().emit("journey:grant-claimed",{experienceId:this.experienceId,sequenceId:t.sequenceId,grant:t.token}),t}async confirmCheckout(e){await this.runCheckoutOperation(()=>this.submitCheckout(e))}async resumeCheckout(){await this.runCheckoutOperation(async()=>{const e=this.pendingCheckoutPaymentInput;if(!e)throw p.validationError("No paused checkout to resume");await this.submitCheckout(e)})}async runCheckoutOperation(e){try{await this.runSerializedOperation(e)}catch(t){if(await this.reconcileMissingCheckoutAdmission(t))return void(this.pendingCheckoutPaymentInput=void 0);throw t}}async reconcileMissingCheckoutAdmission(e){if(!m(e)||e.code!==g.ADMISSION_NOT_FOUND)return!1;const t=N(this.stateAtom.get());try{const e=await this.sdk.experiences.getMe();if(this.destroyed||N(this.stateAtom.get())!==t)return!1;const i=await this.resumeFromMe(e),s=this.stateAtom.get();return i&&N(s)===t&&"ended"===_(s)&&void 0!==Q(s)}catch{return!1}}async submitCheckout(e){const t=this.stateAtom.get(),i=W(t);if("granted"!==i?.phase||"internal"!==i.settlement.processor||"at_end"!==i.settlement.mode||"resolved"!==i.selection.status||this.checkoutStarted)throw p.validationError("No grant awaiting embedded checkout");const s=N(t),r=i.grant.token;this.clearGrantExpiryTimer();try{let t;try{t=await this.sdk.experiences.confirmCheckout(r,i.grant.distributionId,e)}catch(n){throw m(n)&&n.code===g.ADMISSION_EXPIRED&&this.transitionToEnded({type:"expired"}),n}const o=this.stateAtom.get(),a=W(o);if(N(o)!==s||"granted"!==a?.phase||a.grant.token!==r)throw p.validationError("Grant changed before checkout could be confirmed");if("requires_action"===t.outcome)return this.pendingCheckoutPaymentInput=e,this.commit({...a,pendingAction:t.nextAction}),void this.emitEvent("sequence_change","info","user","Checkout awaiting verification",{processor:t.nextAction.processor});this.pendingCheckoutPaymentInput=void 0,this.transitionToEnded({checkout:t.checkout})}finally{const e=W(this.stateAtom.get());"granted"!==e?.phase||e.pendingAction||this.rearmTimersIfNeeded()}}ackEvent(e){this.stateAtom.get().events.some(t=>t.id===e)&&this.patchJourneyBase({lastSeenEventId:e})}ackAllEvents(){const e=this.stateAtom.get();if(!e.events.length)return;const t=e.events[e.events.length-1];this.patchJourneyBase({lastSeenEventId:t.id})}async routeAndLoadDistribution(e,t){let i=t?.carryFrom??this.stateAtom.get();const s=this.store.session;(s?.consumerId!==this.routingSession?.consumerId||s?.type!==this.routingSession?.type)&&"routed"===i.journeyStage&&V(i)&&(this.clearRoutedRuntimeState(),q(this.experienceId,i.sequenceId),i=H({base:this.baseFromSnapshot(i),journeyStage:"ready"}),this.setSnapshot(i)),this.routingSession=s;const r=i,n=N(r);let o,a=!1;try{const i=await this.resolveRouting(e,{transient:t?.transient});if(!i||this.destroyed)return;if(o=this.stateAtom.get().revision,a=n===i.sequenceId,await this.enterExperienceIfReady(),this.destroyed)return;const s=await this.sdk.experiences.getCurrentDistributions(i.sequenceId,w({experienceId:this.experienceId,sequenceId:i.sequenceId}));if(this.destroyed)return;const c=a?z(r):void 0,d=this.buildDistributionSummary(s,i.sequenceId,{consumer:c,settlingDistributionId:a&&"routed"===r.journeyStage&&"settling"===r.sequence.phase?r.sequence.distribution.id:void 0}),u=this.buildWaitlistAttachmentFromContext(s,a?U(r):void 0);d&&k({experienceId:this.experienceId,sequenceId:i.sequenceId,distributionContext:d}),u&&C({waitlistId:u.waitlistId,experienceId:this.experienceId,sequenceId:i.sequenceId});const h=a?J(r):void 0,l=a?Be(r):void 0,p=a?Le(r):void 0,m=a?this.deriveTerminalOutcomeForClosedDistribution(c,d,L(r)):void 0,g=this.withTerminalConsumer(c,m),y=!d&&a&&"routed"===r.journeyStage&&("granted"===r.sequence.phase||"ended"===r.sequence.phase)?r.sequence:this.projectSequenceState({distribution:d,consumer:g,grant:h,settlement:p,selection:a?Je(r):void 0,checkout:l,outcome:m});a||(this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck());const f=this.stateAtom.get(),b=H({base:this.baseFromSnapshot(f,{lastSyncedAt:Date.now(),degraded:!1}),journeyStage:"routed",sequenceId:i.sequenceId,offers:i.offers,sequence:y,waitlist:u,sequenceRef:i.selectedSequence});this.setSnapshot(b),this.resumeDeferredGrantHydration(),this.consecutiveRefreshFailures=0,this.rearmTimersIfNeeded();const S=a?B(r):void 0;this.emitIfDistributionChanged(S,d),this.evaluateDistributionSelfCheck(d)}catch(c){if("routed"===r.journeyStage&&a&&this.isQuietableDegradationError(c))throw this.restoreQuietSnapshot(r),this.markErrorQuietable(c);if("routing"===this.stateAtom.get().journeyStage)if(this.lastClearedSequenceId===n&&this.restoreClearedSequenceContext(r,n),void 0!==o&&this.stateAtom.get().revision===o)this.setSnapshot(r);else{const e=this.stateAtom.get();"routed"===r.journeyStage?this.setSnapshot(H({base:this.baseFromSnapshot(e),journeyStage:"routed",sequenceId:r.sequenceId,offers:r.offers,sequence:r.sequence,waitlist:r.waitlist,sequenceRef:r.sequenceRef})):this.setSnapshot(H({base:this.baseFromSnapshot(e),journeyStage:"ready"}))}throw c}}restoreClearedSequenceContext(e,t){const i=B(e);i&&k({experienceId:this.experienceId,sequenceId:t,distributionContext:i});const s=U(e);s&&C({waitlistId:s.waitlistId,experienceId:this.experienceId,sequenceId:t}),this.lastClearedSequenceToken&&x({experienceId:this.experienceId,sequenceId:t,token:this.lastClearedSequenceToken.token,expiresAt:this.lastClearedSequenceToken.expiresAt}),this.lastClearedSequenceId=null,this.lastClearedSequenceToken=void 0}async resolveRouting(e,t){const i=this.stateAtom.get(),s=N(i);let r;this.transitionToRouting();try{r=await this.sdk.experiences.findSequence(this.experienceId,e)}catch(o){throw this.setSnapshot(i),"routed"===i.journeyStage&&this.armCapabilityRefreshTimer(),this.emitEvent("error","error","user","Failed to route experience"),o}if(this.destroyed)return null;if("gated"===r.outcome&&r.selected){const e=r.selected.gates;return"routed"===i.journeyStage&&this.clearRoutedRuntimeState(),this.transitionToGated({gates:e,selected:{sequence:r.selected.sequence,status:"gated"}}),this.emitEvent("requirement","info","user","Gates required",{gates:e}),null}if("no_access"===r.outcome||!r.selected)throw this.setSnapshot(i),this.emitEvent("error","error","user","No access available for this experience"),new M("No access available for this experience");const n=r.selected.sequence.id;if(s&&s!==n&&(this.lastClearedSequenceId=s,this.lastClearedSequenceToken=j(this.experienceId,s),q(this.experienceId,s)),r.selected.capabilityGrant&&x({experienceId:this.experienceId,sequenceId:n,token:r.selected.capabilityGrant,expiresAt:r.selected.capabilityGrantExpiresAt}),s!==n){const e="routed"===i.journeyStage?i.sequenceRef?.priority:void 0,o=r.selected.sequence.priority,a=function(e,t){return void 0===e?"unknown":t>e?"upgrade":t<e?"downgrade":"lateral"}(e,o);this.emitEvent("reroute","downgrade"===a?"warning":"info",t?.transient?"system":"user","downgrade"===a?"Sequence downgraded":"Sequence changed",{previousSequenceId:s,sequenceId:n,...void 0===e?{}:{previousPriority:e},priority:o,direction:a})}return{sequenceId:n,selectedSequence:r.selected.sequence,offers:r.offers}}async enterExperienceIfReady(){const e=this.stateAtom.get();if($(e).length>0)return;if(e.experience)return;const t=await this.sdk.experiences.enter(this.experienceId);this.destroyed||this.patchJourneyBase({experience:t})}createSequenceDrivers(){return{appointment:c({appointments:this.sdk.appointments,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>W(this.stateAtom.get()),getDisplayState:()=>this.displayAtom?.get()??null,commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>this.ensureDisplayAtom(e),stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),auction:u({auctions:this.sdk.auctions,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>W(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e)}),queue:I({queues:this.sdk.queues,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>W(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),timed_release:R({timedReleases:this.sdk.timedReleases,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>W(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),draw:b({draws:this.sdk.draws,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>W(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)})}}buildView(e){return G(e,{start:e=>this.start(e),reroute:e=>this.reroute(e),submitAccessCode:e=>this.submitAccessCode(e),retry:()=>this.retry(),joinWaitlist:()=>this.joinWaitlistAttachment(),exitWaitlist:()=>this.exitWaitlistAttachment(),claim:()=>this.claim(),select:e=>this.select(e),loadSelectionOptions:()=>this.loadSelectionOptions(),canConfirmCheckout:()=>!this.checkoutStarted,confirmCheckout:e=>this.confirmCheckout(e),resumeCheckout:()=>this.resumeCheckout()},this.displayAtom,this.sequenceDrivers)}projectSequenceState(e){if(!e.distribution)return{phase:"unavailable"};const t=this.sequenceDrivers[e.distribution.type];if(!t)throw new Error(`${e.distribution.type} sequence driver is required`);return t.project(e)}patchJourneyBase(e){if(this.destroyed)return;const t=this.stateAtom.get(),i=this.baseFromSnapshot(t,e);switch(t.journeyStage){case"ready":return void this.setSnapshot(H({base:i,journeyStage:"ready"}));case"routing":return void this.setSnapshot(H({base:i,journeyStage:"routing"}));case"gated":return void this.setSnapshot(H({base:i,journeyStage:"gated",gates:t.gates,selected:t.selected}));case"routed":return void this.setSnapshot(H({base:i,journeyStage:"routed",sequenceId:t.sequenceId,offers:t.offers,sequence:t.sequence,waitlist:t.waitlist,sequenceRef:t.sequenceRef}))}}transitionToRouting(){if(this.destroyed)return;const e=this.stateAtom.get();this.setSnapshot(H({base:this.baseFromSnapshot(e),journeyStage:"routing"}))}transitionToGated(e){if(this.destroyed)return;const t=this.stateAtom.get();this.setSnapshot(H({base:this.baseFromSnapshot(t),journeyStage:"gated",gates:e.gates,selected:e.selected}))}baseFromSnapshot(e,t={}){const i=Object.prototype.hasOwnProperty.call(t,"accessCode")?t.accessCode??void 0:e.accessCode,s=Object.prototype.hasOwnProperty.call(t,"degraded")?t.degraded||void 0:e.degraded,r=Object.prototype.hasOwnProperty.call(t,"lastSyncedAt")?t.lastSyncedAt:e.lastSyncedAt;return{revision:e.revision,updatedAt:e.updatedAt,experienceId:e.experienceId,accessCode:i,experience:t.experience??e.experience,events:t.events??e.events,lastSeenEventId:t.lastSeenEventId??e.lastSeenEventId,degraded:s,lastSyncedAt:r}}commit(e,t={}){if(this.destroyed)throw p.notInitialized("Journey has been destroyed");const i=this.stateAtom.get();if("routed"!==i.journeyStage)throw p.validationError(ie);if(!function(e,t){if("distribution"in e&&e.distribution.sequenceId&&e.distribution.sequenceId!==t)return!1;return!0}(e,i.sequenceId))throw p.validationError(te);const s=Object.prototype.hasOwnProperty.call(t,"waitlist")?t.waitlist??void 0:i.waitlist,r={};Object.prototype.hasOwnProperty.call(t,"lastSyncedAt")&&(r.lastSyncedAt=t.lastSyncedAt),Object.prototype.hasOwnProperty.call(t,"degraded")&&(r.degraded=t.degraded);const n=H({base:this.baseFromSnapshot(i,{...r,events:t.events??i.events}),journeyStage:"routed",sequenceId:i.sequenceId,offers:i.offers,sequence:e,waitlist:s,sequenceRef:i.sequenceRef});this.setSnapshot(n)}markDegraded(){if(this.destroyed)return;const e=this.stateAtom.get();e.degraded||this.setSnapshot(this.rebuildSnapshot(e,{degraded:!0}))}clearDegraded(){if(this.destroyed)return;const e=this.stateAtom.get();e.degraded&&this.setSnapshot(this.rebuildSnapshot(e,{degraded:!1}))}restoreQuietSnapshot(e){this.setSnapshot(this.rebuildSnapshot(e,{degraded:!0}))}isQuietableDegradationError(e){return m(e)&&(e.retryable||re.has(e.code))}markErrorQuietable(e){return e&&"object"==typeof e&&(e.quietable=!0),e}rebuildSnapshot(e,t={}){const i=this.baseFromSnapshot(e,t);switch(e.journeyStage){case"ready":return H({base:i,journeyStage:"ready"});case"routing":return H({base:i,journeyStage:"routing"});case"gated":return H({base:i,journeyStage:"gated",gates:e.gates,selected:e.selected});case"routed":return H({base:i,journeyStage:"routed",sequenceId:e.sequenceId,offers:e.offers,sequence:e.sequence,waitlist:e.waitlist,sequenceRef:e.sequenceRef})}}emitEvent(e,t,i,s,r){const n=this.stateAtom.get(),o={id:f(),ts:Date.now(),kind:e,severity:t,audience:i,message:s,detail:r},a=[...n.events,o],c=a.length>this.EVENT_BUFFER_LIMIT?a.slice(a.length-this.EVENT_BUFFER_LIMIT):a;this.patchJourneyBase({events:c})}emitIfDistributionChanged(e,t){e?.id===t?.id&&e?.lifecycle===t?.lifecycle||this.emitEvent("distribution_change","info","user","Distribution context changed",{previous:e,next:t})}buildDistributionSummary(e,t,i){if(e.active){const s=this.sequenceDrivers[e.active.type],r=!0===s?.settlementCanStartWhileActive&&i?.settlingDistributionId===e.active.id?"settling":"open";return{type:e.active.type,id:e.active.id,sequenceId:t,lifecycle:r,details:e.active.details,opensAt:e.active.details.openAt,closesAt:e.active.details.closeAt,updatedAt:Date.now()}}if(e.upcoming)return{type:e.upcoming.type,id:e.upcoming.id,sequenceId:t,lifecycle:"scheduled",startsAt:e.upcoming.startsAt,opensAt:e.upcoming.startsAt,updatedAt:Date.now()};if(e.recentPast){const s=i?.settlingDistributionId===e.recentPast.id||ee(i?.consumer,e.recentPast.type,e.recentPast.id)?"settling":"closed";return{type:e.recentPast.type,id:e.recentPast.id,sequenceId:t,lifecycle:s,result:e.recentPast.result,closesAt:e.recentPast.endedAt,updatedAt:Date.now()}}}buildWaitlistAttachmentFromContext(e,t){const i=e.waitlist?.id;if(i)return t?.waitlistId===i?t:{waitlistId:i,status:"not_waitlisted"}}buildWaitlistAttachmentFromMe(e,t){const i=e.waitlists?.find(e=>e.experienceId===this.experienceId&&e.sequenceId===t);if(i)return{waitlistId:i.waitlistId,status:"waitlisted"}}normalizeOffers(e){return Array.isArray(e)?e.filter(Boolean):[]}restoreFromStore(){const e=this.store.activeJourneys;if(!e||!e[this.experienceId])return null;const t=ze(e[this.experienceId]);return t?"routing"===t.journeyStage||"routed"===t.journeyStage&&V(t)?("routed"===t.journeyStage&&q(this.experienceId,t.sequenceId),this.restoredSnapshotNeedsPersist=!0,H({base:this.baseFromSnapshot(t),journeyStage:"ready"})):t:(this.store.removeJourney(this.experienceId),null)}persist(){this.store.setJourneyState(this.experienceId,this.stateAtom.get())}setSnapshot(e,t={}){if(this.destroyed)return;const i=this.stateAtom.get(),s=de(e);"auction"===s?.type&&"auction"!==this.displayAtom?.get().type&&(this.resetDisplayAtom("auction"),this.displayParticipationId=s.id),this.stateAtom.set(e),!1!==t.persist&&this.persist(),this.emitPhaseChanged(i,e)}emitPhaseChanged(e,t){const i=e.journeyStage,s="routed"===i?_(e):void 0,r=t.journeyStage,n="routed"===r?_(t):void 0;i===r&&s===n||D().emit("journey:phase-changed",{experienceId:this.experienceId,journeyStage:r,sequencePhase:n})}runSerializedOperation(e){const t=this.operationQueue.then(async()=>{if(this.destroyed)throw p.notInitialized("Journey has been destroyed");return e()});return this.operationQueue=t.then(()=>{},()=>{}),t}transitionToEnded(e,t={}){if(this.destroyed)return;const i=this.stateAtom.get(),s=N(i);if(!s)throw p.validationError(ie);const r=B(i),n="checkout"in e?e.checkout:void 0,o="checkout"in e?{type:"completed"}:e,a=this.reinterpretLapsedGrantOutcome(i,o),c={...a,distributionType:a.distributionType??r?.type,distributionId:a.distributionId??r?.id,at:a.at??/* @__PURE__ */(new Date).toISOString()},d=this.withTerminalConsumer(z(i),c,{finalize:!0}),u=this.projectSequenceState({distribution:r,consumer:d,checkout:n,outcome:c});this.commit(u,t),this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.emitEvent("sequence_change","expired"===c.type?"warning":"info","user","Sequence ended",{outcome:c}),D().emit("journey:ended",{experienceId:this.experienceId,sequenceId:s,outcome:c})}reinterpretLapsedGrantOutcome(e,t){if("granted"!==_(e))return t;return"closed"===t.type&&("not_queued"===t.reason||"not_entered"===t.reason)?{type:"expired",at:t.at,distributionType:t.distributionType,distributionId:t.distributionId}:t}applyMonitorUpdate(e){if(!this.destroyed){if("settling"===e.type){const t=this.stateAtom.get();if(!K(t)||"participating"!==t.sequence.phase)return;const i={...t.sequence.distribution,lifecycle:"settling",settlesAt:e.at},s=this.projectSequenceState({distribution:i,consumer:z(t)});if("settling"!==s.phase)return;return void this.commit(s,{lastSyncedAt:Date.now(),degraded:!1})}"granted"!==e.type?"resync"!==e.type?this.transitionToEnded(e.outcome,{lastSyncedAt:Date.now(),degraded:!1}):this.beginGrantHydration():this.beginGrantHydration(e.token,e.expiresAt)}}beginGrantHydration(e,t){const i=this.stateAtom.get();"routing"!==i.journeyStage?"routed"===i.journeyStage&&(ue(i,i.sequenceId)||this.pendingGrantHydration?.sequenceId!==i.sequenceId&&(this.clearGrantHydration(),this.pendingGrantHydration={sequenceId:i.sequenceId,token:e,expiresAt:t,attempt:0},this.hydrateGrantFromMe(e,t))):this.pendingGrantObservation={token:e,expiresAt:t}}resumeDeferredGrantHydration(){const e=this.pendingGrantObservation;e&&(this.pendingGrantObservation=void 0,this.beginGrantHydration(e.token,e.expiresAt))}async hydrateGrantFromMe(e,t){if(this.destroyed)return;const i=this.pendingGrantHydration,s=this.stateAtom.get();if(i)if("routing"!==s.journeyStage)if(ue(s,i.sequenceId))this.clearGrantHydration();else if(void 0!==t&&Date.now()>=t)this.transitionToEnded({type:"expired"},{lastSyncedAt:Date.now(),degraded:!1});else{try{const e=await this.sdk.experiences.getMe();if(this.destroyed)return;await this.resumeFromMe(e)}catch(r){this.emitEvent("error","warning","system","Could not resolve an observed grant from /me",{grant:e,error:r instanceof Error?r.message:String(r)})}this.scheduleGrantHydrationRetry()}else this.scheduleGrantHydrationRetry()}scheduleGrantHydrationRetry(){const e=this.pendingGrantHydration;if(!e||this.destroyed)return;if(ue(this.stateAtom.get(),e.sequenceId))return void this.clearGrantHydration();const t=ae[e.attempt]??1e4;e.attempt+=1,e.timer=setTimeout(()=>{this.pendingGrantHydration===e&&(e.timer=void 0,this.hydrateGrantFromMe(e.token,e.expiresAt))},t)}clearGrantHydration(){const e=this.pendingGrantHydration;e?.timer&&clearTimeout(e.timer),this.pendingGrantHydration=void 0,this.pendingGrantObservation=void 0}applyMonitorUpdateFromCallback(e){try{this.applyMonitorUpdate(e)}catch(t){if(this.dropStaleCallbackCommit(t,"monitor"))return;throw t}}startMonitorForParticipation(e){const t=this.ensureDisplayAtom(e),i=e=>this.applyMonitorUpdateFromCallback(e),s=e=>{e?this.markDegraded():this.clearDegraded()},r=this.sequenceDrivers[e.type];if(r?.startMonitoring)return r.startMonitoring({participation:e,displayAtom:t,onUpdate:i,onDegradedChange:s}),void(this.activeMonitor={type:e.type,id:e.id,stop:()=>r.stopMonitoring?.()});throw new Error(`Unknown distribution type: ${e.type}`)}stopRuntimeMonitoring(e=!1){this.activeMonitor&&(this.activeMonitor.stop(),this.activeMonitor=null),e&&this.clearRuntimeDisplayState()}clearGrantExpiryTimer(){this.grantExpiryTimer&&(clearTimeout(this.grantExpiryTimer),this.grantExpiryTimer=void 0)}clearCapabilityRefreshTimer(){this.capabilityRefreshTimer&&(clearTimeout(this.capabilityRefreshTimer),this.capabilityRefreshTimer=void 0)}clearDistributionSelfCheck(){this.selfCheckTimer&&(clearTimeout(this.selfCheckTimer),this.selfCheckTimer=void 0),this.selfCheckKey=void 0,this.selfCheckStartedAtMs=0,this.selfCheckAttempts=0}resetDistributionSelfCheck(){this.clearDistributionSelfCheck(),this.selfCheckTotalAttempts=0}evaluateDistributionSelfCheck(e){if(this.destroyed)return;const t=Date.now();if(!ce(e,t))return void this.clearDistributionSelfCheck();const i=`${e?.sequenceId??""}:${e?.id??""}:${e?.opensAt??""}`;if(this.selfCheckKey!==i&&(this.clearDistributionSelfCheck(),this.selfCheckKey=i,this.selfCheckStartedAtMs=t),this.selfCheckTimer)return;if(this.selfCheckAttempts>=ne.length)return;if(this.selfCheckTotalAttempts>=oe)return;const s=this.selfCheckStartedAtMs+ne[this.selfCheckAttempts];this.selfCheckAttempts+=1,this.selfCheckTotalAttempts+=1,this.selfCheckTimer=setTimeout(()=>{this.selfCheckFromTimer()},Math.max(0,s-t))}async selfCheckFromTimer(){if(this.selfCheckTimer=void 0,!this.destroyed)try{await this.refreshDistribution()}catch(e){if(this.destroyed||"routed"!==this.stateAtom.get().journeyStage)return;this.emitEvent("error","warning","system","Distribution self-check failed",{error:e instanceof Error?e.message:String(e)})}}armCapabilityRefreshTimer(){if(this.clearCapabilityRefreshTimer(),this.destroyed||this.checkoutStarted)return;const e=this.stateAtom.get();if("routed"!==e.journeyStage)return;const t=T(this.experienceId,e.sequenceId);if(void 0===t)return;const i=Math.max(t-Date.now()-6e4,5e3);this.scheduleCapabilityRefresh(i)}scheduleCapabilityRefresh(e){if(this.clearCapabilityRefreshTimer(),this.destroyed||this.checkoutStarted)return;"routed"===this.stateAtom.get().journeyStage&&(this.capabilityRefreshTimer=setTimeout(()=>this.refreshCapabilityFromTimer(),e))}rearmTimersIfNeeded(){if(this.destroyed||this.checkoutStarted)return;const e=this.stateAtom.get();"routed"===e.journeyStage&&this.armCapabilityRefreshTimer(),this.pendingGrantHydration&&ue(e,this.pendingGrantHydration.sequenceId)&&this.scheduleGrantHydrationRetry(),"routed"===e.journeyStage&&"granted"===e.sequence.phase&&"awaiting_assignment"===e.sequence.selection.status&&this.pendingGrantHydration?.sequenceId!==e.sequenceId&&(this.clearGrantHydration(),this.pendingGrantHydration={sequenceId:e.sequenceId,token:e.sequence.grant.token,expiresAt:X(e),attempt:0},this.scheduleGrantHydrationRetry());const t=W(e);if("granted"===t?.phase&&(t.pendingAction||"internal"===t.settlement.processor&&"at_end"===t.settlement.mode&&"in_progress"===t.settlement.state))this.clearGrantExpiryTimer();else if("granted"===t?.phase&&!this.grantExpiryTimer){const t=X(e);if(t){const e=t-Date.now();e<=0?this.transitionToEnded({type:"expired"}):this.grantExpiryTimer=setTimeout(()=>this.expireGrantFromTimer(),e)}}}async refreshCapabilityFromTimer(){this.capabilityRefreshTimer=void 0;try{if("routed"!==this.stateAtom.get().journeyStage)return void this.clearCapabilityRefreshTimer();if(this.checkoutStarted)return;const e=Date.now();if(void 0!==this.lastCapabilityRefreshAtMs&&e-this.lastCapabilityRefreshAtMs<se)return void this.scheduleCapabilityRefresh(se);this.lastCapabilityRefreshAtMs=e,await this.retry(),this.consecutiveRefreshFailures=0}catch(e){if(this.dropStaleCallbackCommit(e,"capability refresh timer"))return;const t=Math.min(se*2**this.consecutiveRefreshFailures,6e5);this.consecutiveRefreshFailures+=1,this.emitEvent("error","warning","system","Capability grant refresh failed",{error:e instanceof Error?e.message:String(e),consecutiveFailures:this.consecutiveRefreshFailures}),this.scheduleCapabilityRefresh(t)}}expireGrantFromTimer(){try{this.transitionToEnded({type:"expired"})}catch(e){if(this.dropStaleCallbackCommit(e,"grant-expiry timer"))return;throw e}}dropStaleCallbackCommit(e,t){return!(!m(e)||e.code!==g.VALIDATION_ERROR||e.message!==te&&e.message!==ie)&&(this.logger.debug("Dropped stale journey callback",{experienceId:this.experienceId,source:t,message:e.message}),!0)}getRuntimeBinding(){const e=this.stateAtom.get(),t=de(e),i=N(e);return t&&i?{experienceId:this.experienceId,sequenceId:i,participationId:t.id,participationType:t.type}:null}startRuntimeMonitoring(){const e=this.getRuntimeBinding();if(!e)return;const t=this.activeMonitor;t&&t.id===e.participationId&&t.type===e.participationType&&this.displayAtom||(this.stopRuntimeMonitoring(!1),this.startMonitorForParticipation({id:e.participationId,type:e.participationType}))}getRuntimeDisplayAtom(){return this.displayAtom}applyRuntimeState(e){if(!e)return void this.clearRuntimeDisplayState();const t=this.getRuntimeBinding();if(!t)return;this.ensureDisplayAtom({id:t.participationId,type:t.participationType}).set(e)}reconcileSyncedSnapshot(e){if(this.destroyed)return;if(!e)return this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),void this.setSnapshot(F(this.experienceId),{persist:!1});const t=ze(e);if(!t)return;const i="routing"===t.journeyStage?H({base:this.baseFromSnapshot(t),journeyStage:"ready"}):t,s=this.stateAtom.get();if(s.revision===i.revision&&s.updatedAt===i.updatedAt)return;const r=de(i);r||(this.displayAtom=null,this.displayParticipationId=void 0),this.setSnapshot(i,{persist:!1}),r?this.ensureDisplayAtom(r):this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.rearmTimersIfNeeded()}ensureDisplayAtom(e){const t=this.displayAtom;if(t?.get().type===e.type&&this.displayParticipationId===e.id)return t;const i=this.resetDisplayAtom(e.type);return this.displayParticipationId=e.id,i}resetDisplayAtom(e){const t=this.displayAtom;if(!t||t.get().type!==e){const t=n({type:e});return this.displayAtom=t,t}return t.set({type:e}),t}clearRuntimeDisplayState(){const e=this.getRuntimeBinding();if(!e)return this.displayAtom=null,void(this.displayParticipationId=void 0);this.displayParticipationId=void 0,this.resetDisplayAtom(e.participationType)}clearRoutedRuntimeState(){this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.checkoutStarted=!1}deriveTerminalOutcomeForClosedDistribution(e,t,i){if(i&&!h(i))return i;if(!t||"closed"!==t.lifecycle||!e)return i;const s=this.projectSequenceState({distribution:t,consumer:e});return"ended"===s.phase&&"lost"===s.outcome.type?s.outcome:i??{type:"closed",distributionType:t.type,distributionId:t.id}}withTerminalConsumer(e,t,i){switch(e?.mechanism){case"appointment":return d(e,t);case"auction":return l(e,t,i);case"draw":return S(e,t);case"queue":return v(e,t);case"timed_release":return O(e,t);default:return e}}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0)}}const le=a.picklist(["queue","draw","auction","timed_release","appointment"]),pe=le,me=a.picklist(["queue","draw","auction","timed_release"]),ge=a.picklist(["draw","auction"]),ye=a.strictObject({id:a.string(),ts:a.number(),kind:a.picklist(["reroute","sequence_change","distribution_change","requirement","error","info"]),severity:a.picklist(["info","success","warning","error"]),audience:a.picklist(["user","system","analytics"]),message:a.string(),detail:a.optional(a.record(a.string(),a.unknown()))}),fe=a.strictObject({id:a.string(),name:a.string(),experienceId:a.string(),priority:a.number(),color:a.string()}),be=a.strictObject({type:le,id:a.string(),sequenceId:a.optional(a.string()),lifecycle:a.string(),startsAt:a.optional(a.string()),opensAt:a.optional(a.string()),closesAt:a.optional(a.string()),settlesAt:a.optional(a.string()),result:a.optional(a.string()),details:a.optional(a.unknown()),updatedAt:a.optional(a.number())}),Se=a.strictObject({status:a.string(),selection:a.optional(r),id:a.optional(a.string()),distributionId:a.optional(a.string()),waitlistId:a.optional(a.string()),enteredAt:a.optional(a.string()),admissionGrant:a.optional(a.string()),grantedAt:a.optional(a.string()),deniedReason:a.optional(a.string()),position:a.optional(a.number()),highestBid:a.optional(a.string()),currentBid:a.optional(a.string()),slotId:a.optional(a.string()),locationId:a.optional(a.string()),bookedAt:a.optional(a.string()),checkedInAt:a.optional(a.string()),completedAt:a.optional(a.string()),cancelledAt:a.optional(a.string()),noShowAt:a.optional(a.string())}),Ie=a.strictObject({token:a.string(),distributionType:me,distributionId:a.string(),sequenceId:a.string(),experienceId:a.string(),issuedAt:a.optional(a.string()),expiresAt:a.optional(a.string())}),ve=a.strictObject({orderId:a.string(),amount:a.string(),currencyCode:a.string(),paymentMethodLast4:a.optional(a.string()),paymentMethodBrand:a.optional(a.string())}),Ae=a.strictObject({publishableKey:a.string(),stripeAccount:a.optional(a.string())}),qe=a.strictObject({type:a.string(),reason:a.optional(a.string()),at:a.optional(a.string()),distributionType:a.optional(le),distributionId:a.optional(a.string())}),we=a.strictObject({phase:a.literal("unavailable"),reason:a.optional(a.string())}),ke=a.strictObject({waitlistId:a.string(),status:a.picklist(["not_waitlisted","waitlisted"]),entryId:a.optional(a.string())}),Ce=a.strictObject({phase:a.literal("scheduled"),mechanism:pe,distribution:be}),xe=a.strictObject({phase:a.literal("enterable"),mechanism:pe,distribution:be,consumer:Se,paymentProvider:a.optional(Ae)}),je=a.strictObject({phase:a.literal("participating"),mechanism:pe,distribution:be,consumer:Se}),Te=a.strictObject({phase:a.literal("settling"),mechanism:ge,distribution:be,consumer:Se}),De=a.variant("processor",[a.strictObject({processor:a.literal("external")}),a.strictObject({processor:a.literal("internal"),mode:a.literal("at_end"),state:a.picklist(["awaiting","in_progress"]),paymentProvider:a.optional(Ae)}),a.strictObject({processor:a.literal("internal"),mode:a.literal("pre_auth")})]),Ee=a.strictObject({phase:a.literal("granted"),mechanism:me,distribution:be,consumer:Se,grant:Ie,settlement:De,selection:s}),Re=a.strictObject({phase:a.literal("ended"),mechanism:pe,distribution:be,consumer:Se,outcome:qe,checkout:a.optional(ve)}),Oe=a.union([we,Ce,xe,je,Te,Ee,Re]),Me={schemaVersion:a.literal(5),revision:a.number(),updatedAt:a.number(),experienceId:a.string(),accessCode:a.optional(a.string()),experience:a.optional(a.unknown()),events:a.array(ye),lastSeenEventId:a.optional(a.string()),lastSyncedAt:a.optional(a.number())},Ge=a.strictObject({...Me,journeyStage:a.literal("ready")}),Fe=a.strictObject({...Me,journeyStage:a.literal("routing")}),_e=a.variant("type",[a.object({...a.omit(e,["reason"]).entries,requirement:a.optional(a.picklist(["session","authenticated"]),"authenticated")}),a.omit(t,["reason"]),a.omit(i,["reason"])]),Pe=a.strictObject({...Me,journeyStage:a.literal("gated"),gates:a.array(_e),selected:a.optional(a.strictObject({sequence:a.unknown(),status:a.literal("gated")}))}),He=a.strictObject({...Me,journeyStage:a.literal("routed"),sequenceId:a.string(),offers:a.array(a.object({sequence:a.unknown(),status:a.literal("gated"),gates:a.array(_e)})),sequence:Oe,waitlist:a.optional(ke),sequenceRef:a.optional(fe)}),Ne=a.union([Ge,Fe,Pe,He]);function ze(e){const t=a.safeParse(Ne,e);if(!t.success)return null;const{schemaVersion:i,...s}=t.output;if("routed"===s.journeyStage)try{Z(s.sequence)}catch{return null}return s}function Ue(e){if("participating"!==e.phase&&"settling"!==e.phase)return e;if(!("selection"in e))return e;const{selection:t,...i}=e;return void 0===t?i:{...i,consumer:{...i.consumer,selection:t}}}function Be(e){return"routed"!==e.journeyStage||"granted"!==e.sequence.phase&&"ended"!==e.sequence.phase||!("checkout"in e.sequence)?Q(e):e.sequence.checkout}function Le(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.settlement}function Je(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.selection}export{he as ExperienceJourney,ce as isSelfContradictingDistribution};
1
+ import{AuthenticationRoutingGateV1Schema as e,AccessCodeRoutingGateV1Schema as t,BotCheckRoutingGateV1Schema as i}from"@fanfare-io/fanfare-sdk-contracts/routing";import{SelectionModes as s,GrantedSelectionSchema as r,SelectionPinRequestSchema as n}from"@fanfare-io/fanfare-sdk-contracts/selection";import{atom as o,computed as a}from"nanostores";import*as c from"valibot";import{createAppointmentDriver as d,withAppointmentTerminalConsumer as u}from"../appointments/appointment.driver.js";import{createAuctionDriver as h,isUpgradeableGenericLoss as l,withAuctionTerminalConsumer as p}from"../auctions/auction.driver.js";import{createError as m,isFanfareError as g,ErrorCodes as y}from"../core/errors.js";import{createLogger as f}from"../core/logger.js";import{generateId as b}from"../core/utils.js";import{createDrawDriver as S,withDrawTerminalConsumer as I}from"../draws/draw.driver.js";import{createQueueDriver as v,withQueueTerminalConsumer as q}from"../queues/queue.driver.js";import{clearExperienceContext as A,clearSequenceContext as w,resolveCapabilityOptions as k,bindDistributionContext as C,bindWaitlist as j,upsertSequenceToken as x,peekSequenceToken as T,getSequenceTokenExpiryMs as R}from"../state/capability-token-registry.js";import{getEventBus as E}from"../state/events.js";import{getSDKStore as D}from"../state/store.js";import{createTimedReleaseDriver as M,withTimedReleaseTerminalConsumer as O}from"../timed-releases/timed-release.driver.js";import{NoSequenceAvailableError as G}from"./experience.module.js";import{buildJourneyView as F}from"./journey-view.js";import{createInitialSnapshot as _,getSequencePhase as P,normalizeSequenceState as H,buildSnapshot as N,getSequenceId as z,getConsumer as U,getWaitlistAttachment as B,getDistribution as L,getOutcome as J,getGrant as W,getSequenceState as Q,getCheckout as V,isPreEntryJourney as $,getGates as K,isRoutedState as X,getAdmissionGrantExpiresAt as Y,getParticipation as Z,validateSequenceState as ee}from"./journey.machine.js";import{isUnresolvedSettlementConsumer as te}from"./settlement.js";const ie="Cannot commit a stale sequence transition",se="Cannot commit a sequence transition before routing",re=3e4,ne=6e5,oe=/* @__PURE__ */new Set([y.RATE_LIMITED,y.OVERLOADED,y.SERVICE_UNAVAILABLE,y.TIMEOUT,y.NETWORK_ERROR]),ae=[2e3,5e3,1e4],ce=3*ae.length,de=[2e3,5e3,1e4];function ue(e,t){if("scheduled"!==e?.lifecycle||!e.opensAt)return!1;const i=Date.parse(e.opensAt);return Number.isFinite(i)&&i<=t}function he(e){const t=Z(e);if(t)return t;if(!X(e))return;const i=e.sequence;return"enterable"===i.phase&&"mechanism"in i&&"auction"===i.mechanism?{id:i.distribution.id,type:"auction"}:void 0}function le(e,t){return"routing"!==e.journeyStage&&("routed"!==e.journeyStage||e.sequenceId!==t||"granted"===e.sequence.phase&&"awaiting_assignment"!==e.sequence.selection.status||"ended"===e.sequence.phase)}class pe{constructor(e,t){this.experienceId=e,this.sdk=t,this.store=D(),this.routingSession=this.store.session,this.logger=f(),this.activeMonitor=null,this.selfCheckStartedAtMs=0,this.selfCheckAttempts=0,this.selfCheckTotalAttempts=0,this.consecutiveRefreshFailures=0,this.consecutiveGatedRestores=0,this.checkoutStarted=!1,this.displayAtom=null,this.destroyed=!1,this.operationQueue=Promise.resolve(),this.lastClearedSequenceId=null,this.restoredSnapshotNeedsPersist=!1,this.EVENT_BUFFER_LIMIT=20;const i=this.restoreFromStore(),s=i??_(this.experienceId),r=i?he(i):void 0,n=P(s);!r||"participating"!==n&&"enterable"!==n||this.ensureDisplayAtom(r),this.stateAtom=o(s),this.state=this.stateAtom,this.sequenceDrivers=this.createSequenceDrivers(),this.view$=a(this.stateAtom,e=>this.buildView(e)),this.events$=a(this.stateAtom,e=>e.events),this.latestEvent$=a(this.stateAtom,e=>{if(!e.events.length)return null;const t=e.lastSeenEventId??"",i=e.events.filter(e=>e.id>t);return i.length?i[i.length-1]:null}),i?(this.restoredSnapshotNeedsPersist&&this.persist(),this.rearmTimersIfNeeded()):this.persist()}getExperienceId(){return this.experienceId}async start(e){await this.runSerializedOperation(async()=>{e?.reset&&(this.clearRoutedRuntimeState(),this.setSnapshot(_(this.experienceId))),"accessCode"in(e??{})&&this.patchJourneyBase({accessCode:e?.accessCode??null}),await this.routeAndLoadDistribution(this.stateAtom.get().accessCode)})}async reroute(e={}){await this.runSerializedOperation(async()=>{"accessCode"in e&&this.patchJourneyBase({accessCode:e.accessCode??null}),await this.routeAndLoadDistribution(e.accessCode??this.stateAtom.get().accessCode)})}async submitAccessCode(e){return await this.runSerializedOperation(async()=>{const t=this.stateAtom.get();if("routed"!==t.journeyStage){await this.routeAndLoadDistribution(e,{transient:!0});const t=this.stateAtom.get();return"routed"!==t.journeyStage?"gated"===t.journeyStage?{outcome:"gated"}:{outcome:"unchanged"}:(this.patchJourneyBase({accessCode:e}),{outcome:"advanced",sequenceId:t.sequenceId})}const i=t.sequenceId,s=t.accessCode,r=new Set(t.offers.map(e=>e.sequence.id));await this.routeAndLoadDistribution(e,{transient:!0});let n=this.stateAtom.get();return"routed"===n.journeyStage&&n.sequenceId===i?{outcome:"unchanged"}:"routed"===n.journeyStage&&r.has(n.sequenceId)?(this.patchJourneyBase({accessCode:e}),{outcome:"advanced",sequenceId:n.sequenceId}):("string"==typeof s&&s!==e&&(await this.routeAndLoadDistribution(s,{carryFrom:t,transient:!0}),n=this.stateAtom.get()),"gated"===n.journeyStage?{outcome:"gated"}:{outcome:"unchanged"})})}async retry(){await this.runSerializedOperation(()=>this.routeAndLoadDistribution(this.stateAtom.get().accessCode))}destroy(){this.destroyed||(this.destroyed=!0,this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.stopPolling(),A(this.experienceId),this.store.removeJourney(this.experienceId),this.stateAtom.set(_(this.experienceId)))}async resumeFromMe(e){const t=e.active.journeys.find(e=>e.experienceId===this.experienceId&&"routed"===e.journeyStage);if(!t||"routed"!==t.journeyStage)return!1;const i=this.stateAtom.get(),s=H({sequence:Le(t.sequence)}),r="granted"===s.phase&&!("routed"===i.journeyStage&&i.sequenceId===t.sequenceId&&"granted"===i.sequence.phase),n=N({base:this.baseFromSnapshot(i),journeyStage:"routed",sequenceId:t.sequenceId,offers:this.normalizeOffers(t.offers),sequence:s,waitlist:this.buildWaitlistAttachmentFromMe(e,t.sequenceId)});this.setSnapshot(n),"routed"===i.journeyStage&&i.sequenceId!==t.sequenceId&&w(this.experienceId,i.sequenceId);try{await this.reroute()}catch{}return"granted"!==s.phase&&"ended"!==s.phase||(this.stopRuntimeMonitoring(!0),this.resetDistributionSelfCheck()),r&&"granted"===s.phase&&(this.clearGrantExpiryTimer(),this.checkoutStarted=!1),this.rearmTimersIfNeeded(),r&&"granted"===s.phase&&"granted"===P(this.stateAtom.get())&&(this.emitEvent("sequence_change","success","user","Grant issued",{grant:s.grant.token}),E().emit("journey:granted",{experienceId:this.experienceId,sequenceId:t.sequenceId,grant:s.grant.token,distributionType:s.grant.distributionType})),!0}async refreshDistribution(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get();try{const t=z(e);if(!t)throw m.validationError("Cannot refresh distribution before routing to a sequence");const i=await this.sdk.experiences.getCurrentDistributions(t,k({experienceId:this.experienceId,sequenceId:t})),s=this.stateAtom.get();if(z(s)!==t)return;const r=U(s),n=this.buildDistributionSummary(i,t,{consumer:r,settlingDistributionId:"routed"===s.journeyStage&&"settling"===s.sequence.phase?s.sequence.distribution.id:void 0}),o=this.buildWaitlistAttachmentFromContext(i,B(s)),a=L(s);n&&C({experienceId:this.experienceId,sequenceId:t,distributionContext:n}),o&&j({waitlistId:o.waitlistId,experienceId:this.experienceId,sequenceId:t});const c=this.deriveTerminalOutcomeForClosedDistribution(r,n,J(s)),d=this.withTerminalConsumer(r,c),u=!n&&"routed"===s.journeyStage&&("granted"===s.sequence.phase||"ended"===s.sequence.phase)?s.sequence:this.projectSequenceState({distribution:n,consumer:d,selectionMode:Ve(s),grant:W(s),settlement:We(s),selection:Qe(s),checkout:Je(s),outcome:c});this.commit(u,{waitlist:o,lastSyncedAt:Date.now(),degraded:!1}),this.emitIfDistributionChanged(a,n),"granted"===u.phase||"ended"===u.phase?this.resetDistributionSelfCheck():this.evaluateDistributionSelfCheck(n)}catch(t){const i=this.stateAtom.get();if(z(i)===z(e)&&"routed"===i.journeyStage&&this.isQuietableDegradationError(t))throw this.markDegraded(),this.markErrorQuietable(t);throw t}})}async joinWaitlistAttachment(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get(),t=Q(e),i=L(e),s=B(e)?.waitlistId;if("scheduled"!==t?.phase||!i||!s)throw m.validationError("Waitlist is not available for this sequence");const r=await this.sdk.waitlists.enter(s);this.commit(t,{waitlist:{waitlistId:s,status:"waitlisted",entryId:r.id}}),this.emitEvent("sequence_change","info","user","Entered waitlist",{waitlistId:s})})}async exitWaitlistAttachment(){await this.runSerializedOperation(async()=>{const e=this.stateAtom.get(),t=Q(e),i=L(e),s=B(e)?.waitlistId;"scheduled"===t?.phase&&i&&s&&(await this.sdk.waitlists.leave(s),this.commit(t,{waitlist:{waitlistId:s,status:"not_waitlisted"}}),this.emitEvent("sequence_change","info","user","Left waitlist",{waitlistId:s}))})}async loadSelectionOptions(){const e=z(this.stateAtom.get());if(!e)throw m.validationError("No sequence is available to load selection options");return this.sdk.selections.loadOptions(e,k({experienceId:this.experienceId,sequenceId:e}))}async select(e){await this.runSerializedOperation(async()=>{const t=this.stateAtom.get();if("routed"!==t.journeyStage)throw m.validationError("No sequence is available to select against");const i=t.sequence;if(!("participating"===i.phase&&"draw"===i.mechanism||"granted"===i.phase&&"timed_release"!==i.mechanism))throw m.validationError("Selection is not available in the current phase");const s=t.sequenceId,r=await this.sdk.selections.select(s,e,k({experienceId:this.experienceId,sequenceId:s})),n=this.stateAtom.get();if("routed"!==n.journeyStage||n.sequenceId!==s)return;const o=n.sequence;if("participating"===i.phase){if("participating"!==o.phase||"draw"!==o.mechanism||o.distribution.id!==i.distribution.id||o.consumer.id!==i.consumer.id)return;if("recorded"!==r.status)return;this.commit({...o,consumer:{...o.consumer,selection:{productId:r.productId,variantId:r.variantId}}});const e=this.displayAtom?.get();"draw"===e?.type&&this.displayAtom?.set({...e,selectionAvailability:void 0})}else{if("granted"!==o.phase||o.mechanism!==i.mechanism||o.grant.token!==i.grant.token)return;if("recorded"===r.status)return;this.commit({...o,selection:r})}})}claim(){const e=this.stateAtom.get();if("routed"===e.journeyStage&&"granted"===e.sequence.phase&&"resolved"!==e.sequence.selection.status)throw m.validationError("Selection must be resolved before claiming the grant");const t=W(e);if(!t)throw m.validationError("No grant is available to claim");return this.checkoutStarted=!0,this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.emitEvent("sequence_change","success","user","Grant claimed",{distributionType:t.distributionType,distributionId:t.distributionId,sequenceId:t.sequenceId}),E().emit("journey:grant-claimed",{experienceId:this.experienceId,sequenceId:t.sequenceId,grant:t.token}),t}async confirmCheckout(e){await this.runCheckoutOperation(()=>this.submitCheckout(e))}async resumeCheckout(){await this.runCheckoutOperation(async()=>{const e=this.pendingCheckoutPaymentInput;if(!e)throw m.validationError("No paused checkout to resume");await this.submitCheckout(e)})}async runCheckoutOperation(e){try{await this.runSerializedOperation(e)}catch(t){if(await this.reconcileMissingCheckoutAdmission(t))return void(this.pendingCheckoutPaymentInput=void 0);throw t}}async reconcileMissingCheckoutAdmission(e){if(!g(e)||e.code!==y.ADMISSION_NOT_FOUND)return!1;const t=z(this.stateAtom.get());try{const e=await this.sdk.experiences.getMe();if(this.destroyed||z(this.stateAtom.get())!==t)return!1;const i=await this.resumeFromMe(e),s=this.stateAtom.get();return i&&z(s)===t&&"ended"===P(s)&&void 0!==V(s)}catch{return!1}}async submitCheckout(e){const t=this.stateAtom.get(),i=Q(t);if("granted"!==i?.phase||"internal"!==i.settlement.processor||"at_end"!==i.settlement.mode||"resolved"!==i.selection.status||this.checkoutStarted)throw m.validationError("No grant awaiting embedded checkout");const s=z(t),r=i.grant.token;this.clearGrantExpiryTimer();try{let t;try{t=await this.sdk.experiences.confirmCheckout(r,i.grant.distributionId,e)}catch(n){throw g(n)&&n.code===y.ADMISSION_EXPIRED&&this.transitionToEnded({type:"expired"}),n}const o=this.stateAtom.get(),a=Q(o);if(z(o)!==s||"granted"!==a?.phase||a.grant.token!==r)throw m.validationError("Grant changed before checkout could be confirmed");if("requires_action"===t.outcome)return this.pendingCheckoutPaymentInput=e,this.commit({...a,pendingAction:t.nextAction}),void this.emitEvent("sequence_change","info","user","Checkout awaiting verification",{processor:t.nextAction.processor});this.pendingCheckoutPaymentInput=void 0,this.transitionToEnded({checkout:t.checkout})}finally{const e=Q(this.stateAtom.get());"granted"!==e?.phase||e.pendingAction||this.rearmTimersIfNeeded()}}ackEvent(e){this.stateAtom.get().events.some(t=>t.id===e)&&this.patchJourneyBase({lastSeenEventId:e})}ackAllEvents(){const e=this.stateAtom.get();if(!e.events.length)return;const t=e.events[e.events.length-1];this.patchJourneyBase({lastSeenEventId:t.id})}async routeAndLoadDistribution(e,t){let i=t?.carryFrom??this.stateAtom.get();const s=this.store.session;(s?.consumerId!==this.routingSession?.consumerId||s?.type!==this.routingSession?.type)&&"routed"===i.journeyStage&&$(i)&&(this.clearRoutedRuntimeState(),w(this.experienceId,i.sequenceId),i=N({base:this.baseFromSnapshot(i),journeyStage:"ready"}),this.setSnapshot(i)),this.routingSession=s;const r=i,n=z(r);let o,a=!1;try{const i=await this.resolveRouting(e,{transient:t?.transient});if(!i||this.destroyed)return;if(o=this.stateAtom.get().revision,a=n===i.sequenceId,await this.enterExperienceIfReady(),this.destroyed)return;const s=await this.sdk.experiences.getCurrentDistributions(i.sequenceId,k({experienceId:this.experienceId,sequenceId:i.sequenceId}));if(this.destroyed)return;const c=a?U(r):void 0,d=this.buildDistributionSummary(s,i.sequenceId,{consumer:c,settlingDistributionId:a&&"routed"===r.journeyStage&&"settling"===r.sequence.phase?r.sequence.distribution.id:void 0}),u=this.buildWaitlistAttachmentFromContext(s,a?B(r):void 0);d&&C({experienceId:this.experienceId,sequenceId:i.sequenceId,distributionContext:d}),u&&j({waitlistId:u.waitlistId,experienceId:this.experienceId,sequenceId:i.sequenceId});const h=a?W(r):void 0,l=a?Je(r):void 0,p=a?We(r):void 0,m=a?this.deriveTerminalOutcomeForClosedDistribution(c,d,J(r)):void 0,g=this.withTerminalConsumer(c,m),y=!d&&a&&"routed"===r.journeyStage&&("granted"===r.sequence.phase||"ended"===r.sequence.phase)?r.sequence:this.projectSequenceState({distribution:d,consumer:g,selectionMode:a?Ve(r):void 0,grant:h,settlement:p,selection:a?Qe(r):void 0,checkout:l,outcome:m});a||(this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck());const f=this.stateAtom.get(),b=N({base:this.baseFromSnapshot(f,{lastSyncedAt:Date.now(),degraded:!1}),journeyStage:"routed",sequenceId:i.sequenceId,offers:i.offers,sequence:y,waitlist:u,sequenceRef:i.selectedSequence});this.setSnapshot(b),this.resumeDeferredGrantHydration(),this.consecutiveRefreshFailures=0,this.rearmTimersIfNeeded();const S=a?L(r):void 0;this.emitIfDistributionChanged(S,d),this.evaluateDistributionSelfCheck(d)}catch(c){if("routed"===r.journeyStage&&a&&this.isQuietableDegradationError(c))throw this.restoreQuietSnapshot(r),this.markErrorQuietable(c);if("routing"===this.stateAtom.get().journeyStage)if(this.lastClearedSequenceId===n&&this.restoreClearedSequenceContext(r,n),void 0!==o&&this.stateAtom.get().revision===o)this.setSnapshot(r);else{const e=this.stateAtom.get();"routed"===r.journeyStage?this.setSnapshot(N({base:this.baseFromSnapshot(e),journeyStage:"routed",sequenceId:r.sequenceId,offers:r.offers,sequence:r.sequence,waitlist:r.waitlist,sequenceRef:r.sequenceRef})):this.setSnapshot(N({base:this.baseFromSnapshot(e),journeyStage:"ready"}))}throw c}}restoreClearedSequenceContext(e,t){const i=L(e);i&&C({experienceId:this.experienceId,sequenceId:t,distributionContext:i});const s=B(e);s&&j({waitlistId:s.waitlistId,experienceId:this.experienceId,sequenceId:t}),this.lastClearedSequenceToken&&x({experienceId:this.experienceId,sequenceId:t,token:this.lastClearedSequenceToken.token,expiresAt:this.lastClearedSequenceToken.expiresAt}),this.lastClearedSequenceId=null,this.lastClearedSequenceToken=void 0}restoreUndisplacedJourney(e,t){const i=this.stateAtom.get();return i.revision===t?(this.setSnapshot(e),!0):"routing"===i.journeyStage&&(this.setSnapshot(N({base:this.baseFromSnapshot(i),journeyStage:"routed",sequenceId:e.sequenceId,offers:e.offers,sequence:e.sequence,waitlist:e.waitlist,sequenceRef:e.sequenceRef})),!0)}async resolveRouting(e,t){const i=this.stateAtom.get(),s=z(i);this.transitionToRouting();const r=this.stateAtom.get().revision;let n;try{n=await this.sdk.experiences.findSequence(this.experienceId,e)}catch(a){throw this.setSnapshot(i),"routed"===i.journeyStage&&this.armCapabilityRefreshTimer(),this.emitEvent("error","error","user","Failed to route experience"),a}if(this.destroyed)return null;if("gated"===n.outcome&&n.selected){const e=n.selected.gates;return"routed"!==i.journeyStage||$(i)?("routed"===i.journeyStage&&this.clearRoutedRuntimeState(),this.transitionToGated({gates:e,selected:{sequence:n.selected.sequence,status:"gated"}}),this.emitEvent("requirement","info","user","Gates required",{gates:e}),null):(this.restoreUndisplacedJourney(i,r)&&(this.rearmTimersIfNeeded(),"ended"!==P(this.stateAtom.get())&&(this.scheduleGatedCapabilityRefresh(),this.emitEvent("requirement","info","user","Gates required",{gates:e}))),null)}if("no_access"===n.outcome||!n.selected)throw this.setSnapshot(i),this.emitEvent("error","error","user","No access available for this experience"),new G("No access available for this experience");const o=n.selected.sequence.id;if(s&&s!==o&&(this.lastClearedSequenceId=s,this.lastClearedSequenceToken=T(this.experienceId,s),w(this.experienceId,s)),this.consecutiveGatedRestores=0,n.selected.capabilityGrant&&x({experienceId:this.experienceId,sequenceId:o,token:n.selected.capabilityGrant,expiresAt:n.selected.capabilityGrantExpiresAt}),s!==o){const e="routed"===i.journeyStage?i.sequenceRef?.priority:void 0,r=n.selected.sequence.priority,a=function(e,t){return void 0===e?"unknown":t>e?"upgrade":t<e?"downgrade":"lateral"}(e,r);this.emitEvent("reroute","downgrade"===a?"warning":"info",t?.transient?"system":"user","downgrade"===a?"Sequence downgraded":"Sequence changed",{previousSequenceId:s,sequenceId:o,...void 0===e?{}:{previousPriority:e},priority:r,direction:a})}return{sequenceId:o,selectedSequence:n.selected.sequence,offers:n.offers}}async enterExperienceIfReady(){const e=this.stateAtom.get();if(K(e).length>0)return;if(e.experience)return;const t=await this.sdk.experiences.enter(this.experienceId);this.destroyed||this.patchJourneyBase({experience:t})}createSequenceDrivers(){return{appointment:d({appointments:this.sdk.appointments,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>Q(this.stateAtom.get()),getDisplayState:()=>this.displayAtom?.get()??null,commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>this.ensureDisplayAtom(e),stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),auction:h({auctions:this.sdk.auctions,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>Q(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e)}),queue:v({queues:this.sdk.queues,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>Q(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),timed_release:M({timedReleases:this.sdk.timedReleases,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>Q(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)}),draw:S({draws:this.sdk.draws,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>Q(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e),ensureDisplayAtom:e=>{this.ensureDisplayAtom(e)},stopRuntimeMonitoring:e=>this.stopRuntimeMonitoring(e),emitEvent:(e,t,i,s,r)=>this.emitEvent(e,t,i,s,r)})}}buildView(e){return F(e,{start:e=>this.start(e),reroute:e=>this.reroute(e),submitAccessCode:e=>this.submitAccessCode(e),retry:()=>this.retry(),joinWaitlist:()=>this.joinWaitlistAttachment(),exitWaitlist:()=>this.exitWaitlistAttachment(),claim:()=>this.claim(),select:e=>this.select(e),loadSelectionOptions:()=>this.loadSelectionOptions(),canConfirmCheckout:()=>!this.checkoutStarted,confirmCheckout:e=>this.confirmCheckout(e),resumeCheckout:()=>this.resumeCheckout()},this.displayAtom,this.sequenceDrivers)}projectSequenceState(e){if(!e.distribution)return{phase:"unavailable"};const t=this.sequenceDrivers[e.distribution.type];if(!t)throw new Error(`${e.distribution.type} sequence driver is required`);return t.project(e)}patchJourneyBase(e){if(this.destroyed)return;const t=this.stateAtom.get(),i=this.baseFromSnapshot(t,e);switch(t.journeyStage){case"ready":return void this.setSnapshot(N({base:i,journeyStage:"ready"}));case"routing":return void this.setSnapshot(N({base:i,journeyStage:"routing"}));case"gated":return void this.setSnapshot(N({base:i,journeyStage:"gated",gates:t.gates,selected:t.selected}));case"routed":return void this.setSnapshot(N({base:i,journeyStage:"routed",sequenceId:t.sequenceId,offers:t.offers,sequence:t.sequence,waitlist:t.waitlist,sequenceRef:t.sequenceRef}))}}transitionToRouting(){if(this.destroyed)return;const e=this.stateAtom.get();this.setSnapshot(N({base:this.baseFromSnapshot(e),journeyStage:"routing"}))}transitionToGated(e){if(this.destroyed)return;const t=this.stateAtom.get();this.setSnapshot(N({base:this.baseFromSnapshot(t),journeyStage:"gated",gates:e.gates,selected:e.selected}))}baseFromSnapshot(e,t={}){const i=Object.prototype.hasOwnProperty.call(t,"accessCode")?t.accessCode??void 0:e.accessCode,s=Object.prototype.hasOwnProperty.call(t,"degraded")?t.degraded||void 0:e.degraded,r=Object.prototype.hasOwnProperty.call(t,"lastSyncedAt")?t.lastSyncedAt:e.lastSyncedAt;return{revision:e.revision,updatedAt:e.updatedAt,experienceId:e.experienceId,accessCode:i,experience:t.experience??e.experience,events:t.events??e.events,lastSeenEventId:t.lastSeenEventId??e.lastSeenEventId,degraded:s,lastSyncedAt:r}}commit(e,t={}){if(this.destroyed)throw m.notInitialized("Journey has been destroyed");const i=this.stateAtom.get();if("routed"!==i.journeyStage)throw m.validationError(se);if(!function(e,t){if("distribution"in e&&e.distribution.sequenceId&&e.distribution.sequenceId!==t)return!1;return!0}(e,i.sequenceId))throw m.validationError(ie);const s=Object.prototype.hasOwnProperty.call(t,"waitlist")?t.waitlist??void 0:i.waitlist,r={};Object.prototype.hasOwnProperty.call(t,"lastSyncedAt")&&(r.lastSyncedAt=t.lastSyncedAt),Object.prototype.hasOwnProperty.call(t,"degraded")&&(r.degraded=t.degraded);const n=N({base:this.baseFromSnapshot(i,{...r,events:t.events??i.events}),journeyStage:"routed",sequenceId:i.sequenceId,offers:i.offers,sequence:e,waitlist:s,sequenceRef:i.sequenceRef});this.setSnapshot(n)}markDegraded(){if(this.destroyed)return;const e=this.stateAtom.get();e.degraded||this.setSnapshot(this.rebuildSnapshot(e,{degraded:!0}))}clearDegraded(){if(this.destroyed)return;const e=this.stateAtom.get();e.degraded&&this.setSnapshot(this.rebuildSnapshot(e,{degraded:!1}))}restoreQuietSnapshot(e){this.setSnapshot(this.rebuildSnapshot(e,{degraded:!0}))}isQuietableDegradationError(e){return g(e)&&(e.retryable||oe.has(e.code))}markErrorQuietable(e){return e&&"object"==typeof e&&(e.quietable=!0),e}rebuildSnapshot(e,t={}){const i=this.baseFromSnapshot(e,t);switch(e.journeyStage){case"ready":return N({base:i,journeyStage:"ready"});case"routing":return N({base:i,journeyStage:"routing"});case"gated":return N({base:i,journeyStage:"gated",gates:e.gates,selected:e.selected});case"routed":return N({base:i,journeyStage:"routed",sequenceId:e.sequenceId,offers:e.offers,sequence:e.sequence,waitlist:e.waitlist,sequenceRef:e.sequenceRef})}}emitEvent(e,t,i,s,r){const n=this.stateAtom.get(),o={id:b(),ts:Date.now(),kind:e,severity:t,audience:i,message:s,detail:r},a=[...n.events,o],c=a.length>this.EVENT_BUFFER_LIMIT?a.slice(a.length-this.EVENT_BUFFER_LIMIT):a;this.patchJourneyBase({events:c})}emitIfDistributionChanged(e,t){e?.id===t?.id&&e?.lifecycle===t?.lifecycle||this.emitEvent("distribution_change","info","user","Distribution context changed",{previous:e,next:t})}buildDistributionSummary(e,t,i){if(e.active){const s=this.sequenceDrivers[e.active.type],r=!0===s?.settlementCanStartWhileActive&&i?.settlingDistributionId===e.active.id?"settling":"open";return{type:e.active.type,id:e.active.id,sequenceId:t,lifecycle:r,details:e.active.details,opensAt:e.active.details.openAt,closesAt:e.active.details.closeAt,updatedAt:Date.now()}}if(e.upcoming)return{type:e.upcoming.type,id:e.upcoming.id,sequenceId:t,lifecycle:"scheduled",startsAt:e.upcoming.startsAt,opensAt:e.upcoming.startsAt,updatedAt:Date.now()};if(e.recentPast){const s=i?.settlingDistributionId===e.recentPast.id||te(i?.consumer,e.recentPast.type,e.recentPast.id)?"settling":"closed";return{type:e.recentPast.type,id:e.recentPast.id,sequenceId:t,lifecycle:s,result:e.recentPast.result,closesAt:e.recentPast.endedAt,updatedAt:Date.now()}}}buildWaitlistAttachmentFromContext(e,t){const i=e.waitlist?.id;if(i)return t?.waitlistId===i?t:{waitlistId:i,status:"not_waitlisted"}}buildWaitlistAttachmentFromMe(e,t){const i=e.waitlists?.find(e=>e.experienceId===this.experienceId&&e.sequenceId===t);if(i)return{waitlistId:i.waitlistId,status:"waitlisted"}}normalizeOffers(e){return Array.isArray(e)?e.filter(Boolean):[]}restoreFromStore(){const e=this.store.activeJourneys;if(!e||!e[this.experienceId])return null;const t=Be(e[this.experienceId]);return t?"routing"===t.journeyStage||"routed"===t.journeyStage&&$(t)?("routed"===t.journeyStage&&w(this.experienceId,t.sequenceId),this.restoredSnapshotNeedsPersist=!0,N({base:this.baseFromSnapshot(t),journeyStage:"ready"})):t:(this.store.removeJourney(this.experienceId),null)}persist(){this.store.setJourneyState(this.experienceId,this.stateAtom.get())}setSnapshot(e,t={}){if(this.destroyed)return;const i=this.stateAtom.get(),s=he(e);"auction"===s?.type&&"auction"!==this.displayAtom?.get().type&&(this.resetDisplayAtom("auction"),this.displayParticipationId=s.id),this.stateAtom.set(e),!1!==t.persist&&this.persist(),this.emitPhaseChanged(i,e)}emitPhaseChanged(e,t){const i=e.journeyStage,s="routed"===i?P(e):void 0,r=t.journeyStage,n="routed"===r?P(t):void 0;i===r&&s===n||E().emit("journey:phase-changed",{experienceId:this.experienceId,journeyStage:r,sequencePhase:n})}runSerializedOperation(e){const t=this.operationQueue.then(async()=>{if(this.destroyed)throw m.notInitialized("Journey has been destroyed");return e()});return this.operationQueue=t.then(()=>{},()=>{}),t}transitionToEnded(e,t={}){if(this.destroyed)return;const i=this.stateAtom.get(),s=z(i);if(!s)throw m.validationError(se);const r=L(i),n="checkout"in e?e.checkout:void 0,o="checkout"in e?{type:"completed"}:e,a=this.reinterpretLapsedGrantOutcome(i,o),c={...a,distributionType:a.distributionType??r?.type,distributionId:a.distributionId??r?.id,at:a.at??/* @__PURE__ */(new Date).toISOString()},d=this.withTerminalConsumer(U(i),c,{finalize:!0}),u=this.projectSequenceState({distribution:r,consumer:d,selectionMode:Ve(i),checkout:n,outcome:c});this.commit(u,t),this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.emitEvent("sequence_change","expired"===c.type?"warning":"info","user","Sequence ended",{outcome:c}),E().emit("journey:ended",{experienceId:this.experienceId,sequenceId:s,outcome:c})}reinterpretLapsedGrantOutcome(e,t){if("granted"!==P(e))return t;return"closed"===t.type&&("not_queued"===t.reason||"not_entered"===t.reason)?{type:"expired",at:t.at,distributionType:t.distributionType,distributionId:t.distributionId}:t}applyMonitorUpdate(e){if(!this.destroyed){if("settling"===e.type){const t=this.stateAtom.get();if(!X(t)||"participating"!==t.sequence.phase)return;const i={...t.sequence.distribution,lifecycle:"settling",settlesAt:e.at},s=this.projectSequenceState({distribution:i,consumer:U(t),selectionMode:Ve(t)});if("settling"!==s.phase)return;return void this.commit(s,{lastSyncedAt:Date.now(),degraded:!1})}"granted"!==e.type?"resync"!==e.type?this.transitionToEnded(e.outcome,{lastSyncedAt:Date.now(),degraded:!1}):this.beginGrantHydration():this.beginGrantHydration(e.token,e.expiresAt)}}beginGrantHydration(e,t){const i=this.stateAtom.get();"routing"!==i.journeyStage?"routed"===i.journeyStage&&(le(i,i.sequenceId)||this.pendingGrantHydration?.sequenceId!==i.sequenceId&&(this.clearGrantHydration(),this.pendingGrantHydration={sequenceId:i.sequenceId,token:e,expiresAt:t,attempt:0},this.hydrateGrantFromMe(e,t))):this.pendingGrantObservation={token:e,expiresAt:t}}resumeDeferredGrantHydration(){const e=this.pendingGrantObservation;e&&(this.pendingGrantObservation=void 0,this.beginGrantHydration(e.token,e.expiresAt))}async hydrateGrantFromMe(e,t){if(this.destroyed)return;const i=this.pendingGrantHydration,s=this.stateAtom.get();if(i)if("routing"!==s.journeyStage)if(le(s,i.sequenceId))this.clearGrantHydration();else if(void 0!==t&&Date.now()>=t)this.transitionToEnded({type:"expired"},{lastSyncedAt:Date.now(),degraded:!1});else{try{const e=await this.sdk.experiences.getMe();if(this.destroyed)return;await this.resumeFromMe(e)}catch(r){this.emitEvent("error","warning","system","Could not resolve an observed grant from /me",{grant:e,error:r instanceof Error?r.message:String(r)})}this.scheduleGrantHydrationRetry()}else this.scheduleGrantHydrationRetry()}scheduleGrantHydrationRetry(){const e=this.pendingGrantHydration;if(!e||this.destroyed)return;if(le(this.stateAtom.get(),e.sequenceId))return void this.clearGrantHydration();const t=de[e.attempt]??1e4;e.attempt+=1,e.timer=setTimeout(()=>{this.pendingGrantHydration===e&&(e.timer=void 0,this.hydrateGrantFromMe(e.token,e.expiresAt))},t)}clearGrantHydration(){const e=this.pendingGrantHydration;e?.timer&&clearTimeout(e.timer),this.pendingGrantHydration=void 0,this.pendingGrantObservation=void 0}applyMonitorUpdateFromCallback(e){try{this.applyMonitorUpdate(e)}catch(t){if(this.dropStaleCallbackCommit(t,"monitor"))return;throw t}}startMonitorForParticipation(e){const t=this.ensureDisplayAtom(e),i=e=>this.applyMonitorUpdateFromCallback(e),s=e=>{e?this.markDegraded():this.clearDegraded()},r=this.sequenceDrivers[e.type];if(r?.startMonitoring)return r.startMonitoring({participation:e,displayAtom:t,onUpdate:i,onDegradedChange:s}),void(this.activeMonitor={type:e.type,id:e.id,stop:()=>r.stopMonitoring?.()});throw new Error(`Unknown distribution type: ${e.type}`)}stopRuntimeMonitoring(e=!1){this.activeMonitor&&(this.activeMonitor.stop(),this.activeMonitor=null),e&&this.clearRuntimeDisplayState()}clearGrantExpiryTimer(){this.grantExpiryTimer&&(clearTimeout(this.grantExpiryTimer),this.grantExpiryTimer=void 0)}clearCapabilityRefreshTimer(){this.capabilityRefreshTimer&&(clearTimeout(this.capabilityRefreshTimer),this.capabilityRefreshTimer=void 0)}clearDistributionSelfCheck(){this.selfCheckTimer&&(clearTimeout(this.selfCheckTimer),this.selfCheckTimer=void 0),this.selfCheckKey=void 0,this.selfCheckStartedAtMs=0,this.selfCheckAttempts=0}resetDistributionSelfCheck(){this.clearDistributionSelfCheck(),this.selfCheckTotalAttempts=0}evaluateDistributionSelfCheck(e){if(this.destroyed)return;const t=Date.now();if(!ue(e,t))return void this.clearDistributionSelfCheck();const i=`${e?.sequenceId??""}:${e?.id??""}:${e?.opensAt??""}`;if(this.selfCheckKey!==i&&(this.clearDistributionSelfCheck(),this.selfCheckKey=i,this.selfCheckStartedAtMs=t),this.selfCheckTimer)return;if(this.selfCheckAttempts>=ae.length)return;if(this.selfCheckTotalAttempts>=ce)return;const s=this.selfCheckStartedAtMs+ae[this.selfCheckAttempts];this.selfCheckAttempts+=1,this.selfCheckTotalAttempts+=1,this.selfCheckTimer=setTimeout(()=>{this.selfCheckFromTimer()},Math.max(0,s-t))}async selfCheckFromTimer(){if(this.selfCheckTimer=void 0,!this.destroyed)try{await this.refreshDistribution()}catch(e){if(this.destroyed||"routed"!==this.stateAtom.get().journeyStage)return;this.emitEvent("error","warning","system","Distribution self-check failed",{error:e instanceof Error?e.message:String(e)})}}armCapabilityRefreshTimer(){if(this.clearCapabilityRefreshTimer(),this.destroyed||this.checkoutStarted)return;const e=this.stateAtom.get();if("routed"!==e.journeyStage)return;const t=R(this.experienceId,e.sequenceId);if(void 0===t)return;const i=Math.max(t-Date.now()-6e4,5e3);this.scheduleCapabilityRefresh(i)}scheduleGatedCapabilityRefresh(){const e=this.stateAtom.get();if("routed"!==e.journeyStage)return;const t=Math.min(re*2**this.consecutiveGatedRestores,ne);this.consecutiveGatedRestores+=1;const i=R(this.experienceId,e.sequenceId),s=void 0===i?t:Math.max(i-Date.now()-6e4,t);this.scheduleCapabilityRefresh(s)}scheduleCapabilityRefresh(e){if(this.clearCapabilityRefreshTimer(),this.destroyed||this.checkoutStarted)return;"routed"===this.stateAtom.get().journeyStage&&(this.capabilityRefreshTimer=setTimeout(()=>this.refreshCapabilityFromTimer(),e))}rearmTimersIfNeeded(){if(this.destroyed||this.checkoutStarted)return;const e=this.stateAtom.get();"routed"===e.journeyStage&&this.armCapabilityRefreshTimer(),this.pendingGrantHydration&&le(e,this.pendingGrantHydration.sequenceId)&&this.scheduleGrantHydrationRetry(),"routed"===e.journeyStage&&"granted"===e.sequence.phase&&"awaiting_assignment"===e.sequence.selection.status&&this.pendingGrantHydration?.sequenceId!==e.sequenceId&&(this.clearGrantHydration(),this.pendingGrantHydration={sequenceId:e.sequenceId,token:e.sequence.grant.token,expiresAt:Y(e),attempt:0},this.scheduleGrantHydrationRetry());const t=Q(e);if("granted"===t?.phase&&(t.pendingAction||"internal"===t.settlement.processor&&"at_end"===t.settlement.mode&&"in_progress"===t.settlement.state))this.clearGrantExpiryTimer();else if("granted"===t?.phase&&!this.grantExpiryTimer){const t=Y(e);if(t){const e=t-Date.now();e<=0?this.transitionToEnded({type:"expired"}):this.grantExpiryTimer=setTimeout(()=>this.expireGrantFromTimer(),e)}}}async refreshCapabilityFromTimer(){this.capabilityRefreshTimer=void 0;try{if("routed"!==this.stateAtom.get().journeyStage)return void this.clearCapabilityRefreshTimer();if(this.checkoutStarted)return;const e=Date.now();if(void 0!==this.lastCapabilityRefreshAtMs&&e-this.lastCapabilityRefreshAtMs<re)return void this.scheduleCapabilityRefresh(re);this.lastCapabilityRefreshAtMs=e,await this.retry(),this.consecutiveRefreshFailures=0}catch(e){if(this.dropStaleCallbackCommit(e,"capability refresh timer"))return;const t=Math.min(re*2**this.consecutiveRefreshFailures,ne);this.consecutiveRefreshFailures+=1,this.emitEvent("error","warning","system","Capability grant refresh failed",{error:e instanceof Error?e.message:String(e),consecutiveFailures:this.consecutiveRefreshFailures}),this.scheduleCapabilityRefresh(t)}}expireGrantFromTimer(){this.grantExpiryTimer=void 0;try{this.transitionToEnded({type:"expired"})}catch(e){if(this.dropStaleCallbackCommit(e,"grant-expiry timer"))return;throw e}}dropStaleCallbackCommit(e,t){return!(!g(e)||e.code!==y.VALIDATION_ERROR||e.message!==ie&&e.message!==se)&&(this.logger.debug("Dropped stale journey callback",{experienceId:this.experienceId,source:t,message:e.message}),!0)}getRuntimeBinding(){const e=this.stateAtom.get(),t=he(e),i=z(e);return t&&i?{experienceId:this.experienceId,sequenceId:i,participationId:t.id,participationType:t.type}:null}startRuntimeMonitoring(){const e=this.getRuntimeBinding();if(!e)return;const t=this.activeMonitor;t&&t.id===e.participationId&&t.type===e.participationType&&this.displayAtom||(this.stopRuntimeMonitoring(!1),this.startMonitorForParticipation({id:e.participationId,type:e.participationType}))}getRuntimeDisplayAtom(){return this.displayAtom}applyRuntimeState(e){if(!e)return void this.clearRuntimeDisplayState();const t=this.getRuntimeBinding();if(!t)return;this.ensureDisplayAtom({id:t.participationId,type:t.participationType}).set(e)}reconcileSyncedSnapshot(e){if(this.destroyed)return;if(!e)return this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),void this.setSnapshot(_(this.experienceId),{persist:!1});const t=Be(e);if(!t)return;const i="routing"===t.journeyStage?N({base:this.baseFromSnapshot(t),journeyStage:"ready"}):t,s=this.stateAtom.get();if(s.revision===i.revision&&s.updatedAt===i.updatedAt)return;const r=he(i);r||(this.displayAtom=null,this.displayParticipationId=void 0),this.setSnapshot(i,{persist:!1}),r?this.ensureDisplayAtom(r):this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.rearmTimersIfNeeded()}ensureDisplayAtom(e){const t=this.displayAtom;if(t?.get().type===e.type&&this.displayParticipationId===e.id)return t;const i=this.resetDisplayAtom(e.type);return this.displayParticipationId=e.id,i}resetDisplayAtom(e){const t=this.displayAtom;if(!t||t.get().type!==e){const t=o({type:e});return this.displayAtom=t,t}return t.set({type:e}),t}clearRuntimeDisplayState(){const e=this.getRuntimeBinding();if(!e)return this.displayAtom=null,void(this.displayParticipationId=void 0);this.displayParticipationId=void 0,this.resetDisplayAtom(e.participationType)}clearRoutedRuntimeState(){this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck(),this.checkoutStarted=!1}deriveTerminalOutcomeForClosedDistribution(e,t,i){if(i&&!l(i))return i;if(!t||"closed"!==t.lifecycle||!e)return i;const s=this.projectSequenceState({distribution:t,consumer:e});return"ended"===s.phase&&"lost"===s.outcome.type?s.outcome:i??{type:"closed",distributionType:t.type,distributionId:t.id}}withTerminalConsumer(e,t,i){switch(e?.mechanism){case"appointment":return u(e,t);case"auction":return p(e,t,i);case"draw":return I(e,t);case"queue":return q(e,t);case"timed_release":return O(e,t);default:return e}}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0)}}const me=c.picklist(["queue","draw","auction","timed_release","appointment"]),ge=me,ye=c.picklist(["queue","draw","auction","timed_release"]),fe=c.picklist(["draw","auction"]),be=c.strictObject({id:c.string(),ts:c.number(),kind:c.picklist(["reroute","sequence_change","distribution_change","requirement","error","info"]),severity:c.picklist(["info","success","warning","error"]),audience:c.picklist(["user","system","analytics"]),message:c.string(),detail:c.optional(c.record(c.string(),c.unknown()))}),Se=c.strictObject({id:c.string(),name:c.string(),experienceId:c.string(),priority:c.number(),color:c.string()}),Ie=c.strictObject({type:me,id:c.string(),sequenceId:c.optional(c.string()),lifecycle:c.string(),startsAt:c.optional(c.string()),opensAt:c.optional(c.string()),closesAt:c.optional(c.string()),settlesAt:c.optional(c.string()),result:c.optional(c.string()),details:c.optional(c.unknown()),updatedAt:c.optional(c.number())}),ve=c.strictObject({status:c.string(),selection:c.optional(n),id:c.optional(c.string()),distributionId:c.optional(c.string()),waitlistId:c.optional(c.string()),enteredAt:c.optional(c.string()),admissionGrant:c.optional(c.string()),grantedAt:c.optional(c.string()),deniedReason:c.optional(c.string()),position:c.optional(c.number()),highestBid:c.optional(c.string()),currentBid:c.optional(c.string()),slotId:c.optional(c.string()),locationId:c.optional(c.string()),bookedAt:c.optional(c.string()),checkedInAt:c.optional(c.string()),completedAt:c.optional(c.string()),cancelledAt:c.optional(c.string()),noShowAt:c.optional(c.string())}),qe=c.strictObject({token:c.string(),distributionType:ye,distributionId:c.string(),sequenceId:c.string(),experienceId:c.string(),issuedAt:c.optional(c.string()),expiresAt:c.optional(c.string())}),Ae=c.strictObject({orderId:c.string(),amount:c.string(),currencyCode:c.string(),paymentMethodLast4:c.optional(c.string()),paymentMethodBrand:c.optional(c.string())}),we=c.strictObject({publishableKey:c.string(),stripeAccount:c.optional(c.string())}),ke=c.strictObject({type:c.string(),reason:c.optional(c.string()),at:c.optional(c.string()),distributionType:c.optional(me),distributionId:c.optional(c.string())}),Ce=c.strictObject({phase:c.literal("unavailable"),reason:c.optional(c.string())}),je=c.strictObject({waitlistId:c.string(),status:c.picklist(["not_waitlisted","waitlisted"]),entryId:c.optional(c.string())}),xe=c.strictObject({phase:c.literal("scheduled"),selectionMode:c.optional(c.picklist(s)),mechanism:ge,distribution:Ie}),Te=c.strictObject({phase:c.literal("enterable"),selectionMode:c.optional(c.picklist(s)),mechanism:ge,distribution:Ie,consumer:ve,paymentProvider:c.optional(we)}),Re=c.strictObject({phase:c.literal("participating"),selectionMode:c.optional(c.picklist(s)),mechanism:ge,distribution:Ie,consumer:ve}),Ee=c.strictObject({phase:c.literal("settling"),selectionMode:c.optional(c.picklist(s)),mechanism:fe,distribution:Ie,consumer:ve}),De=c.variant("processor",[c.strictObject({processor:c.literal("external")}),c.strictObject({processor:c.literal("internal"),mode:c.literal("at_end"),state:c.picklist(["awaiting","in_progress"]),paymentProvider:c.optional(we)}),c.strictObject({processor:c.literal("internal"),mode:c.literal("pre_auth")})]),Me=c.strictObject({phase:c.literal("granted"),selectionMode:c.optional(c.picklist(s)),mechanism:ye,distribution:Ie,consumer:ve,grant:qe,settlement:De,selection:r}),Oe=c.strictObject({phase:c.literal("ended"),selectionMode:c.optional(c.picklist(s)),mechanism:ge,distribution:Ie,consumer:ve,outcome:ke,checkout:c.optional(Ae)}),Ge=c.union([Ce,xe,Te,Re,Ee,Me,Oe]),Fe={schemaVersion:c.literal(5),revision:c.number(),updatedAt:c.number(),experienceId:c.string(),accessCode:c.optional(c.string()),experience:c.optional(c.unknown()),events:c.array(be),lastSeenEventId:c.optional(c.string()),lastSyncedAt:c.optional(c.number())},_e=c.strictObject({...Fe,journeyStage:c.literal("ready")}),Pe=c.strictObject({...Fe,journeyStage:c.literal("routing")}),He=c.variant("type",[c.object({...c.omit(e,["reason"]).entries,requirement:c.optional(c.picklist(["session","authenticated"]),"authenticated")}),c.omit(t,["reason"]),c.omit(i,["reason"])]),Ne=c.strictObject({...Fe,journeyStage:c.literal("gated"),gates:c.array(He),selected:c.optional(c.strictObject({sequence:c.unknown(),status:c.literal("gated")}))}),ze=c.strictObject({...Fe,journeyStage:c.literal("routed"),sequenceId:c.string(),offers:c.array(c.object({sequence:c.unknown(),status:c.literal("gated"),gates:c.array(He)})),sequence:Ge,waitlist:c.optional(je),sequenceRef:c.optional(Se)}),Ue=c.union([_e,Pe,Ne,ze]);function Be(e){const t=c.safeParse(Ue,e);if(!t.success)return null;const{schemaVersion:i,...s}=t.output;if("routed"===s.journeyStage)try{ee(s.sequence)}catch{return null}return s}function Le(e){if("participating"!==e.phase&&"settling"!==e.phase)return e;if(!("selection"in e))return e;const{selection:t,...i}=e;return void 0===t?i:{...i,consumer:{...i.consumer,selection:t}}}function Je(e){return"routed"!==e.journeyStage||"granted"!==e.sequence.phase&&"ended"!==e.sequence.phase||!("checkout"in e.sequence)?V(e):e.sequence.checkout}function We(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.settlement}function Qe(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.selection}function Ve(e){if("routed"===e.journeyStage)return"selectionMode"in e.sequence?e.sequence.selectionMode:void 0}export{pe as ExperienceJourney,ue as isSelfContradictingDistribution};
@@ -1 +1 @@
1
- function e(e,o,r){const n=r.confirmCheckout,t=r.resumeCheckout;if(r.canConfirmCheckout&&n&&t)return{processor:"internal",confirmCheckout:e=>n(e),resumeCheckout:()=>t(),...o?{pendingAction:o}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{}}}export{e as buildGrantPaymentAffordance};
1
+ function e(e){return e.selectionMode?{selectionMode:e.selectionMode}:{}}function o(e,o,n){const r=n.confirmCheckout,t=n.resumeCheckout;if(n.canConfirmCheckout&&r&&t)return{processor:"internal",confirmCheckout:e=>r(e),resumeCheckout:()=>t(),...o?{pendingAction:o}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{}}}export{o as buildGrantPaymentAffordance,e as selectionModeFields};
@@ -1 +1 @@
1
- import{createError as e}from"../core/errors.js";import{buildGrantPaymentAffordance as t}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as i,checkoutViewFields as n,isEntryActionRequired as s,canReenter as r,isPreAuthMisconfigured as o}from"../payment/checkout-contract.js";import{isClaimableSettlement as u}from"../payment/settlement.js";function a(e){return o(i(e.details))}function c(e){return r(e.distribution.lifecycle,i(e.distribution.details))}function d(e){return new m(e)}function p(t){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:u,outcome:c}=t;if(!i)return{phase:"unavailable"};const d=function(t){if("queue"!==t.type)throw e.validationError("Queue driver received a non-queue distribution");return t}(i),p=n&&"queue"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):h(i);if(s)return"completed"===c?.type?b(d,p,c,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===d.lifecycle?a(d)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"queue",distribution:d,consumer:h(d)}:b(d,p,{type:"expired"}):o&&u?{phase:"granted",mechanism:"queue",distribution:d,consumer:p,grant:s,settlement:o,selection:u}:{phase:"unavailable"};const l=c??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:"left"===e.status?{type:"left"}:void 0}(p);return l?b(d,p,l,r):function(e){return"queued"===e.status}(p)?{phase:"participating",mechanism:"queue",distribution:d,consumer:p}:"scheduled"===d.lifecycle?{phase:"scheduled",mechanism:"queue",distribution:d}:"open"===d.lifecycle?a(d)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"queue",distribution:d,consumer:p}:b(d,p,{type:"closed"})}function l(e,t){return e&&"queue"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:{...e,status:"not_queued"}:e}class m{constructor(e){this.deps=e,this.mechanism="queue"}project(e){return p(e)}buildView(i,n){if("unavailable"===i.phase)return{phase:"unavailable",reason:i.reason};const s=function(t){if(!("mechanism"in t)||"queue"!==t.mechanism)throw e.validationError("Queue driver received a non-queue sequence");return t}(i);switch(s.phase){case"scheduled":return{phase:"scheduled",mechanism:"queue",distribution:s.distribution,startsAt:s.distribution.startsAt??s.distribution.opensAt};case"enterable":return this.buildEnterableView(s);case"participating":return{phase:"participating",mechanism:"queue",consumer:s.consumer,display$:n.displayAtom,leave:()=>this.leave()};case"granted":{const e={phase:"granted",mechanism:"queue",distribution:s.distribution,consumer:s.consumer,grant:s.grant},{settlement:i}=s,r=s.selection;if("awaiting_assignment"===r.status)return{...e,settlement:i,selection:r};if("required"===r.status)return{...e,settlement:i,selection:r,select:n.select,loadSelectionOptions:n.loadSelectionOptions};if("internal"===i.processor&&"at_end"===i.mode){const o=t(i,s.pendingAction,n);return o?{...e,settlement:i,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim(),payment:o}:{...e,settlement:i,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}}return u(i)?{...e,settlement:i,selection:r,loadSelectionOptions:n.loadSelectionOptions,select:n.select,claim:()=>n.claim()}:{...e,settlement:i,selection:r}}case"ended":return this.buildEndedView(s)}}buildEnterableView(e){const t=i(e.distribution.details),s=n(t);return"pre_auth"===s.checkoutMode?{phase:"enterable",mechanism:"queue",...s,distribution:e.distribution,consumer:e.consumer,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{},enter:e=>this.enter({paymentInput:e})}:{phase:"enterable",mechanism:"queue",...s,distribution:e.distribution,consumer:e.consumer,enter:()=>this.enter()}}buildEndedView(e){const t={phase:"ended",mechanism:"queue",consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!c(e))return t;const s=i(e.distribution.details),r=n(s);return"pre_auth"===r.checkoutMode?{...t,...r,reenter:e=>this.enter({paymentInput:e})}:{...t,...r,reenter:()=>this.enter()}}startMonitoring(e){this.activeMonitorId=e.participation.id,this.deps.queues.startMonitoring(e.participation.id,{displayAtom:e.displayAtom},e.onUpdate,e.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.queues.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(t){const n=this.currentQueueSequence("enterable","No open queue to enter"),r=n.distribution,o=i(r.details),u=t?.paymentInput;if("pre_auth"===o.mode&&!u)throw e.validationError("Payment input is required for pre-auth distributions");const a=u?await this.deps.queues.enter(r.id,void 0,void 0,u):await this.deps.queues.enter(r.id,void 0);if(s(a))return this.deps.commit({...n,pendingAction:a.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:r.id,processor:a.nextAction.processor});const c=function(e){if("QUEUED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("GRANTED"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:"expiresAt"in e&&e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;return{type:"ended",outcome:{type:f(e),reason:"reason"in e?e.reason:void 0}}}(a);if(c)return void this.deps.applyMonitorUpdate(c);const d={mechanism:"queue",status:"queued",id:l=r.id,distributionId:l};var l;this.deps.ensureDisplayAtom({id:r.id,type:"queue"}),this.deps.commit(p({distribution:r,consumer:d})),this.deps.emitEvent("sequence_change","success","user","Entered queue",{distributionId:r.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentQueueSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;this.deps.stopRuntimeMonitoring(!0),await this.deps.queues.leave(t),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"queue"})}currentQueueSequence(t,i="Not participating in a queue"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"queue"!==n.mechanism)throw e.validationError(i);if("enterable"===t&&"ended"===n.phase&&c(n))return{phase:"enterable",mechanism:"queue",distribution:n.distribution,consumer:h(n.distribution)};if(n.phase!==t)throw e.validationError(i);return n}}function h(e){return{status:"not_queued",distributionId:e.id}}function b(e,t,i,n){return{phase:"ended",mechanism:"queue",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}function f(e){return"LEFT"===e.status?"left":"EXPIRED"===e.status?"expired":"COMPLETED"===e.status?"completed":"DENIED"===e.status?"denied":"closed"}export{d as createQueueDriver,p as projectQueueSequence,l as withQueueTerminalConsumer};
1
+ import{createError as e}from"../core/errors.js";import{selectionModeFields as t,buildGrantPaymentAffordance as i}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as n,checkoutViewFields as s,isEntryActionRequired as r,canReenter as o,isPreAuthMisconfigured as u}from"../payment/checkout-contract.js";import{isClaimableSettlement as a}from"../payment/settlement.js";function c(e){return u(n(e.details))}function d(e){return o(e.distribution.lifecycle,n(e.distribution.details))}function p(e){return new h(e)}function l(i){const n=function(t){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:u,outcome:a}=t;if(!i)return{phase:"unavailable"};const d=function(t){if("queue"!==t.type)throw e.validationError("Queue driver received a non-queue distribution");return t}(i),p=n&&"queue"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):b(i);if(s)return"completed"===a?.type?f(d,p,a,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===d.lifecycle?c(d)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"queue",distribution:d,consumer:b(d)}:f(d,p,{type:"expired"}):o&&u?{phase:"granted",mechanism:"queue",distribution:d,consumer:p,grant:s,settlement:o,selection:u}:{phase:"unavailable"};const l=a??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:"left"===e.status?{type:"left"}:void 0}(p);if(l)return f(d,p,l,r);if(function(e){return"queued"===e.status}(p))return{phase:"participating",mechanism:"queue",distribution:d,consumer:p};if("scheduled"===d.lifecycle)return{phase:"scheduled",mechanism:"queue",distribution:d};if("open"===d.lifecycle)return c(d)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"queue",distribution:d,consumer:p};return f(d,p,{type:"closed"})}(i);return"unavailable"===n.phase?n:{...n,...t(i)}}function m(e,t){return e&&"queue"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:{...e,status:"not_queued"}:e}class h{constructor(e){this.deps=e,this.mechanism="queue"}project(e){return l(e)}buildView(n,s){if("unavailable"===n.phase)return{phase:"unavailable",reason:n.reason};const r=function(t){if(!("mechanism"in t)||"queue"!==t.mechanism)throw e.validationError("Queue driver received a non-queue sequence");return t}(n);switch(r.phase){case"scheduled":return{phase:"scheduled",mechanism:"queue",...t(r),distribution:r.distribution,startsAt:r.distribution.startsAt??r.distribution.opensAt};case"enterable":return this.buildEnterableView(r);case"participating":return{phase:"participating",mechanism:"queue",...t(r),consumer:r.consumer,display$:s.displayAtom,leave:()=>this.leave()};case"granted":{const e={phase:"granted",mechanism:"queue",...t(r),distribution:r.distribution,consumer:r.consumer,grant:r.grant},{settlement:n}=r,o=r.selection;if("awaiting_assignment"===o.status)return{...e,settlement:n,selection:o};if("required"===o.status)return{...e,settlement:n,selection:o,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===n.processor&&"at_end"===n.mode){const t=i(n,r.pendingAction,s);return t?{...e,settlement:n,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:t}:{...e,settlement:n,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return a(n)?{...e,settlement:n,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{...e,settlement:n,selection:o}}case"ended":return this.buildEndedView(r)}}buildEnterableView(e){const i=n(e.distribution.details),r=s(i);return"pre_auth"===r.checkoutMode?{phase:"enterable",mechanism:"queue",...t(e),...r,distribution:e.distribution,consumer:e.consumer,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{},enter:e=>this.enter({paymentInput:e})}:{phase:"enterable",mechanism:"queue",...t(e),...r,distribution:e.distribution,consumer:e.consumer,enter:()=>this.enter()}}buildEndedView(e){const i={phase:"ended",mechanism:"queue",...t(e),consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!d(e))return i;const r=n(e.distribution.details),o=s(r);return"pre_auth"===o.checkoutMode?{...i,...o,reenter:e=>this.enter({paymentInput:e})}:{...i,...o,reenter:()=>this.enter()}}startMonitoring(e){this.activeMonitorId=e.participation.id,this.deps.queues.startMonitoring(e.participation.id,{displayAtom:e.displayAtom},e.onUpdate,e.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.queues.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(t){const i=this.currentQueueSequence("enterable","No open queue to enter"),s=i.distribution,o=n(s.details),u=t?.paymentInput;if("pre_auth"===o.mode&&!u)throw e.validationError("Payment input is required for pre-auth distributions");const a=u?await this.deps.queues.enter(s.id,void 0,void 0,u):await this.deps.queues.enter(s.id,void 0);if(r(a))return this.deps.commit({...i,pendingAction:a.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:s.id,processor:a.nextAction.processor});const c=function(e){if("QUEUED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("GRANTED"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:"expiresAt"in e&&e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;return{type:"ended",outcome:{type:y(e),reason:"reason"in e?e.reason:void 0}}}(a);if(c)return void this.deps.applyMonitorUpdate(c);const d={mechanism:"queue",status:"queued",id:p=s.id,distributionId:p};var p;this.deps.ensureDisplayAtom({id:s.id,type:"queue"}),this.deps.commit(l({distribution:s,consumer:d})),this.deps.emitEvent("sequence_change","success","user","Entered queue",{distributionId:s.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentQueueSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;this.deps.stopRuntimeMonitoring(!0),await this.deps.queues.leave(t),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"queue"})}currentQueueSequence(t,i="Not participating in a queue"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"queue"!==n.mechanism)throw e.validationError(i);if("enterable"===t&&"ended"===n.phase&&d(n))return{phase:"enterable",mechanism:"queue",distribution:n.distribution,consumer:b(n.distribution)};if(n.phase!==t)throw e.validationError(i);return n}}function b(e){return{status:"not_queued",distributionId:e.id}}function f(e,t,i,n){return{phase:"ended",mechanism:"queue",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}function y(e){return"LEFT"===e.status?"left":"EXPIRED"===e.status?"expired":"COMPLETED"===e.status?"completed":"DENIED"===e.status?"denied":"closed"}export{p as createQueueDriver,l as projectQueueSequence,m as withQueueTerminalConsumer};
@@ -1,5 +1,5 @@
1
1
  import { AdmissionGrant, GrantedSettlement, QueueConsumerStatus, SequenceOutcome } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
2
- import { GrantedSelection } from '@fanfare-io/fanfare-sdk-contracts/selection';
2
+ import { GrantedSelection, SelectionMode } from '@fanfare-io/fanfare-sdk-contracts/selection';
3
3
  import { ReadableAtom } from 'nanostores';
4
4
  import { QueueDisplayState } from '../experiences/distribution-monitor.types';
5
5
  import { DistributionSummary } from '../experiences/journey.types';
@@ -46,6 +46,7 @@ export type QueueSequence = QueueScheduled | QueueEnterable | QueueParticipating
46
46
  export interface QueueScheduled {
47
47
  /** Mechanism discriminator for queue narrowing. */
48
48
  mechanism: "queue";
49
+ selectionMode?: SelectionMode;
49
50
  /** Phase discriminator; scheduled queues cannot be entered yet. */
50
51
  phase: "scheduled";
51
52
  /** Queue distribution facts from the journey projector. */
@@ -59,6 +60,7 @@ export interface QueueScheduled {
59
60
  export interface QueueEnterable {
60
61
  /** Mechanism discriminator for queue narrowing. */
61
62
  mechanism: "queue";
63
+ selectionMode?: SelectionMode;
62
64
  /** Phase discriminator; `enter()` is legal on the matching view. */
63
65
  phase: "enterable";
64
66
  /** Open queue distribution facts from the journey projector. */
@@ -85,6 +87,7 @@ export interface QueueEnterable {
85
87
  export interface QueueParticipating {
86
88
  /** Mechanism discriminator for queue narrowing. */
87
89
  mechanism: "queue";
90
+ selectionMode?: SelectionMode;
88
91
  /** Phase discriminator; the queue display is live while participating. */
89
92
  phase: "participating";
90
93
  /** Queue distribution facts from the journey projector. */
@@ -100,6 +103,7 @@ export interface QueueParticipating {
100
103
  export interface QueueGranted {
101
104
  /** Mechanism discriminator for queue narrowing. */
102
105
  mechanism: "queue";
106
+ selectionMode?: SelectionMode;
103
107
  /** Phase discriminator; `claim()` is legal on the matching view. */
104
108
  phase: "granted";
105
109
  /** Queue distribution facts from the journey projector. */
@@ -126,6 +130,7 @@ export interface QueueGranted {
126
130
  export interface QueueEnded {
127
131
  /** Mechanism discriminator for queue narrowing. */
128
132
  mechanism: "queue";
133
+ selectionMode?: SelectionMode;
129
134
  /** Phase discriminator; no queue actions are legal after this phase. */
130
135
  phase: "ended";
131
136
  /** Queue distribution facts from the journey projector. */
@@ -155,6 +160,7 @@ export interface QueueScheduledView {
155
160
  phase: "scheduled";
156
161
  /** Mechanism discriminator for queue rendering. */
157
162
  mechanism: "queue";
163
+ selectionMode?: SelectionMode;
158
164
  /** Queue distribution facts from the journey projector. */
159
165
  distribution: DistributionSummary & {
160
166
  type: "queue";
@@ -177,6 +183,7 @@ export type QueueEnterableView = {
177
183
  phase: "enterable";
178
184
  /** Mechanism discriminator for queue rendering. */
179
185
  mechanism: "queue";
186
+ selectionMode?: SelectionMode;
180
187
  /** Money moves after the win; entry places no hold. */
181
188
  checkoutMode: "at_end";
182
189
  /** Open queue distribution facts from the journey projector. */
@@ -197,6 +204,7 @@ export type QueueEnterableView = {
197
204
  phase: "enterable";
198
205
  /** Mechanism discriminator for queue rendering. */
199
206
  mechanism: "queue";
207
+ selectionMode?: SelectionMode;
200
208
  /** Fanfare places a payment authorization hold at entry and captures it on win. */
201
209
  checkoutMode: "pre_auth";
202
210
  /** Open queue distribution facts from the journey projector. */
@@ -236,6 +244,7 @@ export interface QueueParticipatingView {
236
244
  phase: "participating";
237
245
  /** Mechanism discriminator for queue rendering. */
238
246
  mechanism: "queue";
247
+ selectionMode?: SelectionMode;
239
248
  /** Consumer queue participation facts. */
240
249
  consumer: QueueSequenceConsumerState;
241
250
  /** Live queue display facts, such as position and estimated wait time. */
@@ -254,6 +263,7 @@ interface QueueGrantedViewBase {
254
263
  phase: "granted";
255
264
  /** Mechanism discriminator for queue rendering. */
256
265
  mechanism: "queue";
266
+ selectionMode?: SelectionMode;
257
267
  /** Queue distribution facts from the journey projector. */
258
268
  distribution: DistributionSummary & {
259
269
  type: "queue";
@@ -334,6 +344,7 @@ export type QueueEndedView = {
334
344
  phase: "ended";
335
345
  /** Mechanism discriminator for queue rendering. */
336
346
  mechanism: "queue";
347
+ selectionMode?: SelectionMode;
337
348
  /** Consumer queue facts at the terminal outcome. */
338
349
  consumer: QueueSequenceConsumerState;
339
350
  /** Server-derived terminal outcome for the queue participation. */
@@ -349,6 +360,7 @@ export type QueueEndedView = {
349
360
  phase: "ended";
350
361
  /** Mechanism discriminator for queue rendering. */
351
362
  mechanism: "queue";
363
+ selectionMode?: SelectionMode;
352
364
  /** Consumer queue facts at the terminal outcome. */
353
365
  consumer: QueueSequenceConsumerState;
354
366
  /** Server-derived terminal outcome for the queue participation. */
@@ -369,6 +381,7 @@ export type QueueEndedView = {
369
381
  phase: "ended";
370
382
  /** Mechanism discriminator for queue rendering. */
371
383
  mechanism: "queue";
384
+ selectionMode?: SelectionMode;
372
385
  /** Consumer queue facts at the terminal outcome. */
373
386
  consumer: QueueSequenceConsumerState;
374
387
  /** Server-derived terminal outcome for the queue participation. */
@@ -402,6 +415,7 @@ export interface QueueGrantedAwaitingAssignmentView {
402
415
  phase: "granted";
403
416
  /** Mechanism discriminator. */
404
417
  mechanism: "queue";
418
+ selectionMode?: SelectionMode;
405
419
  /** Distribution associated with this grant. */
406
420
  distribution: DistributionSummary & {
407
421
  type: "queue";
@@ -423,6 +437,7 @@ export interface QueueGrantedSelectionRequiredView {
423
437
  phase: "granted";
424
438
  /** Mechanism discriminator. */
425
439
  mechanism: "queue";
440
+ selectionMode?: SelectionMode;
426
441
  /** Distribution associated with this grant. */
427
442
  distribution: DistributionSummary & {
428
443
  type: "queue";
@@ -1 +1 @@
1
- import{createError as e}from"../core/errors.js";import{buildGrantPaymentAffordance as t}from"../experiences/sequence-driver.js";function i(e){return new r(e)}function s(t){const{distribution:i,consumer:s,grant:n,settlement:r,selection:d,outcome:c}=t;if(!i)return{phase:"unavailable"};const m=function(t){if("timed_release"!==t.type)throw e.validationError("Timed-release driver received a non-timed-release distribution");return t}(i),l=s&&"timed_release"===s.mechanism?function(e){const{mechanism:t,...i}=e;return i}(s):a(i);if(n)return"completed"===c?.type?o(m,l,c):n.expiresAt&&Date.now()>new Date(n.expiresAt).getTime()?"open"===m.lifecycle?{phase:"enterable",mechanism:"timed_release",distribution:m,consumer:a(m)}:o(m,l,{type:"expired"}):r&&d&&"required"!==d.status?{phase:"granted",mechanism:"timed_release",distribution:m,consumer:l,grant:n,settlement:r,selection:d}:{phase:"unavailable"};const p=c??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:"left"===e.status?{type:"left"}:void 0}(l);return p?o(m,l,p):function(e){return"entered"===e.status}(l)?{phase:"participating",mechanism:"timed_release",distribution:m,consumer:l}:"scheduled"===m.lifecycle?{phase:"scheduled",mechanism:"timed_release",distribution:m}:"open"===m.lifecycle?{phase:"enterable",mechanism:"timed_release",distribution:m,consumer:l}:o(m,l,{type:"closed"})}function n(e,t){return e&&"timed_release"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:{...e,status:"not_entered"}:e}class r{constructor(e){this.deps=e,this.mechanism="timed_release"}project(e){return s(e)}buildView(i,s){if("unavailable"===i.phase)return{phase:"unavailable",reason:i.reason};const n=function(t){if(!("mechanism"in t)||"timed_release"!==t.mechanism)throw e.validationError("Timed-release driver received a non-timed-release sequence");return t}(i);switch(n.phase){case"scheduled":return{phase:"scheduled",mechanism:"timed_release",distribution:n.distribution,startsAt:n.distribution.startsAt??n.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"timed_release",distribution:n.distribution,consumer:n.consumer,loadSelectionOptions:s.loadSelectionOptions,enter:e=>this.enter({selection:e})};case"participating":return{phase:"participating",mechanism:"timed_release",consumer:n.consumer,display$:s.displayAtom,leave:()=>this.leave(),complete:()=>this.complete()};case"granted":{const e={phase:"granted",mechanism:"timed_release",distribution:n.distribution,consumer:n.consumer,grant:n.grant},{settlement:i}=n,r=n.selection;if("awaiting_assignment"===r.status)return{...e,settlement:i,selection:r};if("internal"===i.processor&&"at_end"===i.mode){const a=t(i,n.pendingAction,s);return a?{...e,settlement:i,selection:r,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim(),payment:a}:{...e,settlement:i,selection:r,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim()}}return"external"===i.processor?{...e,settlement:i,selection:r,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim()}:{...e,settlement:i,selection:r}}case"ended":return{phase:"ended",mechanism:"timed_release",consumer:n.consumer,outcome:n.outcome}}}startMonitoring(e){this.activeMonitorId=e.participation.id,this.deps.timedReleases.startMonitoring(e.participation.id,{displayAtom:e.displayAtom},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.timedReleases.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const t=this.currentTimedReleaseSequence("enterable","No open timed release to enter").distribution,i=e?.selection?await this.deps.timedReleases.enter(t.id,void 0,e.selection):await this.deps.timedReleases.enter(t.id,void 0),n=function(e){if("ENTERED"===e.status)return e.admissionGrant?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};return{type:"ended",outcome:{type:"LEFT"===e.status?"left":"denied",reason:"reason"in e?e.reason:void 0}}}(i);if(n)return void this.deps.applyMonitorUpdate(n);const r="ENTERED"===i.status?i.selection:void 0,a={...(o=t.id,{mechanism:"timed_release",status:"entered",id:o,distributionId:o}),...r?{selection:r}:{}};var o;this.deps.ensureDisplayAtom({id:t.id,type:"timed_release"}),this.deps.commit(s({distribution:t,consumer:a})),this.deps.emitEvent("sequence_change","success","user","Entered timed release",{distributionId:t.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentTimedReleaseSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;this.deps.stopRuntimeMonitoring(!0),await this.deps.timedReleases.leave(t),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"timed_release"})}async complete(){await this.deps.runSerializedOperation(async()=>{const e=this.currentTimedReleaseSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id,i=this.deps.timedReleases.complete(t);i?this.deps.applyMonitorUpdate({type:"granted",token:i}):this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"completed"}}),this.deps.emitEvent("sequence_change","success","user","Completed timed release",{timedReleaseId:t})})}currentTimedReleaseSequence(t,i="Not participating in a timed release"){const s=this.deps.getCurrentSequence();if(!s||s.phase!==t||!("mechanism"in s)||"timed_release"!==s.mechanism)throw e.validationError(i);return s}}function a(e){return{status:"not_entered",distributionId:e.id}}function o(e,t,i){return{phase:"ended",mechanism:"timed_release",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()}}}export{i as createTimedReleaseDriver,s as projectTimedReleaseSequence,n as withTimedReleaseTerminalConsumer};
1
+ import{createError as e}from"../core/errors.js";import{selectionModeFields as t,buildGrantPaymentAffordance as i}from"../experiences/sequence-driver.js";function n(e){return new a(e)}function s(i){const n=function(t){const{distribution:i,consumer:n,grant:s,settlement:r,selection:a,outcome:c}=t;if(!i)return{phase:"unavailable"};const l=function(t){if("timed_release"!==t.type)throw e.validationError("Timed-release driver received a non-timed-release distribution");return t}(i),m=n&&"timed_release"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):o(i);if(s)return"completed"===c?.type?d(l,m,c):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===l.lifecycle?{phase:"enterable",mechanism:"timed_release",distribution:l,consumer:o(l)}:d(l,m,{type:"expired"}):r&&a&&"required"!==a.status?{phase:"granted",mechanism:"timed_release",distribution:l,consumer:m,grant:s,settlement:r,selection:a}:{phase:"unavailable"};const u=c??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:"left"===e.status?{type:"left"}:void 0}(m);if(u)return d(l,m,u);if(function(e){return"entered"===e.status}(m))return{phase:"participating",mechanism:"timed_release",distribution:l,consumer:m};if("scheduled"===l.lifecycle)return{phase:"scheduled",mechanism:"timed_release",distribution:l};if("open"===l.lifecycle)return{phase:"enterable",mechanism:"timed_release",distribution:l,consumer:m};return d(l,m,{type:"closed"})}(i);return"unavailable"===n.phase?n:{...n,...t(i)}}function r(e,t){return e&&"timed_release"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:{...e,status:"not_entered"}:e}class a{constructor(e){this.deps=e,this.mechanism="timed_release"}project(e){return s(e)}buildView(n,s){if("unavailable"===n.phase)return{phase:"unavailable",reason:n.reason};const r=function(t){if(!("mechanism"in t)||"timed_release"!==t.mechanism)throw e.validationError("Timed-release driver received a non-timed-release sequence");return t}(n);switch(r.phase){case"scheduled":return{phase:"scheduled",mechanism:"timed_release",...t(r),distribution:r.distribution,startsAt:r.distribution.startsAt??r.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"timed_release",...t(r),distribution:r.distribution,consumer:r.consumer,loadSelectionOptions:s.loadSelectionOptions,enter:e=>this.enter({selection:e})};case"participating":return{phase:"participating",mechanism:"timed_release",...t(r),consumer:r.consumer,display$:s.displayAtom,leave:()=>this.leave(),complete:()=>this.complete()};case"granted":{const e={phase:"granted",mechanism:"timed_release",...t(r),distribution:r.distribution,consumer:r.consumer,grant:r.grant},{settlement:n}=r,a=r.selection;if("awaiting_assignment"===a.status)return{...e,settlement:n,selection:a};if("internal"===n.processor&&"at_end"===n.mode){const t=i(n,r.pendingAction,s);return t?{...e,settlement:n,selection:a,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim(),payment:t}:{...e,settlement:n,selection:a,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim()}}return"external"===n.processor?{...e,settlement:n,selection:a,loadSelectionOptions:s.loadSelectionOptions,claim:()=>s.claim()}:{...e,settlement:n,selection:a}}case"ended":return{phase:"ended",mechanism:"timed_release",...t(r),consumer:r.consumer,outcome:r.outcome}}}startMonitoring(e){this.activeMonitorId=e.participation.id,this.deps.timedReleases.startMonitoring(e.participation.id,{displayAtom:e.displayAtom},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.timedReleases.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const t=this.currentTimedReleaseSequence("enterable","No open timed release to enter").distribution,i=e?.selection?await this.deps.timedReleases.enter(t.id,void 0,e.selection):await this.deps.timedReleases.enter(t.id,void 0),n=function(e){if("ENTERED"===e.status)return e.admissionGrant?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};return{type:"ended",outcome:{type:"LEFT"===e.status?"left":"denied",reason:"reason"in e?e.reason:void 0}}}(i);if(n)return void this.deps.applyMonitorUpdate(n);const r="ENTERED"===i.status?i.selection:void 0,a={...(o=t.id,{mechanism:"timed_release",status:"entered",id:o,distributionId:o}),...r?{selection:r}:{}};var o;this.deps.ensureDisplayAtom({id:t.id,type:"timed_release"}),this.deps.commit(s({distribution:t,consumer:a})),this.deps.emitEvent("sequence_change","success","user","Entered timed release",{distributionId:t.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentTimedReleaseSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;this.deps.stopRuntimeMonitoring(!0),await this.deps.timedReleases.leave(t),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"timed_release"})}async complete(){await this.deps.runSerializedOperation(async()=>{const e=this.currentTimedReleaseSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id,i=this.deps.timedReleases.complete(t);i?this.deps.applyMonitorUpdate({type:"granted",token:i}):this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"completed"}}),this.deps.emitEvent("sequence_change","success","user","Completed timed release",{timedReleaseId:t})})}currentTimedReleaseSequence(t,i="Not participating in a timed release"){const n=this.deps.getCurrentSequence();if(!n||n.phase!==t||!("mechanism"in n)||"timed_release"!==n.mechanism)throw e.validationError(i);return n}}function o(e){return{status:"not_entered",distributionId:e.id}}function d(e,t,i){return{phase:"ended",mechanism:"timed_release",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()}}}export{n as createTimedReleaseDriver,s as projectTimedReleaseSequence,r as withTimedReleaseTerminalConsumer};
@@ -1,5 +1,5 @@
1
1
  import { AdmissionGrant, GrantedSettlement, SequenceOutcome, TimedReleaseConsumerStatus } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
2
- import { GrantedSelection } from '@fanfare-io/fanfare-sdk-contracts/selection';
2
+ import { GrantedSelection, SelectionMode } from '@fanfare-io/fanfare-sdk-contracts/selection';
3
3
  import { ReadableAtom } from 'nanostores';
4
4
  import { TimedReleaseDisplayState } from '../experiences/distribution-monitor.types';
5
5
  import { DistributionSummary } from '../experiences/journey.types';
@@ -44,6 +44,7 @@ export type TimedReleaseSequence = TimedReleaseScheduled | TimedReleaseEnterable
44
44
  export interface TimedReleaseScheduled {
45
45
  /** Mechanism discriminator for timed release narrowing. */
46
46
  mechanism: "timed_release";
47
+ selectionMode?: SelectionMode;
47
48
  /** Phase discriminator; scheduled timed releases cannot be entered yet. */
48
49
  phase: "scheduled";
49
50
  /** Timed release distribution facts from the journey projector. */
@@ -57,6 +58,7 @@ export interface TimedReleaseScheduled {
57
58
  export interface TimedReleaseEnterable {
58
59
  /** Mechanism discriminator for timed release narrowing. */
59
60
  mechanism: "timed_release";
61
+ selectionMode?: SelectionMode;
60
62
  /** Phase discriminator; `enter()` is legal on the matching view. */
61
63
  phase: "enterable";
62
64
  /** Open timed release distribution facts from the journey projector. */
@@ -72,6 +74,7 @@ export interface TimedReleaseEnterable {
72
74
  export interface TimedReleaseParticipating {
73
75
  /** Mechanism discriminator for timed release narrowing. */
74
76
  mechanism: "timed_release";
77
+ selectionMode?: SelectionMode;
75
78
  /** Phase discriminator; timed release display is live while participating. */
76
79
  phase: "participating";
77
80
  /** Timed release distribution facts from the journey projector. */
@@ -87,6 +90,7 @@ export interface TimedReleaseParticipating {
87
90
  export interface TimedReleaseGranted {
88
91
  /** Mechanism discriminator for timed release narrowing. */
89
92
  mechanism: "timed_release";
93
+ selectionMode?: SelectionMode;
90
94
  /** Phase discriminator; `claim()` is legal on the matching view. */
91
95
  phase: "granted";
92
96
  /** Timed release distribution facts from the journey projector. */
@@ -114,6 +118,7 @@ export interface TimedReleaseGranted {
114
118
  export interface TimedReleaseEnded {
115
119
  /** Mechanism discriminator for timed release narrowing. */
116
120
  mechanism: "timed_release";
121
+ selectionMode?: SelectionMode;
117
122
  /** Phase discriminator; no timed release actions are legal after this phase. */
118
123
  phase: "ended";
119
124
  /** Timed release distribution facts from the journey projector. */
@@ -141,6 +146,7 @@ export interface TimedReleaseScheduledView {
141
146
  phase: "scheduled";
142
147
  /** Mechanism discriminator for timed release rendering. */
143
148
  mechanism: "timed_release";
149
+ selectionMode?: SelectionMode;
144
150
  /** Timed release distribution facts from the journey projector. */
145
151
  distribution: DistributionSummary & {
146
152
  type: "timed_release";
@@ -156,6 +162,7 @@ export interface TimedReleaseEnterableView {
156
162
  phase: "enterable";
157
163
  /** Mechanism discriminator for timed release rendering. */
158
164
  mechanism: "timed_release";
165
+ selectionMode?: SelectionMode;
159
166
  /** Open timed release distribution facts from the journey projector. */
160
167
  distribution: DistributionSummary & {
161
168
  type: "timed_release";
@@ -181,6 +188,7 @@ export interface TimedReleaseParticipatingView {
181
188
  phase: "participating";
182
189
  /** Mechanism discriminator for timed release rendering. */
183
190
  mechanism: "timed_release";
191
+ selectionMode?: SelectionMode;
184
192
  /** Consumer timed release participation facts. */
185
193
  consumer: TimedReleaseSequenceConsumerState;
186
194
  /** Live timed release display facts, such as release timing and availability. */
@@ -209,6 +217,7 @@ interface TimedReleaseGrantedViewBase {
209
217
  phase: "granted";
210
218
  /** Mechanism discriminator for timed release rendering. */
211
219
  mechanism: "timed_release";
220
+ selectionMode?: SelectionMode;
212
221
  /** Timed release distribution facts from the journey projector. */
213
222
  distribution: DistributionSummary & {
214
223
  type: "timed_release";
@@ -279,6 +288,7 @@ export interface TimedReleaseEndedView {
279
288
  phase: "ended";
280
289
  /** Mechanism discriminator for timed release rendering. */
281
290
  mechanism: "timed_release";
291
+ selectionMode?: SelectionMode;
282
292
  /** Consumer timed release facts at the terminal outcome. */
283
293
  consumer: TimedReleaseSequenceConsumerState;
284
294
  /** Server-derived terminal outcome for the timed release participation. */
@@ -290,6 +300,7 @@ export interface TimedReleaseGrantedAwaitingAssignmentView {
290
300
  phase: "granted";
291
301
  /** Mechanism discriminator. */
292
302
  mechanism: "timed_release";
303
+ selectionMode?: SelectionMode;
293
304
  /** Distribution associated with this grant. */
294
305
  distribution: DistributionSummary & {
295
306
  type: "timed_release";
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * SDK version
3
3
  * This is automatically updated during the build process
4
4
  */
5
- export declare const version = "0.17.0";
5
+ export declare const version = "0.19.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.17.0";export{o as version};
1
+ const o="0.19.0";export{o as version};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanfare-io/fanfare-sdk-core",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Official Fanfare Browser SDK for queue, draw, auction, and appointment experiences",
5
5
  "publishConfig": {
6
6
  "registry": "https://registry.npmjs.org",
@@ -115,7 +115,7 @@
115
115
  "uuid": "^14.0.0",
116
116
  "wretch": "^2.11.0",
117
117
  "zustand": "^5.0.6",
118
- "@fanfare-io/fanfare-sdk-contracts": "0.17.0"
118
+ "@fanfare-io/fanfare-sdk-contracts": "0.19.0"
119
119
  },
120
120
  "peerDependencies": {
121
121
  "valibot": "^1.1.0"
@@ -154,7 +154,7 @@
154
154
  "vite-plugin-dts": "^4.5.4",
155
155
  "vite-tsconfig-paths": "^5.1.4",
156
156
  "vitest": "^5.0.0",
157
- "@fanfare-io/shared-models": "0.17.0"
157
+ "@fanfare-io/shared-models": "0.19.0"
158
158
  },
159
159
  "sideEffects": false,
160
160
  "keywords": [