@fanfare-io/fanfare-sdk-core 0.12.0 → 0.13.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.
Files changed (86) hide show
  1. package/dist/auctions/auction-status.js +1 -1
  2. package/dist/auctions/auction.driver.js +1 -1
  3. package/dist/auctions/auction.module.js +1 -1
  4. package/dist/auctions/types.d.ts +6 -0
  5. package/dist/core/client.js +1 -1
  6. package/dist/core/error-display.d.ts +5 -0
  7. package/dist/core/error-display.js +1 -1
  8. package/dist/core/error-disposition.js +1 -1
  9. package/dist/core/errors.d.ts +2 -0
  10. package/dist/core/errors.js +1 -1
  11. package/dist/version.d.ts +1 -1
  12. package/dist/version.js +1 -1
  13. package/dist/waitlists/types.d.ts +1 -1
  14. package/dist/waitlists/waitlist.module.js +1 -1
  15. package/package.json +8 -28
  16. package/dist/appointments/appointment.driver.d.ts +0 -44
  17. package/dist/appointments/appointment.module.d.ts +0 -33
  18. package/dist/appointments/index.d.ts +0 -2
  19. package/dist/auctions/auction-status.d.ts +0 -4
  20. package/dist/auctions/auction.driver.d.ts +0 -60
  21. package/dist/auctions/auction.module.d.ts +0 -73
  22. package/dist/auctions/index.d.ts +0 -5
  23. package/dist/auth/auth.module.d.ts +0 -167
  24. package/dist/beacon/batching.d.ts +0 -52
  25. package/dist/challenges/challenge.module.d.ts +0 -9
  26. package/dist/challenges/index.d.ts +0 -3
  27. package/dist/core/logger.d.ts +0 -46
  28. package/dist/core/money.d.ts +0 -10
  29. package/dist/core/parse-response.d.ts +0 -62
  30. package/dist/core/poll-scheduler.d.ts +0 -21
  31. package/dist/draws/draw.driver.d.ts +0 -45
  32. package/dist/draws/draw.module.d.ts +0 -48
  33. package/dist/draws/index.d.ts +0 -5
  34. package/dist/experiences/distribution-monitor.runtime.d.ts +0 -12
  35. package/dist/experiences/experience.module.d.ts +0 -89
  36. package/dist/experiences/index.d.ts +0 -3
  37. package/dist/experiences/index.js +0 -1
  38. package/dist/experiences/journey-contract.fixtures.d.ts +0 -12
  39. package/dist/experiences/journey-view.d.ts +0 -25
  40. package/dist/experiences/journey.d.ts +0 -204
  41. package/dist/experiences/sequence-driver.d.ts +0 -116
  42. package/dist/experiences/settlement.d.ts +0 -3
  43. package/dist/harness.d.ts +0 -21
  44. package/dist/harness.js +0 -1
  45. package/dist/payment/checkout-contract.d.ts +0 -39
  46. package/dist/payment/payment.module.d.ts +0 -16
  47. package/dist/queues/queue.driver.d.ts +0 -45
  48. package/dist/queues/queue.module.d.ts +0 -46
  49. package/dist/state/capability-token-registry.d.ts +0 -58
  50. package/dist/state/store.d.ts +0 -61
  51. package/dist/sync/broadcast-transport.d.ts +0 -19
  52. package/dist/sync/cross-tab-coordinator.d.ts +0 -44
  53. package/dist/sync/index.d.ts +0 -8
  54. package/dist/sync/localstorage-transport.d.ts +0 -32
  55. package/dist/sync/protocol-transport.d.ts +0 -52
  56. package/dist/sync/protocol.d.ts +0 -283
  57. package/dist/sync/recovery.d.ts +0 -68
  58. package/dist/sync/transport-factory.d.ts +0 -16
  59. package/dist/sync/transport-interface.d.ts +0 -33
  60. package/dist/sync/transport.d.ts +0 -49
  61. package/dist/test-utils/harness-scenarios.d.ts +0 -85
  62. package/dist/test-utils/harness-scenarios.js +0 -1
  63. package/dist/test-utils/index.d.ts +0 -13
  64. package/dist/test-utils/index.js +0 -1
  65. package/dist/test-utils/mock-journey.d.ts +0 -76
  66. package/dist/test-utils/mock-journey.js +0 -1
  67. package/dist/test-utils/mock-sdk-vitest.d.ts +0 -81
  68. package/dist/test-utils/mock-sdk-vitest.js +0 -1
  69. package/dist/test-utils/mock-sdk.d.ts +0 -30
  70. package/dist/test-utils/mock-sdk.js +0 -1
  71. package/dist/test-utils/mock-server.d.ts +0 -125
  72. package/dist/test-utils/mock-server.js +0 -1
  73. package/dist/test-utils/phone-formatter-contract.d.ts +0 -24
  74. package/dist/test-utils/phone-formatter-contract.js +0 -1
  75. package/dist/test-utils/sdk-factory.d.ts +0 -3
  76. package/dist/test-utils/sdk-factory.js +0 -1
  77. package/dist/test-utils/verification-scenarios.d.ts +0 -51
  78. package/dist/test-utils/verification-scenarios.js +0 -1
  79. package/dist/test-utils/verification-state.d.ts +0 -1
  80. package/dist/test-utils/verification-state.js +0 -1
  81. package/dist/timed-releases/index.d.ts +0 -6
  82. package/dist/timed-releases/timed-release.driver.d.ts +0 -45
  83. package/dist/timed-releases/timed-release.module.d.ts +0 -36
  84. package/dist/utils/index.d.ts +0 -4
  85. package/dist/waitlists/index.d.ts +0 -2
  86. package/dist/waitlists/waitlist.module.d.ts +0 -17
