@fanfare-io/fanfare-sdk-core 0.22.0 → 0.24.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.
- package/dist/adapters/google-analytics.js +1 -1
- package/dist/auctions/auction.driver.js +1 -1
- package/dist/auth/auth.module.js +1 -1
- package/dist/auth/types.d.ts +12 -0
- package/dist/core/client.js +2 -2
- package/dist/core/internal-sdk-registry.d.ts +14 -0
- package/dist/core/internal-sdk-registry.js +1 -0
- package/dist/core/money.js +1 -1
- package/dist/experiences/dom-bridge.js +1 -1
- package/dist/experiences/journey.js +1 -1
- package/dist/experiences/public.d.ts +1 -1
- package/dist/experiences/types.d.ts +13 -0
- package/dist/internals.d.ts +1 -0
- package/dist/internals.js +1 -1
- package/dist/queues/queue.module.js +1 -1
- package/dist/queues/types.d.ts +3 -2
- package/dist/state/events.d.ts +1 -1
- package/dist/sync/cross-tab-coordinator.js +1 -1
- package/dist/sync/protocol.js +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={"experience:entered":"fanfare_experience_entered","experience:left":"fanfare_experience_left","experience:distribution-entered":"fanfare_distribution_entered","queue:entered":"fanfare_queue_entered","queue:granted":"fanfare_queue_granted","queue:left":"fanfare_queue_left","queue:expired":"fanfare_queue_expired","draw:entered":"fanfare_draw_entered","draw:won":"fanfare_draw_won","draw:lost":"fanfare_draw_lost","auction:entered":"fanfare_auction_entered","auction:bid-placed":"fanfare_auction_bid_placed","auction:outbid":"fanfare_auction_outbid","auction:won":"fanfare_auction_won","auction:lost":"fanfare_auction_lost","waitlist:entered":"fanfare_waitlist_entered","waitlist:left":"fanfare_waitlist_left","timed_release:entered":"fanfare_timed_release_entered","timed_release:completed":"fanfare_timed_release_completed","auth:authenticated":"fanfare_auth_authenticated"},t=Object.keys(e),i={"experience:entered":e=>({experience_id:String(e.experienceId??"")}),"experience:left":e=>({experience_id:String(e.experienceId??"")}),"experience:distribution-entered":e=>({distribution_type:String(e.distributionType??""),distribution_id:String(e.distributionId??"")}),"queue:entered":e=>({queue_id:String(e.queueId??"")
|
|
1
|
+
const e={"experience:entered":"fanfare_experience_entered","experience:left":"fanfare_experience_left","experience:distribution-entered":"fanfare_distribution_entered","queue:entered":"fanfare_queue_entered","queue:granted":"fanfare_queue_granted","queue:left":"fanfare_queue_left","queue:expired":"fanfare_queue_expired","draw:entered":"fanfare_draw_entered","draw:won":"fanfare_draw_won","draw:lost":"fanfare_draw_lost","auction:entered":"fanfare_auction_entered","auction:bid-placed":"fanfare_auction_bid_placed","auction:outbid":"fanfare_auction_outbid","auction:won":"fanfare_auction_won","auction:lost":"fanfare_auction_lost","waitlist:entered":"fanfare_waitlist_entered","waitlist:left":"fanfare_waitlist_left","timed_release:entered":"fanfare_timed_release_entered","timed_release:completed":"fanfare_timed_release_completed","auth:authenticated":"fanfare_auth_authenticated"},t=Object.keys(e),i={"experience:entered":e=>({experience_id:String(e.experienceId??"")}),"experience:left":e=>({experience_id:String(e.experienceId??"")}),"experience:distribution-entered":e=>({distribution_type:String(e.distributionType??""),distribution_id:String(e.distributionId??"")}),"queue:entered":e=>({queue_id:String(e.queueId??""),...null!=e.position?{position:Number(e.position)}:{},...null!=e.estimatedWaitTime?{estimated_wait_time:Number(e.estimatedWaitTime)}:{}}),"queue:granted":e=>({queue_id:String(e.queueId??"")}),"queue:left":e=>({queue_id:String(e.queueId??""),...e.reason?{reason:String(e.reason)}:{}}),"queue:expired":e=>({queue_id:String(e.queueId??"")}),"draw:entered":e=>({draw_id:String(e.drawId??""),...e.entryNumber?{entry_number:String(e.entryNumber)}:{}}),"draw:won":e=>({draw_id:String(e.drawId??"")}),"draw:lost":e=>({draw_id:String(e.drawId??"")}),"auction:entered":e=>({auction_id:String(e.auctionId??"")}),"auction:bid-placed":e=>({auction_id:String(e.auctionId??""),amount:String(e.amount??""),status:String(e.status??"")}),"auction:outbid":e=>({auction_id:String(e.auctionId??""),your_bid:String(e.yourBid??""),highest_bid:String(e.highestBid??"")}),"auction:won":e=>({auction_id:String(e.auctionId??""),winning_bid:String(e.winningBid??"")}),"auction:lost":e=>({auction_id:String(e.auctionId??""),highest_bid:String(e.highestBid??"")}),"waitlist:entered":e=>({waitlist_id:String(e.waitlistId??""),sequence_id:String(e.sequenceId??"")}),"waitlist:left":e=>({waitlist_id:String(e.waitlistId??"")}),"timed_release:entered":e=>({timed_release_id:String(e.timedReleaseId??"")}),"timed_release:completed":e=>({timed_release_id:String(e.timedReleaseId??"")}),"auth:authenticated":e=>({is_new:Boolean(e.isNew)})};function n(n){const r=[];return{id:"google-analytics",init(a,d){if(r.length>0)throw new Error("GA adapter already initialized. Create a new adapter instance per SDK via createGAAdapter().");const u=[...new Set(d?.events??n?.events??t)];for(const t of u){const d=e[t];if(!d)continue;const u=a.on(t,e=>{if("undefined"==typeof window||"function"!=typeof window.gtag)return;const r=i[t],a={fanfare_event:t,...r?r(e):{},...n?.measurementId?{send_to:n.measurementId}:{}};window.gtag("event",d,a)});r.push(u)}},destroy(){for(const e of r)e();r.length=0}}}export{n as createGAAdapter};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as e}from"../core/errors.js";import{readEntrySelectionRequirement as i}from"../experiences/selection-requirement.js";import{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 r(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function a(t){return new d(t)}function c(i){const{distribution:n,consumer:s,grant:a,settlement:c,selection:u,outcome:d}=i;if(!n)return{phase:"unavailable"};const l=function(t){if("auction"!==t.type)throw e.validationError("Auction driver received a non-auction distribution");return t}(n),h=s&&"auction"===s.mechanism?function(t){const{mechanism:e,...i}=t;return i}(s):p(n);if(a)return"completed"===d?.type?m(l,h,d):a.expiresAt&&Date.now()>new Date(a.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:a,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===l.lifecycle){if("not_bid"===h.status&&l.result===t.FLOOR_UNSOLD&&r(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);return b?m(l,h,b):"settling"===l.lifecycle?{phase:"settling",mechanism:"auction",distribution:l,consumer:h}:o(h)?{phase:"participating",mechanism:"auction",distribution:l,consumer:h}:"scheduled"===l.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:l}:"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:h}:m(l,h,{type:"closed"})}function u(t,e,i){return t&&"auction"===t.mechanism&&e?"won"===e.type?{...t,status:"won"}:!i?.finalize&&"not_bid"===t.status&&r(e)?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 e.validationError("Auction driver received a non-auction sequence");return t}(t);switch(o.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:o.distribution,startsAt:o.distribution.startsAt??o.distribution.opensAt};case"enterable":{const t={phase:"enterable",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,display$:s.displayAtom};return i(o.distribution.details)?{...t,selection:{required:!0},loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)}:{...t,selection:{required:!1},bid:t=>this.bid(t)}}case"participating":return{phase:"participating",mechanism:"auction",consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:o.distribution,consumer:o.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,grant:o.grant},{settlement:e}=o,i=o.selection;if("awaiting_assignment"===i.status)return{...t,settlement:e,selection:i};if("required"===i.status)return{...t,settlement:e,selection:i,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===e.processor&&"at_end"===e.mode){const r=n(e,o.pendingAction,s);return r?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:r}:{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return"external"===e.processor?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",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 n=this.currentAuctionSequenceForBid(),o=n.consumer.distributionId??n.consumer.id??n.distribution.id,r="auction"===n.distribution.details?.type?n.distribution.details:void 0,a=n.consumer.selection,u=i(n.distribution.details),d="enterable"===n.phase;if(d&&u&&!t.selection)throw e.validationError("A product selection is required to enter");const p=d?u?t.selection:void 0:a,{selection:m,...h}=t,b=p?{...h,selection:p}:h;l(b,r?.auctionType);const f=await this.deps.auctions.bid(o,b),g=this.deps.getCurrentSequence(),y=g&&("enterable"===g.phase||"participating"===g.phase||"settling"===g.phase)&&"mechanism"in g&&"auction"===g.mechanism&&g.distribution.id===o;if("won"===f.status||"lost"===f.status)return void(y&&("won"===f.status&&f.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:f.admissionGrant}):"lost"===f.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):s(f)||this.deps.applyMonitorUpdate({type:"resync"})));if(!y)return;const v=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(f.status);if(void 0===v)return;const w=void 0!==f.selection?.variantId?{productId:f.selection.productId,variantId:f.selection.variantId}:p,S=a??w;this.deps.commit(c({distribution:n.distribution,consumer:{..."participating"===n.phase?n.consumer:{},mechanism:"auction",status:v,id:o,distributionId:o,...S?{selection:S}:{},currentBid:f.amount,highestBid:f.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw e.validationError("No auction is available to bid on");return t}}function l(t,i){if("dutch"!==i){if(void 0===t.amount)throw e.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw e.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,e,i){return{phase:"ended",mechanism:"auction",distribution:t,consumer:e,outcome:{...i,distributionType:i.distributionType??t.type,distributionId:i.distributionId??t.id,at:i.at??/* @__PURE__ */(new Date).toISOString()}}}export{l as assertBidInputMatchesMechanism,a as createAuctionDriver,r as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionTerminalConsumer};
|
|
1
|
+
import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as e}from"../core/errors.js";import{readEntrySelectionRequirement as i}from"../experiences/selection-requirement.js";import{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 r(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function a(t){return new d(t)}function c(i){const{distribution:n,consumer:s,grant:a,settlement:c,selection:u,outcome:d}=i;if(!n)return{phase:"unavailable"};const l=function(t){if("auction"!==t.type)throw e.validationError("Auction driver received a non-auction distribution");return t}(n),h=s&&"auction"===s.mechanism?function(t){const{mechanism:e,...i}=t;return i}(s):p(n);if(a)return"completed"===d?.type?m(l,h,d):a.expiresAt&&Date.now()>new Date(a.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:a,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===l.lifecycle){if("not_bid"===h.status&&l.result===t.FLOOR_UNSOLD&&r(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);return b?m(l,h,b):"settling"===l.lifecycle?{phase:"settling",mechanism:"auction",distribution:l,consumer:h}:o(h)?{phase:"participating",mechanism:"auction",distribution:l,consumer:h}:"scheduled"===l.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:l}:"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:h}:m(l,h,{type:"closed"})}function u(t,e,i){return t&&"auction"===t.mechanism&&e?"won"===e.type?{...t,status:"won"}:!i?.finalize&&"not_bid"===t.status&&r(e)?t:{...t,status:"lost"}:t}class d{constructor(t){this.deps=t,this.mechanism="auction",this.settlementCanStartWhileActive=!0}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 e.validationError("Auction driver received a non-auction sequence");return t}(t);switch(o.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:o.distribution,startsAt:o.distribution.startsAt??o.distribution.opensAt};case"enterable":{const t={phase:"enterable",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,display$:s.displayAtom};return i(o.distribution.details)?{...t,selection:{required:!0},loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)}:{...t,selection:{required:!1},bid:t=>this.bid(t)}}case"participating":return{phase:"participating",mechanism:"auction",consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:o.distribution,consumer:o.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,grant:o.grant},{settlement:e}=o,i=o.selection;if("awaiting_assignment"===i.status)return{...t,settlement:e,selection:i};if("required"===i.status)return{...t,settlement:e,selection:i,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===e.processor&&"at_end"===e.mode){const r=n(e,o.pendingAction,s);return r?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:r}:{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return"external"===e.processor?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",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 n=this.currentAuctionSequenceForBid(),o=n.consumer.distributionId??n.consumer.id??n.distribution.id,r="auction"===n.distribution.details?.type?n.distribution.details:void 0,a=n.consumer.selection,u=i(n.distribution.details),d="enterable"===n.phase;if(d&&u&&!t.selection)throw e.validationError("A product selection is required to enter");const p=d?u?t.selection:void 0:a,{selection:m,...h}=t,b=p?{...h,selection:p}:h;l(b,r?.auctionType);const f=await this.deps.auctions.bid(o,b),g=this.deps.getCurrentSequence(),y=g&&("enterable"===g.phase||"participating"===g.phase||"settling"===g.phase)&&"mechanism"in g&&"auction"===g.mechanism&&g.distribution.id===o;if("won"===f.status||"lost"===f.status)return void(y&&("won"===f.status&&f.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:f.admissionGrant}):"lost"===f.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):s(f)||this.deps.applyMonitorUpdate({type:"resync"})));if(!y)return;const v=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(f.status);if(void 0===v)return;const w=void 0!==f.selection?.variantId?{productId:f.selection.productId,variantId:f.selection.variantId}:p,S=a??w;this.deps.commit(c({distribution:n.distribution,consumer:{..."participating"===n.phase?n.consumer:{},mechanism:"auction",status:v,id:o,distributionId:o,...S?{selection:S}:{},currentBid:f.amount,highestBid:f.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw e.validationError("No auction is available to bid on");return t}}function l(t,i){if("dutch"!==i){if(void 0===t.amount)throw e.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw e.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,e,i){return{phase:"ended",mechanism:"auction",distribution:t,consumer:e,outcome:{...i,distributionType:i.distributionType??t.type,distributionId:i.distributionId??t.id,at:i.at??/* @__PURE__ */(new Date).toISOString()}}}export{l as assertBidInputMatchesMechanism,a as createAuctionDriver,r as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionTerminalConsumer};
|
package/dist/auth/auth.module.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"valibot";import{FanfareError as t}from"../core/errors.js";import{getLogger as s}from"../core/logger.js";import{parseResponse as r}from"../core/parse-response.js";import{loadRefreshToken as o,clearRefreshToken as i,clearLegacySessionTokens as n,buildAdmissionProofHeaders as a,persistRefreshToken as h}from"../security/admission-proof.js";import{getEventBus as c}from"../state/events.js";import{getSDKStore as g}from"../state/store.js";import{BroadcastChannelTransport as f}from"../sync/broadcast-transport.js";const l=e.object({accessToken:e.pipe(e.string(),e.minLength(1)),refreshToken:e.optional(e.pipe(e.string(),e.minLength(1))),beaconToken:e.pipe(e.string(),e.minLength(1)),accessTokenExpiresAt:e.optional(e.string()),refreshTokenTtlSeconds:e.optional(e.number())});function u(e){const t={};for(const[s,r]of Object.entries(e))"string"==typeof r&&(t[s]=r);return t}class p{constructor(e,t){this.logger=s(),this.store=g(),this.events=c(),this.lastBroadcastTokens=null,this.http=e,this.beaconHttp=t,this.setupTokenChannel(),this.http.updateConfig({...this.http.getConfig(),onUnauthorized:async()=>{await this.handleUnauthorized()}});const r=this.store.beaconToken;r&&this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":r}})}setupTokenChannel(){const e=new f("fanfare-auth-tokens");e.isAvailable()&&(this.authChannel=e,e.onMessage(e=>{const t=e.data;t&&"string"==typeof t.accessToken&&"string"==typeof t.beaconToken&&"string"==typeof t.refreshToken&&(this.lastBroadcastTokens={accessToken:t.accessToken,beaconToken:t.beaconToken,refreshToken:t.refreshToken})}))}broadcastSessionTokens(e){this.authChannel?.send(e)}check(){const e=this.store.session;return e?{isAuthenticated:!0,session:e,isGuest:"guest"===e.type,identityExpiresAt:e.identityExpiresAt}:{isAuthenticated:!1}}async guest(){try{this.logger.info("Creating guest session");const e=await this.sessionMintProofHeaders("/auth/guest"),{session:t,accessToken:s,refreshToken:r,beaconToken:o,refreshTokenTtlSeconds:i}=await this.http.post("/auth/guest",void 0,{headers:e});return this.attachIdentityExpiresAt(t,i),this.store.setSession(t),await this.setRefreshTokenDurable(r??null),this.store.setBeaconToken(o),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${s}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":o}}),this.scheduleTokenRefresh(t.expiresAt),this.events.emit("auth:authenticated",{session:t,isNew:!0}),t}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Failed to create guest session",t),this.events.emit("auth:error",{error:t,context:"guest"}),t}}async requestOtp(e){try{this.logger.info("Requesting OTP");const t="string"==typeof e?{email:e}:e;await this.http.post("/auth/otp/request",t)}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to request OTP",e),this.events.emit("auth:error",{error:e,context:"requestOtp"}),e}}async verifyOtp(e){try{const t=e;this.logger.info("Verifying OTP",{email:t.email,phone:t.phone});const s=await this.sessionMintProofHeaders("/auth/otp/verify"),{session:r,accessToken:o,refreshToken:i,beaconToken:n,refreshTokenTtlSeconds:a}=await this.http.post("/auth/otp/verify",t,{headers:s});return this.attachIdentityExpiresAt(r,a),this.store.setSession(r),await this.setRefreshTokenDurable(i??null),this.store.setBeaconToken(n),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${o}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":n}}),this.scheduleTokenRefresh(r.expiresAt),this.events.emit("auth:authenticated",{session:r,isNew:!0}),r}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to verify OTP",e),this.events.emit("auth:error",{error:e,context:"verifyOtp"}),e}}async exchangeExternal(e){try{const t="string"==typeof e?{exchangeCode:e}:e;this.logger.info("Exchanging external auth code");const s=await this.sessionMintProofHeaders("/auth/external/exchange"),{session:r,accessToken:o,refreshToken:i,beaconToken:n,refreshTokenTtlSeconds:a}=await this.http.post("/auth/external/exchange",t,{headers:s});return this.attachIdentityExpiresAt(r,a),this.store.setSession(r),await this.setRefreshTokenDurable(i??null),this.store.setBeaconToken(n),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${o}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":n}}),this.scheduleTokenRefresh(r.expiresAt),this.events.emit("auth:authenticated",{session:r,isNew:!0}),r}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to exchange external auth code",e),this.events.emit("auth:error",{error:e,context:"exchangeExternal"}),e}}async login(e){await this.requestOtp({email:e.email})}async logout(){try{if(!this.store.session)return;const e=this.store.refreshToken??await o();await this.http.post("/auth/logout",e?{refreshToken:e}:{},{skipUnauthorizedHandler:!0}).catch(()=>{}),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"user"})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Error during logout",t),this.store.clearAll(),this.lastBroadcastTokens=null,await i(),t}}async clearAuthState(){this.cancelTokenRefresh(),this.store.clearAll(),this.lastBroadcastTokens=null,await i();const e=this.http.getConfig(),{Authorization:t,...s}=e.headers||{};this.http.updateConfig({...e,headers:s});const r=this.beaconHttp.getConfig(),{"X-Beacon-Token":o,...n}=r.headers||{};this.beaconHttp.updateConfig({...r,headers:n})}getSession(){return this.store.session}async rehydrate(){const e=await o();if(n(),!e)return;if(this.store.setRefreshToken(e),!this.hasBearer()){try{await this.refresh()}catch(s){this.logger.debug("Eager rehydrate refresh failed; falling back to reactive 401",{error:s instanceof Error?s.message:String(s)})}return}const t=this.store.session;t?.expiresAt&&this.scheduleTokenRefresh(t.expiresAt)}hasBearer(){return Boolean(this.http.getConfig().headers?.Authorization)}async refresh(){if("undefined"!=typeof navigator&&"locks"in navigator){const e=await o(),t=e??this.store.refreshToken;return navigator.locks.request("fanfare-refresh",()=>this._doRefresh(t,e))}return this.refreshPromise?(this.logger.debug("Refresh already in progress, returning existing promise"),this.refreshPromise):(this.refreshPromise=this._doRefresh().finally(()=>{this.refreshPromise=void 0}),this.refreshPromise)}absoluteAuthUrl(e){return new URL(e,this.http.getConfig().baseUrl).toString()}async sessionMintProofHeaders(e){const t=await a({url:this.absoluteAuthUrl(e),method:"POST"});return t?u(t):{}}computeIdentityExpiresAt(e){if("number"==typeof e&&Number.isFinite(e))return new Date(Date.now()+1e3*e).toISOString()}attachIdentityExpiresAt(e,t){const s=this.computeIdentityExpiresAt(t);s&&(e.identityExpiresAt=s)}async setRefreshTokenDurable(e){this.store.setRefreshToken(e),e?await h(e):await i()}applySessionTokens(e){this.store.setBeaconToken(e.beaconToken),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${e.accessToken}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":e.beaconToken}});const t=this.store.session;t?.expiresAt&&this.scheduleTokenRefresh(t.expiresAt),this.store.session&&this.events.emit("auth:refreshed",{session:this.store.session})}async _doRefresh(e,s){const i=await o(),n=i??this.store.refreshToken;if(null!==i&&i!==this.store.refreshToken&&this.store.setRefreshToken(i),!n)throw this.logger.info("No refresh token available; clearing auth state"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("No refresh token available");if(s&&null===i)throw this.logger.debug("Durable refresh token cleared by a concurrent caller; skipping re-POST"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("Refresh token cleared by a concurrent caller");if(void 0!==e&&null!==i&&i!==e){this.logger.debug("Refresh already completed by a concurrent caller; adopting rotated session");const e=this.lastBroadcastTokens;return void(e&&e.refreshToken===i?this.applySessionTokens(e):this.store.session&&this.events.emit("auth:refreshed",{session:this.store.session}))}const h=await a({url:this.absoluteAuthUrl("/auth/refresh"),method:"POST"});if(!h)throw this.logger.info("No DPoP proof available for refresh; clearing auth state"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("DPoP proof unavailable for refresh");try{this.logger.info("Refreshing access token");const e=await this.http.post("/auth/refresh",{refreshToken:n},{headers:u(h),skipUnauthorizedHandler:!0}),t=r(l,e,{endpoint:"/auth/refresh"},{throwOnFailure:!0});if(!t.ok)throw t.error;const{accessToken:s,refreshToken:o,beaconToken:i,accessTokenExpiresAt:a,refreshTokenTtlSeconds:c}=t.value;if(await this.setRefreshTokenDurable(o??null),o&&this.broadcastSessionTokens({accessToken:s,beaconToken:i,refreshToken:o}),a){const e=this.computeIdentityExpiresAt(c);e?this.store.updateSessionExpiry(a,e):this.store.updateSessionExpiry(a)}this.applySessionTokens({accessToken:s,beaconToken:i})}catch(c){const e=c instanceof Error?c:new Error(String(c)),s=c instanceof t?c.status:void 0;throw 401===s?(this.logger.error("Refresh rejected as unauthorized; clearing auth state",e),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"})):this.logger.warn("Refresh failed transiently; preserving durable refresh token",{status:s,error:e.message}),e}}async handleUnauthorized(){this.logger.warn("Received 401, attempting to refresh token");try{await this.refresh()}catch(e){const t=e instanceof Error?e:new Error(String(e));this.logger.error("Failed to handle 401",t),this.events.emit("auth:error",{error:new Error("Session expired"),context:"unauthorized"})}}scheduleTokenRefresh(e){if(this.cancelTokenRefresh(),!this.store.refreshToken)return;const t=Date.now(),s=new Date(e).getTime(),r=Number.isFinite(s),o=r?Math.max(s-3e5-t,3e4):3e4;this.logger.debug("Scheduling token refresh",{expiresAt:r?new Date(s).toISOString():"invalid",delayMs:o}),this.refreshTimer=setTimeout(()=>{this.refresh().catch(e=>{this.logger.error("Scheduled token refresh failed",e)})},o)}cancelTokenRefresh(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=void 0,this.logger.debug("Cancelled token refresh timer"))}destroy(){this.cancelTokenRefresh(),this.refreshPromise=void 0,this.authChannel?.close(),this.authChannel=void 0}}export{p as AuthenticationModule};
|
|
1
|
+
import*as e from"valibot";import{FanfareError as t}from"../core/errors.js";import{getLogger as s}from"../core/logger.js";import{parseResponse as r}from"../core/parse-response.js";import{loadRefreshToken as o,clearRefreshToken as i,clearLegacySessionTokens as n,buildAdmissionProofHeaders as a,persistRefreshToken as h}from"../security/admission-proof.js";import{getEventBus as c}from"../state/events.js";import{getSDKStore as g}from"../state/store.js";import{BroadcastChannelTransport as f}from"../sync/broadcast-transport.js";const l=e.object({accessToken:e.pipe(e.string(),e.minLength(1)),refreshToken:e.optional(e.pipe(e.string(),e.minLength(1))),beaconToken:e.pipe(e.string(),e.minLength(1)),accessTokenExpiresAt:e.optional(e.string()),refreshTokenTtlSeconds:e.optional(e.number())});function u(e){const t={};for(const[s,r]of Object.entries(e))"string"==typeof r&&(t[s]=r);return t}class d{constructor(e,t){this.logger=s(),this.store=g(),this.events=c(),this.lastBroadcastTokens=null,this.http=e,this.beaconHttp=t,this.setupTokenChannel(),this.http.updateConfig({...this.http.getConfig(),onUnauthorized:async()=>{await this.handleUnauthorized()}});const r=this.store.beaconToken;r&&this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":r}})}setupTokenChannel(){const e=new f("fanfare-auth-tokens");e.isAvailable()&&(this.authChannel=e,e.onMessage(e=>{const t=e.data;t&&"string"==typeof t.accessToken&&"string"==typeof t.beaconToken&&"string"==typeof t.refreshToken&&(this.lastBroadcastTokens={accessToken:t.accessToken,beaconToken:t.beaconToken,refreshToken:t.refreshToken})}))}broadcastSessionTokens(e){this.authChannel?.send(e)}check(){const e=this.store.session;return e?{isAuthenticated:!0,session:e,isGuest:"guest"===e.type,identityExpiresAt:e.identityExpiresAt}:{isAuthenticated:!1}}async guest(){try{this.logger.info("Creating guest session");const e=await this.sessionMintProofHeaders("/auth/guest"),{session:t,accessToken:s,refreshToken:r,beaconToken:o,refreshTokenTtlSeconds:i}=await this.http.post("/auth/guest",void 0,{headers:e});return this.attachIdentityExpiresAt(t,i),this.store.setSession(t),await this.setRefreshTokenDurable(r??null),this.store.setBeaconToken(o),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${s}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":o}}),this.scheduleTokenRefresh(t.expiresAt),this.events.emit("auth:authenticated",{session:t,isNew:!0}),t}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Failed to create guest session",t),this.events.emit("auth:error",{error:t,context:"guest"}),t}}async requestOtp(e){try{this.logger.info("Requesting OTP");const t="string"==typeof e?{email:e}:e;await this.http.post("/auth/otp/request",t)}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to request OTP",e),this.events.emit("auth:error",{error:e,context:"requestOtp"}),e}}async verifyOtp(e){try{const t=e;this.logger.info("Verifying OTP",{credential:t.email?"email":"phone"});const s=await this.sessionMintProofHeaders("/auth/otp/verify"),{session:r,accessToken:o,refreshToken:i,beaconToken:n,refreshTokenTtlSeconds:a}=await this.http.post("/auth/otp/verify",t,{headers:s});return this.attachIdentityExpiresAt(r,a),this.store.setSession(r),await this.setRefreshTokenDurable(i??null),this.store.setBeaconToken(n),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${o}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":n}}),this.scheduleTokenRefresh(r.expiresAt),this.events.emit("auth:authenticated",{session:r,isNew:!0}),r}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to verify OTP",e),this.events.emit("auth:error",{error:e,context:"verifyOtp"}),e}}async exchangeExternal(e){try{const t="string"==typeof e?{exchangeCode:e}:e;this.logger.info("Exchanging external auth code");const s=await this.sessionMintProofHeaders("/auth/external/exchange"),{session:r,accessToken:o,refreshToken:i,beaconToken:n,refreshTokenTtlSeconds:a}=await this.http.post("/auth/external/exchange",t,{headers:s});return this.attachIdentityExpiresAt(r,a),this.store.setSession(r),await this.setRefreshTokenDurable(i??null),this.store.setBeaconToken(n),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${o}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":n}}),this.scheduleTokenRefresh(r.expiresAt),this.events.emit("auth:authenticated",{session:r,isNew:!0}),r}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to exchange external auth code",e),this.events.emit("auth:error",{error:e,context:"exchangeExternal"}),e}}async login(e){await this.requestOtp({email:e.email})}async logout(){try{if(!this.store.session)return;const e=this.store.refreshToken??await o();await this.http.post("/auth/logout",e?{refreshToken:e}:{},{skipUnauthorizedHandler:!0}).catch(()=>{}),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"user"})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Error during logout",t),this.store.clearAll(),this.lastBroadcastTokens=null,await i(),t}}async clearAuthState(){this.cancelTokenRefresh(),this.store.clearAll(),this.lastBroadcastTokens=null,await i();const e=this.http.getConfig(),{Authorization:t,...s}=e.headers||{};this.http.updateConfig({...e,headers:s});const r=this.beaconHttp.getConfig(),{"X-Beacon-Token":o,...n}=r.headers||{};this.beaconHttp.updateConfig({...r,headers:n})}getSession(){return this.store.session}async rehydrate(){const e=await o();if(n(),!e)return;if(this.store.setRefreshToken(e),!this.hasBearer()){try{await this.refresh()}catch(s){this.logger.debug("Eager rehydrate refresh failed; falling back to reactive 401",{error:s instanceof Error?s.message:String(s)})}return}const t=this.store.session;t?.expiresAt&&this.scheduleTokenRefresh(t.expiresAt)}hasBearer(){return Boolean(this.http.getConfig().headers?.Authorization)}async refresh(){if("undefined"!=typeof navigator&&"locks"in navigator){const e=await o(),t=e??this.store.refreshToken;return navigator.locks.request("fanfare-refresh",()=>this._doRefresh(t,e))}return this.refreshPromise?(this.logger.debug("Refresh already in progress, returning existing promise"),this.refreshPromise):(this.refreshPromise=this._doRefresh().finally(()=>{this.refreshPromise=void 0}),this.refreshPromise)}absoluteAuthUrl(e){return new URL(e,this.http.getConfig().baseUrl).toString()}async sessionMintProofHeaders(e){const t=await a({url:this.absoluteAuthUrl(e),method:"POST"});return t?u(t):{}}computeIdentityExpiresAt(e){if("number"==typeof e&&Number.isFinite(e))return new Date(Date.now()+1e3*e).toISOString()}attachIdentityExpiresAt(e,t){const s=this.computeIdentityExpiresAt(t);s&&(e.identityExpiresAt=s)}async setRefreshTokenDurable(e){this.store.setRefreshToken(e),e?await h(e):await i()}applySessionTokens(e){this.store.setBeaconToken(e.beaconToken),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${e.accessToken}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":e.beaconToken}});const t=this.store.session;t?.expiresAt&&this.scheduleTokenRefresh(t.expiresAt),this.store.session&&this.events.emit("auth:refreshed",{session:this.store.session})}async _doRefresh(e,s){const i=await o(),n=i??this.store.refreshToken;if(null!==i&&i!==this.store.refreshToken&&this.store.setRefreshToken(i),!n)throw this.logger.info("No refresh token available; clearing auth state"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("No refresh token available");if(s&&null===i)throw this.logger.debug("Durable refresh token cleared by a concurrent caller; skipping re-POST"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("Refresh token cleared by a concurrent caller");if(void 0!==e&&null!==i&&i!==e){this.logger.debug("Refresh already completed by a concurrent caller; adopting rotated session");const e=this.lastBroadcastTokens;return void(e&&e.refreshToken===i?this.applySessionTokens(e):this.store.session&&this.events.emit("auth:refreshed",{session:this.store.session}))}const h=await a({url:this.absoluteAuthUrl("/auth/refresh"),method:"POST"});if(!h)throw this.logger.info("No DPoP proof available for refresh; clearing auth state"),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"}),new Error("DPoP proof unavailable for refresh");try{this.logger.info("Refreshing access token");const e=await this.http.post("/auth/refresh",{refreshToken:n},{headers:u(h),skipUnauthorizedHandler:!0}),t=r(l,e,{endpoint:"/auth/refresh"},{throwOnFailure:!0});if(!t.ok)throw t.error;const{accessToken:s,refreshToken:o,beaconToken:i,accessTokenExpiresAt:a,refreshTokenTtlSeconds:c}=t.value;if(await this.setRefreshTokenDurable(o??null),o&&this.broadcastSessionTokens({accessToken:s,beaconToken:i,refreshToken:o}),a){const e=this.computeIdentityExpiresAt(c);e?this.store.updateSessionExpiry(a,e):this.store.updateSessionExpiry(a)}this.applySessionTokens({accessToken:s,beaconToken:i})}catch(c){const e=c instanceof Error?c:new Error(String(c)),s=c instanceof t?c.status:void 0;throw 401===s?(this.logger.error("Refresh rejected as unauthorized; clearing auth state",e),await this.clearAuthState(),this.events.emit("auth:logout",{reason:"expired"})):this.logger.warn("Refresh failed transiently; preserving durable refresh token",{status:s,error:e.message}),e}}async handleUnauthorized(){this.logger.warn("Received 401, attempting to refresh token");try{await this.refresh()}catch(e){const t=e instanceof Error?e:new Error(String(e));this.logger.error("Failed to handle 401",t),this.events.emit("auth:error",{error:new Error("Session expired"),context:"unauthorized"})}}scheduleTokenRefresh(e){if(this.cancelTokenRefresh(),!this.store.refreshToken)return;const t=Date.now(),s=new Date(e).getTime(),r=Number.isFinite(s),o=r?Math.max(s-3e5-t,3e4):3e4;this.logger.debug("Scheduling token refresh",{expiresAt:r?new Date(s).toISOString():"invalid",delayMs:o}),this.refreshTimer=setTimeout(()=>{this.refresh().catch(e=>{this.logger.error("Scheduled token refresh failed",e)})},o)}cancelTokenRefresh(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=void 0,this.logger.debug("Cancelled token refresh timer"))}destroy(){this.cancelTokenRefresh(),this.refreshPromise=void 0,this.authChannel?.close(),this.authChannel=void 0}}export{d as AuthenticationModule};
|
package/dist/auth/types.d.ts
CHANGED
|
@@ -67,6 +67,18 @@ export interface OtpVerify {
|
|
|
67
67
|
phone?: string;
|
|
68
68
|
code: string;
|
|
69
69
|
defaultCountry?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Marketing SMS consent, recorded only on a phone verify, against the number the
|
|
72
|
+
* code just proved; ignored on an email verify. Send true only when the consumer
|
|
73
|
+
* ticked the consent box on this step.
|
|
74
|
+
*/
|
|
75
|
+
marketingSmsConsent?: boolean;
|
|
76
|
+
/**
|
|
77
|
+
* The experience the consumer is verifying on, validated against the caller's
|
|
78
|
+
* organization server-side. It records where consent was given; it does not
|
|
79
|
+
* restrict the session to that experience.
|
|
80
|
+
*/
|
|
81
|
+
experienceId?: string;
|
|
70
82
|
}
|
|
71
83
|
export interface ExternalExchange {
|
|
72
84
|
exchangeCode: string;
|
package/dist/core/client.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createBeaconLifecycleAdapter as e}from"../adapters/beacon-lifecycle.js";import{AppointmentManagementModule as t}from"../appointments/appointment.module.js";import{AuctionManagementModule as r}from"../auctions/auction.module.js";import{AuthenticationModule as n}from"../auth/auth.module.js";import{BeaconTrackingModule as i}from"../beacon/beacon.module.js";import{ChallengeManagementModule as o}from"../challenges/challenge.module.js";import{Config as s}from"../config/index.js";import{DrawManagementModule as a}from"../draws/draw.module.js";import{ExperienceManagementModule as d}from"../experiences/experience.module.js";import{ExperienceJourney as l}from"../experiences/journey.js";import{PaymentMethodManagementModule as c}from"../payment/payment.module.js";import{QueueManagementModule as u}from"../queues/queue.module.js";import{SelectionModule as g}from"../selections/selection.module.js";import{resolveCapabilityOptions as m,resolveCapabilityAttribution as y}from"../state/capability-token-registry.js";import{getEventBus as p}from"../state/events.js";import{getSDKStore as f}from"../state/store.js";import{CrossTabCoordinator as b}from"../sync/cross-tab-coordinator.js";import{TimedReleaseManagementModule as w}from"../timed-releases/timed-release.module.js";import{version as I}from"../version.js";import{WaitlistManagementModule as h}from"../waitlists/waitlist.module.js";import{FanfareError as v,ErrorCodes as M}from"./errors.js";import{createHttpClient as j}from"./http.js";import{
|
|
2
|
-
/* @__PURE__ */new Set([...
|
|
1
|
+
import{createBeaconLifecycleAdapter as e}from"../adapters/beacon-lifecycle.js";import{AppointmentManagementModule as t}from"../appointments/appointment.module.js";import{AuctionManagementModule as r}from"../auctions/auction.module.js";import{AuthenticationModule as n}from"../auth/auth.module.js";import{BeaconTrackingModule as i}from"../beacon/beacon.module.js";import{ChallengeManagementModule as o}from"../challenges/challenge.module.js";import{Config as s}from"../config/index.js";import{DrawManagementModule as a}from"../draws/draw.module.js";import{ExperienceManagementModule as d}from"../experiences/experience.module.js";import{ExperienceJourney as l}from"../experiences/journey.js";import{PaymentMethodManagementModule as c}from"../payment/payment.module.js";import{QueueManagementModule as u}from"../queues/queue.module.js";import{SelectionModule as g}from"../selections/selection.module.js";import{resolveCapabilityOptions as m,resolveCapabilityAttribution as y}from"../state/capability-token-registry.js";import{getEventBus as p}from"../state/events.js";import{getSDKStore as f}from"../state/store.js";import{CrossTabCoordinator as b}from"../sync/cross-tab-coordinator.js";import{TimedReleaseManagementModule as w}from"../timed-releases/timed-release.module.js";import{version as I}from"../version.js";import{WaitlistManagementModule as h}from"../waitlists/waitlist.module.js";import{FanfareError as v,ErrorCodes as M}from"./errors.js";import{createHttpClient as j}from"./http.js";import{registerInternalSdk as S,unregisterInternalSdk as k}from"./internal-sdk-registry.js";import{createLogger as x}from"./logger.js";let D=null;async function E(E){const A=new s(E),q=A.get(),C=x({enabled:q.debug||!1,level:q.debug?"debug":"warn",prefix:"Fanfare"});if(C.info("Initializing Fanfare SDK",{organizationId:E.organizationId,environment:q.environment}),D)throw new v("Fanfare SDK is already initialized. The SDK uses a shared event bus and store; multiple concurrent instances will corrupt state and analytics. Call destroy() on the existing instance before initializing a new one.",M.ALREADY_INITIALIZED);const z=/* @__PURE__ */Symbol("fanfare-sdk"),O=j({baseUrl:A.apiUrl,credentials:q.credentials,headers:{"X-Organization-Id":E.organizationId,"X-Publishable-Key":E.publishableKey,"X-Fanfare-API-Version":"2025-01-15","X-Fanfare-SDK-Version":I,"X-Fanfare-Client-Type":"browser"},timeout:3e4,retryConfig:{maxRetries:3,delayTimer:1e3,retryOnNetworkError:!0}},q),F=j({baseUrl:A.beaconUrl,credentials:"omit",headers:{"X-Organization-Id":E.organizationId,"X-Publishable-Key":E.publishableKey,"X-Fanfare-API-Version":"2025-01-15","X-Fanfare-SDK-Version":I,"X-Fanfare-Client-Type":"browser"},timeout:3e4,retryConfig:{maxRetries:3,delayTimer:1e3,retryOnNetworkError:!0}},q),K=new n(O,F),X=new o(O),R=new u(O),P=new a(O),T=new r(O),$=new t(O),J=new h(O),N=new g(O),V=new w(O),L=new d(O,R,P,J,V),U=new c(O),B=p(),G=f();B.on("auth:logout",()=>U.destroy());const _=/* @__PURE__ */new Map,Y=/* @__PURE__ */new Map,Z=new i(F,q.beacon||{},e=>{const t=Y.get(e)?.snapshot$.get();return"routed"===t?.journeyStage?t.sequenceId:void 0}),H=/* @__PURE__ */new Map;let Q,W;const ee=e=>{const t=Y.get(e);if(t)return C.debug("Returning existing journey handle",{experienceId:e}),t;C.info("Creating new journey",{experienceId:e});const r=new l(e,Q);_.set(e,r),W?.registerJourney(r);const n={view$:r.view$,events$:r.events$,latestEvent$:r.latestEvent$,snapshot$:r.state,ackEvent:e=>r.ackEvent(e),ackAllEvents:()=>r.ackAllEvents(),destroy:()=>{r.destroy(),W?.unregisterJourney(e),_.delete(e),Y.delete(e)}};return Y.set(e,n),n},te=async e=>{const t=e??await L.getMe(),r=/* @__PURE__ */new Set,n=new Set(t.active.journeys.map(e=>e.experienceId));for(const i of n)ee(i);for(const i of n){const e=_.get(i);e&&await e.resumeFromMe(t)&&r.add(i)}return[...r]},re=async e=>{const t=/* @__PURE__ */new Set;for(const r of Object.keys(G.activeJourneys))ee(r),t.add(r);if(!e&&!K.getSession())return[...t];for(const r of await te(e))t.add(r);return[...t]},ne={check:()=>K.check(),guest:()=>K.guest(),requestOtp:e=>K.requestOtp(e),verifyOtp:e=>K.verifyOtp(e),exchangeExternal:e=>K.exchangeExternal(e),login:e=>K.login(e),logout:()=>K.logout(),getSession:()=>K.getSession(),refresh:()=>K.refresh()},ie={initiate:e=>X.initiate(e),verify:e=>X.verify(e)},oe={get:e=>ee(e),list:()=>Array.from(
|
|
2
|
+
/* @__PURE__ */new Set([...Y.keys(),..._.keys(),...Object.keys(G.activeJourneys)])),resumeAll:e=>re(e)},se={bind:e=>Z.bind(e),track:e=>Z.track(e),trackBatch:e=>Z.trackBatch(e),flush:()=>Z.flush()},ae=(e,t)=>{if(H.has(e.id))C.warn("CDP adapter already registered, skipping",{adapterId:e.id});else{try{e.init(B,t)}catch(r){return void C.error("CDP adapter failed to initialize",{adapterId:e.id,error:r})}H.set(e.id,e),C.info("CDP adapter registered",{adapterId:e.id})}},de=(e,t)=>B.on(e,t),le=async()=>{C.info("Destroying SDK instance");for(const t of H.values())try{t.destroy()}catch(e){C.error("CDP adapter failed to destroy",{adapterId:t.id,error:e})}H.clear();for(const t of Array.from(Y.values()))try{t.destroy()}catch(e){C.error("Journey handle failed to destroy",{error:e})}_.clear(),Y.clear(),"destroy"in K&&"function"==typeof K.destroy&&K.destroy(),R.destroy(),P.destroy(),T.destroy(),$.destroy(),J.destroy(),V.destroy(),L.destroy(),Z.destroy(),U.destroy(),W?.close(),B.off(),k(ue),D===z&&(D=null)};Q={auth:ne,challenges:ie,journeys:oe,queues:{get:e=>R.get(e),enter:(e,t,r,n)=>R.enter(e,t,m({distributionId:e},r),n,y({distributionId:e})),leave:(e,t)=>R.leave(e,m({distributionId:e},t)),status:e=>R.status(e),startMonitoring:(e,t,r)=>R.startMonitoring(e,t,r),stopMonitoring:e=>R.stopMonitoring(e),isMonitoring:e=>R.isMonitoring(e)},draws:{get:e=>P.get(e),enter:(e,t,r,n,i)=>P.enter(e,t,m({distributionId:e},r),n,i,y({distributionId:e})),leave:(e,t)=>P.leave(e,m({distributionId:e},t)),status:e=>P.status(e),startMonitoring:(e,t,r)=>P.startMonitoring(e,t,r),stopMonitoring:e=>P.stopMonitoring(e),isMonitoring:e=>P.isMonitoring(e)},auctions:{get:e=>T.get(e),bid:(e,t,r)=>T.bid(e,t,m({distributionId:e},r),y({distributionId:e})),status:e=>T.status(e),startMonitoring:(e,t,r)=>T.startMonitoring(e,t,r),stopMonitoring:e=>T.stopMonitoring(e),isMonitoring:e=>T.isMonitoring(e),destroy:()=>T.destroy()},experiences:{get:e=>L.get(e),enter:e=>L.enter(e),leave:e=>L.leave(e),getMe:()=>L.getMe(),confirmCheckout:(e,t,r)=>L.confirmCheckout(e,t,r),findSequence:(e,t)=>L.findSequence(e,t),validateSequenceAccess:(e,t)=>L.validateSequenceAccess(e,t),selectSequence:e=>L.selectSequence(e),getCurrentDistributions:(e,t)=>L.getCurrentDistributions(e,t),enterDistribution:e=>{if(!e)throw new v("Distribution is required",M.VALIDATION_ERROR);return L.enterDistribution(e)},getActiveSession:()=>L.getActiveSession(),isInExperience:e=>L.isInExperience(e),getSelectedSequence:()=>L.getSelectedSequence(),createJourney:e=>ee(e),resumeJourneysFromMe:e=>te(e),destroy:()=>L.destroy()},selections:N,waitlists:{enter:(e,t)=>J.enter(e,m({waitlistId:e},t),y({waitlistId:e})),leave:(e,t)=>J.leave(e,m({waitlistId:e},t),y({waitlistId:e})),getStatus:e=>J.getStatus(e),destroy:()=>J.destroy()},timedReleases:{get:e=>V.get(e),enter:(e,t,r)=>V.enter(e,m({distributionId:e},t),r,y({distributionId:e})),leave:(e,t)=>V.leave(e,m({distributionId:e},t)),complete:e=>V.complete(e),status:e=>V.status(e),startMonitoring:(e,t,r)=>V.startMonitoring(e,t,r),stopMonitoring:e=>V.stopMonitoring(e),isMonitoring:e=>V.isMonitoring(e)},appointments:{get:(e,t)=>$.get(e,m({distributionId:e},t)),getSlots:(e,t,r)=>$.getSlots(e,t,m({distributionId:e},r)),getMe:e=>$.getMe(e),book:(e,t,r,n)=>$.book(e,t,r,m({distributionId:e},n),y({distributionId:e})),cancel:(e,t,r,n)=>$.cancel(e,t,r,m({distributionId:e},n)),reschedule:(e,t,r,n)=>$.reschedule(e,t,r,m({distributionId:e},n)),startMonitoring:(e,t,r,n)=>$.startMonitoring(e,t,r,n),stopMonitoring:e=>$.stopMonitoring(e),isMonitoring:e=>$.isMonitoring(e),bumpMonitorGeneration:e=>$.bumpMonitorGeneration(e),destroy:()=>$.destroy()},beacon:se,payment:U,use:ae,on:de,destroy:le};const ce=!1!==E.sync&&"object"==typeof E.sync?E.sync:{};W=new b({enabled:!1!==E.sync&&!1!==ce.enabled,channelName:ce.channelName}),C.info("Inter-tab sync initialized",{tabId:W.getTabId(),enabled:W.isEnabled()});!q.beacon?.disableLifecycleEvents&&ae(e(e=>Z.track(e)));const ue={auth:ne,challenges:ie,journeys:oe,beacon:se,appointments:Q.appointments,payment:U,use:ae,on:de,destroy:le};if(S(ue,Q),await K.rehydrate(),q.autoResume&&K.getSession())try{await re()}catch(ge){C.warn("Auto-resume on init failed; journeys can be resumed manually",{error:ge instanceof Error?ge.message:String(ge)})}return D=z,C.info("SDK initialized successfully"),ue}export{E as init};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ExperienceDetails } from '../experiences/types';
|
|
2
|
+
import { FanfareSDK, InternalFanfareSDK } from '../types';
|
|
3
|
+
/** Binds a public SDK object to its runtime surface for the lifetime of the instance. */
|
|
4
|
+
export declare function registerInternalSdk(sdk: FanfareSDK, internal: InternalFanfareSDK): void;
|
|
5
|
+
/** Unbinds a destroyed SDK object. */
|
|
6
|
+
export declare function unregisterInternalSdk(sdk: FanfareSDK): void;
|
|
7
|
+
/**
|
|
8
|
+
* Reads an experience's details through the instance's own experience read, so
|
|
9
|
+
* concurrent reads of one experience on one instance share a single request.
|
|
10
|
+
*
|
|
11
|
+
* Rejects with `NOT_INITIALIZED` for an object `init` did not create, or one
|
|
12
|
+
* that has been destroyed.
|
|
13
|
+
*/
|
|
14
|
+
export declare function readExperienceDetails(sdk: FanfareSDK, experienceId: string): Promise<ExperienceDetails>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createError as e}from"./errors.js";const n=/* @__PURE__ */new WeakMap;function t(e,t){n.set(e,t)}function i(e){n.delete(e)}async function o(t,i){const o=n.get(t);if(!o)throw e.notInitialized("SDK instance is not initialized or has been destroyed");return o.experiences.get(i)}export{o as readExperienceDetails,t as registerInternalSdk,i as unregisterInternalSdk};
|
package/dist/core/money.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
const n=8,t=/^\d{1,12}(\.\d{1,8})?$/;function r(n){return"string"==typeof n&&t.test(n)}function u(n,t="0"){return n&&r(n)?n:t}function e(n){return n.split(".")[1]?.length??0}function i(n,t){return Math.max(e(n),e(t))}function o(n){const[t="0",r=""]=n.split(".");return BigInt(t+r.padEnd(8,"0"))}function c(n,t){const r=n<0n,u=(r?-n:n).toString().padStart(9,"0"),e=u.length-8,i=u.slice(e,e+t);return`${r?"-":""}${u.slice(0,e)}${i?`.${i}`:""}`}function f(n,t){return c(o(n)+o(t),i(n,t))}function s(n,t){return c(o(n)-o(t),i(n,t))}function l(n,t){return o(n)>o(t)}function p(n,t){return o(n)>=o(t)}function a(n,t){return o(n)<=o(t)}export{n as MONEY_FRACTIONAL_DIGITS,t as MONEY_REGEX,f as addMoney,l as isMoneyGreaterThan,p as isMoneyGreaterThanOrEqualTo,a as isMoneyLessThanOrEqualTo,r as isMoneyString,u as normalizeMoney,s as subtractMoney};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{BRIDGE_EVENT_VERSION as e,FANFARE_STATE_CHANGE_EVENT as t}from"@fanfare-io/fanfare-sdk-contracts/bridge";import{describeJourneyState as n}from"./journey-display.js";const r="data-fanfare-experience-id",i="data-fanfare-stage",s="data-fanfare-phase",o="data-fanfare-mechanism",a="data-fanfare-expires-at",c=[r,i,s,o,a];function u(e,t){const r=n(e)
|
|
1
|
+
import{BRIDGE_EVENT_VERSION as e,FANFARE_STATE_CHANGE_EVENT as t}from"@fanfare-io/fanfare-sdk-contracts/bridge";import{describeJourneyState as n}from"./journey-display.js";const r="data-fanfare-experience-id",i="data-fanfare-stage",s="data-fanfare-phase",o="data-fanfare-mechanism",a="data-fanfare-expires-at",c=[r,i,s,o,a];function u(e,t){const r=n(e),i=void 0===t?r.position:"number"==typeof t.position?t.position:void 0;if("routed"!==e.journeyStage||!("sequence"in e))return{stage:e.journeyStage};const s=e.sequence;let o;"grant"in s&&(o=function(e){if(void 0===e)return;const t=Date.parse(e);return Number.isNaN(t)?void 0:t}(s.grant.expiresAt));const a={...void 0===r.mechanism?{}:{mechanism:r.mechanism},...void 0===i?{}:{position:i},...void 0===o?{}:{expiresAt:o}};return"ended"===s.phase?{stage:"routed",phase:"ended",outcomeType:s.outcome.type,...a}:{stage:"routed",phase:s.phase,...a}}function d(t,n){const r=e;switch(t.stage){case"ready":return{version:r,experienceId:n,stage:"ready"};case"routing":return{version:r,experienceId:n,stage:"routing"};case"gated":return{version:r,experienceId:n,stage:"gated"};case"routed":{const e=void 0===t.mechanism?{}:{mechanism:t.mechanism},i=void 0===t.expiresAt?{}:{expiresAt:t.expiresAt};switch(t.phase){case"unavailable":return{version:r,experienceId:n,stage:"routed",phase:"unavailable"};case"scheduled":return{version:r,experienceId:n,stage:"routed",phase:"scheduled",...e};case"enterable":return{version:r,experienceId:n,stage:"routed",phase:"enterable",...e};case"participating":if("queue"===t.mechanism){return{version:r,experienceId:n,stage:"routed",phase:"participating",mechanism:"queue",...void 0===t.position?{}:{position:t.position}}}return{version:r,experienceId:n,stage:"routed",phase:"participating",...void 0===t.mechanism?{}:{mechanism:t.mechanism}};case"settling":return{version:r,experienceId:n,stage:"routed",phase:"settling",...e};case"granted":return{version:r,experienceId:n,stage:"routed",phase:"granted",...e,...i};case"ended":return{version:r,experienceId:n,stage:"routed",phase:"ended",...e,outcome:{type:t.outcomeType}}}return null}}}function p(e,n){const p=n?.target??("undefined"!=typeof document?document.documentElement:null);if(!p){const t=d(u(e.view$.get()),e.snapshot$.get().experienceId);return null!==t&&("outcome"in t&&Object.freeze(t.outcome),Object.freeze(t)),{getState(){if(null===t)throw new Error("DOM bridge projection has no event detail");return t},dispose(){}}}return function(e,n){const p=n,m=e.snapshot$.get().experienceId,l=/* @__PURE__ */new Set,g=/* @__PURE__ */new Set,h=new Map(c.map(e=>[e,p.getAttribute(e)]));let f,v=e.view$.get(),x=null,b=!1;function y(e){const t=/* @__PURE__ */new Map([[r,m],[i,e.stage]]);void 0!==e.phase&&t.set(s,e.phase),void 0!==e.mechanism&&t.set(o,e.mechanism),void 0!==e.expiresAt&&t.set(a,String(e.expiresAt));for(const n of l)t.has(n)||p.removeAttribute(n);l.clear();for(const[n,r]of t)p.getAttribute(n)!==r&&p.setAttribute(n,r),l.add(n),g.add(n)}function A(e){if(r=e,(n=I).stage===r.stage&&n.phase===r.phase&&n.mechanism===r.mechanism&&n.position===r.position&&n.expiresAt===r.expiresAt&&n.outcomeType===r.outcomeType)return;var n,r;const i=d(e,m);null!==i&&(I=e,y(e),"outcome"in i&&Object.freeze(i.outcome),Object.freeze(i),O=i,p.dispatchEvent(new CustomEvent(t,{bubbles:!0,composed:!0,detail:i})))}function w(e){const t="routed"===e.journeyStage&&"sequence"in e?e.sequence:null,n="participating"===t?.phase&&"queue"===t.mechanism?t.display$:null;return n===x?x:(f?.(),f=void 0,x=null,null==n?null:(x=n,f=n.listen(e=>{A(u(v,e))}),n))}const j=w(v);let I=u(v,j?.get()),O=d(I,m);null!==O&&("outcome"in O&&Object.freeze(O.outcome),Object.freeze(O)),y(I);const S=e.view$.listen(e=>{v=e,w(e),A(u(e,x?.get()))});return{getState(){if(null===O)throw new Error("DOM bridge projection has no event detail");return O},dispose(){if(!b){b=!0,S(),f?.(),f=void 0;for(const e of g){const t=h.get(e)??null;null===t?p.removeAttribute(e):p.setAttribute(e,t)}g.clear(),l.clear()}}}}(e,p)}export{p as createDomBridge};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AuthenticationRoutingGateV1Schema as e,AccessCodeRoutingGateV1Schema as t,BotCheckRoutingGateV1Schema as i,RoutingSequenceAvailabilityV1Schema as s}from"@fanfare-io/fanfare-sdk-contracts/routing";import{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 A,withQueueTerminalConsumer as v}from"../queues/queue.driver.js";import{clearExperienceContext as q,clearSequenceContext as w,resolveCapabilityOptions as C,bindDistributionContext as k,bindWaitlist as j,upsertSequenceToken as x,peekSequenceToken as T,getSequenceTokenExpiryMs as E}from"../state/capability-token-registry.js";import{getEventBus as D}from"../state/events.js";import{getSDKStore as R}from"../state/store.js";import{createTimedReleaseDriver as O,withTimedReleaseTerminalConsumer as M}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,getDistribution as H,normalizeSequenceState as N,buildSnapshot as U,getSequenceId as z,getConsumer as B,getWaitlistAttachment as L,getOutcome as J,getGrant as W,getSequenceState as V,getCheckout as Q,isPreEntryJourney as $,getGates as K,isRoutedState as X,getAdmissionGrantExpiresAt as Z,getParticipation as Y,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=/* @__PURE__ */new Set([y.NETWORK_ERROR,y.TIMEOUT,y.UNAUTHORIZED]),ce=[2e3,5e3,1e4],de=3*ce.length,ue=[2e3,5e3,1e4];function he(e,t){if("scheduled"!==e?.lifecycle||!e.opensAt)return!1;const i=Date.parse(e.opensAt);return Number.isFinite(i)&&i<=t}function le(e){const t=Y(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 pe(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)}function me(e){const{grant:t}=e;return t.issuedAt?`${t.sequenceId}|${t.distributionId}|${t.issuedAt}`:t.token}class ge{constructor(e,t){this.experienceId=e,this.sdk=t,this.store=R(),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.automaticAttemptAtom=o(void 0),this.refusedDistributionAtom=o(/* @__PURE__ */new Set),this.automaticEntry=!0,this.EVENT_BUFFER_LIMIT=20;const i=this.restoreFromStore(),s=i??_(this.experienceId),r=i?le(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,this.automaticAttemptAtom,this.refusedDistributionAtom],(e,t,i)=>{const s="routed"===e.journeyStage?H(e)?.id:void 0,r=void 0!==s&&i.has(s);return this.buildView(e,t??(r?"refused":void 0))}),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()=>{void 0!==e?.automaticEntry&&(this.automaticEntry=e.automaticEntry),e?.reset&&(this.refusedDistributionAtom.set(/* @__PURE__ */new Set),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}),await this.attemptAutomaticEntry(),{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}),await this.attemptAutomaticEntry(),{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(),q(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=N({sequence:We(t.sequence)}),r="granted"===s.phase&&!("routed"===i.journeyStage&&i.sequenceId===t.sequenceId&&"granted"===i.sequence.phase),n=U({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}),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=z(e);if(!t)throw m.validationError("Cannot refresh distribution before routing to a sequence");const i=await this.sdk.experiences.getCurrentDistributions(t,C({experienceId:this.experienceId,sequenceId:t})),s=this.stateAtom.get();if(z(s)!==t)return;const r=B(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,L(s)),a=H(s);n&&k({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,grant:W(s),settlement:Qe(s),selection:$e(s),checkout:Ve(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),await this.attemptAutomaticEntry()}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=V(e),i=H(e),s=L(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=V(e),i=H(e),s=L(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,C({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,C({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||me(o)!==me(i))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}),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 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!==Q(s)}catch{return!1}}async submitCheckout(e){const t=this.stateAtom.get(),i=V(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,n=me(i);this.clearGrantExpiryTimer();try{let t;try{t=await this.sdk.experiences.confirmCheckout(r,i.grant.distributionId,e)}catch(o){throw g(o)&&o.code===y.ADMISSION_EXPIRED&&this.transitionToEnded({type:"expired"}),o}const a=this.stateAtom.get(),c=V(a);if(z(a)!==s||"granted"!==c?.phase||me(c)!==n)throw m.validationError("Grant changed before checkout could be confirmed");if("requires_action"===t.outcome)return this.pendingCheckoutPaymentInput=e,this.commit({...c,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=V(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,r=s?.consumerId!==this.routingSession?.consumerId||s?.type!==this.routingSession?.type;r&&this.refusedDistributionAtom.set(/* @__PURE__ */new Set),r&&"routed"===i.journeyStage&&$(i)&&(this.clearRoutedRuntimeState(),w(this.experienceId,i.sequenceId),i=U({base:this.baseFromSnapshot(i),journeyStage:"ready"}),this.setSnapshot(i)),this.routingSession=s;const n=i,o=z(n);let a,c=!1;try{const i=await this.resolveRouting(e,{transient:t?.transient});if(!i||this.destroyed)return;if(a=this.stateAtom.get().revision,c=o===i.sequenceId,await this.enterExperienceIfReady(),this.destroyed)return;const s=await this.sdk.experiences.getCurrentDistributions(i.sequenceId,C({experienceId:this.experienceId,sequenceId:i.sequenceId}));if(this.destroyed)return;const r=c?B(n):void 0,d=this.buildDistributionSummary(s,i.sequenceId,{consumer:r,settlingDistributionId:c&&"routed"===n.journeyStage&&"settling"===n.sequence.phase?n.sequence.distribution.id:void 0}),u=this.buildWaitlistAttachmentFromContext(s,c?L(n):void 0);d&&k({experienceId:this.experienceId,sequenceId:i.sequenceId,distributionContext:d}),u&&j({waitlistId:u.waitlistId,experienceId:this.experienceId,sequenceId:i.sequenceId});const h=c?W(n):void 0,l=c?Ve(n):void 0,p=c?Qe(n):void 0,m=c?this.deriveTerminalOutcomeForClosedDistribution(r,d,J(n)):void 0,g=this.withTerminalConsumer(r,m),y=!d&&c&&"routed"===n.journeyStage&&("granted"===n.sequence.phase||"ended"===n.sequence.phase)?n.sequence:this.projectSequenceState({distribution:d,consumer:g,grant:h,settlement:p,selection:c?$e(n):void 0,checkout:l,outcome:m});c||(this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck());const f=this.stateAtom.get(),b=U({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=c?H(n):void 0;this.emitIfDistributionChanged(S,d),this.evaluateDistributionSelfCheck(d),t?.transient||await this.attemptAutomaticEntry()}catch(d){if("routed"===n.journeyStage&&c&&this.isQuietableDegradationError(d))throw this.restoreQuietSnapshot(n),this.markErrorQuietable(d);if("routing"===this.stateAtom.get().journeyStage)if(this.lastClearedSequenceId===o&&this.restoreClearedSequenceContext(n,o),void 0!==a&&this.stateAtom.get().revision===a)this.setSnapshot(n);else{const e=this.stateAtom.get();"routed"===n.journeyStage?this.setSnapshot(U({base:this.baseFromSnapshot(e),journeyStage:"routed",sequenceId:n.sequenceId,offers:n.offers,sequence:n.sequence,waitlist:n.waitlist,sequenceRef:n.sequenceRef})):this.setSnapshot(U({base:this.baseFromSnapshot(e),journeyStage:"ready"}))}throw d}}clearRefusedDistributionOnStanding(e){const t=this.refusedDistributionAtom.get();if(0===t.size||"routed"!==e.journeyStage)return;const i=H(e)?.id;if(void 0===i||!t.has(i))return;const s=e.sequence.phase;"participating"!==s&&"granted"!==s||this.refusedDistributionAtom.set(new Set([...t].filter(e=>e!==i)))}clearAutomaticAttemptIfSuperseded(e){const t=this.automaticAttemptTarget;if(!t||"routing"===e.journeyStage)return;"routed"===e.journeyStage&&e.sequenceId===t.sequenceId&&H(e)?.id===t.distributionId&&"enterable"===e.sequence.phase||this.clearAutomaticAttempt()}clearAutomaticAttempt(){this.automaticAttemptTarget=void 0,this.automaticAttemptAtom.set(void 0)}async attemptAutomaticEntry(){if(!this.automaticEntry||this.destroyed)return;const e=this.buildView(this.stateAtom.get());if("routed"!==e.journeyStage)return;const t=H(this.stateAtom.get())?.id;if(void 0!==t&&this.refusedDistributionAtom.get().has(t))return;const i=this.automaticAttemptAtom.get()?this.automaticAttemptTarget:void 0;if(i&&i.distributionId===t)return;const s=e.sequence;if("enterable"!==s.phase||!("entry"in s)||!s.entry.automatic)return;const r=this.sequenceDrivers[s.mechanism];if(!r?.enterWithinOperation)return;const n=e.sequenceId;this.automaticAttemptTarget={sequenceId:n,distributionId:t},this.automaticAttemptAtom.set("entering");try{await r.enterWithinOperation()}catch(o){if(this.destroyed)return;const e=this.stateAtom.get();if("routed"!==e.journeyStage||e.sequenceId!==n||"enterable"!==e.sequence.phase)return void this.clearAutomaticAttempt();this.clearAutomaticAttempt(),void 0===t||g(o)&&ae.has(o.code)||this.refusedDistributionAtom.set(/* @__PURE__ */new Set([...this.refusedDistributionAtom.get(),t])),this.emitEvent("error","error","user","Automatic entry was refused",{action:"enter",...t?{distributionId:t}:{},...g(o)?{code:o.code}:{}})}}restoreClearedSequenceContext(e,t){const i=H(e);i&&k({experienceId:this.experienceId,sequenceId:t,distributionContext:i});const s=L(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(U({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:()=>V(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:()=>V(this.stateAtom.get()),commit:(e,t)=>this.commit(e,t),applyMonitorUpdate:e=>this.applyMonitorUpdate(e)}),queue:A({queues:this.sdk.queues,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>V(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:O({timedReleases:this.sdk.timedReleases,runSerializedOperation:e=>this.runSerializedOperation(e),getCurrentSequence:()=>V(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:()=>V(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,t){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,t)}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(U({base:i,journeyStage:"ready"}));case"routing":return void this.setSnapshot(U({base:i,journeyStage:"routing"}));case"gated":return void this.setSnapshot(U({base:i,journeyStage:"gated",gates:t.gates,selected:t.selected}));case"routed":return void this.setSnapshot(U({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(U({base:this.baseFromSnapshot(e),journeyStage:"routing"}))}transitionToGated(e){if(this.destroyed)return;const t=this.stateAtom.get();this.setSnapshot(U({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=U({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 U({base:i,journeyStage:"ready"});case"routing":return U({base:i,journeyStage:"routing"});case"gated":return U({base:i,journeyStage:"gated",gates:e.gates,selected:e.selected});case"routed":return U({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",...e.upcoming.details?{details:e.upcoming.details,closesAt:e.upcoming.details.closeAt}:{},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=Je(e[this.experienceId]);return t?"routing"===t.journeyStage||"routed"===t.journeyStage&&$(t)?("routed"===t.journeyStage&&w(this.experienceId,t.sequenceId),this.restoredSnapshotNeedsPersist=!0,U({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=le(e);"auction"===s?.type&&"auction"!==this.displayAtom?.get().type&&(this.resetDisplayAtom("auction"),this.displayParticipationId=s.id),"routed"!==e.journeyStage&&"routing"!==e.journeyStage&&this.refusedDistributionAtom.set(/* @__PURE__ */new Set),this.clearRefusedDistributionOnStanding(e),this.clearAutomaticAttemptIfSuperseded(e),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||D().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=H(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(B(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"!==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:B(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&&(pe(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(pe(s,i.sequenceId))this.clearGrantHydration();else{if(void 0!==t&&Date.now()>=t)return this.clearAutomaticAttempt(),void this.transitionToEnded({type:"expired"},{lastSyncedAt:Date.now(),degraded:!1});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(pe(this.stateAtom.get(),e.sequenceId))return void this.clearGrantHydration();const t=ue[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(!he(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>=ce.length)return;if(this.selfCheckTotalAttempts>=de)return;const s=this.selfCheckStartedAtMs+ce[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=E(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=E(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&&pe(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:Z(e),attempt:0},this.scheduleGrantHydrationRetry());const t=V(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=Z(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=le(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=Je(e);if(!t)return;const i="routing"===t.journeyStage?U({base:this.baseFromSnapshot(t),journeyStage:"ready"}):t,s=this.stateAtom.get();if(s.revision===i.revision&&s.updatedAt===i.updatedAt)return;const r=le(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 v(e,t);case"timed_release":return M(e,t);default:return e}}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0)}}const ye=c.picklist(["queue","draw","auction","timed_release","appointment"]),fe=ye,be=c.picklist(["queue","draw","auction","timed_release"]),Se=c.picklist(["draw","auction"]),Ie=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()))}),Ae=c.object({id:c.string(),name:c.string(),experienceId:c.string(),priority:c.number(),color:c.nullable(c.string()),availability:c.optional(s)}),ve=c.strictObject({type:ye,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())}),qe=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())}),we=c.strictObject({token:c.string(),distributionType:be,distributionId:c.string(),sequenceId:c.string(),experienceId:c.string(),issuedAt:c.optional(c.string()),expiresAt:c.optional(c.string())}),Ce=c.strictObject({orderId:c.string(),amount:c.string(),currencyCode:c.string(),paymentMethodLast4:c.optional(c.string()),paymentMethodBrand:c.optional(c.string())}),ke=c.strictObject({publishableKey:c.string(),stripeAccount:c.optional(c.string())}),je=c.strictObject({type:c.string(),reason:c.optional(c.string()),at:c.optional(c.string()),distributionType:c.optional(ye),distributionId:c.optional(c.string())}),xe=c.strictObject({phase:c.literal("unavailable"),reason:c.optional(c.string())}),Te=c.strictObject({waitlistId:c.string(),status:c.picklist(["not_waitlisted","waitlisted"]),entryId:c.optional(c.string())}),Ee=c.strictObject({phase:c.literal("scheduled"),mechanism:fe,distribution:ve}),De=c.strictObject({phase:c.literal("enterable"),mechanism:fe,distribution:ve,consumer:qe,paymentProvider:c.optional(ke)}),Re=c.strictObject({phase:c.literal("participating"),mechanism:fe,distribution:ve,consumer:qe}),Oe=c.strictObject({phase:c.literal("settling"),mechanism:Se,distribution:ve,consumer:qe}),Me=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(ke)}),c.strictObject({processor:c.literal("internal"),mode:c.literal("pre_auth")})]),Ge=c.strictObject({phase:c.literal("granted"),mechanism:be,distribution:ve,consumer:qe,grant:we,settlement:Me,selection:r}),Fe=c.strictObject({phase:c.literal("ended"),mechanism:fe,distribution:ve,consumer:qe,outcome:je,checkout:c.optional(Ce)}),_e=c.union([xe,Ee,De,Re,Oe,Ge,Fe]),Pe={schemaVersion:c.literal(6),revision:c.number(),updatedAt:c.number(),experienceId:c.string(),accessCode:c.optional(c.string()),experience:c.optional(c.unknown()),events:c.array(Ie),lastSeenEventId:c.optional(c.string()),lastSyncedAt:c.optional(c.number())},He=c.strictObject({...Pe,journeyStage:c.literal("ready")}),Ne=c.strictObject({...Pe,journeyStage:c.literal("routing")}),Ue=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"])]),ze=c.strictObject({...Pe,journeyStage:c.literal("gated"),gates:c.array(Ue),selected:c.optional(c.strictObject({sequence:c.unknown(),status:c.literal("gated")}))}),Be=c.strictObject({...Pe,journeyStage:c.literal("routed"),sequenceId:c.string(),offers:c.array(c.object({sequence:c.unknown(),status:c.literal("gated"),gates:c.array(Ue)})),sequence:_e,waitlist:c.optional(Te),sequenceRef:c.optional(Ae)}),Le=c.union([He,Ne,ze,Be]);function Je(e){const t=c.safeParse(Le,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 We(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 Ve(e){return"routed"!==e.journeyStage||"granted"!==e.sequence.phase&&"ended"!==e.sequence.phase||!("checkout"in e.sequence)?Q(e):e.sequence.checkout}function Qe(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.settlement}function $e(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.selection}export{ge as ExperienceJourney,he as isSelfContradictingDistribution};
|
|
1
|
+
import{AuthenticationRoutingGateV1Schema as e,AccessCodeRoutingGateV1Schema as t,BotCheckRoutingGateV1Schema as i,RoutingSequenceAvailabilityV1Schema as s}from"@fanfare-io/fanfare-sdk-contracts/routing";import{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 S}from"../core/utils.js";import{createDrawDriver as b,withDrawTerminalConsumer as A}from"../draws/draw.driver.js";import{createQueueDriver as I,withQueueTerminalConsumer as v}from"../queues/queue.driver.js";import{advanceQueuePrivacyEpoch as q}from"../queues/queue.module.js";import{clearExperienceContext as w,clearSequenceContext as C,resolveCapabilityOptions as k,bindDistributionContext as j,bindWaitlist as x,upsertSequenceToken as T,peekSequenceToken as E,getSequenceTokenExpiryMs as D}from"../state/capability-token-registry.js";import{getEventBus as R}from"../state/events.js";import{getSDKStore as O}from"../state/store.js";import{createTimedReleaseDriver as M,withTimedReleaseTerminalConsumer as G}from"../timed-releases/timed-release.driver.js";import{NoSequenceAvailableError as F}from"./experience.module.js";import{buildJourneyView as _}from"./journey-view.js";import{createInitialSnapshot as P,getSequencePhase as H,getDistribution as N,normalizeSequenceState as U,buildSnapshot as z,getSequenceId as B,getConsumer as L,getWaitlistAttachment as W,getOutcome as J,getGrant as V,getSequenceState as Q,getCheckout as $,isPreEntryJourney as K,getGates as X,isRoutedState as Z,getAdmissionGrantExpiresAt as Y,getParticipation as ee,validateSequenceState as te}from"./journey.machine.js";import{isUnresolvedSettlementConsumer as ie}from"./settlement.js";const se="Cannot commit a stale sequence transition",re="Cannot commit a sequence transition before routing",ne=3e4,oe=6e5,ae=/* @__PURE__ */new Set([y.RATE_LIMITED,y.OVERLOADED,y.SERVICE_UNAVAILABLE,y.TIMEOUT,y.NETWORK_ERROR]),ce=/* @__PURE__ */new Set([y.NETWORK_ERROR,y.TIMEOUT,y.UNAUTHORIZED]),de=[2e3,5e3,1e4],ue=3*de.length,he=[2e3,5e3,1e4];function le(e,t){if("scheduled"!==e?.lifecycle||!e.opensAt)return!1;const i=Date.parse(e.opensAt);return Number.isFinite(i)&&i<=t}function pe(e){const t=ee(e);if(t)return t;if(!Z(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 me(e){const t="queue"===e?.type&&"queue"===e.details?.type?e.details.openAt:null;return"string"==typeof t&&t?t:null}function ge(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)}function ye(e){const{grant:t}=e;return t.issuedAt?`${t.sequenceId}|${t.distributionId}|${t.issuedAt}`:t.token}class fe{constructor(e,t){this.experienceId=e,this.sdk=t,this.store=O(),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.automaticAttemptAtom=o(void 0),this.refusedDistributionAtom=o(/* @__PURE__ */new Set),this.automaticEntry=!0,this.EVENT_BUFFER_LIMIT=20;const i=this.restoreFromStore(),s=i??P(this.experienceId),r=i?pe(i):void 0,n=H(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,this.automaticAttemptAtom,this.refusedDistributionAtom],(e,t,i)=>{const s="routed"===e.journeyStage?N(e)?.id:void 0,r=void 0!==s&&i.has(s);return this.buildView(e,t??(r?"refused":void 0))}),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()=>{void 0!==e?.automaticEntry&&(this.automaticEntry=e.automaticEntry),e?.reset&&(this.refusedDistributionAtom.set(/* @__PURE__ */new Set),this.clearRoutedRuntimeState(),this.setSnapshot(P(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}),await this.attemptAutomaticEntry(),{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}),await this.attemptAutomaticEntry(),{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(),w(this.experienceId),this.store.removeJourney(this.experienceId),this.stateAtom.set(P(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=U({sequence:Qe(t.sequence)}),r="granted"===s.phase&&!("routed"===i.journeyStage&&i.sequenceId===t.sequenceId&&"granted"===i.sequence.phase),n=z({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&&C(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"===H(this.stateAtom.get())&&(this.emitEvent("sequence_change","success","user","Grant issued",{grant:s.grant.token}),R().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=B(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(B(s)!==t)return;const r=L(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,W(s)),a=N(s);n&&j({experienceId:this.experienceId,sequenceId:t,distributionContext:n}),o&&x({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,grant:V(s),settlement:Ke(s),selection:Xe(s),checkout:$e(s),outcome:c});this.commit(u,{waitlist:o,lastSyncedAt:Date.now(),degraded:!1},!0),this.emitIfDistributionChanged(a,n),"granted"===u.phase||"ended"===u.phase?this.resetDistributionSelfCheck():this.evaluateDistributionSelfCheck(n),await this.attemptAutomaticEntry()}catch(t){const i=this.stateAtom.get();if(B(i)===B(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=N(e),s=W(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=N(e),s=W(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=B(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||ye(o)!==ye(i))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=V(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}),R().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=B(this.stateAtom.get());try{const e=await this.sdk.experiences.getMe();if(this.destroyed||B(this.stateAtom.get())!==t)return!1;const i=await this.resumeFromMe(e),s=this.stateAtom.get();return i&&B(s)===t&&"ended"===H(s)&&void 0!==$(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=B(t),r=i.grant.token,n=ye(i);this.clearGrantExpiryTimer();try{let t;try{t=await this.sdk.experiences.confirmCheckout(r,i.grant.distributionId,e)}catch(o){throw g(o)&&o.code===y.ADMISSION_EXPIRED&&this.transitionToEnded({type:"expired"}),o}const a=this.stateAtom.get(),c=Q(a);if(B(a)!==s||"granted"!==c?.phase||ye(c)!==n)throw m.validationError("Grant changed before checkout could be confirmed");if("requires_action"===t.outcome)return this.pendingCheckoutPaymentInput=e,this.commit({...c,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,r=s?.consumerId!==this.routingSession?.consumerId||s?.type!==this.routingSession?.type;r&&this.refusedDistributionAtom.set(/* @__PURE__ */new Set),r&&"routed"===i.journeyStage&&K(i)&&(this.clearRoutedRuntimeState(),C(this.experienceId,i.sequenceId),i=z({base:this.baseFromSnapshot(i),journeyStage:"ready"}),this.setSnapshot(i)),this.routingSession=s;const n=i,o=B(n);let a,c=!1;try{const i=await this.resolveRouting(e,{transient:t?.transient});if(!i||this.destroyed)return;if(a=this.stateAtom.get().revision,c=o===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 r=c?L(n):void 0,d=this.buildDistributionSummary(s,i.sequenceId,{consumer:r,settlingDistributionId:c&&"routed"===n.journeyStage&&"settling"===n.sequence.phase?n.sequence.distribution.id:void 0}),u=this.buildWaitlistAttachmentFromContext(s,c?W(n):void 0);d&&j({experienceId:this.experienceId,sequenceId:i.sequenceId,distributionContext:d}),u&&x({waitlistId:u.waitlistId,experienceId:this.experienceId,sequenceId:i.sequenceId});const h=c?V(n):void 0,l=c?$e(n):void 0,p=c?Ke(n):void 0,m=c?this.deriveTerminalOutcomeForClosedDistribution(r,d,J(n)):void 0,g=this.withTerminalConsumer(r,m),y=!d&&c&&"routed"===n.journeyStage&&("granted"===n.sequence.phase||"ended"===n.sequence.phase)?n.sequence:this.projectSequenceState({distribution:d,consumer:g,grant:h,settlement:p,selection:c?Xe(n):void 0,checkout:l,outcome:m});c||(this.stopRuntimeMonitoring(!0),this.clearGrantExpiryTimer(),this.clearGrantHydration(),this.clearCapabilityRefreshTimer(),this.resetDistributionSelfCheck());const f=this.stateAtom.get(),S=z({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.setServerSnapshot(S,n),this.resumeDeferredGrantHydration(),this.consecutiveRefreshFailures=0,this.rearmTimersIfNeeded();const b=c?N(n):void 0;this.emitIfDistributionChanged(b,d),this.evaluateDistributionSelfCheck(d),t?.transient||await this.attemptAutomaticEntry()}catch(d){if("routed"===n.journeyStage&&c&&this.isQuietableDegradationError(d))throw this.restoreQuietSnapshot(n),this.markErrorQuietable(d);if("routing"===this.stateAtom.get().journeyStage)if(this.lastClearedSequenceId===o&&this.restoreClearedSequenceContext(n,o),void 0!==a&&this.stateAtom.get().revision===a)this.setSnapshot(n);else{const e=this.stateAtom.get();"routed"===n.journeyStage?this.setSnapshot(z({base:this.baseFromSnapshot(e),journeyStage:"routed",sequenceId:n.sequenceId,offers:n.offers,sequence:n.sequence,waitlist:n.waitlist,sequenceRef:n.sequenceRef})):this.setSnapshot(z({base:this.baseFromSnapshot(e),journeyStage:"ready"}))}throw d}}clearRefusedDistributionOnStanding(e){const t=this.refusedDistributionAtom.get();if(0===t.size||"routed"!==e.journeyStage)return;const i=N(e)?.id;if(void 0===i||!t.has(i))return;const s=e.sequence.phase;"participating"!==s&&"granted"!==s||this.refusedDistributionAtom.set(new Set([...t].filter(e=>e!==i)))}clearAutomaticAttemptIfSuperseded(e){const t=this.automaticAttemptTarget;if(!t||"routing"===e.journeyStage)return;"routed"===e.journeyStage&&e.sequenceId===t.sequenceId&&N(e)?.id===t.distributionId&&"enterable"===e.sequence.phase||this.clearAutomaticAttempt()}clearAutomaticAttempt(){this.automaticAttemptTarget=void 0,this.automaticAttemptAtom.set(void 0)}async attemptAutomaticEntry(){if(!this.automaticEntry||this.destroyed)return;const e=this.buildView(this.stateAtom.get());if("routed"!==e.journeyStage)return;const t=N(this.stateAtom.get())?.id;if(void 0!==t&&this.refusedDistributionAtom.get().has(t))return;const i=this.automaticAttemptAtom.get()?this.automaticAttemptTarget:void 0;if(i&&i.distributionId===t)return;const s=e.sequence;if("enterable"!==s.phase||!("entry"in s)||!s.entry.automatic)return;const r=this.sequenceDrivers[s.mechanism];if(!r?.enterWithinOperation)return;const n=e.sequenceId;this.automaticAttemptTarget={sequenceId:n,distributionId:t},this.automaticAttemptAtom.set("entering");try{await r.enterWithinOperation()}catch(o){if(this.destroyed)return;const e=this.stateAtom.get();if("routed"!==e.journeyStage||e.sequenceId!==n||"enterable"!==e.sequence.phase)return void this.clearAutomaticAttempt();this.clearAutomaticAttempt(),void 0===t||g(o)&&ce.has(o.code)||this.refusedDistributionAtom.set(/* @__PURE__ */new Set([...this.refusedDistributionAtom.get(),t])),this.emitEvent("error","error","user","Automatic entry was refused",{action:"enter",...t?{distributionId:t}:{},...g(o)?{code:o.code}:{}})}}restoreClearedSequenceContext(e,t){const i=N(e);i&&j({experienceId:this.experienceId,sequenceId:t,distributionContext:i});const s=W(e);s&&x({waitlistId:s.waitlistId,experienceId:this.experienceId,sequenceId:t}),this.lastClearedSequenceToken&&T({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(z({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=B(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||K(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"!==H(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 F("No access available for this experience");const o=n.selected.sequence.id;if(s&&s!==o&&(this.lastClearedSequenceId=s,this.lastClearedSequenceToken=E(this.experienceId,s),C(this.experienceId,s)),this.consecutiveGatedRestores=0,n.selected.capabilityGrant&&T({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(X(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:I({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:b({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,t){return _(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,t)}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(z({base:i,journeyStage:"ready"}));case"routing":return void this.setSnapshot(z({base:i,journeyStage:"routing"}));case"gated":return void this.setSnapshot(z({base:i,journeyStage:"gated",gates:t.gates,selected:t.selected}));case"routed":return void this.setSnapshot(z({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(z({base:this.baseFromSnapshot(e),journeyStage:"routing"}))}transitionToGated(e){if(this.destroyed)return;const t=this.stateAtom.get();this.setSnapshot(z({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={},i=!1){if(this.destroyed)throw m.notInitialized("Journey has been destroyed");const s=this.stateAtom.get();if("routed"!==s.journeyStage)throw m.validationError(re);if(!function(e,t){if("distribution"in e&&e.distribution.sequenceId&&e.distribution.sequenceId!==t)return!1;return!0}(e,s.sequenceId))throw m.validationError(se);const r=Object.prototype.hasOwnProperty.call(t,"waitlist")?t.waitlist??void 0:s.waitlist,n={};Object.prototype.hasOwnProperty.call(t,"lastSyncedAt")&&(n.lastSyncedAt=t.lastSyncedAt),Object.prototype.hasOwnProperty.call(t,"degraded")&&(n.degraded=t.degraded);const o=z({base:this.baseFromSnapshot(s,{...n,events:t.events??s.events}),journeyStage:"routed",sequenceId:s.sequenceId,offers:s.offers,sequence:e,waitlist:r,sequenceRef:s.sequenceRef});i?this.setServerSnapshot(o):this.setSnapshot(o)}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||ae.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 z({base:i,journeyStage:"ready"});case"routing":return z({base:i,journeyStage:"routing"});case"gated":return z({base:i,journeyStage:"gated",gates:e.gates,selected:e.selected});case"routed":return z({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:S(),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){const i=void 0===e.upcoming.details&&"queue"===e.upcoming.type?{id:e.upcoming.id,type:"queue",openAt:e.upcoming.startsAt}:e.upcoming.details;return{type:e.upcoming.type,id:e.upcoming.id,sequenceId:t,lifecycle:"scheduled",...i?{details:i,closesAt:i.closeAt}:{},startsAt:e.upcoming.startsAt,opensAt:e.upcoming.startsAt,updatedAt:Date.now()}}if(e.recentPast){const s=i?.settlingDistributionId===e.recentPast.id||ie(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=Ve(e[this.experienceId]);return t?"routing"===t.journeyStage||"routed"===t.journeyStage&&K(t)?("routed"===t.journeyStage&&C(this.experienceId,t.sequenceId),this.restoredSnapshotNeedsPersist=!0,z({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=pe(e);"auction"===s?.type&&"auction"!==this.displayAtom?.get().type&&(this.resetDisplayAtom("auction"),this.displayParticipationId=s.id),"routed"!==e.journeyStage&&"routing"!==e.journeyStage&&this.refusedDistributionAtom.set(/* @__PURE__ */new Set),this.clearRefusedDistributionOnStanding(e),this.clearAutomaticAttemptIfSuperseded(e),this.stateAtom.set(e),!1!==t.persist&&this.persist(),this.emitPhaseChanged(i,e)}setServerSnapshot(e,t=this.stateAtom.get(),i=!0){const s=function(e,t){const i=N(e),s=N(t),r=me(s);return"queue"!==i?.type||"queue"!==s?.type||i.id!==s.id||"scheduled"!==s.lifecycle||null===r||me(i)===r?null:s.id}(t,e);if(!s)return void this.setSnapshot(e,{persist:i});q(this.sdk.queues,s);const r=this.displayParticipationId===s&&"queue"===this.displayAtom?.get().type?this.displayAtom:null,{position:n,estimatedWaitTime:o,...a}=r?.get()??{type:"queue"},c="queue"===this.activeMonitor?.type&&this.activeMonitor.id===s;r?.set(a),this.setSnapshot(e,{persist:i}),r?.set({...a}),c&&(this.activeMonitor?.stop(),this.activeMonitor=null,this.startMonitorForParticipation({id:s,type:"queue"}))}emitPhaseChanged(e,t){const i=e.journeyStage,s="routed"===i?H(e):void 0,r=t.journeyStage,n="routed"===r?H(t):void 0;i===r&&s===n||R().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=B(i);if(!s)throw m.validationError(re);const r=N(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(L(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}),R().emit("journey:ended",{experienceId:this.experienceId,sequenceId:s,outcome:c})}reinterpretLapsedGrantOutcome(e,t){if("granted"!==H(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(!Z(t)||"participating"!==t.sequence.phase)return;const i={...t.sequence.distribution,lifecycle:"settling",settlesAt:e.at},s=this.projectSequenceState({distribution:i,consumer:L(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&&(ge(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(ge(s,i.sequenceId))this.clearGrantHydration();else{if(void 0!==t&&Date.now()>=t)return this.clearAutomaticAttempt(),void this.transitionToEnded({type:"expired"},{lastSyncedAt:Date.now(),degraded:!1});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(ge(this.stateAtom.get(),e.sequenceId))return void this.clearGrantHydration();const t=he[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(!le(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>=de.length)return;if(this.selfCheckTotalAttempts>=ue)return;const s=this.selfCheckStartedAtMs+de[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=D(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(ne*2**this.consecutiveGatedRestores,oe);this.consecutiveGatedRestores+=1;const i=D(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&&ge(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<ne)return void this.scheduleCapabilityRefresh(ne);this.lastCapabilityRefreshAtMs=e,await this.retry(),this.consecutiveRefreshFailures=0}catch(e){if(this.dropStaleCallbackCommit(e,"capability refresh timer"))return;const t=Math.min(ne*2**this.consecutiveRefreshFailures,oe);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!==se&&e.message!==re)&&(this.logger.debug("Dropped stale journey callback",{experienceId:this.experienceId,source:t,message:e.message}),!0)}getRuntimeBinding(){const e=this.stateAtom.get(),t=pe(e),i=B(e);if(!t||!i)return null;const s="queue"===t.type?me(N(e)):null;return{experienceId:this.experienceId,sequenceId:i,participationId:t.id,participationType:t.type,...s?{runtimeContextToken:s}:{}}}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(P(this.experienceId),{persist:!1});const t=Ve(e);if(!t)return;const i="routing"===t.journeyStage?z({base:this.baseFromSnapshot(t),journeyStage:"ready"}):t,s=this.stateAtom.get();if(s.revision===i.revision&&s.updatedAt===i.updatedAt)return;const r=pe(i);r||(this.displayAtom=null,this.displayParticipationId=void 0),this.setServerSnapshot(i,void 0,!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 A(e,t);case"queue":return v(e,t);case"timed_release":return G(e,t);default:return e}}stopPolling(){this.pollTimer&&(clearInterval(this.pollTimer),this.pollTimer=void 0)}}const Se=c.picklist(["queue","draw","auction","timed_release","appointment"]),be=Se,Ae=c.picklist(["queue","draw","auction","timed_release"]),Ie=c.picklist(["draw","auction"]),ve=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()))}),qe=c.object({id:c.string(),name:c.string(),experienceId:c.string(),priority:c.number(),color:c.nullable(c.string()),availability:c.optional(s)}),we=c.strictObject({type:Se,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())}),Ce=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())}),ke=c.strictObject({token:c.string(),distributionType:Ae,distributionId:c.string(),sequenceId:c.string(),experienceId:c.string(),issuedAt:c.optional(c.string()),expiresAt:c.optional(c.string())}),je=c.strictObject({orderId:c.string(),amount:c.string(),currencyCode:c.string(),paymentMethodLast4:c.optional(c.string()),paymentMethodBrand:c.optional(c.string())}),xe=c.strictObject({publishableKey:c.string(),stripeAccount:c.optional(c.string())}),Te=c.strictObject({type:c.string(),reason:c.optional(c.string()),at:c.optional(c.string()),distributionType:c.optional(Se),distributionId:c.optional(c.string())}),Ee=c.strictObject({phase:c.literal("unavailable"),reason:c.optional(c.string())}),De=c.strictObject({waitlistId:c.string(),status:c.picklist(["not_waitlisted","waitlisted"]),entryId:c.optional(c.string())}),Re=c.strictObject({phase:c.literal("scheduled"),mechanism:be,distribution:we}),Oe=c.strictObject({phase:c.literal("enterable"),mechanism:be,distribution:we,consumer:Ce,paymentProvider:c.optional(xe)}),Me=c.strictObject({phase:c.literal("participating"),mechanism:be,distribution:we,consumer:Ce}),Ge=c.strictObject({phase:c.literal("settling"),mechanism:Ie,distribution:we,consumer:Ce}),Fe=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(xe)}),c.strictObject({processor:c.literal("internal"),mode:c.literal("pre_auth")})]),_e=c.strictObject({phase:c.literal("granted"),mechanism:Ae,distribution:we,consumer:Ce,grant:ke,settlement:Fe,selection:r}),Pe=c.strictObject({phase:c.literal("ended"),mechanism:be,distribution:we,consumer:Ce,outcome:Te,checkout:c.optional(je)}),He=c.union([Ee,Re,Oe,Me,Ge,_e,Pe]),Ne={schemaVersion:c.literal(6),revision:c.number(),updatedAt:c.number(),experienceId:c.string(),accessCode:c.optional(c.string()),experience:c.optional(c.unknown()),events:c.array(ve),lastSeenEventId:c.optional(c.string()),lastSyncedAt:c.optional(c.number())},Ue=c.strictObject({...Ne,journeyStage:c.literal("ready")}),ze=c.strictObject({...Ne,journeyStage:c.literal("routing")}),Be=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"])]),Le=c.strictObject({...Ne,journeyStage:c.literal("gated"),gates:c.array(Be),selected:c.optional(c.strictObject({sequence:c.unknown(),status:c.literal("gated")}))}),We=c.strictObject({...Ne,journeyStage:c.literal("routed"),sequenceId:c.string(),offers:c.array(c.object({sequence:c.unknown(),status:c.literal("gated"),gates:c.array(Be)})),sequence:He,waitlist:c.optional(De),sequenceRef:c.optional(qe)}),Je=c.union([Ue,ze,Le,We]);function Ve(e){const t=c.safeParse(Je,e);if(!t.success)return null;const{schemaVersion:i,...s}=t.output;if("routed"===s.journeyStage)try{te(s.sequence)}catch{return null}return s}function Qe(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 $e(e){return"routed"!==e.journeyStage||"granted"!==e.sequence.phase&&"ended"!==e.sequence.phase||!("checkout"in e.sequence)?$(e):e.sequence.checkout}function Ke(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.settlement}function Xe(e){if("routed"===e.journeyStage&&"granted"===e.sequence.phase)return e.sequence.selection}export{fe as ExperienceJourney,le as isSelfContradictingDistribution};
|
|
@@ -23,4 +23,4 @@ export type { DomBridge, DomBridgeOptions } from './dom-bridge';
|
|
|
23
23
|
export { describeJourneyState, selectJourneyDisplay } from './journey-display';
|
|
24
24
|
export type { JourneyDisplaySelection, JourneyStateDescription } from './journey-display';
|
|
25
25
|
export type { AccessCodeSubmitResult, AdmissionGrant, AppointmentConsumerStatus, AppointmentEnded, AppointmentEndedView, AppointmentEnterable, AppointmentEnterableView, AppointmentParticipating, AppointmentParticipatingView, AppointmentSequence, AppointmentSequenceView, AuctionConsumerStatus, AuctionEnded, AuctionEndedView, AuctionEnterable, AuctionEnterableView, AuctionGranted, AuctionGrantedAwaitingAssignmentView, AuctionGrantedSelectionRequiredView, AuctionGrantedView, AuctionParticipating, AuctionParticipatingView, AuctionScheduled, AuctionScheduledView, AuctionSequence, AuctionSequenceView, AuctionSettling, AuctionSettlingView, ConsumerJourneyState, ConsumerSequenceState, DistributionLifecycle, DistributionSummary, DistributionType, DrawConsumerStatus, DrawEnded, DrawEndedView, DrawEnterable, DrawEnterableView, DrawGranted, DrawGrantedAwaitingAssignmentView, DrawGrantedSelectionRequiredView, DrawGrantedView, DrawParticipating, DrawParticipatingView, DrawScheduled, DrawScheduledView, DrawSequence, DrawSequenceView, DrawSettling, DrawSettlingView, EnterableSequenceView, GatedSnapshot, GatedView, JourneyEvent, JourneyEventAudience, JourneyEventKind, JourneyEventSeverity, JourneyHandle, JourneySnapshot, JourneyStage, JourneyView, ParticipatingSequenceView, Participation, PrimarySequenceMechanism, QueueConsumerStatus, QueueEnded, QueueEndedView, QueueEnterable, QueueEnterableView, QueueGranted, QueueGrantedAwaitingAssignmentView, QueueGrantedSelectionRequiredView, QueueGrantedView, QueueParticipating, QueueParticipatingView, QueueScheduled, QueueScheduledView, QueueSequence, QueueSequenceView, ReadySnapshot, ReadyView, RoutedSnapshot, RoutedView, RoutingGate, RoutingOffer, RoutingSnapshot, RoutingView, SequenceMechanism, SequenceOutcome, SequenceOutcomeType, SequencePhase, SequenceState, SequenceView, ServiceJourneyStage, ServiceJourneyState, TimedReleaseConsumerStatus, TimedReleaseEnded, TimedReleaseEndedView, TimedReleaseEnterable, TimedReleaseEnterableView, TimedReleaseGranted, TimedReleaseGrantedAwaitingAssignmentView, TimedReleaseGrantedView, TimedReleaseParticipating, TimedReleaseParticipatingView, TimedReleaseScheduled, TimedReleaseScheduledView, TimedReleaseSequence, TimedReleaseSequenceView, WaitlistAttachment, WaitlistAttachmentView, WaitlistConsumerStatus, } from './journey.types';
|
|
26
|
-
export type { ConsumerMe, Distribution, DistributionContext, Experience, ExperienceDetails, ExperienceSession, JourneyDistributionType, JourneyParticipationType, Sequence, } from './types';
|
|
26
|
+
export type { ConsumerMe, Distribution, DistributionContext, Experience, ExperienceDetails, ExperienceSession, ExperienceTiming, JourneyDistributionType, JourneyParticipationType, Sequence, } from './types';
|
|
@@ -31,6 +31,17 @@ export interface Experience {
|
|
|
31
31
|
/** ISO 8601 timestamp when the experience was last updated. */
|
|
32
32
|
updatedAt: string;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Public timing of an experience: whether it is upcoming, open or closed, and
|
|
36
|
+
* the boundaries around that status.
|
|
37
|
+
*/
|
|
38
|
+
export interface ExperienceTiming {
|
|
39
|
+
status?: "upcoming" | "open" | "closed" | null;
|
|
40
|
+
nextOpensAt?: string | null;
|
|
41
|
+
lastClosedAt?: string | null;
|
|
42
|
+
/** Set only while open: the instant the drop stops being open; null when the open run has no end. */
|
|
43
|
+
closesAt?: string | null;
|
|
44
|
+
}
|
|
34
45
|
/**
|
|
35
46
|
* Experience metadata with embeddable configuration and sequence context.
|
|
36
47
|
*
|
|
@@ -46,6 +57,8 @@ export interface ExperienceDetails extends Experience {
|
|
|
46
57
|
i18n?: Record<string, Record<string, string>>;
|
|
47
58
|
/** Brand theme applied by SDK UI adapters. */
|
|
48
59
|
theme?: BrandTheme;
|
|
60
|
+
/** Public timing; absent or null when the experience publishes none. */
|
|
61
|
+
timing?: ExperienceTiming | null;
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
51
64
|
* Consumer session for an entered experience.
|
package/dist/internals.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* release. Customer-facing API lives on the domain subpaths (see
|
|
6
6
|
* docs/PUBLIC_SURFACE.md).
|
|
7
7
|
*/
|
|
8
|
+
export { readExperienceDetails } from './core/internal-sdk-registry';
|
|
8
9
|
export type { DistributionMonitor, MonitorUpdate } from './experiences/distribution-monitor.types';
|
|
9
10
|
export { createDomBridge } from './experiences/dom-bridge';
|
|
10
11
|
export { describeJourneyState, selectJourneyDisplay } from './experiences/journey-display';
|
package/dist/internals.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{readExperienceDetails as e}from"./core/internal-sdk-registry.js";import{createDomBridge as r}from"./experiences/dom-bridge.js";import{describeJourneyState as o,selectJourneyDisplay as i}from"./experiences/journey-display.js";import{SnapshotInvariantError as m,getAdmissionGrant as s,getAdmissionGrantExpiresAt as t,getDistribution as p,getGates as n,getOffers as j,getParticipation as f,getSelected as c,getSequenceId as d,getSequencePhase as a,getSequenceState as l,isGateState as u,isPreEntryJourney as x,isRoutedState as y}from"./experiences/journey.machine.js";import{getEventBus as g}from"./state/events.js";import{generateFingerprint as b,generateFingerprintSync as h}from"./utils/fingerprint.module.js";export{m as SnapshotInvariantError,r as createDomBridge,o as describeJourneyState,b as generateFingerprint,h as generateFingerprintSync,s as getAdmissionGrant,t as getAdmissionGrantExpiresAt,p as getDistribution,g as getEventBus,n as getGates,j as getOffers,f as getParticipation,c as getSelected,d as getSequenceId,a as getSequencePhase,l as getSequenceState,u as isGateState,x as isPreEntryJourney,y as isRoutedState,e as readExperienceDetails,i as selectJourneyDisplay};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createError as t}from"../core/errors.js";import{getLogger as e}from"../core/logger.js";import{createPollScheduler as s}from"../core/poll-scheduler.js";import{DistributionMonitorRuntime as i}from"../experiences/distribution-monitor.runtime.js";import{isEntryActionRequired as o}from"../payment/checkout-contract.js";import{getEventBus as n}from"../state/events.js";import{getSDKStore as r}from"../state/store.js";class a{constructor(t){this.logger=e(),this.store=r(),this.events=n(),this.trackedParticipations=/* @__PURE__ */new Map,this.pollSchedulers=/* @__PURE__ */new Map,this.inFlightRequests=/* @__PURE__ */new Map,this.monitorRuntime=new i,this.monitorGenerations=/* @__PURE__ */new Map,this.operationGenerations=/* @__PURE__ */new Map,this.hasSuccessfulReadThisSession=/* @__PURE__ */new Map,this.lastQueueStatus=/* @__PURE__ */new Map,this.destroyed=!1,this.lifecycleGeneration=0,this.http=t}async get(t){try{return await this.http.get(`/queues/${t}`)}catch(e){throw this.logger.error("Failed to get queue",{queueId:t,error:e}),e}}async enter(e,s,i,n,r){const a=this.lifecycleGeneration;let u;try{if(!this.store.session)throw t.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");u=this.bumpOperationGeneration(e),this.logger.info("Entering queue",{queueId:e});const
|
|
1
|
+
import{createError as t}from"../core/errors.js";import{getLogger as e}from"../core/logger.js";import{createPollScheduler as s}from"../core/poll-scheduler.js";import{DistributionMonitorRuntime as i}from"../experiences/distribution-monitor.runtime.js";import{isEntryActionRequired as o}from"../payment/checkout-contract.js";import{getEventBus as n}from"../state/events.js";import{getSDKStore as r}from"../state/store.js";class a{constructor(t){this.logger=e(),this.store=r(),this.events=n(),this.trackedParticipations=/* @__PURE__ */new Map,this.pollSchedulers=/* @__PURE__ */new Map,this.inFlightRequests=/* @__PURE__ */new Map,this.monitorRuntime=new i,this.monitorGenerations=/* @__PURE__ */new Map,this.operationGenerations=/* @__PURE__ */new Map,this.queuedDisplayPrivacyEpochs=/* @__PURE__ */new Map,this.hasSuccessfulReadThisSession=/* @__PURE__ */new Map,this.lastQueueStatus=/* @__PURE__ */new Map,this.destroyed=!1,this.lifecycleGeneration=0,this.http=t}async get(t){try{return await this.http.get(`/queues/${t}`)}catch(e){throw this.logger.error("Failed to get queue",{queueId:t,error:e}),e}}async enter(e,s,i,n,r){const a=this.lifecycleGeneration;let u,p=0;try{if(!this.store.session)throw t.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");u=this.bumpOperationGeneration(e),p=this.queuedDisplayPrivacyEpochs.get(e)??0,this.logger.info("Entering queue",{queueId:e});const c={metadata:s};n&&(c.paymentInput=n);const l=await this.http.post(`/queues/${e}/enter`,c,i);if(o(l))return l;const h=this.canApplyAsyncResult(e,a,void 0,u),d=this.projectResponse(e,l,p,h);if(!h)return d;const y=this.buildTransition(e,d,{source:"enter",enteredAt:/* @__PURE__ */(new Date).toISOString(),metadata:s});return"QUEUED"!==l.status&&"GRANTED"!==l.status&&"COMPLETED"!==l.status||y.events.push({type:"experience:distribution-entered",payload:{distributionType:"queue",distributionId:e,...r}}),this.applyTransition(e,y),d}catch(c){if(!this.canApplyAsyncResult(e,a,void 0,u))throw c;throw this.logger.error("Failed to enter queue",{queueId:e,error:c}),this.events.emit("queue:error",{queueId:e,error:c}),c}}async leave(t,e){const s=this.lifecycleGeneration,i=this.bumpOperationGeneration(t);try{if(this.logger.info("Leaving queue",{queueId:t}),await this.http.post(`/queues/${t}/leave`,void 0,e),!this.canApplyAsyncResult(t,s,void 0,i))return;this.trackedParticipations.delete(t),this.stopStatusPolling(t),this.events.emit("queue:left",{queueId:t,reason:"user"})}catch(o){if(!this.canApplyAsyncResult(t,s,void 0,i))throw o;throw this.logger.error("Failed to leave queue",{queueId:t,error:o}),this.events.emit("queue:error",{queueId:t,error:o}),o}}async status(t){const e=this.inFlightRequests.get(t);if(e)return this.logger.debug("Returning existing in-flight request",{queueId:t}),e;const s=this.lifecycleGeneration,i=this.bumpOperationGeneration(t),o=this._doStatus(t,s,void 0,i).finally(()=>{this.inFlightRequests.delete(t)});return this.inFlightRequests.set(t,o),o}async _doStatus(t,e,s,i){const o=this.queuedDisplayPrivacyEpochs.get(t)??0;try{const n=await this.http.get(`/queues/${t}/status`),r=this.canApplyAsyncResult(t,e,s,i),a=this.projectResponse(t,n,o,r);if(!r)return a;const u=this.buildTransition(t,a,{source:"status",previousParticipation:this.trackedParticipations.get(t)});return this.applyTransition(t,u),this.events.emit("queue:status-updated",{queueId:t,status:a}),a}catch(n){if(n&&"object"==typeof n&&"status"in n&&404===n.status){const o={status:"NOT_QUEUED"};if(!this.canApplyAsyncResult(t,e,s,i))return o;const n=this.buildTransition(t,o,{source:"status",previousParticipation:this.trackedParticipations.get(t)});return this.applyTransition(t,n),this.events.emit("queue:status-updated",{queueId:t,status:o}),o}if(!this.canApplyAsyncResult(t,e,s,i)){return{status:"NOT_QUEUED"}}throw this.logger.error("Failed to get queue status",{queueId:t,error:n}),this.events.emit("queue:error",{queueId:t,error:n}),n}}startMonitoring(t,e,s,i){this.monitorRuntime.start(t,e,s),this.startStatusPolling(t,1e4,i)}stopMonitoring(t){this.stopStatusPolling(t),this.monitorRuntime.stop(t)}isMonitoring(t){return this.isStatusPolling(t)||this.monitorRuntime.has(t)}startStatusPolling(t,e=1e4,i){this.stopStatusPolling(t);const o=this.lifecycleGeneration,n=this.bumpMonitorGeneration(t);this.hasSuccessfulReadThisSession.set(t,!1),this.lastQueueStatus.delete(t),this.logger.debug("Starting queue polling",{queueId:t,intervalMs:e});const r=s({baseMs:e,suppressBackoff:()=>this.shouldSuppressBackoff(t),onDegradedChange:i,shouldContinue:()=>this.pollSchedulers.has(t)&&this.canApplyAsyncResult(t,o,n),run:async()=>{const e=this.getOperationGeneration(t);try{const s=await this._doStatus(t,o,n,e);this.canApplyAsyncResult(t,o,n,e)&&(this.hasSuccessfulReadThisSession.set(t,!0),this.lastQueueStatus.set(t,s))}catch(s){if(!this.canApplyAsyncResult(t,o,n,e))return;throw this.logger.error("Polling error",{queueId:t,error:s}),s}}});this.pollSchedulers.set(t,r),r.start()}stopStatusPolling(t){this.bumpMonitorGeneration(t);const e=this.pollSchedulers.get(t);e&&(e.stop(),this.pollSchedulers.delete(t),this.hasSuccessfulReadThisSession.delete(t),this.lastQueueStatus.delete(t),this.logger.debug("Stopped queue polling",{queueId:t}))}isStatusPolling(t){return this.pollSchedulers.has(t)}shouldSuppressBackoff(t){if(!this.hasSuccessfulReadThisSession.get(t))return!0;const e=this.lastQueueStatus.get(t);return"QUEUED"===e?.status&&void 0!==e.position&&e.position<=5||!("GRANTED"!==e?.status||!("expiresAt"in e)||!e.expiresAt)&&Date.now()<new Date(e.expiresAt).getTime()}bumpMonitorGeneration(t){const e=(this.monitorGenerations.get(t)??0)+1;return this.monitorGenerations.set(t,e),e}getOperationGeneration(t){return this.operationGenerations.get(t)??0}bumpOperationGeneration(t){const e=this.getOperationGeneration(t)+1;return this.operationGenerations.set(t,e),e}advancePrivacyEpoch(t){this.queuedDisplayPrivacyEpochs.set(t,(this.queuedDisplayPrivacyEpochs.get(t)??0)+1)}projectResponse(t,e,s,i){if("QUEUED"!==e.status)return e;const o=this.queuedDisplayPrivacyEpochs.get(t)??0;if(void 0===e.position&&void 0===e.estimatedWaitTimeInSeconds&&i)return this.queuedDisplayPrivacyEpochs.set(t,Math.max(o,s+1)),e;if(s>=o)return e;const{position:n,estimatedWaitTimeInSeconds:r,...a}=e;return a}canApplyAsyncResult(t,e,s,i){return!this.destroyed&&this.lifecycleGeneration===e&&((void 0===s||this.monitorGenerations.get(t)===s)&&(void 0===i||this.getOperationGeneration(t)===i))}buildTransition(t,e,{source:s,previousParticipation:i,enteredAt:o,metadata:n}){switch(e.status){case"QUEUED":{const r={...void 0===e.position?{}:{position:e.position},...void 0===e.estimatedWaitTimeInSeconds?{}:{estimatedWaitTime:e.estimatedWaitTimeInSeconds}};return{trackedParticipation:{queueId:t,enteredAt:i?.enteredAt??o??/* @__PURE__ */(new Date).toISOString(),...r,positionDisplayMode:e.positionDisplayMode,metadata:i?.metadata??n},displayState:{...r,positionDisplayMode:e.positionDisplayMode,admissionsPaused:e.admissionsPaused},events:"enter"===s?[{type:"queue:entered",payload:{queueId:t,...r}}]:void 0!==e.position&&void 0!==i?.position&&i.position!==e.position?[{type:"queue:position-changed",payload:{queueId:t,position:e.position,previousPosition:i.position}}]:[],monitorUpdate:null,stopMonitoring:!1}}case"GRANTED":return{trackedParticipation:null,events:[{type:"queue:granted",payload:{queueId:t,grant:e.admissionGrant}}],monitorUpdate:"status"===s?{type:"granted",token:e.admissionGrant,expiresAt:"expiresAt"in e&&e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null,stopMonitoring:"status"===s};case"COMPLETED":return{trackedParticipation:null,events:[],monitorUpdate:"status"===s?{type:"ended",outcome:{type:"completed"}}:null,stopMonitoring:"status"===s};case"EXPIRED":return{trackedParticipation:null,events:[{type:"queue:expired",payload:{queueId:t}}],monitorUpdate:"status"===s?{type:"ended",outcome:{type:"expired"}}:null,stopMonitoring:"status"===s};case"DENIED":return{trackedParticipation:null,events:[],monitorUpdate:"status"===s?{type:"ended",outcome:{type:"denied",reason:e.reason}}:null,stopMonitoring:"status"===s};case"LEFT":return{trackedParticipation:null,events:[],monitorUpdate:"status"===s?{type:"ended",outcome:{type:"left"}}:null,stopMonitoring:"status"===s};case"NOT_QUEUED":return{trackedParticipation:null,events:[],monitorUpdate:"status"===s?{type:"ended",outcome:{type:"closed",reason:"not_queued"}}:null,stopMonitoring:"status"===s}}}applyTransition(t,e){if(e.trackedParticipation?this.trackedParticipations.set(t,e.trackedParticipation):this.trackedParticipations.delete(t),e.displayState){const s=this.monitorRuntime.getDisplayAtom(t);s&&s.set({type:"queue",...e.displayState})}for(const s of e.events)this.events.emit(s.type,s.payload);e.monitorUpdate&&this.monitorRuntime.notify(t,e.monitorUpdate),e.stopMonitoring&&this.stopStatusPolling(t)}destroy(){this.destroyed=!0,this.lifecycleGeneration+=1;for(const t of this.pollSchedulers.values())t.stop();this.pollSchedulers.clear(),this.inFlightRequests.clear(),this.trackedParticipations.clear(),this.monitorGenerations.clear(),this.operationGenerations.clear(),this.queuedDisplayPrivacyEpochs.clear(),this.hasSuccessfulReadThisSession.clear(),this.lastQueueStatus.clear(),this.monitorRuntime.clear()}}function u(t,e){t instanceof a&&t.advancePrivacyEpoch(e)}export{a as QueueManagementModule,u as advanceQueuePrivacyEpoch};
|
package/dist/queues/types.d.ts
CHANGED
|
@@ -83,8 +83,9 @@ export type QueueConsumerState = QueuedConsumerState | GrantedConsumerState | Co
|
|
|
83
83
|
export interface QueuedConsumerState {
|
|
84
84
|
status: "QUEUED";
|
|
85
85
|
admissionsPaused?: boolean;
|
|
86
|
-
|
|
87
|
-
|
|
86
|
+
/** Absent until the queue opens. */
|
|
87
|
+
position?: number;
|
|
88
|
+
/** Absent before opening or when the queue reports no finite wait estimate. */
|
|
88
89
|
estimatedWaitTimeInSeconds?: number;
|
|
89
90
|
positionDisplayMode?: "precise" | "qualitative";
|
|
90
91
|
}
|
package/dist/state/events.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getLogger as e}from"../core/logger.js";import{deepClone as t}from"../core/utils.js";import{useSDKStore as i,toPersistedSnapshot as s}from"../state/store.js";import{isHeartbeatMessage as
|
|
1
|
+
import{getLogger as e}from"../core/logger.js";import{deepClone as t}from"../core/utils.js";import{useSDKStore as i,toPersistedSnapshot as s}from"../state/store.js";import{isHeartbeatMessage as n,isDurableBootstrapRequestMessage as a,isDurableBootstrapResponseMessage as r,isSessionUpdateMessage as o,isCapabilityTokensUpdateMessage as p,isDistributionCapabilityIndexUpdateMessage as d,isWaitlistCapabilityIndexUpdateMessage as l,isJourneyUpsertMessage as h,isJourneyRemoveMessage as u,isRuntimeStateMessage as c}from"./protocol.js";import{ProtocolTransport as b}from"./protocol-transport.js";class y{constructor(y){if(this.logger=e(),this.liveJourneys=/* @__PURE__ */new Map,this.activeTabs=/* @__PURE__ */new Map,this.runtimeOwners=/* @__PURE__ */new Map,this.runtimeCursors=/* @__PURE__ */new Map,this.unsubscribers=[],this.isApplyingRemoteUpdate=!1,this.leaderId=null,this.bootstrapSettled=!1,this.handleMessage=e=>{if(n(e))return this.recordHeartbeat(e.source,e.payload.active),void this.markBootstrapSettled();if(this.recordHeartbeat(e.source,!0),this.markBootstrapSettled(),a(e)){if(this.isLeader()){const e=i.getState();this.transport.sendDurableBootstrapResponse({session:t(e.session),sessionVersion:e.versionMap.session||0,capabilityTokens:t(e.capabilityTokens),capabilityTokensVersion:e.versionMap.capabilityTokens||0,distributionCapabilityIndex:t(e.distributionCapabilityIndex),distributionCapabilityIndexVersion:e.versionMap.distributionCapabilityIndex||0,waitlistCapabilityIndex:t(e.waitlistCapabilityIndex),waitlistCapabilityIndexVersion:e.versionMap.waitlistCapabilityIndex||0,journeys:Object.fromEntries(Object.entries(e.activeJourneys).map(([e,i])=>[e,{snapshot:t(s(i)),version:i.revision}]))})}}else r(e)?this.applyBootstrapResponse(e.payload):o(e)?this.applyVersionedStoreField("session",e.payload.value,e.payload.version):p(e)?this.applyVersionedStoreField("capabilityTokens",e.payload.value,e.payload.version):d(e)?this.applyVersionedStoreField("distributionCapabilityIndex",e.payload.value,e.payload.version):l(e)?this.applyVersionedStoreField("waitlistCapabilityIndex",e.payload.value,e.payload.version):h(e)?this.applyJourneyUpsert(e.payload.experienceId,e.payload.snapshot,e.payload.version):u(e)?this.applyJourneyRemove(e.payload.experienceId,e.payload.version):c(e)&&this.applyRuntimeState(e.payload)},this.transport=new b(y.channelName),this.enabled=(y.enabled??!0)&&this.transport.isAvailable(),this.localOnly=!this.enabled,this.unsubscribers.push(i.subscribe((e,t)=>{this.isApplyingRemoteUpdate||this.handleLocalStateChange(e,t)})),this.enabled)return this.unsubscribers.push(this.transport.onMessage(this.handleMessage)),this.sendHeartbeat(!0),this.heartbeatTimer=setInterval(()=>{this.sendHeartbeat(!0),this.pruneDeadTabs()},2e3),this.requestBootstrap(),void(this.bootstrapTimer=setTimeout(()=>{this.markBootstrapSettled()},100));this.leaderId=this.transport.getTabId(),this.activeTabs.set(this.transport.getTabId(),Date.now()),this.bootstrapSettled=!0}registerJourney(e){this.liveJourneys.set(e.getExperienceId(),e),this.syncRuntimeOwnership()}unregisterJourney(e){this.stopRuntimeOwner(e,!1),this.liveJourneys.delete(e),this.runtimeCursors.delete(e)}close(){this.enabled&&this.sendHeartbeat(!1),this.bootstrapTimer&&(clearTimeout(this.bootstrapTimer),this.bootstrapTimer=void 0),this.heartbeatTimer&&(clearInterval(this.heartbeatTimer),this.heartbeatTimer=void 0);for(const e of Array.from(this.runtimeOwners.keys()))this.stopRuntimeOwner(e,!1);for(const e of this.unsubscribers)e();this.unsubscribers.length=0,this.transport.close()}isEnabled(){return this.enabled}getTabId(){return this.transport.getTabId()}isLeader(){return this.leaderId===this.transport.getTabId()}handleLocalStateChange(e,i){this.enabled&&e.session!==i.session&&this.transport.sendSessionUpdate(t(e.session),e.versionMap.session||0),this.enabled&&e.capabilityTokens!==i.capabilityTokens&&this.transport.sendCapabilityTokensUpdate(t(e.capabilityTokens),e.versionMap.capabilityTokens||0),this.enabled&&e.distributionCapabilityIndex!==i.distributionCapabilityIndex&&this.transport.sendDistributionCapabilityIndexUpdate(t(e.distributionCapabilityIndex),e.versionMap.distributionCapabilityIndex||0),this.enabled&&e.waitlistCapabilityIndex!==i.waitlistCapabilityIndex&&this.transport.sendWaitlistCapabilityIndexUpdate(t(e.waitlistCapabilityIndex),e.versionMap.waitlistCapabilityIndex||0);const n=e.activeJourneys,a=i.activeJourneys,r=/* @__PURE__ */new Set([...Object.keys(n),...Object.keys(a)]);for(const o of r){const e=n[o],i=a[o];if(!this.enabled||!e||i&&e.revision===i.revision)this.enabled&&!e&&i&&this.transport.sendJourneyRemove(o,i.revision+1);else{const i=s(e);this.transport.sendJourneyUpsert(o,t(i),i.revision)}}n!==a&&this.syncRuntimeOwnership()}applyBootstrapResponse(e){this.applyVersionedStoreField("session",e.session,e.sessionVersion),this.applyVersionedStoreField("capabilityTokens",e.capabilityTokens,e.capabilityTokensVersion),this.applyVersionedStoreField("distributionCapabilityIndex",e.distributionCapabilityIndex,e.distributionCapabilityIndexVersion),this.applyVersionedStoreField("waitlistCapabilityIndex",e.waitlistCapabilityIndex,e.waitlistCapabilityIndexVersion);for(const[t,i]of Object.entries(e.journeys))this.applyJourneyUpsert(t,i.snapshot,i.version)}applyVersionedStoreField(e,t,s){const n=i.getState();s<=(n.versionMap[e]||0)||(this.isApplyingRemoteUpdate=!0,i.setState({[e]:t,versionMap:{...n.versionMap,[e]:s}}),this.isApplyingRemoteUpdate=!1)}applyJourneyUpsert(e,t,n){const a=i.getState(),r=a.activeJourneys[e];if(r&&r.revision>=n)return;this.isApplyingRemoteUpdate=!0;const o=s(t);i.setState({activeJourneys:{...a.activeJourneys,[e]:o}}),this.isApplyingRemoteUpdate=!1,this.liveJourneys.get(e)?.reconcileSyncedSnapshot(o),this.syncRuntimeOwnership()}applyJourneyRemove(e,t){const s=i.getState(),n=s.activeJourneys[e];if(n&&n.revision>=t)return;const{[e]:a,...r}=s.activeJourneys;this.isApplyingRemoteUpdate=!0,i.setState({activeJourneys:r}),this.isApplyingRemoteUpdate=!1,this.liveJourneys.get(e)?.reconcileSyncedSnapshot(null),this.syncRuntimeOwnership()}applyRuntimeState(e){if(e.leaderId!==this.leaderId)return;const t=this.liveJourneys.get(e.experienceId);if(!t||this.isLeader())return;const i=t.getRuntimeBinding();if(!i||i.sequenceId!==e.sequenceId||i.participationId!==e.participationId||i.participationType!==e.participationType||"queue"===i.participationType&&i.runtimeContextToken!==e.runtimeContextToken)return;const s=this.runtimeCursors.get(e.experienceId);s&&s.leaderId===e.leaderId&&s.runtimeVersion>=e.runtimeVersion||(this.runtimeCursors.set(e.experienceId,{leaderId:e.leaderId,runtimeVersion:e.runtimeVersion}),t.applyRuntimeState(e.state??null))}syncRuntimeOwnership(){if(this.bootstrapSettled){for(const[e,i]of this.liveJourneys.entries()){const s=i.getRuntimeBinding(),n=this.runtimeOwners.get(e);if(!this.isLeader()||!s){n?this.stopRuntimeOwner(e,!0):s||i.applyRuntimeState(null);continue}const a=`${s.sequenceId}:${s.participationType}:${s.participationId}`;if(n?.bindingKey===a)continue;n&&this.stopRuntimeOwner(e,!0),i.startRuntimeMonitoring();const r=i.getRuntimeDisplayAtom();if(!r)continue;const o={bindingKey:a,sequenceId:s.sequenceId,participationId:s.participationId,participationType:s.participationType,runtimeContextToken:s.runtimeContextToken,unsubscribe:()=>{},runtimeVersion:0},p=s=>{const n=i.getRuntimeBinding();if(!n)return;`${n.sequenceId}:${n.participationType}:${n.participationId}`===a&&(o.runtimeVersion+=1,o.runtimeContextToken=n.runtimeContextToken,this.enabled&&this.transport.sendRuntimeState({experienceId:e,sequenceId:n.sequenceId,participationId:n.participationId,participationType:n.participationType,runtimeContextToken:n.runtimeContextToken,leaderId:this.transport.getTabId(),runtimeVersion:o.runtimeVersion,state:t(s.get())}))};o.unsubscribe=r.listen(()=>{p(r)}),p(r),this.runtimeOwners.set(e,o)}for(const e of Array.from(this.runtimeOwners.keys()))this.liveJourneys.has(e)||this.stopRuntimeOwner(e,!0)}}stopRuntimeOwner(e,t){const i=this.runtimeOwners.get(e),s=this.liveJourneys.get(e);i?(i.unsubscribe(),t&&this.enabled&&this.isLeader()&&this.transport.sendRuntimeState({experienceId:e,sequenceId:i.sequenceId,participationId:i.participationId,participationType:i.participationType,runtimeContextToken:i.runtimeContextToken,leaderId:this.transport.getTabId(),runtimeVersion:i.runtimeVersion+1,state:null}),s?.stopRuntimeMonitoring(!0),this.runtimeOwners.delete(e)):this.runtimeOwners.delete(e)}sendHeartbeat(e){this.enabled&&(this.transport.sendHeartbeat(e),this.recordHeartbeat(this.transport.getTabId(),e))}requestBootstrap(){this.enabled&&this.transport.sendDurableBootstrapRequest()}markBootstrapSettled(){this.bootstrapSettled||(this.bootstrapSettled=!0,this.bootstrapTimer&&(clearTimeout(this.bootstrapTimer),this.bootstrapTimer=void 0),this.syncRuntimeOwnership())}recordHeartbeat(e,t){t||e===this.transport.getTabId()?this.activeTabs.set(e,Date.now()):this.activeTabs.delete(e),this.updateLeader()}pruneDeadTabs(){const e=Date.now();let t=!1;for(const[i,s]of this.activeTabs.entries())i!==this.transport.getTabId()&&e-s>6e3&&(this.activeTabs.delete(i),t=!0);t&&this.updateLeader()}updateLeader(){if(this.localOnly)return void(this.leaderId=this.transport.getTabId());const e=[this.transport.getTabId(),...this.activeTabs.keys()].sort()[0]??this.transport.getTabId();e!==this.leaderId&&(this.leaderId=e,this.runtimeCursors.clear(),this.logger.info("Cross-tab leader changed",{leaderId:e,tabId:this.transport.getTabId(),isLeader:this.isLeader()}),this.isLeader()||this.requestBootstrap(),this.syncRuntimeOwnership())}}export{y as CrossTabCoordinator};
|
package/dist/sync/protocol.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import*as e from"valibot";const t=e.object({id:e.string(),timestamp:e.number(),source:e.string(),version:e.number()}),n=e.intersect([t,e.object({type:e.literal("durable:bootstrap:request"),payload:e.object({})})]),i=e.object({snapshot:e.unknown(),version:e.number()}),r=e.intersect([t,e.object({type:e.literal("durable:bootstrap:response"),payload:e.object({session:e.unknown(),sessionVersion:e.number(),capabilityTokens:e.unknown(),capabilityTokensVersion:e.number(),distributionCapabilityIndex:e.unknown(),distributionCapabilityIndexVersion:e.number(),waitlistCapabilityIndex:e.unknown(),waitlistCapabilityIndexVersion:e.number(),journeys:e.record(e.string(),i)})})]),o=e.intersect([t,e.object({type:e.literal("session:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),a=e.intersect([t,e.object({type:e.literal("capability-tokens:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),s=e.intersect([t,e.object({type:e.literal("distribution-capability-index:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),u=e.intersect([t,e.object({type:e.literal("waitlist-capability-index:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),p=e.intersect([t,e.object({type:e.literal("journey:upsert"),payload:e.object({experienceId:e.string(),snapshot:e.unknown(),version:e.number()})})]),c=e.intersect([t,e.object({type:e.literal("journey:remove"),payload:e.object({experienceId:e.string(),version:e.number()})})]),
|
|
1
|
+
import*as e from"valibot";const t=e.object({id:e.string(),timestamp:e.number(),source:e.string(),version:e.number()}),n=e.intersect([t,e.object({type:e.literal("durable:bootstrap:request"),payload:e.object({})})]),i=e.object({snapshot:e.unknown(),version:e.number()}),r=e.intersect([t,e.object({type:e.literal("durable:bootstrap:response"),payload:e.object({session:e.unknown(),sessionVersion:e.number(),capabilityTokens:e.unknown(),capabilityTokensVersion:e.number(),distributionCapabilityIndex:e.unknown(),distributionCapabilityIndexVersion:e.number(),waitlistCapabilityIndex:e.unknown(),waitlistCapabilityIndexVersion:e.number(),journeys:e.record(e.string(),i)})})]),o=e.intersect([t,e.object({type:e.literal("session:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),a=e.intersect([t,e.object({type:e.literal("capability-tokens:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),s=e.intersect([t,e.object({type:e.literal("distribution-capability-index:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),u=e.intersect([t,e.object({type:e.literal("waitlist-capability-index:update"),payload:e.object({value:e.unknown(),version:e.number()})})]),p=e.intersect([t,e.object({type:e.literal("journey:upsert"),payload:e.object({experienceId:e.string(),snapshot:e.unknown(),version:e.number()})})]),c=e.intersect([t,e.object({type:e.literal("journey:remove"),payload:e.object({experienceId:e.string(),version:e.number()})})]),l=e.intersect([t,e.object({type:e.literal("runtime:state"),payload:e.object({experienceId:e.string(),sequenceId:e.string(),participationId:e.string(),participationType:e.picklist(["queue","draw","auction","timed_release","appointment"]),runtimeContextToken:e.optional(e.string()),leaderId:e.string(),runtimeVersion:e.number(),state:e.nullable(e.unknown())})})]),b=e.intersect([t,e.object({type:e.literal("heartbeat"),payload:e.object({active:e.boolean()})})]),y=e.union([n,r,o,a,s,u,p,c,l,b]),d=new Set(y.options.map(e=>e.options[1].entries.type.literal));function j(e){const t=null!==e&&"object"==typeof e&&"type"in e?e.type:void 0;return"string"==typeof t&&d.has(t)?t:"<unknown>"}function m(e){return"durable:bootstrap:request"===e.type}function k(e){return"durable:bootstrap:response"===e.type}function w(e){return"session:update"===e.type}function v(e){return"capability-tokens:update"===e.type}function f(e){return"distribution-capability-index:update"===e.type}function x(e){return"waitlist-capability-index:update"===e.type}function g(e){return"journey:upsert"===e.type}function I(e){return"journey:remove"===e.type}function h(e){return"runtime:state"===e.type}function C(e){return"heartbeat"===e.type}const V=3,q="fanfare-sdk-sync";export{q as DEFAULT_CHANNEL_NAME,V as PROTOCOL_VERSION,y as SyncMessageSchema,v as isCapabilityTokensUpdateMessage,f as isDistributionCapabilityIndexUpdateMessage,m as isDurableBootstrapRequestMessage,k as isDurableBootstrapResponseMessage,C as isHeartbeatMessage,I as isJourneyRemoveMessage,g as isJourneyUpsertMessage,h as isRuntimeStateMessage,w as isSessionUpdateMessage,x as isWaitlistCapabilityIndexUpdateMessage,j as messageType};
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const o="0.
|
|
1
|
+
const o="0.24.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.
|
|
3
|
+
"version": "0.24.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",
|
|
@@ -110,12 +110,11 @@
|
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
112
|
"dependencies": {
|
|
113
|
-
"big.js": "^7.0.1",
|
|
114
113
|
"nanostores": "^1.1.0",
|
|
115
114
|
"uuid": "^14.0.0",
|
|
116
115
|
"wretch": "^2.11.0",
|
|
117
116
|
"zustand": "^5.0.6",
|
|
118
|
-
"@fanfare-io/fanfare-sdk-contracts": "0.
|
|
117
|
+
"@fanfare-io/fanfare-sdk-contracts": "0.24.0"
|
|
119
118
|
},
|
|
120
119
|
"peerDependencies": {
|
|
121
120
|
"valibot": "^1.1.0"
|
|
@@ -127,7 +126,6 @@
|
|
|
127
126
|
"@storybook/addon-onboarding": "^10.2.16",
|
|
128
127
|
"@storybook/addon-vitest": "^10.2.16",
|
|
129
128
|
"@storybook/react-vite": "^10.2.16",
|
|
130
|
-
"@types/big.js": "^6.2.2",
|
|
131
129
|
"@types/node": "^24.1.0",
|
|
132
130
|
"@types/react": "^19.1.12",
|
|
133
131
|
"@types/react-dom": "^19.1.9",
|
|
@@ -154,7 +152,7 @@
|
|
|
154
152
|
"vite-plugin-dts": "^4.5.4",
|
|
155
153
|
"vite-tsconfig-paths": "^5.1.4",
|
|
156
154
|
"vitest": "^5.0.0",
|
|
157
|
-
"@fanfare-io/shared-models": "0.
|
|
155
|
+
"@fanfare-io/shared-models": "0.24.0"
|
|
158
156
|
},
|
|
159
157
|
"sideEffects": false,
|
|
160
158
|
"keywords": [
|
|
@@ -171,7 +169,7 @@
|
|
|
171
169
|
{
|
|
172
170
|
"name": "Core + Queues",
|
|
173
171
|
"path": "dist/index.js",
|
|
174
|
-
"limit": "56 KB"
|
|
172
|
+
"limit": "56.5 KB"
|
|
175
173
|
}
|
|
176
174
|
],
|
|
177
175
|
"scripts": {
|