@@ -1 +1 @@
1
- function n(n){switch(n){case"NOT_BID":return"not_bid";case"BIDDING":return"bidding";case"WINNING":return"winning";case"OUTBID":return"outbid";case"WON":return"won";case"LOST":return"lost"}}function r(n){return"won"===n||"lost"===n}export{r as isTerminalAuctionStatus,n as toAuctionConsumerStatus};
1
+ function n(n){switch(n){case"NOT_BID":return"not_bid";case"BIDDING":return"bidding";case"WINNING":return"winning";case"OUTBID":return"outbid";case"WON":return"won";case"LOST":return"lost"}}function t(n){return"won"===n||"lost"===n}function r(n){return"won"===n.status&&!0===n.degraded&&!n.admissionGrant}export{r as isGrantPendingWin,t as isTerminalAuctionStatus,n as toAuctionConsumerStatus};
@@ -1 +1 @@
1
- import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as i}from"../core/errors.js";import{isMoneyString as e,addMoney as n}from"../core/money.js";import{isUnresolvedAuctionConsumer as s}from"./auction.sequence.js";function o(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function a(t){return new d(t)}function r(e){const{distribution:n,consumer:a,grant:r,outcome:c}=e;if(!n)return{phase:"unavailable"};const u=function(t){if("auction"!==t.type)throw i.validationError("Auction driver received a non-auction distribution");return t}(n),d=a&&"auction"===a.mechanism?function(t){const{mechanism:i,...e}=t;return e}(a):p(n);if(r)return"completed"===c?.type?h(u,d,c):r.expiresAt&&Date.now()>new Date(r.expiresAt).getTime()?"open"===u.lifecycle?{phase:"enterable",mechanism:"auction",distribution:u,consumer:p(u)}:h(u,d,{type:"expired"}):{phase:"granted",mechanism:"auction",distribution:u,consumer:d,grant:r};if("closed"===u.lifecycle){if("not_bid"===d.status&&u.result===t.FLOOR_UNSOLD&&o(c))return h(u,d,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===a?.mechanism&&!c)return h(u,d,{type:"lost"})}const m=c??function(t){return"lost"===t.status?{type:"lost"}:void 0}(d);return m?h(u,d,m):"settling"===u.lifecycle?{phase:"settling",mechanism:"auction",distribution:u,consumer:d}:s(d)?{phase:"participating",mechanism:"auction",distribution:u,consumer:d}:"scheduled"===u.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:u}:"open"===u.lifecycle?{phase:"enterable",mechanism:"auction",distribution:u,consumer:d}:h(u,d,{type:"closed"})}function c(t,i){return"auction"===t?.mechanism?{...t,status:"won"}:{mechanism:"auction",status:"won",id:i.id,distributionId:i.id}}function u(t,i,e){return t&&"auction"===t.mechanism&&i?"won"===i.type?{...t,status:"won"}:!e?.finalize&&"not_bid"===t.status&&o(i)?t:{...t,status:"lost"}:t}class d{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return r(t)}buildView(t,e){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const n=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("Auction driver received a non-auction sequence");return t}(t);switch(n.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:n.distribution,startsAt:n.distribution.startsAt??n.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"auction",distribution:n.distribution,consumer:n.consumer,bid:t=>this.bid(t)};case"participating":return{phase:"participating",mechanism:"auction",consumer:n.consumer,display$:e.displayAtom,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:n.distribution,consumer:n.consumer};case"granted":return{phase:"granted",mechanism:"auction",distribution:n.distribution,consumer:n.consumer,grant:n.grant,claim:()=>e.claim()};case"ended":return{phase:"ended",mechanism:"auction",consumer:n.consumer,outcome:n.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 enter(){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation()})}async enterWithinOperation(){const t=this.currentAuctionSequence("enterable","No open auction to enter").distribution;await this.deps.auctions.enter(t.id,void 0),await this.deps.auctions.status(t.id);const i={mechanism:"auction",status:"not_bid",id:e=t.id,distributionId:e};var e;this.deps.ensureDisplayAtom({id:t.id,type:"auction"}),this.deps.commit(r({distribution:t,consumer:i})),this.deps.emitEvent("sequence_change","success","user","Entered auction",{distributionId:t.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const t=this.currentAuctionSequence("participating"),i=t.consumer.distributionId??t.consumer.id??t.distribution.id;await this.deps.auctions.leave(i),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"auction"})}async bid(t){await this.deps.runSerializedOperation(async()=>{const i=this.currentAuctionSequenceForBid(),s=i.consumer.distributionId??i.consumer.id??i.distribution.id,o=await this.deps.auctions.bid(s,t);if("won"===o.status||"lost"===o.status){const t=this.deps.getCurrentSequence();return void(t&&("enterable"===t.phase||"participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"auction"===t.mechanism&&t.distribution.id===s&&("won"===o.status&&o.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:o.admissionGrant}):this.deps.applyMonitorUpdate({type:"ended",outcome:{type:o.status}})))}const a=function(t){switch(t){case"not_bid":case"bidding":case"winning":case"outbid":return t;case"won":case"lost":return}}(o.status);if(void 0===a)return;const c="auction"===i.distribution.details?.type?i.distribution.details:void 0,u=c?.bidIncrement,d=o.highestBid&&u&&e(o.highestBid)&&e(u)?n(o.highestBid,u):void 0,p=this.deps.getDisplayState(),h="auction"===p?.type?p.settleAt:void 0,m=this.deps.ensureDisplayAtom({id:s,type:"auction"});"enterable"===i.phase&&this.deps.commit(r({distribution:i.distribution,consumer:{mechanism:"auction",status:a,id:s,distributionId:s,currentBid:t,highestBid:o.highestBid}})),m.set({type:"auction",currentBid:t,highestBid:o.highestBid,bidCount:o.bidCount,status:a,currencyCode:c?.currencyCode,bidIncrement:u,minNextBid:d,closeAt:c?.closeAt??c?.endsAt,settleAt:h})})}currentAuctionSequence(t,e="Not participating in an auction"){const n=this.deps.getCurrentSequence();if(!n||n.phase!==t||!("mechanism"in n)||"auction"!==n.mechanism)throw i.validationError(e);return n}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("No auction is available to bid on");return t}}function p(t){return{status:"not_bid",distributionId:t.id}}function h(t,i,e){return{phase:"ended",mechanism:"auction",distribution:t,consumer:i,outcome:{...e,distributionType:e.distributionType??t.type,distributionId:e.distributionId??t.id,at:e.at??/* @__PURE__ */(new Date).toISOString()}}}export{a as createAuctionDriver,o as isUpgradeableGenericLoss,r as projectAuctionSequence,c as withAuctionGrantedConsumer,u as withAuctionTerminalConsumer};
1
+ import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as i}from"../core/errors.js";import{isMoneyString as e,addMoney as n}from"../core/money.js";import{isGrantPendingWin as s}from"./auction-status.js";import{isUnresolvedAuctionConsumer as o}from"./auction.sequence.js";function a(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function r(t){return new p(t)}function c(e){const{distribution:n,consumer:s,grant:r,outcome:c}=e;if(!n)return{phase:"unavailable"};const u=function(t){if("auction"!==t.type)throw i.validationError("Auction driver received a non-auction distribution");return t}(n),d=s&&"auction"===s.mechanism?function(t){const{mechanism:i,...e}=t;return e}(s):h(n);if(r)return"completed"===c?.type?m(u,d,c):r.expiresAt&&Date.now()>new Date(r.expiresAt).getTime()?"open"===u.lifecycle?{phase:"enterable",mechanism:"auction",distribution:u,consumer:h(u)}:m(u,d,{type:"expired"}):{phase:"granted",mechanism:"auction",distribution:u,consumer:d,grant:r};if("closed"===u.lifecycle){if("not_bid"===d.status&&u.result===t.FLOOR_UNSOLD&&a(c))return m(u,d,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===s?.mechanism&&!c)return m(u,d,{type:"lost"})}const p=c??function(t){return"lost"===t.status?{type:"lost"}:void 0}(d);return p?m(u,d,p):"settling"===u.lifecycle?{phase:"settling",mechanism:"auction",distribution:u,consumer:d}:o(d)?{phase:"participating",mechanism:"auction",distribution:u,consumer:d}:"scheduled"===u.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:u}:"open"===u.lifecycle?{phase:"enterable",mechanism:"auction",distribution:u,consumer:d}:m(u,d,{type:"closed"})}function u(t,i){return"auction"===t?.mechanism?{...t,status:"won"}:{mechanism:"auction",status:"won",id:i.id,distributionId:i.id}}function d(t,i,e){return t&&"auction"===t.mechanism&&i?"won"===i.type?{...t,status:"won"}:!e?.finalize&&"not_bid"===t.status&&a(i)?t:{...t,status:"lost"}:t}class p{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return c(t)}buildView(t,e){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const n=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("Auction driver received a non-auction sequence");return t}(t);switch(n.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:n.distribution,startsAt:n.distribution.startsAt??n.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"auction",distribution:n.distribution,consumer:n.consumer,bid:t=>this.bid(t)};case"participating":return{phase:"participating",mechanism:"auction",consumer:n.consumer,display$:e.displayAtom,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:n.distribution,consumer:n.consumer};case"granted":return{phase:"granted",mechanism:"auction",distribution:n.distribution,consumer:n.consumer,grant:n.grant,claim:()=>e.claim()};case"ended":return{phase:"ended",mechanism:"auction",consumer:n.consumer,outcome:n.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 enter(){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation()})}async enterWithinOperation(){const t=this.currentAuctionSequence("enterable","No open auction to enter").distribution;await this.deps.auctions.enter(t.id,void 0),await this.deps.auctions.status(t.id);const i={mechanism:"auction",status:"not_bid",id:e=t.id,distributionId:e};var e;this.deps.ensureDisplayAtom({id:t.id,type:"auction"}),this.deps.commit(c({distribution:t,consumer:i})),this.deps.emitEvent("sequence_change","success","user","Entered auction",{distributionId:t.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const t=this.currentAuctionSequence("participating"),i=t.consumer.distributionId??t.consumer.id??t.distribution.id;await this.deps.auctions.leave(i),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"auction"})}async bid(t){await this.deps.runSerializedOperation(async()=>{const i=this.currentAuctionSequenceForBid(),o=i.consumer.distributionId??i.consumer.id??i.distribution.id,a=await this.deps.auctions.bid(o,t);if("won"===a.status||"lost"===a.status){const t=this.deps.getCurrentSequence();return void(t&&("enterable"===t.phase||"participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"auction"===t.mechanism&&t.distribution.id===o&&("won"===a.status&&a.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:a.admissionGrant}):s(a)||this.deps.applyMonitorUpdate({type:"ended",outcome:{type:a.status}})))}const r=function(t){switch(t){case"not_bid":case"bidding":case"winning":case"outbid":return t;case"won":case"lost":return}}(a.status);if(void 0===r)return;const u="auction"===i.distribution.details?.type?i.distribution.details:void 0,d=u?.bidIncrement,p=a.highestBid&&d&&e(a.highestBid)&&e(d)?n(a.highestBid,d):void 0,h=this.deps.getDisplayState(),m="auction"===h?.type?h.settleAt:void 0,l=this.deps.ensureDisplayAtom({id:o,type:"auction"});"enterable"===i.phase&&this.deps.commit(c({distribution:i.distribution,consumer:{mechanism:"auction",status:r,id:o,distributionId:o,currentBid:t,highestBid:a.highestBid}})),l.set({type:"auction",currentBid:t,highestBid:a.highestBid,bidCount:a.bidCount,status:r,currencyCode:u?.currencyCode,bidIncrement:d,minNextBid:p,closeAt:u?.closeAt??u?.endsAt,settleAt:m})})}currentAuctionSequence(t,e="Not participating in an auction"){const n=this.deps.getCurrentSequence();if(!n||n.phase!==t||!("mechanism"in n)||"auction"!==n.mechanism)throw i.validationError(e);return n}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("No auction is available to bid on");return t}}function h(t){return{status:"not_bid",distributionId:t.id}}function m(t,i,e){return{phase:"ended",mechanism:"auction",distribution:t,consumer:i,outcome:{...e,distributionType:e.distributionType??t.type,distributionId:e.distributionId??t.id,at:e.at??/* @__PURE__ */(new Date).toISOString()}}}export{r as createAuctionDriver,a as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionGrantedConsumer,d as withAuctionTerminalConsumer};
@@ -1 +1 @@
1
- import{AuctionBidderStateResponseSchema as t,AuctionHighestBidResponseSchema as i,AuctionBidHistoryResponseSchema as e}from"@fanfare-io/fanfare-sdk-contracts/auction";import{createError as s}from"../core/errors.js";import{getLogger as n}from"../core/logger.js";import{isMoneyString as a,addMoney as o,isMoneyGreaterThan as r,normalizeMoney as u,isMoneyLessThanOrEqualTo as d,subtractMoney as h}from"../core/money.js";import{parseResponse as c}from"../core/parse-response.js";import{createPollScheduler as l}from"../core/poll-scheduler.js";import{DistributionMonitorRuntime as g}from"../experiences/distribution-monitor.runtime.js";import{getEventBus as p}from"../state/events.js";import{getSDKStore as m}from"../state/store.js";import{isTerminalAuctionStatus as b,toAuctionConsumerStatus as y}from"./auction-status.js";class f{constructor(t){this.logger=n(),this.events=p(),this.trackedParticipations=/* @__PURE__ */new Map,this.inFlightRequests=/* @__PURE__ */new Map,this.pollSchedulers=/* @__PURE__ */new Map,this.lastStatusCache=/* @__PURE__ */new Map,this.hasSuccessfulReadThisSession=/* @__PURE__ */new Map,this.lastSettleAtMs=/* @__PURE__ */new Map,this.visibilityHandlers=/* @__PURE__ */new Map,this.autoRebidConfigs=/* @__PURE__ */new Map,this.monitorRuntime=new g,this.bidHistoryCache=/* @__PURE__ */new Map,this.auctionDetailsCache=/* @__PURE__ */new Map,this.monitorGenerations=/* @__PURE__ */new Map,this.operationGenerations=/* @__PURE__ */new Map,this.BID_HISTORY_CACHE_TTL=5e3,this.AUCTION_DETAILS_CACHE_TTL=3e4,this.NO_BID_END_GRACE_MS=5e3,this.destroyed=!1,this.lifecycleGeneration=0,this.http=t}get store(){return m()}computeMinNextBid(t,i){if(i&&a(t)&&a(i))return o(t,i)}async getAuctionDetailsCached(t){const i=this.auctionDetailsCache.get(t);if(i&&Date.now()-i.fetchedAt<this.AUCTION_DETAILS_CACHE_TTL)return i.details;const e=await this.http.get(`/auctions/${t}`);return this.auctionDetailsCache.set(t,{details:e,fetchedAt:Date.now()}),e}getTrackedParticipation(t){return this.trackedParticipations.get(t)}getAuctionCloseAt(t){return t.closeAt??t.settleAt}getAuctionSettleAt(t){return t.settleAt??t.closeAt}buildDisplayState(t,{status:i,highestBid:e,currentBid:s,bidCount:n}){return{highestBid:e,currentBid:s,bidCount:n,closeAt:this.getAuctionCloseAt(t),settleAt:t.settleAt,status:i,currencyCode:t.currencyCode,minNextBid:e?this.computeMinNextBid(e,t.minBidIncrement):void 0,bidIncrement:t.minBidIncrement??void 0}}emitTransitionEvents(t){for(const i of t)this.events.emit(i.type,i.payload)}applyTransition(t,i){void 0!==i.trackedParticipation&&(i.trackedParticipation?this.trackedParticipations.set(t,i.trackedParticipation):this.trackedParticipations.delete(t));const e=this.monitorRuntime.getDisplayAtom(t);e&&i.displayState&&e.set({type:"auction",...i.displayState}),this.emitTransitionEvents(i.events),i.monitorUpdate&&this.monitorRuntime.notify(t,i.monitorUpdate),i.stopWatching&&this.stopWatching(t),i.autoRebidStatus&&this.handleAutoRebid(t,i.autoRebidStatus)}checkOutbidConditions(t,i,e){if("outbid"!==i.status)return!1;if("winning"===t.status&&"outbid"===i.status)return!0;if(e?.currentBid&&i.highestBid){const s=e.currentBid,n=i.highestBid,o=t.highestBid||"0";if(a(s)&&a(n)&&a(o))return r(n,o)&&r(n,s)&&"outbid"===i.status}return"outbid"!==t.status&&"outbid"===i.status}buildBidTransition(t,i,e,s,n,a){const o={type:"auction:bid-placed",payload:{auctionId:t,amount:e,status:i.status}};if("won"===i.status||"lost"===i.status){const a=this.buildTerminalTransition(t,i.status,s,{currentBid:e,highestBid:i.highestBid,bidCount:i.bidCount,admissionGrant:n});return{...a,events:[o,...a.events]}}return{trackedParticipation:{auctionId:t,enteredAt:a?.enteredAt??/* @__PURE__ */(new Date).toISOString(),status:i.status,currentBid:e,highestBid:i.highestBid,bidCount:i.bidCount,lastBidAt:/* @__PURE__ */(new Date).toISOString(),metadata:a?.metadata,fingerprint:a?.fingerprint},displayState:this.buildDisplayState(s,{status:i.status,highestBid:i.highestBid,currentBid:e,bidCount:i.bidCount}),events:[o,..."winning"===i.status?[{type:"auction:winning",payload:{auctionId:t,amount:e,highestBid:i.highestBid}}]:[],..."outbid"===i.status?[{type:"auction:outbid",payload:{auctionId:t,yourBid:e,highestBid:i.highestBid}}]:[]],monitorUpdate:null,stopWatching:!1,autoRebidStatus:null}}buildTerminalTransition(t,i,e,s){return"won"===i?{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:i,highestBid:s.highestBid,currentBid:s.currentBid,bidCount:s.bidCount}),events:[{type:"auction:won",payload:{auctionId:t,winningBid:s.currentBid??"",admissionGrant:s.admissionGrant}}],monitorUpdate:s.admissionGrant?{type:"granted",token:s.admissionGrant}:{type:"ended",outcome:{type:"won",distributionType:"auction",distributionId:t}},stopWatching:!0,autoRebidStatus:null}:{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:i,highestBid:s.highestBid,currentBid:s.currentBid,bidCount:s.bidCount}),events:[{type:"auction:lost",payload:{auctionId:t,highestBid:s.highestBid}}],monitorUpdate:{type:"ended",outcome:{type:"lost"}},stopWatching:!0,autoRebidStatus:null}}buildStatusTransition(t,i,e,{previousParticipation:s,previousStatus:n}){const a=i.currentBid??s?.currentBid,o=i.bidCount??s?.bidCount;if(b(n?.status))return{displayState:null,events:[],monitorUpdate:null,stopWatching:!1,autoRebidStatus:null};if("won"===i.status||"lost"===i.status)return this.buildTerminalTransition(t,i.status,e,{currentBid:a,highestBid:i.highestBid,bidCount:o,admissionGrant:i.admissionGrant});const r=e.closeAt?new Date(e.closeAt).getTime():void 0;if("not_bid"===i.status&&void 0!==r&&Date.now()>=r+this.NO_BID_END_GRACE_MS)return{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:"ended",highestBid:i.highestBid,currentBid:a,bidCount:o}),events:[],monitorUpdate:{type:"ended",outcome:{type:"closed",reason:"ended"}},stopWatching:!0,autoRebidStatus:null};const u={auctionId:t,enteredAt:s?.enteredAt??/* @__PURE__ */(new Date).toISOString(),status:i.status,currentBid:a,highestBid:i.highestBid,bidCount:o,metadata:s?.metadata,fingerprint:s?.fingerprint},d=[];let h=null;return n&&(this.checkOutbidConditions(n,i,s)&&(d.push({type:"auction:outbid",payload:{auctionId:t,yourBid:n.currentBid||s?.currentBid||"",highestBid:i.highestBid}}),h=i),"winning"!==n.status&&"winning"===i.status&&d.push({type:"auction:winning",payload:{auctionId:t,amount:a||"",highestBid:i.highestBid}}),n.highestBid!==i.highestBid&&"winning"!==i.status&&d.push({type:"auction:bid-updated",payload:{auctionId:t,highestBid:i.highestBid,bidCount:i.bidCount||0}})),{trackedParticipation:u,displayState:this.buildDisplayState(e,{status:i.status,highestBid:i.highestBid,currentBid:a,bidCount:o}),events:d,monitorUpdate:null,stopWatching:!1,autoRebidStatus:h}}buildMissingTransition(){return{trackedParticipation:null,displayState:{status:"lost"},events:[],monitorUpdate:{type:"ended",outcome:{type:"closed",reason:"not_participating"}},stopWatching:!0,autoRebidStatus:null}}async get(t){try{return await this.getAuctionDetailsCached(t)}catch(i){throw this.logger.error("Failed to get auction",{auctionId:t,error:i}),i}}async bid(e,n,o){try{const r=this.lifecycleGeneration;if(!a(n))throw s.validationError("Invalid bid amount format. Must be a numeric string (e.g., '100.00')");if(!this.store.session)throw s.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");let d=this.bumpOperationGeneration(e),h=this.getTrackedParticipation(e);h||(this.logger.warn("Attempting to bid without entering auction first",{auctionId:e}),await this.enter(e,void 0,o),h=this.getTrackedParticipation(e),d=this.bumpOperationGeneration(e)),this.logger.info("Placing bid",{auctionId:e,amount:n});const l=`/auctions/${e}/bid`,g=`/auctions/${e}/highest-bid`,[p,m,f]=await Promise.all([this.http.post(l,{amount:n},o),this.http.get(g),this.getAuctionDetailsCached(e)]),B=c(t,p,{endpoint:l},{throwOnFailure:!0});if(!B.ok)throw B.error;const S=c(i,m,{endpoint:g},{throwOnFailure:!0});if(!S.ok)throw S.error;const v=B.value,C=S.value,w=u(C.amount),A=y(v.status),I={status:A,amount:n,highestBid:w,bidCount:v.bidCount??(h?.bidCount||0)+1,admissionGrant:v.admissionGrant};if(!this.canApplyAsyncResult(e,r,void 0,d))return I;this.applyTransition(e,this.buildBidTransition(e,I,n,f,v.admissionGrant,h));const R=this.lastStatusCache.get(e);return b(R?.status)||this.lastStatusCache.set(e,{auctionId:e,status:A,currentBid:n,highestBid:w,timeRemaining:0,bidCount:I.bidCount,admissionGrant:v.admissionGrant}),I}catch(r){throw this.logger.error("Failed to place bid",{auctionId:e,amount:n,error:r}),this.events.emit("auction:error",{auctionId:e,error:r}),r}}async enter(t,i,e){try{const n=this.lifecycleGeneration,a=this.store.session;if(!a)throw s.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");const o=this.bumpOperationGeneration(t);if(this.logger.info("Entering auction",{auctionId:t}),await this.http.post(`/auctions/${t}/enter`,{metadata:i},e),!this.canApplyAsyncResult(t,n,void 0,o))return;this.trackedParticipations.set(t,{auctionId:t,enteredAt:/* @__PURE__ */(new Date).toISOString(),status:"not_bid",metadata:i,fingerprint:a.deviceFingerprint}),this.lastStatusCache.delete(t),this.emitTransitionEvents([{type:"auction:entered",payload:{auctionId:t}},{type:"experience:distribution-entered",payload:{distributionType:"auction",distributionId:t}}])}catch(n){throw this.logger.error("Failed to enter auction",{auctionId:t,error:n}),this.events.emit("auction:error",{auctionId:t,error:n}),n}}async leave(t,i){const e=this.getTrackedParticipation(t);if(e&&(void 0!==e.currentBid||"not_bid"!==e.status))throw s.cannotLeaveAfterBid(t);try{const e=this.lifecycleGeneration,s=this.bumpOperationGeneration(t);this.logger.info("Leaving auction",{auctionId:t});try{await this.http.post(`/auctions/${t}/leave`,void 0,i)}catch(n){if(404!==n?.status)throw n;this.logger.debug("Leave endpoint not available",{auctionId:t})}if(!this.canApplyAsyncResult(t,e,void 0,s))return;this.stopMonitoring(t),this.trackedParticipations.delete(t),this.emitTransitionEvents([{type:"auction:left",payload:{auctionId:t}}])}catch(n){throw this.logger.error("Failed to leave auction",{auctionId:t,error:n}),this.events.emit("auction:error",{auctionId:t,error:n}),n}}async status(t){const i=this.inFlightRequests.get(t);if(i)return this.logger.debug("Returning existing in-flight request",{auctionId:t}),i;const e=this.lifecycleGeneration,s=this.bumpOperationGeneration(t),n=this.doStatus(t,e,void 0,s).finally(()=>{this.inFlightRequests.delete(t)});return this.inFlightRequests.set(t,n),n}async doStatus(e,s,n,a){try{const o=`/auctions/${e}/status`,r=`/auctions/${e}/highest-bid`,[d,h,l]=await Promise.all([this.http.get(o),this.http.get(r),this.getAuctionDetailsCached(e)]),g=c(t,d,{endpoint:o},{throwOnFailure:!0});if(!g.ok)throw g.error;const p=c(i,h,{endpoint:r},{throwOnFailure:!0});if(!p.ok)throw p.error;const m=g.value,f=p.value,B=this.getAuctionSettleAt(l),S=B?new Date(B).getTime():Number.NaN,v=u(f.amount),C=this.getTrackedParticipation(e),w=m.lastBidAmount??m.winningBidAmount,A={auctionId:e,status:y(m.status),currentBid:C?.currentBid??(w?u(w):void 0),highestBid:v,timeRemaining:Number.isFinite(S)?Math.max(0,S-Date.now()):0,bidCount:m.bidCount,admissionGrant:m.admissionGrant};if(!this.canApplyAsyncResult(e,s,n,a))return A;const I=this.lastStatusCache.get(e),R=this.buildStatusTransition(e,A,l,{previousParticipation:C,previousStatus:I});return this.applyTransition(e,R),this.hasSuccessfulReadThisSession.set(e,!0),Number.isFinite(S)?this.lastSettleAtMs.set(e,S):this.lastSettleAtMs.delete(e),b(I?.status)?this.lastStatusCache.set(e,I):b(A.status)?this.lastStatusCache.set(e,A):R.stopWatching?this.lastStatusCache.delete(e):this.lastStatusCache.set(e,A),this.events.emit("auction:status-updated",{auctionId:e,status:A}),A}catch(o){if(o&&"object"==typeof o&&"status"in o&&404===o.status){const t={auctionId:e,status:"not_bid",highestBid:"0.00",timeRemaining:0};if(!this.canApplyAsyncResult(e,s,n,a))return t;const i=this.lastStatusCache.get(e);if(!b(i?.status)){const t=this.buildMissingTransition();this.applyTransition(e,t),this.lastStatusCache.delete(e)}return this.hasSuccessfulReadThisSession.set(e,!0),this.lastSettleAtMs.delete(e),this.events.emit("auction:status-updated",{auctionId:e,status:t}),t}if(!this.canApplyAsyncResult(e,s,n,a))return this.lastStatusCache.get(e)??{auctionId:e,status:"not_bid",highestBid:"0.00",timeRemaining:0};throw this.logger.error("Failed to get auction status",{auctionId:e,error:o}),this.events.emit("auction:error",{auctionId:e,error:o}),o}}async getBidHistory(t){try{const i=this.bidHistoryCache.get(t);if(i&&Date.now()-i.fetchedAt<this.BID_HISTORY_CACHE_TTL)return this.logger.debug("Returning cached bid history",{auctionId:t}),i.bids;this.logger.info("Fetching bid history",{auctionId:t});const s=`/auctions/${t}/bids/history`,n=await this.http.get(s),a=c(e,n,{endpoint:s},{throwOnFailure:!0});if(!a.ok)throw a.error;const o=a.value.map(t=>({amount:u(t.amount),timestamp:t.timestamp,isWinning:t.isHighest,isYours:!0}));return this.bidHistoryCache.set(t,{bids:o,fetchedAt:Date.now()}),this.events.emit("auction:history-fetched",{auctionId:t,bidCount:o.length}),o}catch(i){throw this.logger.error("Failed to get bid history",{auctionId:t,error:i}),this.events.emit("auction:error",{auctionId:t,error:i}),i}}startWatching(t,i=5e3,e){this.stopWatching(t);const s=this.lifecycleGeneration,n=this.bumpMonitorGeneration(t);this.hasSuccessfulReadThisSession.set(t,!1),this.lastStatusCache.delete(t),this.lastSettleAtMs.delete(t),this.logger.info("Starting auction status polling",{auctionId:t,intervalMs:i});const a=l({baseMs:i,suppressBackoff:()=>this.shouldSuppressBackoff(t),onDegradedChange:e,shouldContinue:()=>this.pollSchedulers.has(t)&&this.canApplyAsyncResult(t,s,n),run:async()=>{const i=this.getOperationGeneration(t);try{await this.doStatus(t,s,n,i)}catch(e){if(!this.canApplyAsyncResult(t,s,n,i))return;throw this.logger.error("Polling failed",{auctionId:t,error:e}),e}}});this.pollSchedulers.set(t,a),this.registerVisibilityPoke(t,a),a.start(),this.events.emit("auction:watching-started",{auctionId:t,intervalMs:i})}stopWatching(t){this.bumpMonitorGeneration(t);const i=this.pollSchedulers.get(t);i&&(i.stop(),this.pollSchedulers.delete(t),this.unregisterVisibilityPoke(t),this.lastStatusCache.delete(t),this.hasSuccessfulReadThisSession.delete(t),this.lastSettleAtMs.delete(t),this.logger.info("Stopped watching auction",{auctionId:t}),this.events.emit("auction:watching-stopped",{auctionId:t}))}stopAllWatching(){for(const t of Array.from(this.pollSchedulers.keys()))this.stopWatching(t)}shouldSuppressBackoff(t){return!this.hasSuccessfulReadThisSession.get(t)||this.isInSettlingWindow(t)}isInSettlingWindow(t){const i=this.lastSettleAtMs.get(t);return void 0!==i&&(Date.now()>=i-12e4&&!b(this.lastStatusCache.get(t)?.status))}registerVisibilityPoke(t,i){if("undefined"==typeof document)return;const e=()=>{"visible"===document.visibilityState&&this.isInSettlingWindow(t)&&i.poke()};document.addEventListener("visibilitychange",e),this.visibilityHandlers.set(t,e)}unregisterVisibilityPoke(t){if("undefined"==typeof document)return void this.visibilityHandlers.delete(t);const i=this.visibilityHandlers.get(t);i&&(document.removeEventListener("visibilitychange",i),this.visibilityHandlers.delete(t))}bumpMonitorGeneration(t){const i=(this.monitorGenerations.get(t)??0)+1;return this.monitorGenerations.set(t,i),i}getOperationGeneration(t){return this.operationGenerations.get(t)??0}bumpOperationGeneration(t){const i=this.getOperationGeneration(t)+1;return this.operationGenerations.set(t,i),i}canApplyAsyncResult(t,i,e,s){return!this.destroyed&&this.lifecycleGeneration===i&&((void 0===e||this.monitorGenerations.get(t)===e)&&(void 0===s||this.getOperationGeneration(t)===s))}enableAutoRebid(t,i,e){if(!a(i)||!a(e))throw s.validationError("Invalid monetary format. Must be numeric strings (e.g., '100.00')");if(d(i,"0")||d(e,"0"))throw s.validationError("Max bid and increment must be positive");if(r(e,i))throw s.validationError("Increment cannot be greater than max bid");const n=this.getTrackedParticipation(t);if(!n)throw s.validationError("Must enter auction before enabling auto-rebid");const o=u(n.currentBid),c=h(i,o);this.autoRebidConfigs.set(t,{enabled:!0,maxBid:i,increment:e,remainingBudget:c,rebidCount:0}),this.logger.info("Auto-rebid enabled",{auctionId:t,maxBid:i,increment:e,remainingBudget:c}),this.events.emit("auction:auto-rebid-enabled",{auctionId:t,maxBid:i,increment:e})}disableAutoRebid(t){const i=this.autoRebidConfigs.get(t);i&&(i.enabled=!1,this.logger.info("Auto-rebid disabled",{auctionId:t}),this.events.emit("auction:auto-rebid-disabled",{auctionId:t,finalRebidCount:i.rebidCount||0}))}getAutoRebidConfig(t){return this.autoRebidConfigs.get(t)}async handleAutoRebid(t,i){const e=this.autoRebidConfigs.get(t);if(e&&e.enabled)try{if(!a(i.highestBid)||!a(e.maxBid)||!a(e.increment))return void this.logger.error("Invalid auto-rebid amounts",{auctionId:t,config:e});const s=o(i.highestBid,e.increment);if(r(s,e.maxBid))return this.logger.info("Auto-rebid would exceed max bid, disabling",{auctionId:t,wouldBid:s,maxBid:e.maxBid}),this.disableAutoRebid(t),void this.events.emit("auction:auto-rebid-max-reached",{auctionId:t,maxBid:e.maxBid,wouldNeedToBid:s});this.logger.info("Placing auto-rebid",{auctionId:t,amount:s});const n=await this.bid(t,s);e.lastRebidAt=/* @__PURE__ */(new Date).toISOString(),e.rebidCount=(e.rebidCount||0)+1,e.remainingBudget=h(e.maxBid,s),this.events.emit("auction:auto-rebid-placed",{auctionId:t,amount:s,remainingBudget:e.remainingBudget,status:n.status})}catch(s){this.logger.error("Auto-rebid failed",{auctionId:t,error:s}),this.events.emit("auction:auto-rebid-failed",{auctionId:t,error:s})}}startMonitoring(t,i,e,s){b(this.lastStatusCache.get(t)?.status)||(this.monitorRuntime.start(t,i,e),this.trackedParticipations.has(t)||this.trackedParticipations.set(t,{auctionId:t,enteredAt:/* @__PURE__ */(new Date).toISOString(),status:"not_bid"}),this.startWatching(t,5e3,s))}stopMonitoring(t){this.stopWatching(t),this.monitorRuntime.stop(t)}isMonitoring(t){return this.monitorRuntime.has(t)||this.pollSchedulers.has(t)}destroy(){this.destroyed=!0,this.lifecycleGeneration+=1,this.stopAllWatching(),this.inFlightRequests.clear(),this.lastStatusCache.clear(),this.hasSuccessfulReadThisSession.clear(),this.lastSettleAtMs.clear(),this.visibilityHandlers.clear(),this.trackedParticipations.clear(),this.monitorGenerations.clear(),this.operationGenerations.clear(),this.bidHistoryCache.clear(),this.auctionDetailsCache.clear(),this.autoRebidConfigs.clear(),this.monitorRuntime.clear()}}export{f as AuctionManagementModule};
1
+ import{AuctionBidderStateResponseSchema as t,AuctionHighestBidResponseSchema as i,AuctionBidHistoryResponseSchema as e}from"@fanfare-io/fanfare-sdk-contracts/auction";import{createError as s}from"../core/errors.js";import{getLogger as n}from"../core/logger.js";import{isMoneyString as a,addMoney as o,isMoneyGreaterThan as r,normalizeMoney as d,isMoneyLessThanOrEqualTo as u,subtractMoney as h}from"../core/money.js";import{parseResponse as c}from"../core/parse-response.js";import{createPollScheduler as l}from"../core/poll-scheduler.js";import{DistributionMonitorRuntime as g}from"../experiences/distribution-monitor.runtime.js";import{getEventBus as p}from"../state/events.js";import{getSDKStore as m}from"../state/store.js";import{isGrantPendingWin as b,isTerminalAuctionStatus as y,toAuctionConsumerStatus as f}from"./auction-status.js";class B{constructor(t){this.logger=n(),this.events=p(),this.trackedParticipations=/* @__PURE__ */new Map,this.inFlightRequests=/* @__PURE__ */new Map,this.pollSchedulers=/* @__PURE__ */new Map,this.lastStatusCache=/* @__PURE__ */new Map,this.hasSuccessfulReadThisSession=/* @__PURE__ */new Map,this.lastSettleAtMs=/* @__PURE__ */new Map,this.visibilityHandlers=/* @__PURE__ */new Map,this.autoRebidConfigs=/* @__PURE__ */new Map,this.monitorRuntime=new g,this.bidHistoryCache=/* @__PURE__ */new Map,this.auctionDetailsCache=/* @__PURE__ */new Map,this.monitorGenerations=/* @__PURE__ */new Map,this.operationGenerations=/* @__PURE__ */new Map,this.BID_HISTORY_CACHE_TTL=5e3,this.AUCTION_DETAILS_CACHE_TTL=3e4,this.NO_BID_END_GRACE_MS=5e3,this.destroyed=!1,this.lifecycleGeneration=0,this.http=t}get store(){return m()}computeMinNextBid(t,i){if(i&&a(t)&&a(i))return o(t,i)}async getAuctionDetailsCached(t){const i=this.auctionDetailsCache.get(t);if(i&&Date.now()-i.fetchedAt<this.AUCTION_DETAILS_CACHE_TTL)return i.details;const e=await this.http.get(`/auctions/${t}`);return this.auctionDetailsCache.set(t,{details:e,fetchedAt:Date.now()}),e}getTrackedParticipation(t){return this.trackedParticipations.get(t)}getAuctionCloseAt(t){return t.closeAt??t.settleAt}getAuctionSettleAt(t){return t.settleAt??t.closeAt}buildDisplayState(t,{status:i,highestBid:e,currentBid:s,bidCount:n}){return{highestBid:e,currentBid:s,bidCount:n,closeAt:this.getAuctionCloseAt(t),settleAt:t.settleAt,status:i,currencyCode:t.currencyCode,minNextBid:e?this.computeMinNextBid(e,t.minBidIncrement):void 0,bidIncrement:t.minBidIncrement??void 0}}emitTransitionEvents(t){for(const i of t)this.events.emit(i.type,i.payload)}applyTransition(t,i){void 0!==i.trackedParticipation&&(i.trackedParticipation?this.trackedParticipations.set(t,i.trackedParticipation):this.trackedParticipations.delete(t));const e=this.monitorRuntime.getDisplayAtom(t);e&&i.displayState&&e.set({type:"auction",...i.displayState}),this.emitTransitionEvents(i.events),i.monitorUpdate&&this.monitorRuntime.notify(t,i.monitorUpdate),i.stopWatching&&this.stopWatching(t),i.autoRebidStatus&&this.handleAutoRebid(t,i.autoRebidStatus)}checkOutbidConditions(t,i,e){if("outbid"!==i.status)return!1;if("winning"===t.status&&"outbid"===i.status)return!0;if(e?.currentBid&&i.highestBid){const s=e.currentBid,n=i.highestBid,o=t.highestBid||"0";if(a(s)&&a(n)&&a(o))return r(n,o)&&r(n,s)&&"outbid"===i.status}return"outbid"!==t.status&&"outbid"===i.status}buildBidTransition(t,i,e,s,n,a){const o={type:"auction:bid-placed",payload:{auctionId:t,amount:e,status:i.status}};if("won"===i.status&&!b(i)||"lost"===i.status){const a=this.buildTerminalTransition(t,i.status,s,{currentBid:e,highestBid:i.highestBid,bidCount:i.bidCount,admissionGrant:n});return{...a,events:[o,...a.events]}}return{trackedParticipation:{auctionId:t,enteredAt:a?.enteredAt??/* @__PURE__ */(new Date).toISOString(),status:i.status,currentBid:e,highestBid:i.highestBid,bidCount:i.bidCount,lastBidAt:/* @__PURE__ */(new Date).toISOString(),metadata:a?.metadata,fingerprint:a?.fingerprint},displayState:this.buildDisplayState(s,{status:i.status,highestBid:i.highestBid,currentBid:e,bidCount:i.bidCount}),events:[o,..."winning"===i.status?[{type:"auction:winning",payload:{auctionId:t,amount:e,highestBid:i.highestBid}}]:[],..."outbid"===i.status?[{type:"auction:outbid",payload:{auctionId:t,yourBid:e,highestBid:i.highestBid}}]:[]],monitorUpdate:null,stopWatching:!1,autoRebidStatus:null}}buildTerminalTransition(t,i,e,s){return"won"===i?{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:i,highestBid:s.highestBid,currentBid:s.currentBid,bidCount:s.bidCount}),events:[{type:"auction:won",payload:{auctionId:t,winningBid:s.currentBid??"",admissionGrant:s.admissionGrant}}],monitorUpdate:s.admissionGrant?{type:"granted",token:s.admissionGrant}:{type:"ended",outcome:{type:"won",distributionType:"auction",distributionId:t}},stopWatching:!0,autoRebidStatus:null}:{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:i,highestBid:s.highestBid,currentBid:s.currentBid,bidCount:s.bidCount}),events:[{type:"auction:lost",payload:{auctionId:t,highestBid:s.highestBid}}],monitorUpdate:{type:"ended",outcome:{type:"lost"}},stopWatching:!0,autoRebidStatus:null}}buildStatusTransition(t,i,e,{previousParticipation:s,previousStatus:n}){const a=i.currentBid??s?.currentBid,o=i.bidCount??s?.bidCount;if(y(n?.status))return{displayState:null,events:[],monitorUpdate:null,stopWatching:!1,autoRebidStatus:null};if("won"===i.status||"lost"===i.status)return this.buildTerminalTransition(t,i.status,e,{currentBid:a,highestBid:i.highestBid,bidCount:o,admissionGrant:i.admissionGrant});const r=e.closeAt?new Date(e.closeAt).getTime():void 0;if("not_bid"===i.status&&void 0!==r&&Date.now()>=r+this.NO_BID_END_GRACE_MS)return{trackedParticipation:null,displayState:this.buildDisplayState(e,{status:"ended",highestBid:i.highestBid,currentBid:a,bidCount:o}),events:[],monitorUpdate:{type:"ended",outcome:{type:"closed",reason:"ended"}},stopWatching:!0,autoRebidStatus:null};const d={auctionId:t,enteredAt:s?.enteredAt??/* @__PURE__ */(new Date).toISOString(),status:i.status,currentBid:a,highestBid:i.highestBid,bidCount:o,metadata:s?.metadata,fingerprint:s?.fingerprint},u=[];let h=null;return n&&(this.checkOutbidConditions(n,i,s)&&(u.push({type:"auction:outbid",payload:{auctionId:t,yourBid:n.currentBid||s?.currentBid||"",highestBid:i.highestBid}}),h=i),"winning"!==n.status&&"winning"===i.status&&u.push({type:"auction:winning",payload:{auctionId:t,amount:a||"",highestBid:i.highestBid}}),n.highestBid!==i.highestBid&&"winning"!==i.status&&u.push({type:"auction:bid-updated",payload:{auctionId:t,highestBid:i.highestBid,bidCount:i.bidCount||0}})),{trackedParticipation:d,displayState:this.buildDisplayState(e,{status:i.status,highestBid:i.highestBid,currentBid:a,bidCount:o}),events:u,monitorUpdate:null,stopWatching:!1,autoRebidStatus:h}}buildMissingTransition(){return{trackedParticipation:null,displayState:{status:"lost"},events:[],monitorUpdate:{type:"ended",outcome:{type:"closed",reason:"not_participating"}},stopWatching:!0,autoRebidStatus:null}}async get(t){try{return await this.getAuctionDetailsCached(t)}catch(i){throw this.logger.error("Failed to get auction",{auctionId:t,error:i}),i}}async bid(i,e,n){try{const o=this.lifecycleGeneration;if(!a(e))throw s.validationError("Invalid bid amount format. Must be a numeric string (e.g., '100.00')");if(!this.store.session)throw s.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");let r=this.bumpOperationGeneration(i),d=this.getTrackedParticipation(i);d||(this.logger.warn("Attempting to bid without entering auction first",{auctionId:i}),await this.enter(i,void 0,n),d=this.getTrackedParticipation(i),r=this.bumpOperationGeneration(i)),this.logger.info("Placing bid",{auctionId:i,amount:e});const u=`/auctions/${i}/bid`,h=await this.getAuctionDetailsCached(i),l=await this.http.post(u,{amount:e},n),g=c(t,l,{endpoint:u},{throwOnFailure:!0});if(!g.ok)throw g.error;const p=g.value;p.degraded&&this.logger.warn("Bid committed; the server deferred a post-commit effect to replay",{auctionId:i});const m=await this.proveHighestBid(i,p,e),B=f(p.status),S={status:B,amount:e,highestBid:m,bidCount:p.bidCount??(d?.bidCount||0)+1,admissionGrant:p.admissionGrant,...p.degraded?{degraded:!0}:{}};if(!this.canApplyAsyncResult(i,o,void 0,r))return S;if(this.applyTransition(i,this.buildBidTransition(i,S,e,h,p.admissionGrant,d)),b(S))return S;const v=this.lastStatusCache.get(i);return y(v?.status)||this.lastStatusCache.set(i,{auctionId:i,status:B,currentBid:e,highestBid:m,timeRemaining:0,bidCount:S.bidCount,admissionGrant:p.admissionGrant}),S}catch(o){throw this.logger.error("Failed to place bid",{auctionId:i,amount:e,error:o}),this.events.emit("auction:error",{auctionId:i,error:o}),o}}async proveHighestBid(t,e,s){const n=`/auctions/${t}/highest-bid`,a=d(e.winningBidAmount??e.lastBidAmount??s);try{const t=await this.http.get(n),e=c(i,t,{endpoint:n});return e.ok?d(e.value.amount):a}catch(o){return this.logger.warn("Highest-bid read failed after a committed bid; reporting the committed amount",{auctionId:t,error:o}),a}}async enter(t,i,e){try{const n=this.lifecycleGeneration,a=this.store.session;if(!a)throw s.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");const o=this.bumpOperationGeneration(t);if(this.logger.info("Entering auction",{auctionId:t}),await this.http.post(`/auctions/${t}/enter`,{metadata:i},e),!this.canApplyAsyncResult(t,n,void 0,o))return;this.trackedParticipations.set(t,{auctionId:t,enteredAt:/* @__PURE__ */(new Date).toISOString(),status:"not_bid",metadata:i,fingerprint:a.deviceFingerprint}),this.lastStatusCache.delete(t),this.emitTransitionEvents([{type:"auction:entered",payload:{auctionId:t}},{type:"experience:distribution-entered",payload:{distributionType:"auction",distributionId:t}}])}catch(n){throw this.logger.error("Failed to enter auction",{auctionId:t,error:n}),this.events.emit("auction:error",{auctionId:t,error:n}),n}}async leave(t,i){const e=this.getTrackedParticipation(t);if(e&&(void 0!==e.currentBid||"not_bid"!==e.status))throw s.cannotLeaveAfterBid(t);try{const e=this.lifecycleGeneration,s=this.bumpOperationGeneration(t);this.logger.info("Leaving auction",{auctionId:t});try{await this.http.post(`/auctions/${t}/leave`,void 0,i)}catch(n){if(404!==n?.status)throw n;this.logger.debug("Leave endpoint not available",{auctionId:t})}if(!this.canApplyAsyncResult(t,e,void 0,s))return;this.stopMonitoring(t),this.trackedParticipations.delete(t),this.emitTransitionEvents([{type:"auction:left",payload:{auctionId:t}}])}catch(n){throw this.logger.error("Failed to leave auction",{auctionId:t,error:n}),this.events.emit("auction:error",{auctionId:t,error:n}),n}}async status(t){const i=this.inFlightRequests.get(t);if(i)return this.logger.debug("Returning existing in-flight request",{auctionId:t}),i;const e=this.lifecycleGeneration,s=this.bumpOperationGeneration(t),n=this.doStatus(t,e,void 0,s).finally(()=>{this.inFlightRequests.delete(t)});return this.inFlightRequests.set(t,n),n}async doStatus(e,s,n,a){try{const r=`/auctions/${e}/status`,u=`/auctions/${e}/highest-bid`,[h,l,g]=await Promise.allSettled([this.http.get(r),this.http.get(u),this.getAuctionDetailsCached(e)]);if("rejected"===h.status){if("object"==typeof(o=h.reason)&&null!==o&&"status"in o&&404===o.status)return this.applyMissingStatus(e,s,n,a);throw h.reason}if("rejected"===l.status)throw l.reason;if("rejected"===g.status)throw g.reason;const p=h.value,m=l.value,b=g.value,B=c(t,p,{endpoint:r},{throwOnFailure:!0});if(!B.ok)throw B.error;const S=c(i,m,{endpoint:u},{throwOnFailure:!0});if(!S.ok)throw S.error;const v=B.value,w=S.value,C=this.getAuctionSettleAt(b),A=C?new Date(C).getTime():Number.NaN,I=d(w.amount),R=this.getTrackedParticipation(e),T=v.lastBidAmount??v.winningBidAmount,G={auctionId:e,status:f(v.status),currentBid:R?.currentBid??(T?d(T):void 0),highestBid:I,timeRemaining:Number.isFinite(A)?Math.max(0,A-Date.now()):0,bidCount:v.bidCount,admissionGrant:v.admissionGrant};if(!this.canApplyAsyncResult(e,s,n,a))return G;const M=this.lastStatusCache.get(e),k=this.buildStatusTransition(e,G,b,{previousParticipation:R,previousStatus:M});return this.applyTransition(e,k),this.hasSuccessfulReadThisSession.set(e,!0),Number.isFinite(A)?this.lastSettleAtMs.set(e,A):this.lastSettleAtMs.delete(e),y(M?.status)?this.lastStatusCache.set(e,M):y(G.status)?this.lastStatusCache.set(e,G):k.stopWatching?this.lastStatusCache.delete(e):this.lastStatusCache.set(e,G),this.events.emit("auction:status-updated",{auctionId:e,status:G}),G}catch(o){if(!this.canApplyAsyncResult(e,s,n,a))return this.lastStatusCache.get(e)??{auctionId:e,status:"not_bid",highestBid:"0.00",timeRemaining:0};throw this.logger.error("Failed to get auction status",{auctionId:e,error:o}),this.events.emit("auction:error",{auctionId:e,error:o}),o}var o}applyMissingStatus(t,i,e,s){const n={auctionId:t,status:"not_bid",highestBid:"0.00",timeRemaining:0};if(!this.canApplyAsyncResult(t,i,e,s))return n;const a=this.lastStatusCache.get(t);if(!y(a?.status)){const i=this.buildMissingTransition();this.applyTransition(t,i),this.lastStatusCache.delete(t)}return this.hasSuccessfulReadThisSession.set(t,!0),this.lastSettleAtMs.delete(t),this.events.emit("auction:status-updated",{auctionId:t,status:n}),n}async getBidHistory(t){try{const i=this.bidHistoryCache.get(t);if(i&&Date.now()-i.fetchedAt<this.BID_HISTORY_CACHE_TTL)return this.logger.debug("Returning cached bid history",{auctionId:t}),i.bids;this.logger.info("Fetching bid history",{auctionId:t});const s=`/auctions/${t}/bids/history`,n=await this.http.get(s),a=c(e,n,{endpoint:s},{throwOnFailure:!0});if(!a.ok)throw a.error;const o=a.value.map(t=>({amount:d(t.amount),timestamp:t.timestamp,isWinning:t.isHighest,isYours:!0}));return this.bidHistoryCache.set(t,{bids:o,fetchedAt:Date.now()}),this.events.emit("auction:history-fetched",{auctionId:t,bidCount:o.length}),o}catch(i){throw this.logger.error("Failed to get bid history",{auctionId:t,error:i}),this.events.emit("auction:error",{auctionId:t,error:i}),i}}startWatching(t,i=5e3,e){this.stopWatching(t);const s=this.lifecycleGeneration,n=this.bumpMonitorGeneration(t);this.hasSuccessfulReadThisSession.set(t,!1),this.lastStatusCache.delete(t),this.lastSettleAtMs.delete(t),this.logger.info("Starting auction status polling",{auctionId:t,intervalMs:i});const a=l({baseMs:i,suppressBackoff:()=>this.shouldSuppressBackoff(t),onDegradedChange:e,shouldContinue:()=>this.pollSchedulers.has(t)&&this.canApplyAsyncResult(t,s,n),run:async()=>{const i=this.getOperationGeneration(t);try{await this.doStatus(t,s,n,i)}catch(e){if(!this.canApplyAsyncResult(t,s,n,i))return;throw this.logger.error("Polling failed",{auctionId:t,error:e}),e}}});this.pollSchedulers.set(t,a),this.registerVisibilityPoke(t,a),a.start(),this.events.emit("auction:watching-started",{auctionId:t,intervalMs:i})}stopWatching(t){this.bumpMonitorGeneration(t);const i=this.pollSchedulers.get(t);i&&(i.stop(),this.pollSchedulers.delete(t),this.unregisterVisibilityPoke(t),this.lastStatusCache.delete(t),this.hasSuccessfulReadThisSession.delete(t),this.lastSettleAtMs.delete(t),this.logger.info("Stopped watching auction",{auctionId:t}),this.events.emit("auction:watching-stopped",{auctionId:t}))}stopAllWatching(){for(const t of Array.from(this.pollSchedulers.keys()))this.stopWatching(t)}shouldSuppressBackoff(t){return!this.hasSuccessfulReadThisSession.get(t)||this.isInSettlingWindow(t)}isInSettlingWindow(t){const i=this.lastSettleAtMs.get(t);return void 0!==i&&(Date.now()>=i-12e4&&!y(this.lastStatusCache.get(t)?.status))}registerVisibilityPoke(t,i){if("undefined"==typeof document)return;const e=()=>{"visible"===document.visibilityState&&this.isInSettlingWindow(t)&&i.poke()};document.addEventListener("visibilitychange",e),this.visibilityHandlers.set(t,e)}unregisterVisibilityPoke(t){if("undefined"==typeof document)return void this.visibilityHandlers.delete(t);const i=this.visibilityHandlers.get(t);i&&(document.removeEventListener("visibilitychange",i),this.visibilityHandlers.delete(t))}bumpMonitorGeneration(t){const i=(this.monitorGenerations.get(t)??0)+1;return this.monitorGenerations.set(t,i),i}getOperationGeneration(t){return this.operationGenerations.get(t)??0}bumpOperationGeneration(t){const i=this.getOperationGeneration(t)+1;return this.operationGenerations.set(t,i),i}canApplyAsyncResult(t,i,e,s){return!this.destroyed&&this.lifecycleGeneration===i&&((void 0===e||this.monitorGenerations.get(t)===e)&&(void 0===s||this.getOperationGeneration(t)===s))}enableAutoRebid(t,i,e){if(!a(i)||!a(e))throw s.validationError("Invalid monetary format. Must be numeric strings (e.g., '100.00')");if(u(i,"0")||u(e,"0"))throw s.validationError("Max bid and increment must be positive");if(r(e,i))throw s.validationError("Increment cannot be greater than max bid");const n=this.getTrackedParticipation(t);if(!n)throw s.validationError("Must enter auction before enabling auto-rebid");const o=d(n.currentBid),c=h(i,o);this.autoRebidConfigs.set(t,{enabled:!0,maxBid:i,increment:e,remainingBudget:c,rebidCount:0}),this.logger.info("Auto-rebid enabled",{auctionId:t,maxBid:i,increment:e,remainingBudget:c}),this.events.emit("auction:auto-rebid-enabled",{auctionId:t,maxBid:i,increment:e})}disableAutoRebid(t){const i=this.autoRebidConfigs.get(t);i&&(i.enabled=!1,this.logger.info("Auto-rebid disabled",{auctionId:t}),this.events.emit("auction:auto-rebid-disabled",{auctionId:t,finalRebidCount:i.rebidCount||0}))}getAutoRebidConfig(t){return this.autoRebidConfigs.get(t)}async handleAutoRebid(t,i){const e=this.autoRebidConfigs.get(t);if(e&&e.enabled)try{if(!a(i.highestBid)||!a(e.maxBid)||!a(e.increment))return void this.logger.error("Invalid auto-rebid amounts",{auctionId:t,config:e});const s=o(i.highestBid,e.increment);if(r(s,e.maxBid))return this.logger.info("Auto-rebid would exceed max bid, disabling",{auctionId:t,wouldBid:s,maxBid:e.maxBid}),this.disableAutoRebid(t),void this.events.emit("auction:auto-rebid-max-reached",{auctionId:t,maxBid:e.maxBid,wouldNeedToBid:s});this.logger.info("Placing auto-rebid",{auctionId:t,amount:s});const n=await this.bid(t,s);e.lastRebidAt=/* @__PURE__ */(new Date).toISOString(),e.rebidCount=(e.rebidCount||0)+1,e.remainingBudget=h(e.maxBid,s),this.events.emit("auction:auto-rebid-placed",{auctionId:t,amount:s,remainingBudget:e.remainingBudget,status:n.status})}catch(s){this.logger.error("Auto-rebid failed",{auctionId:t,error:s}),this.events.emit("auction:auto-rebid-failed",{auctionId:t,error:s})}}startMonitoring(t,i,e,s){y(this.lastStatusCache.get(t)?.status)||(this.monitorRuntime.start(t,i,e),this.trackedParticipations.has(t)||this.trackedParticipations.set(t,{auctionId:t,enteredAt:/* @__PURE__ */(new Date).toISOString(),status:"not_bid"}),this.startWatching(t,5e3,s))}stopMonitoring(t){this.stopWatching(t),this.monitorRuntime.stop(t)}isMonitoring(t){return this.monitorRuntime.has(t)||this.pollSchedulers.has(t)}destroy(){this.destroyed=!0,this.lifecycleGeneration+=1,this.stopAllWatching(),this.inFlightRequests.clear(),this.lastStatusCache.clear(),this.hasSuccessfulReadThisSession.clear(),this.lastSettleAtMs.clear(),this.visibilityHandlers.clear(),this.trackedParticipations.clear(),this.monitorGenerations.clear(),this.operationGenerations.clear(),this.bidHistoryCache.clear(),this.auctionDetailsCache.clear(),this.autoRebidConfigs.clear(),this.monitorRuntime.clear()}}export{B as AuctionManagementModule};
@@ -36,6 +36,12 @@ export interface BidResult {
36
36
  bidCount: number;
37
37
  admissionGrant?: string;
38
38
  position?: number;
39
+ /**
40
+ * The bid committed but the server deferred a post-commit effect — a `won` with no
41
+ * `admissionGrant` here is a live standing whose credential the status lane delivers on a
42
+ * later read, not a settled outcome.
43
+ */
44
+ degraded?: boolean;
39
45
  }
40
46
  /**
41
47
  * Auction status from API
@@ -1,2 +1,2 @@
1
1
  import{AppointmentManagementModule as e}from"../appointments/appointment.module.js";import{AuctionManagementModule as t}from"../auctions/auction.module.js";import{AuthenticationModule as r}from"../auth/auth.module.js";import{BeaconTrackingModule as n}from"../beacon/beacon.module.js";import{ChallengeManagementModule as i}from"../challenges/challenge.module.js";import{Config as o}from"../config/index.js";import{DrawManagementModule as s}from"../draws/draw.module.js";import{ExperienceManagementModule as a}from"../experiences/experience.module.js";import{ExperienceJourney as d}from"../experiences/journey.js";import{PaymentMethodManagementModule as l}from"../payment/payment.module.js";import{ReservationManagementModule as u}from"../payment/reservations.module.js";import{QueueManagementModule as c}from"../queues/queue.module.js";import{resolveCapabilityOptions as g}from"../state/capability-token-registry.js";import{getEventBus as y}from"../state/events.js";import{getSDKStore as m}from"../state/store.js";import{CrossTabCoordinator as p}from"../sync/cross-tab-coordinator.js";import{TimedReleaseManagementModule as f}from"../timed-releases/timed-release.module.js";import{version as b}from"../version.js";import{WaitlistManagementModule as w}from"../waitlists/waitlist.module.js";import{FanfareError as h,ErrorCodes as v}from"./errors.js";import{createHttpClient as I}from"./http.js";import{createLogger as M}from"./logger.js";let S=null;async function j(j){const A=new o(j),k=A.get(),x=M({enabled:k.debug||!1,level:k.debug?"debug":"warn",prefix:"Fanfare"});if(x.info("Initializing Fanfare SDK",{organizationId:j.organizationId,environment:k.environment}),S)throw new h("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.",v.ALREADY_INITIALIZED);const D=/* @__PURE__ */Symbol("fanfare-sdk"),E=I({baseUrl:A.apiUrl,credentials:k.credentials,headers:{"X-Organization-Id":j.organizationId,"X-Publishable-Key":j.publishableKey,"X-Fanfare-API-Version":"2025-01-15","X-Fanfare-SDK-Version":b,"X-Fanfare-Client-Type":"browser"},timeout:3e4,retryConfig:{maxRetries:3,delayTimer:1e3,retryOnNetworkError:!0}},k),q=I({baseUrl:A.beaconUrl,credentials:"omit",headers:{"X-Organization-Id":j.organizationId,"X-Publishable-Key":j.publishableKey,"X-Fanfare-API-Version":"2025-01-15","X-Fanfare-SDK-Version":b,"X-Fanfare-Client-Type":"browser"},timeout:3e4,retryConfig:{maxRetries:3,delayTimer:1e3,retryOnNetworkError:!0}},k),R=new r(E,q),C=new i(E),z=new c(E),O=new s(E),F=new t(E),K=new e(E),X=new w(E),P=new f(E),T=new a(E,z,O,F,X,P),$=new l(E),J=new u(E),N=y(),V=m();N.on("auth:logout",()=>$.destroy());const B=/* @__PURE__ */new Map,U=/* @__PURE__ */new Map,L=new n(q,k.beacon||{},e=>{const t=U.get(e)?.snapshot$.get();return"routed"===t?.journeyStage?t.sequenceId:void 0}),G=/* @__PURE__ */new Map;let H,_;const Y=e=>{const t=U.get(e);if(t)return x.debug("Returning existing journey handle",{experienceId:e}),t;x.info("Creating new journey",{experienceId:e});const r=new d(e,H);B.set(e,r),_?.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(),_?.unregisterJourney(e),B.delete(e),U.delete(e)}};return U.set(e,n),n},Z=async e=>{const t=e??await T.getMe(),r=/* @__PURE__ */new Set,n=new Set(t.active.journeys.map(e=>e.experienceId));for(const i of n)Y(i);for(const i of n){const e=B.get(i);e&&await e.resumeFromMe(t)&&r.add(i)}return[...r]},Q=async e=>{const t=/* @__PURE__ */new Set;for(const r of Object.keys(V.activeJourneys))Y(r),t.add(r);if(!e&&!R.getSession())return[...t];for(const r of await Z(e))t.add(r);return[...t]},W={check:()=>R.check(),guest:()=>R.guest(),requestOtp:e=>R.requestOtp(e),verifyOtp:e=>R.verifyOtp(e),exchangeExternal:e=>R.exchangeExternal(e),login:e=>R.login(e),logout:()=>R.logout(),getSession:()=>R.getSession(),refresh:()=>R.refresh()},ee={initiate:e=>C.initiate(e),verify:e=>C.verify(e)},te={get:e=>Y(e),list:()=>Array.from(
2
- /* @__PURE__ */new Set([...U.keys(),...B.keys(),...Object.keys(V.activeJourneys)])),resumeAll:e=>Q(e)},re={bind:e=>L.bind(e),track:e=>L.track(e),trackBatch:e=>L.trackBatch(e),flush:()=>L.flush()},ne=(e,t)=>{if(G.has(e.id))x.warn("CDP adapter already registered, skipping",{adapterId:e.id});else{try{e.init(N,t)}catch(r){return void x.error("CDP adapter failed to initialize",{adapterId:e.id,error:r})}G.set(e.id,e),x.info("CDP adapter registered",{adapterId:e.id})}},ie=(e,t)=>N.on(e,t),oe=async()=>{x.info("Destroying SDK instance");for(const t of G.values())try{t.destroy()}catch(e){x.error("CDP adapter failed to destroy",{adapterId:t.id,error:e})}G.clear();for(const t of Array.from(U.values()))try{t.destroy()}catch(e){x.error("Journey handle failed to destroy",{error:e})}B.clear(),U.clear(),"destroy"in R&&"function"==typeof R.destroy&&R.destroy(),z.destroy(),O.destroy(),F.destroy(),K.destroy(),X.destroy(),P.destroy(),T.destroy(),L.destroy(),$.destroy(),_?.close(),N.off(),S===D&&(S=null)};H={auth:W,challenges:ee,journeys:te,queues:{get:e=>z.get(e),enter:(e,t,r,n)=>z.enter(e,t,g({distributionId:e},r),n),leave:(e,t)=>z.leave(e,g({distributionId:e},t)),status:e=>z.status(e),startMonitoring:(e,t,r)=>z.startMonitoring(e,t,r),stopMonitoring:e=>z.stopMonitoring(e),isMonitoring:e=>z.isMonitoring(e)},draws:{get:e=>O.get(e),enter:(e,t,r,n)=>O.enter(e,t,g({distributionId:e},r),n),leave:(e,t)=>O.leave(e,g({distributionId:e},t)),status:e=>O.status(e),startMonitoring:(e,t,r)=>O.startMonitoring(e,t,r),stopMonitoring:e=>O.stopMonitoring(e),isMonitoring:e=>O.isMonitoring(e)},auctions:{get:e=>F.get(e),bid:(e,t,r)=>F.bid(e,t,g({distributionId:e},r)),enter:(e,t,r)=>F.enter(e,t,g({distributionId:e},r)),leave:(e,t)=>F.leave(e,g({distributionId:e},t)),status:e=>F.status(e),getBidHistory:e=>F.getBidHistory(e),enableAutoRebid:(e,t,r)=>F.enableAutoRebid(e,t,r),disableAutoRebid:e=>F.disableAutoRebid(e),getAutoRebidConfig:e=>F.getAutoRebidConfig(e),startMonitoring:(e,t,r)=>F.startMonitoring(e,t,r),stopMonitoring:e=>F.stopMonitoring(e),isMonitoring:e=>F.isMonitoring(e),destroy:()=>F.destroy()},experiences:{get:e=>T.get(e),enter:e=>T.enter(e),leave:e=>T.leave(e),getMe:()=>T.getMe(),findSequence:(e,t)=>T.findSequence(e,t),validateSequenceAccess:(e,t)=>T.validateSequenceAccess(e,t),selectSequence:e=>T.selectSequence(e),getCurrentDistributions:(e,t)=>T.getCurrentDistributions(e,t),enterDistribution:e=>{if(!e)throw new h("Distribution is required",v.VALIDATION_ERROR);return T.enterDistribution(e)},getActiveSession:()=>T.getActiveSession(),isInExperience:e=>T.isInExperience(e),getSelectedSequence:()=>T.getSelectedSequence(),createJourney:e=>Y(e),resumeJourneysFromMe:e=>Z(e),destroy:()=>T.destroy()},waitlists:{enter:(e,t)=>X.enter(e,g({waitlistId:e},t)),leave:(e,t)=>X.leave(e,g({waitlistId:e},t)),getStatus:e=>X.getStatus(e),destroy:()=>X.destroy()},reservations:J,timedReleases:{get:e=>P.get(e),enter:(e,t,r)=>P.enter(e,t,g({distributionId:e},r)),leave:(e,t)=>P.leave(e,g({distributionId:e},t)),complete:e=>P.complete(e),status:e=>P.status(e),startMonitoring:(e,t,r)=>P.startMonitoring(e,t,r),stopMonitoring:e=>P.stopMonitoring(e),isMonitoring:e=>P.isMonitoring(e)},appointments:{get:(e,t)=>K.get(e,g({distributionId:e},t)),getSlots:(e,t,r)=>K.getSlots(e,t,g({distributionId:e},r)),getMe:e=>K.getMe(e),book:(e,t,r,n)=>K.book(e,t,r,g({distributionId:e},n)),cancel:(e,t,r,n,i)=>K.cancel(e,t,r,n,g({distributionId:e},i)),reschedule:(e,t,r,n)=>K.reschedule(e,t,r,g({distributionId:e},n)),startMonitoring:(e,t,r)=>K.startMonitoring(e,t,r),stopMonitoring:e=>K.stopMonitoring(e),isMonitoring:e=>K.isMonitoring(e),bumpMonitorGeneration:e=>K.bumpMonitorGeneration(e),destroy:()=>K.destroy()},beacon:re,payment:$,use:ne,on:ie,destroy:oe};const se=!1!==j.sync&&"object"==typeof j.sync?j.sync:{};_=new p({enabled:!1!==j.sync&&!1!==se.enabled,channelName:se.channelName}),x.info("Inter-tab sync initialized",{tabId:_.getTabId(),enabled:_.isEnabled()});const ae={auth:W,challenges:ee,journeys:te,beacon:re,appointments:H.appointments,payment:$,use:ne,on:ie,destroy:oe};if(await R.rehydrate(),k.autoResume&&R.getSession())try{await Q()}catch(de){x.warn("Auto-resume on init failed; journeys can be resumed manually",{error:de instanceof Error?de.message:String(de)})}return S=D,x.info("SDK initialized successfully"),ae}export{j as init};
2
+ /* @__PURE__ */new Set([...U.keys(),...B.keys(),...Object.keys(V.activeJourneys)])),resumeAll:e=>Q(e)},re={bind:e=>L.bind(e),track:e=>L.track(e),trackBatch:e=>L.trackBatch(e),flush:()=>L.flush()},ne=(e,t)=>{if(G.has(e.id))x.warn("CDP adapter already registered, skipping",{adapterId:e.id});else{try{e.init(N,t)}catch(r){return void x.error("CDP adapter failed to initialize",{adapterId:e.id,error:r})}G.set(e.id,e),x.info("CDP adapter registered",{adapterId:e.id})}},ie=(e,t)=>N.on(e,t),oe=async()=>{x.info("Destroying SDK instance");for(const t of G.values())try{t.destroy()}catch(e){x.error("CDP adapter failed to destroy",{adapterId:t.id,error:e})}G.clear();for(const t of Array.from(U.values()))try{t.destroy()}catch(e){x.error("Journey handle failed to destroy",{error:e})}B.clear(),U.clear(),"destroy"in R&&"function"==typeof R.destroy&&R.destroy(),z.destroy(),O.destroy(),F.destroy(),K.destroy(),X.destroy(),P.destroy(),T.destroy(),L.destroy(),$.destroy(),_?.close(),N.off(),S===D&&(S=null)};H={auth:W,challenges:ee,journeys:te,queues:{get:e=>z.get(e),enter:(e,t,r,n)=>z.enter(e,t,g({distributionId:e},r),n),leave:(e,t)=>z.leave(e,g({distributionId:e},t)),status:e=>z.status(e),startMonitoring:(e,t,r)=>z.startMonitoring(e,t,r),stopMonitoring:e=>z.stopMonitoring(e),isMonitoring:e=>z.isMonitoring(e)},draws:{get:e=>O.get(e),enter:(e,t,r,n)=>O.enter(e,t,g({distributionId:e},r),n),leave:(e,t)=>O.leave(e,g({distributionId:e},t)),status:e=>O.status(e),startMonitoring:(e,t,r)=>O.startMonitoring(e,t,r),stopMonitoring:e=>O.stopMonitoring(e),isMonitoring:e=>O.isMonitoring(e)},auctions:{get:e=>F.get(e),bid:(e,t,r)=>F.bid(e,t,g({distributionId:e},r)),enter:(e,t,r)=>F.enter(e,t,g({distributionId:e},r)),leave:(e,t)=>F.leave(e,g({distributionId:e},t)),status:e=>F.status(e),getBidHistory:e=>F.getBidHistory(e),enableAutoRebid:(e,t,r)=>F.enableAutoRebid(e,t,r),disableAutoRebid:e=>F.disableAutoRebid(e),getAutoRebidConfig:e=>F.getAutoRebidConfig(e),startMonitoring:(e,t,r)=>F.startMonitoring(e,t,r),stopMonitoring:e=>F.stopMonitoring(e),isMonitoring:e=>F.isMonitoring(e),destroy:()=>F.destroy()},experiences:{get:e=>T.get(e),enter:e=>T.enter(e),leave:e=>T.leave(e),getMe:()=>T.getMe(),findSequence:(e,t)=>T.findSequence(e,t),validateSequenceAccess:(e,t)=>T.validateSequenceAccess(e,t),selectSequence:e=>T.selectSequence(e),getCurrentDistributions:(e,t)=>T.getCurrentDistributions(e,t),enterDistribution:e=>{if(!e)throw new h("Distribution is required",v.VALIDATION_ERROR);return T.enterDistribution(e)},getActiveSession:()=>T.getActiveSession(),isInExperience:e=>T.isInExperience(e),getSelectedSequence:()=>T.getSelectedSequence(),createJourney:e=>Y(e),resumeJourneysFromMe:e=>Z(e),destroy:()=>T.destroy()},waitlists:{enter:(e,t)=>X.enter(e,g({waitlistId:e},t)),leave:(e,t)=>X.leave(e,g({waitlistId:e},t)),getStatus:e=>X.getStatus(e),destroy:()=>X.destroy()},reservations:J,timedReleases:{get:e=>P.get(e),enter:(e,t,r)=>P.enter(e,t,g({distributionId:e},r)),leave:(e,t)=>P.leave(e,g({distributionId:e},t)),complete:e=>P.complete(e),status:e=>P.status(e),startMonitoring:(e,t,r)=>P.startMonitoring(e,t,r),stopMonitoring:e=>P.stopMonitoring(e),isMonitoring:e=>P.isMonitoring(e)},appointments:{get:(e,t)=>K.get(e,g({distributionId:e},t)),getSlots:(e,t,r)=>K.getSlots(e,t,g({distributionId:e},r)),getMe:e=>K.getMe(e),book:(e,t,r,n)=>K.book(e,t,r,g({distributionId:e},n)),cancel:(e,t,r,n,i)=>K.cancel(e,t,r,n,g({distributionId:e},i)),reschedule:(e,t,r,n)=>K.reschedule(e,t,r,g({distributionId:e},n)),startMonitoring:(e,t,r,n)=>K.startMonitoring(e,t,r,n),stopMonitoring:e=>K.stopMonitoring(e),isMonitoring:e=>K.isMonitoring(e),bumpMonitorGeneration:e=>K.bumpMonitorGeneration(e),destroy:()=>K.destroy()},beacon:re,payment:$,use:ne,on:ie,destroy:oe};const se=!1!==j.sync&&"object"==typeof j.sync?j.sync:{};_=new p({enabled:!1!==j.sync&&!1!==se.enabled,channelName:se.channelName}),x.info("Inter-tab sync initialized",{tabId:_.getTabId(),enabled:_.isEnabled()});const ae={auth:W,challenges:ee,journeys:te,beacon:re,appointments:H.appointments,payment:$,use:ne,on:ie,destroy:oe};if(await R.rehydrate(),k.autoResume&&R.getSession())try{await Q()}catch(de){x.warn("Auto-resume on init failed; journeys can be resumed manually",{error:de instanceof Error?de.message:String(de)})}return S=D,x.info("SDK initialized successfully"),ae}export{j as init};
@@ -24,6 +24,11 @@ export interface DisplayError {
24
24
  readonly retryAfter?: number;
25
25
  /** Opaque support reference/confirmation codes — safe to show. */
26
26
  readonly support?: ConsumerApiError["support"];
27
+ /**
28
+ * Whether offering the consumer a retry is honest. False where the refusal is
29
+ * settled for them, so an adapter must render no retry affordance.
30
+ */
31
+ readonly allowRetry: boolean;
27
32
  }
28
33
  /** Structured debug payload for `onError` telemetry. NOT for rendering. */
29
34
  export interface DebugErrorInfo {
@@ -1 +1 @@
1
- import{classify as r}from"./error-disposition.js";import{FanfareError as e,ErrorCodes as o}from"./errors.js";const t={[o.OTP_INVALID]:"auth.invalidCode",[o.OTP_EXPIRED]:"auth.codeExpired",[o.INVALID_SESSION]:"common.sessionExpired",[o.INVALID_REFRESH_TOKEN]:"common.sessionExpired",[o.SERVICE_UNAVAILABLE]:"error.overloadedGeneric",[o.TIMEOUT]:"error.overloadedGeneric",[o.NETWORK_ERROR]:"error.overloadedGeneric",[o.FEATURE_DISABLED]:"error.featureDisabled",[o.NO_ACCESS]:"widget.noAccess.message",[o.FORBIDDEN]:"error.forbidden",[o.DISTRIBUTION_NOT_OPEN]:"error.notOpen",[o.ALREADY_BOOKED]:"appointment.error.alreadyBooked",[o.ACTIVE_BOOKING_EXISTS]:"appointment.error.activeBookingExists",[o.SLOT_NOT_AVAILABLE]:"appointment.error.slotNotAvailable",[o.SLOT_EXPIRED]:"appointment.error.slotExpired",[o.SLOT_OUT_OF_WINDOW]:"appointment.error.slotOutOfWindow",[o.CANNOT_CANCEL_ONGOING_OR_PAST]:"appointment.error.cannotCancel",[o.NEW_SLOT_FULL]:"appointment.error.newSlotFull",[o.NO_EXISTING_BOOKING]:"appointment.error.noExistingBooking",[o.INVALID_SLOT]:"appointment.error.invalidSlot"};function i(r){return"INLINE"===r||"STEP_RESET"===r?"error.inlineGeneric":"error.description"}function n(e,n){const{disposition:s}=r(e.code,e.status,e.action),d="number"==typeof e.retryAfter&&Number.isFinite(e.retryAfter)?e.retryAfter:void 0,E=function(r,e,n){return r===o.RATE_LIMITED?n?"error.rateLimited":"error.rateLimitedGeneric":r===o.OVERLOADED?n?"error.overloaded":"error.overloadedGeneric":t[r]??i(e)}(e.code,s,void 0!==d);let a=n(E,void 0!==d?{values:{seconds:d}}:void 0);a.includes("{{")&&(a=n(i(s)));const c="PANEL"===s?n("error.title"):void 0;return{code:e.code,title:c,description:a,disposition:s,retryAfter:e.retryAfter,support:e.support}}function s(r){if(r instanceof e)return r;const t=r instanceof Error?r.message:String(r);return new e(t,o.INTERNAL_ERROR)}function d(r){return{code:r.code,status:r.status,requestId:r.requestId,correlationId:r.correlationId,details:r.details,issues:r.issues}}export{s as ensureFanfareError,d as toDebug,n as toDisplay};
1
+ import{classify as r}from"./error-disposition.js";import{FanfareError as e,ErrorCodes as o}from"./errors.js";const t={[o.OTP_INVALID]:"auth.invalidCode",[o.OTP_EXPIRED]:"auth.codeExpired",[o.INVALID_SESSION]:"common.sessionExpired",[o.INVALID_REFRESH_TOKEN]:"common.sessionExpired",[o.SERVICE_UNAVAILABLE]:"error.overloadedGeneric",[o.TIMEOUT]:"error.overloadedGeneric",[o.NETWORK_ERROR]:"error.overloadedGeneric",[o.FEATURE_DISABLED]:"error.featureDisabled",[o.NO_ACCESS]:"widget.noAccess.message",[o.FORBIDDEN]:"error.forbidden",[o.DISTRIBUTION_NOT_OPEN]:"error.notOpen",[o.DISTRIBUTION_DEACTIVATED]:"error.deactivated",[o.ALREADY_BOOKED]:"appointment.error.alreadyBooked",[o.ACTIVE_BOOKING_EXISTS]:"appointment.error.activeBookingExists",[o.SLOT_NOT_AVAILABLE]:"appointment.error.slotNotAvailable",[o.SLOT_EXPIRED]:"appointment.error.slotExpired",[o.SLOT_OUT_OF_WINDOW]:"appointment.error.slotOutOfWindow",[o.CANNOT_CANCEL_ONGOING_OR_PAST]:"appointment.error.cannotCancel",[o.NEW_SLOT_FULL]:"appointment.error.newSlotFull",[o.NO_EXISTING_BOOKING]:"appointment.error.noExistingBooking",[o.INVALID_SLOT]:"appointment.error.invalidSlot"},i=/* @__PURE__ */new Set([o.DISTRIBUTION_DEACTIVATED,o.DISTRIBUTION_CLOSED,o.DISTRIBUTION_ORDER_LIMIT,o.SOLD_OUT,o.CHECKOUT_MISCONFIGURED]);function n(r){return"INLINE"===r||"STEP_RESET"===r?"error.inlineGeneric":"error.description"}function s(e,s){const{disposition:I}=r(e.code,e.status,e.action),d="number"==typeof e.retryAfter&&Number.isFinite(e.retryAfter)?e.retryAfter:void 0,E=function(r,e,i){return r===o.RATE_LIMITED?i?"error.rateLimited":"error.rateLimitedGeneric":r===o.OVERLOADED?i?"error.overloaded":"error.overloadedGeneric":t[r]??n(e)}(e.code,I,void 0!==d);let O=s(E,void 0!==d?{values:{seconds:d}}:void 0);O.includes("{{")&&(O=s(n(I)));const a="PANEL"===I?s("error.title"):void 0;return{code:e.code,title:a,description:O,disposition:I,retryAfter:e.retryAfter,support:e.support,allowRetry:!i.has(e.code)}}function I(r){if(r instanceof e)return r;const t=r instanceof Error?r.message:String(r);return new e(t,o.INTERNAL_ERROR)}function d(r){return{code:r.code,status:r.status,requestId:r.requestId,correlationId:r.correlationId,details:r.details,issues:r.issues}}export{I as ensureFanfareError,d as toDebug,s as toDisplay};
@@ -1 +1 @@
1
- import{ErrorCodes as E}from"./errors.js";const I={[E.OTP_INVALID]:"INLINE",[E.INVALID_CREDENTIALS]:"INLINE",[E.VALIDATION_ERROR]:"INLINE",[E.RATE_LIMITED]:"INLINE",[E.SLOT_OUT_OF_WINDOW]:"INLINE",[E.OVERLOADED]:"INLINE",[E.SERVICE_UNAVAILABLE]:"INLINE",[E.TIMEOUT]:"INLINE",[E.NETWORK_ERROR]:"INLINE",[E.FEATURE_DISABLED]:"INLINE",[E.PAYMENT_REQUIRED]:"INLINE",[E.PAYMENT_FAILED]:"INLINE",[E.PAYMENT_AUTHENTICATION_FAILED]:"INLINE",[E.OTP_EXPIRED]:"STEP_RESET",[E.BOT_CHALLENGE_INVALID]:"STEP_RESET",[E.BOT_CHALLENGE_EXPIRED]:"STEP_RESET",[E.SLOT_EXPIRED]:"STEP_RESET",[E.SLOT_NOT_AVAILABLE]:"STEP_RESET",[E.NEW_SLOT_FULL]:"STEP_RESET",[E.RESERVATION_EXPIRED]:"STEP_RESET",[E.INVALID_SESSION]:"RESTART",[E.INVALID_REFRESH_TOKEN]:"RESTART",[E.UNAUTHORIZED]:"RESTART",[E.ENTRY_TOKEN_REQUIRED]:"RESTART",[E.ENTRY_TOKEN_INVALID]:"RESTART",[E.ENTRY_TOKEN_EXPIRED]:"RESTART",[E.ADMISSION_GRANT_INVALID]:"RESTART",[E.ADMISSION_PROOF_REQUIRED]:"RESTART",[E.ADMISSION_KEY_THUMBPRINT_REQUIRED]:"RESTART",[E.ADMISSION_ORIGINAL_ENTRY_REQUIRED]:"RESTART",[E.RATE_LIMIT_UNAVAILABLE]:"PANEL",[E.FINGERPRINT_REQUIRED]:"PANEL",[E.FINGERPRINT_DEVICE_MISMATCH]:"PANEL",[E.FINGERPRINT_INVALID]:"PANEL",[E.BOT_CHALLENGE_SUBJECT_MISMATCH]:"PANEL",[E.ADMISSION_KEY_MISMATCH]:"PANEL",[E.DISTRIBUTION_NOT_OPEN]:"PANEL",[E.DISTRIBUTION_CLOSED]:"PANEL",[E.DISTRIBUTION_FULL]:"PANEL",[E.DISTRIBUTION_ORDER_LIMIT]:"PANEL",[E.PROTOCOL_ERROR]:"PANEL",[E.NO_ACCESS]:"PANEL",[E.CHECKOUT_MISCONFIGURED]:"PANEL"},N=/* @__PURE__ */new Set([E.ENTRY_TOKEN_MISMATCH]);function T(E,T,R){const A=function(E,T){return"reroute"===T&&N.has(E)?"RESTART":I[E]??"PANEL"}(E,R);return{disposition:A,autoRetryOnce:false}}export{T as classify};
1
+ import{ErrorCodes as E}from"./errors.js";const I={[E.OTP_INVALID]:"INLINE",[E.INVALID_CREDENTIALS]:"INLINE",[E.VALIDATION_ERROR]:"INLINE",[E.RATE_LIMITED]:"INLINE",[E.SLOT_OUT_OF_WINDOW]:"INLINE",[E.OVERLOADED]:"INLINE",[E.SERVICE_UNAVAILABLE]:"INLINE",[E.TIMEOUT]:"INLINE",[E.NETWORK_ERROR]:"INLINE",[E.FEATURE_DISABLED]:"INLINE",[E.PAYMENT_REQUIRED]:"INLINE",[E.PAYMENT_FAILED]:"INLINE",[E.PAYMENT_AUTHENTICATION_FAILED]:"INLINE",[E.OTP_EXPIRED]:"STEP_RESET",[E.BOT_CHALLENGE_INVALID]:"STEP_RESET",[E.BOT_CHALLENGE_EXPIRED]:"STEP_RESET",[E.SLOT_EXPIRED]:"STEP_RESET",[E.SLOT_NOT_AVAILABLE]:"STEP_RESET",[E.NEW_SLOT_FULL]:"STEP_RESET",[E.RESERVATION_EXPIRED]:"STEP_RESET",[E.INVALID_SESSION]:"RESTART",[E.INVALID_REFRESH_TOKEN]:"RESTART",[E.UNAUTHORIZED]:"RESTART",[E.ENTRY_TOKEN_REQUIRED]:"RESTART",[E.ENTRY_TOKEN_INVALID]:"RESTART",[E.ENTRY_TOKEN_EXPIRED]:"RESTART",[E.ADMISSION_GRANT_INVALID]:"RESTART",[E.ADMISSION_PROOF_REQUIRED]:"RESTART",[E.ADMISSION_KEY_THUMBPRINT_REQUIRED]:"RESTART",[E.ADMISSION_ORIGINAL_ENTRY_REQUIRED]:"RESTART",[E.RATE_LIMIT_UNAVAILABLE]:"PANEL",[E.FINGERPRINT_REQUIRED]:"PANEL",[E.FINGERPRINT_DEVICE_MISMATCH]:"PANEL",[E.FINGERPRINT_INVALID]:"PANEL",[E.BOT_CHALLENGE_SUBJECT_MISMATCH]:"PANEL",[E.ADMISSION_KEY_MISMATCH]:"PANEL",[E.DISTRIBUTION_NOT_OPEN]:"PANEL",[E.DISTRIBUTION_CLOSED]:"PANEL",[E.DISTRIBUTION_DEACTIVATED]:"PANEL",[E.DISTRIBUTION_FULL]:"PANEL",[E.DISTRIBUTION_ORDER_LIMIT]:"PANEL",[E.PROTOCOL_ERROR]:"PANEL",[E.NO_ACCESS]:"PANEL",[E.CHECKOUT_MISCONFIGURED]:"PANEL"},T=/* @__PURE__ */new Set([E.ENTRY_TOKEN_MISMATCH]);function N(E,N,R){const A=function(E,N){return"reroute"===N&&T.has(E)?"RESTART":I[E]??"PANEL"}(E,R);return{disposition:A,autoRetryOnce:false}}export{N as classify};
@@ -75,8 +75,10 @@ export declare const ErrorCodes: {
75
75
  readonly ADMISSION_GRANT_INVALID: "ADMISSION_GRANT_INVALID";
76
76
  readonly ADMISSION_ORIGINAL_ENTRY_REQUIRED: "ADMISSION_ORIGINAL_ENTRY_REQUIRED";
77
77
  readonly ADMISSION_KEY_MISMATCH: "ADMISSION_KEY_MISMATCH";
78
+ readonly ADMISSION_ACTIVE: "ADMISSION_ACTIVE";
78
79
  readonly DISTRIBUTION_NOT_OPEN: "DISTRIBUTION_NOT_OPEN";
79
80
  readonly DISTRIBUTION_CLOSED: "DISTRIBUTION_CLOSED";
81
+ readonly DISTRIBUTION_DEACTIVATED: "DISTRIBUTION_DEACTIVATED";
80
82
  readonly DISTRIBUTION_FULL: "DISTRIBUTION_FULL";
81
83
  readonly DISTRIBUTION_ORDER_LIMIT: "DISTRIBUTION_ORDER_LIMIT";
82
84
  readonly FINGERPRINT_REQUIRED: "FINGERPRINT_REQUIRED";
@@ -1 +1 @@
1
- import{CheckoutErrorCodes as e,ErrorCodeMap as t}from"@fanfare-io/fanfare-sdk-contracts/errors";const I={NETWORK_ERROR:"NETWORK_ERROR",TIMEOUT:"TIMEOUT",ABORTED:"ABORTED",NOT_INITIALIZED:"NOT_INITIALIZED",ALREADY_INITIALIZED:"ALREADY_INITIALIZED",INVALID_CONFIG:"INVALID_CONFIG",ADMISSION_PROOF_UNAVAILABLE:"ADMISSION_PROOF_UNAVAILABLE",PROTOCOL_ERROR:"PROTOCOL_ERROR",CANNOT_LEAVE_AFTER_BID:"CANNOT_LEAVE_AFTER_BID",NO_ACCESS:"NO_ACCESS"},r=e,E={...t,...I,...r};function o(e,t){if(e&&"object"==typeof e&&t in e){const I=e[t];if("string"==typeof I)return I}}function N(e){if(!e)return;const t=+e,I=Math.ceil(isFinite(t)?t:(Date.parse(e)-Date.now())/1e3);return I>=0?I:I<0?0:void 0}const O=/* @__PURE__ */new Set([t.VALIDATION_ERROR,t.UNAUTHORIZED,t.FORBIDDEN,t.NOT_FOUND,t.RATE_LIMITED,t.RATE_LIMIT_UNAVAILABLE,t.PAYLOAD_TOO_LARGE,t.INVALID_CREDENTIALS,t.INVALID_SESSION,t.INVALID_REFRESH_TOKEN,t.OTP_INVALID,t.OTP_EXPIRED,t.ENTRY_TOKEN_REQUIRED,t.ENTRY_TOKEN_INVALID,t.ENTRY_TOKEN_EXPIRED,t.ENTRY_TOKEN_MISMATCH,t.SLOT_EXPIRED,t.SLOT_OUT_OF_WINDOW,t.ALREADY_BOOKED,t.ACTIVE_BOOKING_EXISTS,t.NO_EXISTING_BOOKING,t.INVALID_SLOT,t.CANNOT_CANCEL_ONGOING_OR_PAST,t.FINGERPRINT_REQUIRED,t.FINGERPRINT_DEVICE_MISMATCH,t.FINGERPRINT_INVALID,t.SLOT_NOT_AVAILABLE,t.NEW_SLOT_FULL,t.DISTRIBUTION_NOT_OPEN,t.DISTRIBUTION_CLOSED,t.DISTRIBUTION_FULL,t.ADMISSION_KEY_THUMBPRINT_REQUIRED,t.ADMISSION_PROOF_REQUIRED,t.ADMISSION_GRANT_INVALID,t.ADMISSION_ORIGINAL_ENTRY_REQUIRED,t.ADMISSION_KEY_MISMATCH,t.BOT_CHALLENGE_INVALID,t.BOT_CHALLENGE_EXPIRED,t.BOT_CHALLENGE_SUBJECT_MISMATCH]);class _ extends Error{constructor(e,t,I,r,E,o,N=!1,O,n){super(e),this.name="FanfareError",this.code=t,this.status=I,this.details=r,this.requestId=E,this.correlationId=o,this.retryable=N,this.retryAfter=O,this.issues=n?.issues,this.action=n?.action,this.support=n?.support,this.quietable=n?.quietable,Error.captureStackTrace&&Error.captureStackTrace(this,_)}static fromResponse(e,t,I){const r=e.headers.get("X-Request-Id")||void 0,E=e.headers.get("X-Correlation-Id")||I,R=N(e.headers.get("Retry-After")),{code:T,retryable:i}=n(e.status,t),s=o(t,"message"),A=(s&&e.status<500&&O.has(T)?s:null)||e.statusText||"An error occurred",a=(t&&"object"==typeof t&&"details"in t?t.details:t)??t,D=t&&"object"==typeof t&&Array.isArray(t.issues)?t.issues:void 0,c=o(t,"action"),L=t&&"object"==typeof t&&"support"in t?t.support:void 0;return new _(A,T,e.status,a,r,E,i,R,{issues:D,action:c,support:L})}is(e){return this.code===e}}function n(e,t){const I=429===e||e>=500,r=o(t,"code");return r?{code:r,retryable:I}:429===e?{code:E.RATE_LIMITED,retryable:I}:401===e?{code:E.UNAUTHORIZED,retryable:I}:403===e?{code:E.FORBIDDEN,retryable:I}:413===e?{code:E.PAYLOAD_TOO_LARGE,retryable:I}:422===e||400===e?{code:E.VALIDATION_ERROR,retryable:I}:404===e?{code:E.NOT_FOUND,retryable:I}:423===e?{code:E.DISTRIBUTION_NOT_OPEN,retryable:I}:503===e?{code:E.SERVICE_UNAVAILABLE,retryable:I}:e>=500?{code:E.INTERNAL_ERROR,retryable:I}:{code:`HTTP_${e}`,retryable:I}}class R extends _{constructor(e,t,I,r){super(e,E.PROTOCOL_ERROR,void 0,I,r),this.name="ProtocolError",this.endpoint=t,this.issues=I}}function T(e){return e instanceof _}function i(e){return e instanceof R}const s=/* @__PURE__ */new Set([E.ENTRY_TOKEN_REQUIRED,E.ENTRY_TOKEN_INVALID,E.ENTRY_TOKEN_EXPIRED,E.ENTRY_TOKEN_MISMATCH]);function A(e){return e instanceof _&&(403===e.status&&s.has(e.code))}function a(e){return A(e)}function D(e){return!!A(e)&&"reroute"===e.action}function c(e){return D(e)}const L={networkError:(e,t)=>new _(e,E.NETWORK_ERROR,void 0,t),timeout:(e="Request timed out")=>new _(e,E.TIMEOUT),unauthorized:(e="Unauthorized")=>new _(e,E.UNAUTHORIZED,401),invalidSession:(e="Session is no longer valid")=>new _(e,E.INVALID_SESSION,401),notInitialized:(e="SDK not initialized")=>new _(e,E.NOT_INITIALIZED),invalidConfig:(e,t)=>new _(e,E.INVALID_CONFIG,void 0,t),validationError:(e,t)=>new _(e,E.VALIDATION_ERROR,void 0,t),internalError:(e,t)=>new _(e,E.INTERNAL_ERROR,void 0,t),cannotLeaveAfterBid:e=>new _(`Cannot leave auction ${e} after placing a bid — a bid is a binding commitment`,E.CANNOT_LEAVE_AFTER_BID,void 0,{auctionId:e})};export{r as CheckoutErrorCodes,E as ErrorCodes,_ as FanfareError,R as ProtocolError,I as SdkClientErrorCodes,n as classifyHttpError,L as createError,a as isCapabilityGrantError,c as isCapabilityGrantRerouteError,A as isCapabilityTokenError,D as isCapabilityTokenRerouteError,T as isFanfareError,i as isProtocolError,N as parseRetryAfterSeconds};
1
+ import{CheckoutErrorCodes as e,ErrorCodeMap as t}from"@fanfare-io/fanfare-sdk-contracts/errors";const I={NETWORK_ERROR:"NETWORK_ERROR",TIMEOUT:"TIMEOUT",ABORTED:"ABORTED",NOT_INITIALIZED:"NOT_INITIALIZED",ALREADY_INITIALIZED:"ALREADY_INITIALIZED",INVALID_CONFIG:"INVALID_CONFIG",ADMISSION_PROOF_UNAVAILABLE:"ADMISSION_PROOF_UNAVAILABLE",PROTOCOL_ERROR:"PROTOCOL_ERROR",CANNOT_LEAVE_AFTER_BID:"CANNOT_LEAVE_AFTER_BID",NO_ACCESS:"NO_ACCESS"},E=e,r={...t,...I,...E};function o(e,t){if(e&&"object"==typeof e&&t in e){const I=e[t];if("string"==typeof I)return I}}function N(e){if(!e)return;const t=+e,I=Math.ceil(isFinite(t)?t:(Date.parse(e)-Date.now())/1e3);return I>=0?I:I<0?0:void 0}const O=/* @__PURE__ */new Set([t.VALIDATION_ERROR,t.UNAUTHORIZED,t.FORBIDDEN,t.NOT_FOUND,t.RATE_LIMITED,t.RATE_LIMIT_UNAVAILABLE,t.PAYLOAD_TOO_LARGE,t.INVALID_CREDENTIALS,t.INVALID_SESSION,t.INVALID_REFRESH_TOKEN,t.OTP_INVALID,t.OTP_EXPIRED,t.ENTRY_TOKEN_REQUIRED,t.ENTRY_TOKEN_INVALID,t.ENTRY_TOKEN_EXPIRED,t.ENTRY_TOKEN_MISMATCH,t.SLOT_EXPIRED,t.SLOT_OUT_OF_WINDOW,t.ALREADY_BOOKED,t.ACTIVE_BOOKING_EXISTS,t.NO_EXISTING_BOOKING,t.INVALID_SLOT,t.CANNOT_CANCEL_ONGOING_OR_PAST,t.FINGERPRINT_REQUIRED,t.FINGERPRINT_DEVICE_MISMATCH,t.FINGERPRINT_INVALID,t.SLOT_NOT_AVAILABLE,t.NEW_SLOT_FULL,t.DISTRIBUTION_NOT_OPEN,t.DISTRIBUTION_CLOSED,t.DISTRIBUTION_DEACTIVATED,t.DISTRIBUTION_FULL,t.ADMISSION_KEY_THUMBPRINT_REQUIRED,t.ADMISSION_PROOF_REQUIRED,t.ADMISSION_GRANT_INVALID,t.ADMISSION_ORIGINAL_ENTRY_REQUIRED,t.ADMISSION_KEY_MISMATCH,t.ADMISSION_ACTIVE,t.BOT_CHALLENGE_INVALID,t.BOT_CHALLENGE_EXPIRED,t.BOT_CHALLENGE_SUBJECT_MISMATCH]);class _ extends Error{constructor(e,t,I,E,r,o,N=!1,O,T){super(e),this.name="FanfareError",this.code=t,this.status=I,this.details=E,this.requestId=r,this.correlationId=o,this.retryable=N,this.retryAfter=O,this.issues=T?.issues,this.action=T?.action,this.support=T?.support,this.quietable=T?.quietable,Error.captureStackTrace&&Error.captureStackTrace(this,_)}static fromResponse(e,t,I){const E=e.headers.get("X-Request-Id")||void 0,r=e.headers.get("X-Correlation-Id")||I,n=N(e.headers.get("Retry-After")),{code:R,retryable:i}=T(e.status,t),s=o(t,"message"),A=(s&&e.status<500&&O.has(R)?s:null)||e.statusText||"An error occurred",a=(t&&"object"==typeof t&&"details"in t?t.details:t)??t,D=t&&"object"==typeof t&&Array.isArray(t.issues)?t.issues:void 0,c=o(t,"action"),L=t&&"object"==typeof t&&"support"in t?t.support:void 0;return new _(A,R,e.status,a,E,r,i,n,{issues:D,action:c,support:L})}is(e){return this.code===e}}function T(e,t){const I=429===e||e>=500,E=o(t,"code");return E?{code:E,retryable:I}:429===e?{code:r.RATE_LIMITED,retryable:I}:401===e?{code:r.UNAUTHORIZED,retryable:I}:403===e?{code:r.FORBIDDEN,retryable:I}:413===e?{code:r.PAYLOAD_TOO_LARGE,retryable:I}:422===e||400===e?{code:r.VALIDATION_ERROR,retryable:I}:404===e?{code:r.NOT_FOUND,retryable:I}:423===e?{code:r.DISTRIBUTION_NOT_OPEN,retryable:I}:503===e?{code:r.SERVICE_UNAVAILABLE,retryable:I}:e>=500?{code:r.INTERNAL_ERROR,retryable:I}:{code:`HTTP_${e}`,retryable:I}}class n extends _{constructor(e,t,I,E){super(e,r.PROTOCOL_ERROR,void 0,I,E),this.name="ProtocolError",this.endpoint=t,this.issues=I}}function R(e){return e instanceof _}function i(e){return e instanceof n}const s=/* @__PURE__ */new Set([r.ENTRY_TOKEN_REQUIRED,r.ENTRY_TOKEN_INVALID,r.ENTRY_TOKEN_EXPIRED,r.ENTRY_TOKEN_MISMATCH]);function A(e){return e instanceof _&&(403===e.status&&s.has(e.code))}function a(e){return A(e)}function D(e){return!!A(e)&&"reroute"===e.action}function c(e){return D(e)}const L={networkError:(e,t)=>new _(e,r.NETWORK_ERROR,void 0,t),timeout:(e="Request timed out")=>new _(e,r.TIMEOUT),unauthorized:(e="Unauthorized")=>new _(e,r.UNAUTHORIZED,401),invalidSession:(e="Session is no longer valid")=>new _(e,r.INVALID_SESSION,401),notInitialized:(e="SDK not initialized")=>new _(e,r.NOT_INITIALIZED),invalidConfig:(e,t)=>new _(e,r.INVALID_CONFIG,void 0,t),validationError:(e,t)=>new _(e,r.VALIDATION_ERROR,void 0,t),internalError:(e,t)=>new _(e,r.INTERNAL_ERROR,void 0,t),cannotLeaveAfterBid:e=>new _(`Cannot leave auction ${e} after placing a bid — a bid is a binding commitment`,r.CANNOT_LEAVE_AFTER_BID,void 0,{auctionId:e})};export{E as CheckoutErrorCodes,r as ErrorCodes,_ as FanfareError,n as ProtocolError,I as SdkClientErrorCodes,T as classifyHttpError,L as createError,a as isCapabilityGrantError,c as isCapabilityGrantRerouteError,A as isCapabilityTokenError,D as isCapabilityTokenRerouteError,R as isFanfareError,i as isProtocolError,N as parseRetryAfterSeconds};
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * SDK version
3
3
  * This is automatically updated during the build process
4
4
  */
5
- export declare const version = "0.12.0";
5
+ export declare const version = "0.13.0";
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- const o="0.12.0";export{o as version};
1
+ const o="0.13.0";export{o as version};
@@ -19,7 +19,7 @@ export interface WaitlistEntry {
19
19
  enteredAt: string;
20
20
  }
21
21
  /**
22
- * Error thrown when waitlist is closed
22
+ * Public waitlist-closed error. Not produced by enter(); retained as a published export.
23
23
  */
24
24
  export declare class WaitlistClosedError extends Error {
25
25
  constructor(message: string);
@@ -1 +1 @@
1
- import{createError as t}from"../core/errors.js";import{getLogger as e}from"../core/logger.js";import{generateId as s}from"../core/utils.js";import{getEventBus as i}from"../state/events.js";import{getSDKStore as r}from"../state/store.js";import{WaitlistClosedError as o}from"./types.js";class a{constructor(t){this.logger=e(),this.events=i(),this.http=t}get store(){return r()}async enter(e,i){try{if(!this.store.session)throw t.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");this.logger.info("Entering waitlist",{waitlistId:e});const s=await this.http.post(`/waitlists/${e}/enter`,void 0,i);return this.events.emit("waitlist:entered",{waitlistId:e,sequenceId:s.sequenceId,enteredAt:s.enteredAt}),s}catch(r){if(r&&"object"==typeof r&&"message"in r){const t=r.message.toLowerCase();if(t.includes("already on list")||t.includes("already entered")||t.includes("already joined")){this.logger.info("Waitlist entry already exists",{waitlistId:e});const t=await this.getStatus(e);return{id:s(),waitlistId:e,sequenceId:t.sequenceId??"",consumerId:this.store.session?.consumerId||"unknown",enteredAt:t.enteredAt||/* @__PURE__ */(new Date).toISOString()}}if(t.includes("waitlist closed")||t.includes("not accepting")){const t=new o("Waitlist is no longer accepting entries");throw this.logger.error("Waitlist closed",{waitlistId:e}),this.events.emit("waitlist:error",{waitlistId:e,error:t.message}),t}}throw this.logger.error("Failed to enter waitlist",{waitlistId:e,error:r}),this.events.emit("waitlist:error",{waitlistId:e,error:r instanceof Error?r.message:"Unknown error"}),r}}async leave(t,e){try{this.logger.info("Leaving waitlist",{waitlistId:t}),await this.http.delete(`/waitlists/${t}/leave`,e),this.events.emit("waitlist:left",{waitlistId:t})}catch(s){throw this.logger.error("Failed to leave waitlist",{waitlistId:t,error:s}),this.events.emit("waitlist:error",{waitlistId:t,error:s instanceof Error?s.message:"Unknown error"}),s}}async getStatus(t){try{return await this.http.get(`/waitlists/${t}/status`)}catch(e){if(e&&"object"==typeof e&&"status"in e&&404===e.status)return{waitlistId:t,isEntered:!1};throw this.logger.error("Failed to get waitlist status",{waitlistId:t,error:e}),this.events.emit("waitlist:error",{waitlistId:t,error:e instanceof Error?e.message:"Unknown error"}),e}}destroy(){this.logger.debug("WaitlistManagementModule destroyed")}}export{a as WaitlistManagementModule};
1
+ import{createError as t}from"../core/errors.js";import{getLogger as e}from"../core/logger.js";import{generateId as s}from"../core/utils.js";import{getEventBus as r}from"../state/events.js";import{getSDKStore as i}from"../state/store.js";class o{constructor(t){this.logger=e(),this.events=r(),this.http=t}get store(){return i()}async enter(e,r){try{if(!this.store.session)throw t.unauthorized("Not authenticated. Call auth.guest() or auth.login() first");this.logger.info("Entering waitlist",{waitlistId:e});const s=await this.http.post(`/waitlists/${e}/enter`,void 0,r);return this.events.emit("waitlist:entered",{waitlistId:e,sequenceId:s.sequenceId,enteredAt:s.enteredAt}),s}catch(i){if(i&&"object"==typeof i&&"message"in i){const t=i.message.toLowerCase();if(t.includes("already on list")||t.includes("already entered")||t.includes("already joined")){this.logger.info("Waitlist entry already exists",{waitlistId:e});const t=await this.getStatus(e);return{id:s(),waitlistId:e,sequenceId:t.sequenceId??"",consumerId:this.store.session?.consumerId||"unknown",enteredAt:t.enteredAt||/* @__PURE__ */(new Date).toISOString()}}}throw this.logger.error("Failed to enter waitlist",{waitlistId:e,error:i}),this.events.emit("waitlist:error",{waitlistId:e,error:i instanceof Error?i.message:"Unknown error"}),i}}async leave(t,e){try{this.logger.info("Leaving waitlist",{waitlistId:t}),await this.http.delete(`/waitlists/${t}/leave`,e),this.events.emit("waitlist:left",{waitlistId:t})}catch(s){throw this.logger.error("Failed to leave waitlist",{waitlistId:t,error:s}),this.events.emit("waitlist:error",{waitlistId:t,error:s instanceof Error?s.message:"Unknown error"}),s}}async getStatus(t){try{return await this.http.get(`/waitlists/${t}/status`)}catch(e){if(e&&"object"==typeof e&&"status"in e&&404===e.status)return{waitlistId:t,isEntered:!1};throw this.logger.error("Failed to get waitlist status",{waitlistId:t,error:e}),this.events.emit("waitlist:error",{waitlistId:t,error:e instanceof Error?e.message:"Unknown error"}),e}}destroy(){this.logger.debug("WaitlistManagementModule destroyed")}}export{o as WaitlistManagementModule};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fanfare-io/fanfare-sdk-core",
3
- "version": "0.12.0",
3
+ "version": "0.13.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",
@@ -17,9 +17,6 @@
17
17
  "type": "module",
18
18
  "files": [
19
19
  "dist/",
20
- "!dist/**/*.map",
21
- "!dist/**/*.tsbuildinfo",
22
- "!dist/stats.html",
23
20
  "README.md",
24
21
  "LICENSE"
25
22
  ],
@@ -82,14 +79,6 @@
82
79
  "types": "./dist/internals.d.ts",
83
80
  "import": "./dist/internals.js"
84
81
  },
85
- "./test-utils": {
86
- "types": "./dist/test-utils/index.d.ts",
87
- "import": "./dist/test-utils/index.js"
88
- },
89
- "./test-utils/vitest": {
90
- "types": "./dist/test-utils/mock-sdk-vitest.d.ts",
91
- "import": "./dist/test-utils/mock-sdk-vitest.js"
92
- },
93
82
  "./errors": {
94
83
  "types": "./dist/errors.d.ts",
95
84
  "import": "./dist/errors.js"
@@ -98,10 +87,6 @@
98
87
  "types": "./dist/admission-proof.d.ts",
99
88
  "import": "./dist/admission-proof.js"
100
89
  },
101
- "./harness": {
102
- "types": "./dist/harness.d.ts",
103
- "import": "./dist/harness.js"
104
- },
105
90
  "./draws": {
106
91
  "types": "./dist/draws/public.d.ts",
107
92
  "import": "./dist/draws/public.js"
@@ -126,16 +111,10 @@
126
111
  "uuid": "^14.0.0",
127
112
  "wretch": "^2.11.0",
128
113
  "zustand": "^5.0.6",
129
- "@fanfare-io/fanfare-sdk-contracts": "0.12.0"
114
+ "@fanfare-io/fanfare-sdk-contracts": "0.13.0"
130
115
  },
131
116
  "peerDependencies": {
132
- "valibot": "^1.1.0",
133
- "vitest": ">=3"
134
- },
135
- "peerDependenciesMeta": {
136
- "vitest": {
137
- "optional": true
138
- }
117
+ "valibot": "^1.1.0"
139
118
  },
140
119
  "devDependencies": {
141
120
  "@chromatic-com/storybook": "^5.0.1",
@@ -171,7 +150,7 @@
171
150
  "vite-plugin-dts": "^4.5.4",
172
151
  "vite-tsconfig-paths": "^5.1.4",
173
152
  "vitest": "^4.1.10",
174
- "@fanfare-io/shared-models": "0.12.0"
153
+ "@fanfare-io/shared-models": "0.13.0"
175
154
  },
176
155
  "sideEffects": false,
177
156
  "keywords": [
@@ -192,20 +171,21 @@
192
171
  }
193
172
  ],
194
173
  "scripts": {
195
- "build": "vite build && pnpm size",
174
+ "build": "vite build && pnpm build:publish && pnpm size",
196
175
  "build:deps": "vite build --emptyOutDir false",
197
176
  "build:incremental": "vite build --emptyOutDir false",
198
177
  "build:dist": "rimraf dist && vite build",
178
+ "build:publish": "node ../../scripts/sdk-core-publish-package.mjs build",
199
179
  "build:strict": "pnpm typecheck && pnpm build",
200
180
  "build-storybook": "storybook build",
201
181
  "dev": "vite build --watch",
202
182
  "fmt": "prettier src --write",
203
183
  "lint": "oxlint src",
204
184
  "lint:fix": "oxlint --fix src",
205
- "prebuild": "rimraf dist",
185
+ "prebuild": "rimraf dist publish",
206
186
  "prebuild-storybook": "pnpm typecheck",
207
187
  "size": "size-limit",
208
- "storybook": "storybook dev -p 6007 --no-open",
188
+ "storybook": "storybook dev -p 6007 --host 127.0.0.1 --no-open",
209
189
  "build:test-deps": "[ \"$SKIP_TEST_DEP_BUILDS\" = \"1\" ] || { pnpm --filter @fanfare-io/fanfare-sdk-contracts run build:incremental && pnpm --filter @fanfare-io/fanfare-sdk-shopify run build:deps; }",
210
190
  "test": "pnpm build:test-deps && vitest run",
211
191
  "test:debug": "NODE_OPTIONS='--expose-gc' vitest run --reporter=verbose",
@@ -1,44 +0,0 @@
1
- import { WritableAtom } from 'nanostores';
2
- import { DistributionDisplayState, DistributionMonitor, MonitorUpdate } from '../experiences/distribution-monitor.types';
3
- import { JourneyEvent, JourneyEventAudience, JourneyEventKind, JourneyEventSeverity, MechanismConsumerState, Participation, SequenceOutcome, SequenceState } from '../experiences/journey.types';
4
- import { SequenceDriver, SequenceProjectionFacts } from '../experiences/sequence-driver';
5
- import { AppointmentModule } from './types';
6
- type AppointmentMonitorModule = AppointmentModule & Pick<DistributionMonitor, "startMonitoring" | "stopMonitoring">;
7
- /**
8
- * Narrow shell and module capabilities required by the appointment driver.
9
- */
10
- export interface AppointmentDriverDependencies {
11
- /** Appointment module functions used by appointment actions and monitoring. */
12
- appointments: Pick<AppointmentMonitorModule, "book" | "cancel" | "reschedule" | "startMonitoring" | "stopMonitoring" | "bumpMonitorGeneration">;
13
- /** Serialize an appointment action with the shell's operation queue. */
14
- runSerializedOperation(operation: () => Promise<void>): Promise<void>;
15
- /** Read the current routed sequence before validating an appointment action. */
16
- getCurrentSequence(): SequenceState | undefined;
17
- /** Read the current shell-owned display state for cancellation details. */
18
- getDisplayState(): DistributionDisplayState | null;
19
- /** Commit a concrete next appointment sequence into the shell. */
20
- commit(next: SequenceState, opts?: {
21
- events?: JourneyEvent[];
22
- }): void;
23
- /** Apply shell-owned terminal lifecycle side effects. */
24
- applyMonitorUpdate(update: MonitorUpdate): void;
25
- /** Ensure the shell-owned display atom exists for this appointment participation. */
26
- ensureDisplayAtom(participation: Participation): WritableAtom<DistributionDisplayState>;
27
- /** Stop shell runtime monitoring and optionally clear display state. */
28
- stopRuntimeMonitoring(clearDisplay?: boolean): void;
29
- /** Append a shell-visible journey event to the snapshot. */
30
- emitEvent(kind: JourneyEventKind, severity: JourneyEventSeverity, audience: JourneyEventAudience, message: string, detail?: Record<string, unknown>): void;
31
- }
32
- /**
33
- * Create the appointment sequence driver for one journey instance.
34
- */
35
- export declare function createAppointmentDriver(deps: AppointmentDriverDependencies): SequenceDriver;
36
- /**
37
- * Project appointment server facts into an appointment sequence state.
38
- */
39
- export declare function projectAppointmentSequence(facts: SequenceProjectionFacts): SequenceState;
40
- /**
41
- * Return the appointment consumer state that represents a terminal outcome.
42
- */
43
- export declare function withAppointmentTerminalConsumer(consumer: MechanismConsumerState | undefined, outcome?: SequenceOutcome): MechanismConsumerState | undefined;
44
- export {};
@@ -1,33 +0,0 @@
1
- import { HttpClient, RequestOptions } from '../core/http';
2
- import { MonitorUpdate } from '../experiences/distribution-monitor.types';
3
- import { AppointmentDetails } from '../experiences/types';
4
- import { AppointmentBooking, AppointmentModule, AppointmentSlot } from './types';
5
- export declare class AppointmentManagementModule implements AppointmentModule {
6
- private readonly http;
7
- private readonly logger;
8
- private readonly monitorRuntime;
9
- private readonly pollSchedulers;
10
- private readonly monitorGenerations;
11
- private readonly observedBooking;
12
- private readonly pollingIntervalMs;
13
- private destroyed;
14
- constructor(http: HttpClient, opts?: {
15
- pollingIntervalMs?: number;
16
- });
17
- get(appointmentId: string, options?: RequestOptions): Promise<AppointmentDetails>;
18
- getSlots(appointmentId: string, range: {
19
- startDate: string;
20
- endDate: string;
21
- timezone?: string;
22
- }, options?: RequestOptions): Promise<AppointmentSlot[]>;
23
- getMe(appointmentId: string): Promise<AppointmentBooking | null>;
24
- book(appointmentId: string, slotId: string, locationId?: string, options?: RequestOptions): Promise<AppointmentBooking>;
25
- cancel(appointmentId: string, slotId: string, locationId?: string, reason?: string, options?: RequestOptions): Promise<void>;
26
- reschedule(appointmentId: string, newSlotId: string, newLocationId?: string, options?: RequestOptions): Promise<AppointmentBooking>;
27
- startMonitoring(id: string, context?: Record<string, unknown>, onUpdate?: (update: MonitorUpdate) => void, onDegradedChange?: (degraded: boolean) => void): void;
28
- stopMonitoring(id: string): void;
29
- isMonitoring(id: string): boolean;
30
- bumpMonitorGeneration(id: string): void;
31
- destroy(): void;
32
- private stopPolling;
33
- }
@@ -1,2 +0,0 @@
1
- export { AppointmentManagementModule } from './appointment.module';
2
- export type { AppointmentBooking, AppointmentModule, AppointmentSlot } from './types';
@@ -1,4 +0,0 @@
1
- import { AuctionBidderStateResponse } from '@fanfare-io/fanfare-sdk-contracts/auction';
2
- import { AuctionConsumerStatus } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
3
- export declare function toAuctionConsumerStatus(status: AuctionBidderStateResponse["status"]): AuctionConsumerStatus;
4
- export declare function isTerminalAuctionStatus(status: AuctionConsumerStatus | undefined): status is "won" | "lost";
@@ -1,60 +0,0 @@
1
- import { WritableAtom } from 'nanostores';
2
- import { DistributionDisplayState, DistributionMonitor, MonitorUpdate } from '../experiences/distribution-monitor.types';
3
- import { DistributionSummary, JourneyEvent, JourneyEventAudience, JourneyEventKind, JourneyEventSeverity, MechanismConsumerState, Participation, SequenceOutcome, SequenceState } from '../experiences/journey.types';
4
- import { SequenceDriver, SequenceProjectionFacts } from '../experiences/sequence-driver';
5
- import { AuctionModule } from './types';
6
- type AuctionMonitorModule = AuctionModule & Pick<DistributionMonitor, "startMonitoring" | "stopMonitoring">;
7
- /**
8
- * True for an outcome that carries no specific reason (or is absent entirely) and can
9
- * still be replaced once a more specific terminal result — e.g. floor-unsold — becomes
10
- * available. A `lost`/`closed` outcome that already has a `reason` is final.
11
- */
12
- export declare function isUpgradeableGenericLoss(outcome: SequenceOutcome | undefined): boolean;
13
- /**
14
- * Narrow shell and module capabilities required by the auction driver.
15
- */
16
- export interface AuctionDriverDependencies {
17
- /** Auction module functions used by auction actions and monitoring. */
18
- auctions: Pick<AuctionMonitorModule, "enter" | "leave" | "status" | "bid" | "startMonitoring" | "stopMonitoring">;
19
- /** Serialize an auction action with the shell's operation queue. */
20
- runSerializedOperation(operation: () => Promise<void>): Promise<void>;
21
- /** Read the current routed sequence before validating an auction action. */
22
- getCurrentSequence(): SequenceState | undefined;
23
- /** Read the live display state before ensureDisplayAtom resets it (settleAt lives here). */
24
- getDisplayState(): DistributionDisplayState | null;
25
- /** Commit a concrete next auction sequence into the shell. */
26
- commit(next: SequenceState, opts?: {
27
- events?: JourneyEvent[];
28
- }): void;
29
- /** Apply shell-owned grant and terminal lifecycle side effects. */
30
- applyMonitorUpdate(update: MonitorUpdate): void;
31
- /** Ensure the shell-owned display atom exists for this auction participation. */
32
- ensureDisplayAtom(participation: Participation): WritableAtom<DistributionDisplayState>;
33
- /** Stop shell runtime monitoring and optionally clear display state. */
34
- stopRuntimeMonitoring(clearDisplay?: boolean): void;
35
- /** Append a shell-visible journey event to the snapshot. */
36
- emitEvent(kind: JourneyEventKind, severity: JourneyEventSeverity, audience: JourneyEventAudience, message: string, detail?: Record<string, unknown>): void;
37
- }
38
- /**
39
- * Create the auction sequence driver for one journey instance.
40
- */
41
- export declare function createAuctionDriver(deps: AuctionDriverDependencies): SequenceDriver;
42
- /**
43
- * Project auction server facts into an auction sequence state.
44
- */
45
- export declare function projectAuctionSequence(facts: SequenceProjectionFacts): SequenceState;
46
- /**
47
- * Return the auction consumer state that represents an issued grant.
48
- */
49
- export declare function withAuctionGrantedConsumer(consumer: MechanismConsumerState | undefined, distribution: DistributionSummary): MechanismConsumerState;
50
- /**
51
- * Return the auction consumer state that represents a terminal outcome. A not_bid
52
- * consumer facing a still-upgradeable generic loss is left unresolved (unless
53
- * `finalize` is set) so a later refresh's floor-unsold re-derivation can still see
54
- * `not_bid` and upgrade the outcome — finalize=true is for a definitive terminal
55
- * transition (e.g. an immediate bid result) that will never be re-derived.
56
- */
57
- export declare function withAuctionTerminalConsumer(consumer: MechanismConsumerState | undefined, outcome?: SequenceOutcome, options?: {
58
- finalize?: boolean;
59
- }): MechanismConsumerState | undefined;
60
- export {};