@fanfare-io/fanfare-sdk-core 0.19.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as i}from"../core/errors.js";import{selectionModeFields as e,buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{isGrantPendingWin as s}from"./auction-status.js";import{isUnresolvedAuctionConsumer as o}from"./auction.sequence.js";function a(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function r(t){return new d(t)}function c(n){const s=function(e){const{distribution:n,consumer:s,grant:r,settlement:c,selection:u,outcome:d}=e;if(!n)return{phase:"unavailable"};const l=function(t){if("auction"!==t.type)throw i.validationError("Auction driver received a non-auction distribution");return t}(n),h=s&&"auction"===s.mechanism?function(t){const{mechanism:i,...e}=t;return e}(s):p(n);if(r)return"completed"===d?.type?m(l,h,d):r.expiresAt&&Date.now()>new Date(r.expiresAt).getTime()?"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:p(l)}:m(l,h,{type:"expired"}):c&&u?{phase:"granted",mechanism:"auction",distribution:l,consumer:h,grant:r,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===l.lifecycle){if("not_bid"===h.status&&l.result===t.FLOOR_UNSOLD&&a(d))return m(l,h,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===s?.mechanism&&!d)return m(l,h,{type:"lost"})}const b=d??function(t){return"lost"===t.status?{type:"lost"}:void 0}(h);if(b)return m(l,h,b);if("settling"===l.lifecycle)return{phase:"settling",mechanism:"auction",distribution:l,consumer:h};if(o(h))return{phase:"participating",mechanism:"auction",distribution:l,consumer:h};if("scheduled"===l.lifecycle)return{phase:"scheduled",mechanism:"auction",distribution:l};if("open"===l.lifecycle)return{phase:"enterable",mechanism:"auction",distribution:l,consumer:h};return m(l,h,{type:"closed"})}(n);return"unavailable"===s.phase?s:{...s,...e(n)}}function u(t,i,e){return t&&"auction"===t.mechanism&&i?"won"===i.type?{...t,status:"won"}:!e?.finalize&&"not_bid"===t.status&&a(i)?t:{...t,status:"lost"}:t}class d{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return c(t)}buildView(t,s){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const o=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("Auction driver received a non-auction sequence");return t}(t);switch(o.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",...e(o),distribution:o.distribution,startsAt:o.distribution.startsAt??o.distribution.opensAt};case"enterable":return{phase:"enterable",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"participating":return{phase:"participating",mechanism:"auction",...e(o),consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",...e(o),distribution:o.distribution,consumer:o.consumer,grant:o.grant},{settlement:i}=o,a=o.selection;if("awaiting_assignment"===a.status)return{...t,settlement:i,selection:a};if("required"===a.status)return{...t,settlement:i,selection:a,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===i.processor&&"at_end"===i.mode){const e=n(i,o.pendingAction,s);return e?{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:e}:{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return"external"===i.processor?{...t,settlement:i,selection:a,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",...e(o),consumer:o.consumer,outcome:o.outcome}}}startMonitoring(t){this.activeMonitorId=t.participation.id,this.deps.auctions.startMonitoring(t.participation.id,{displayAtom:t.displayAtom},t.onUpdate,t.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.auctions.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async bid(t){await this.deps.runSerializedOperation(async()=>{const i=this.currentAuctionSequenceForBid(),e=i.consumer.distributionId??i.consumer.id??i.distribution.id,n=i.consumer.selection,o="auction"===i.distribution.details?.type?i.distribution.details:void 0;l(t,o?.auctionType);const a=await this.deps.auctions.bid(e,t),r=this.deps.getCurrentSequence(),u=r&&("enterable"===r.phase||"participating"===r.phase||"settling"===r.phase)&&"mechanism"in r&&"auction"===r.mechanism&&r.distribution.id===e;if("won"===a.status||"lost"===a.status)return void(u&&("won"===a.status&&a.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:a.admissionGrant}):"lost"===a.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):s(a)||this.deps.applyMonitorUpdate({type:"resync"})));if(!u)return;const d=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(a.status);void 0!==d&&this.deps.commit(c({distribution:i.distribution,consumer:{..."participating"===i.phase?i.consumer:{},mechanism:"auction",status:d,id:e,distributionId:e,...n?{selection:n}:{},currentBid:a.amount,highestBid:a.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw i.validationError("No auction is available to bid on");return t}}function l(t,e){if("dutch"!==e){if(void 0===t.amount)throw i.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw i.validationError("A Dutch auction clinches at the current price; omit the bid amount")}function p(t){return{status:"not_bid",distributionId:t.id}}function m(t,i,e){return{phase:"ended",mechanism:"auction",distribution:t,consumer:i,outcome:{...e,distributionType:e.distributionType??t.type,distributionId:e.distributionId??t.id,at:e.at??/* @__PURE__ */(new Date).toISOString()}}}export{l as assertBidInputMatchesMechanism,r as createAuctionDriver,a as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionTerminalConsumer};
1
+ import{AuctionDistributionResults as t}from"@fanfare-io/fanfare-sdk-contracts";import{createError as e}from"../core/errors.js";import{readEntrySelectionRequirement as i}from"../experiences/selection-requirement.js";import{buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{isGrantPendingWin as s}from"./auction-status.js";import{isUnresolvedAuctionConsumer as o}from"./auction.sequence.js";function r(t){return!t||("lost"===t.type||"closed"===t.type)&&!t.reason}function a(t){return new d(t)}function c(i){const{distribution:n,consumer:s,grant:a,settlement:c,selection:u,outcome:d}=i;if(!n)return{phase:"unavailable"};const l=function(t){if("auction"!==t.type)throw e.validationError("Auction driver received a non-auction distribution");return t}(n),h=s&&"auction"===s.mechanism?function(t){const{mechanism:e,...i}=t;return i}(s):p(n);if(a)return"completed"===d?.type?m(l,h,d):a.expiresAt&&Date.now()>new Date(a.expiresAt).getTime()?"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:p(l)}:m(l,h,{type:"expired"}):c&&u?{phase:"granted",mechanism:"auction",distribution:l,consumer:h,grant:a,settlement:c,selection:u}:{phase:"unavailable"};if("closed"===l.lifecycle){if("not_bid"===h.status&&l.result===t.FLOOR_UNSOLD&&r(d))return m(l,h,{type:"lost",reason:t.FLOOR_UNSOLD});if("auction"===s?.mechanism&&!d)return m(l,h,{type:"lost"})}const b=d??function(t){return"lost"===t.status?{type:"lost"}:void 0}(h);return b?m(l,h,b):"settling"===l.lifecycle?{phase:"settling",mechanism:"auction",distribution:l,consumer:h}:o(h)?{phase:"participating",mechanism:"auction",distribution:l,consumer:h}:"scheduled"===l.lifecycle?{phase:"scheduled",mechanism:"auction",distribution:l}:"open"===l.lifecycle?{phase:"enterable",mechanism:"auction",distribution:l,consumer:h}:m(l,h,{type:"closed"})}function u(t,e,i){return t&&"auction"===t.mechanism&&e?"won"===e.type?{...t,status:"won"}:!i?.finalize&&"not_bid"===t.status&&r(e)?t:{...t,status:"lost"}:t}class d{constructor(t){this.deps=t,this.mechanism="auction"}project(t){return c(t)}buildView(t,s){if("unavailable"===t.phase)return{phase:"unavailable",reason:t.reason};const o=function(t){if(!("mechanism"in t)||"auction"!==t.mechanism)throw e.validationError("Auction driver received a non-auction sequence");return t}(t);switch(o.phase){case"scheduled":return{phase:"scheduled",mechanism:"auction",distribution:o.distribution,startsAt:o.distribution.startsAt??o.distribution.opensAt};case"enterable":{const t={phase:"enterable",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,display$:s.displayAtom};return i(o.distribution.details)?{...t,selection:{required:!0},loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)}:{...t,selection:{required:!1},bid:t=>this.bid(t)}}case"participating":return{phase:"participating",mechanism:"auction",consumer:o.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,bid:t=>this.bid(t)};case"settling":return{phase:"settling",mechanism:"auction",distribution:o.distribution,consumer:o.consumer};case"granted":{const t={phase:"granted",mechanism:"auction",distribution:o.distribution,consumer:o.consumer,grant:o.grant},{settlement:e}=o,i=o.selection;if("awaiting_assignment"===i.status)return{...t,settlement:e,selection:i};if("required"===i.status)return{...t,settlement:e,selection:i,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===e.processor&&"at_end"===e.mode){const r=n(e,o.pendingAction,s);return r?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:r}:{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return"external"===e.processor?{...t,settlement:e,selection:i,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{phase:"unavailable",reason:"checkout_misconfigured"}}case"ended":return{phase:"ended",mechanism:"auction",consumer:o.consumer,outcome:o.outcome}}}startMonitoring(t){this.activeMonitorId=t.participation.id,this.deps.auctions.startMonitoring(t.participation.id,{displayAtom:t.displayAtom},t.onUpdate,t.onDegradedChange)}stopMonitoring(){this.activeMonitorId&&(this.deps.auctions.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async bid(t){await this.deps.runSerializedOperation(async()=>{const n=this.currentAuctionSequenceForBid(),o=n.consumer.distributionId??n.consumer.id??n.distribution.id,r="auction"===n.distribution.details?.type?n.distribution.details:void 0,a=n.consumer.selection,u=i(n.distribution.details),d="enterable"===n.phase;if(d&&u&&!t.selection)throw e.validationError("A product selection is required to enter");const p=d?u?t.selection:void 0:a,{selection:m,...h}=t,b=p?{...h,selection:p}:h;l(b,r?.auctionType);const f=await this.deps.auctions.bid(o,b),g=this.deps.getCurrentSequence(),y=g&&("enterable"===g.phase||"participating"===g.phase||"settling"===g.phase)&&"mechanism"in g&&"auction"===g.mechanism&&g.distribution.id===o;if("won"===f.status||"lost"===f.status)return void(y&&("won"===f.status&&f.admissionGrant?this.deps.applyMonitorUpdate({type:"granted",token:f.admissionGrant}):"lost"===f.status?this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"lost"}}):s(f)||this.deps.applyMonitorUpdate({type:"resync"})));if(!y)return;const v=function(t){switch(t){case"not_bid":case"winning":case"outbid":return t;case"won":case"lost":return}}(f.status);if(void 0===v)return;const w=void 0!==f.selection?.variantId?{productId:f.selection.productId,variantId:f.selection.variantId}:p,S=a??w;this.deps.commit(c({distribution:n.distribution,consumer:{..."participating"===n.phase?n.consumer:{},mechanism:"auction",status:v,id:o,distributionId:o,...S?{selection:S}:{},currentBid:f.amount,highestBid:f.highestBid}}))})}currentAuctionSequenceForBid(){const t=this.deps.getCurrentSequence();if(!t||"enterable"!==t.phase&&"participating"!==t.phase||!("mechanism"in t)||"auction"!==t.mechanism)throw e.validationError("No auction is available to bid on");return t}}function l(t,i){if("dutch"!==i){if(void 0===t.amount)throw e.validationError("A bid amount is required for an English auction")}else if(void 0!==t.amount)throw e.validationError("A Dutch auction clinches at the current price; omit the bid amount")}function p(t){return{status:"not_bid",distributionId:t.id}}function m(t,e,i){return{phase:"ended",mechanism:"auction",distribution:t,consumer:e,outcome:{...i,distributionType:i.distributionType??t.type,distributionId:i.distributionId??t.id,at:i.at??/* @__PURE__ */(new Date).toISOString()}}}export{l as assertBidInputMatchesMechanism,a as createAuctionDriver,r as isUpgradeableGenericLoss,c as projectAuctionSequence,u as withAuctionTerminalConsumer};
@@ -1,5 +1,5 @@
1
1
  import { AdmissionGrant, AuctionConsumerStatus, GrantedSettlement, SequenceOutcome } from '@fanfare-io/fanfare-sdk-contracts/consumer-me';
2
- import { GrantedSelection, SelectionMode } from '@fanfare-io/fanfare-sdk-contracts/selection';
2
+ import { GrantedSelection } from '@fanfare-io/fanfare-sdk-contracts/selection';
3
3
  import { ReadableAtom } from 'nanostores';
4
4
  import { AuctionDisplayState } from '../experiences/distribution-monitor.types';
5
5
  import { DistributionSummary } from '../experiences/journey.types';
@@ -52,7 +52,6 @@ export type AuctionSequence = AuctionScheduled | AuctionEnterable | AuctionParti
52
52
  export interface AuctionScheduled {
53
53
  /** Mechanism discriminator for auction narrowing. */
54
54
  mechanism: "auction";
55
- selectionMode?: SelectionMode;
56
55
  /** Phase discriminator; scheduled auctions cannot be bid on yet. */
57
56
  phase: "scheduled";
58
57
  /** Auction distribution facts from the journey projector. */
@@ -66,7 +65,6 @@ export interface AuctionScheduled {
66
65
  export interface AuctionEnterable {
67
66
  /** Mechanism discriminator for auction narrowing. */
68
67
  mechanism: "auction";
69
- selectionMode?: SelectionMode;
70
68
  /** Phase discriminator; `bid()` is legal on the matching view. */
71
69
  phase: "enterable";
72
70
  /** Open auction distribution facts from the journey projector. */
@@ -82,7 +80,6 @@ export interface AuctionEnterable {
82
80
  export interface AuctionParticipating {
83
81
  /** Mechanism discriminator for auction narrowing. */
84
82
  mechanism: "auction";
85
- selectionMode?: SelectionMode;
86
83
  /** Phase discriminator; auction display and bidding are live. */
87
84
  phase: "participating";
88
85
  /** Auction distribution facts from the journey projector. */
@@ -98,7 +95,6 @@ export interface AuctionParticipating {
98
95
  export interface AuctionSettling {
99
96
  /** Mechanism discriminator for auction narrowing. */
100
97
  mechanism: "auction";
101
- selectionMode?: SelectionMode;
102
98
  /** Phase discriminator; no consumer action is legal while settling. */
103
99
  phase: "settling";
104
100
  /** Settling auction distribution facts from the journey projector. */
@@ -114,7 +110,6 @@ export interface AuctionSettling {
114
110
  export interface AuctionGranted {
115
111
  /** Mechanism discriminator for auction narrowing. */
116
112
  mechanism: "auction";
117
- selectionMode?: SelectionMode;
118
113
  /** Phase discriminator; `claim()` is legal on the matching view. */
119
114
  phase: "granted";
120
115
  /** Auction distribution facts from the journey projector. */
@@ -140,7 +135,6 @@ export interface AuctionGranted {
140
135
  export interface AuctionEnded {
141
136
  /** Mechanism discriminator for auction narrowing. */
142
137
  mechanism: "auction";
143
- selectionMode?: SelectionMode;
144
138
  /** Phase discriminator; no auction actions are legal after this phase. */
145
139
  phase: "ended";
146
140
  /** Auction distribution facts from the journey projector. */
@@ -168,7 +162,6 @@ export interface AuctionScheduledView {
168
162
  phase: "scheduled";
169
163
  /** Mechanism discriminator for auction rendering. */
170
164
  mechanism: "auction";
171
- selectionMode?: SelectionMode;
172
165
  /** Auction distribution facts from the journey projector. */
173
166
  distribution: DistributionSummary & {
174
167
  type: "auction";
@@ -176,15 +169,12 @@ export interface AuctionScheduledView {
176
169
  /** ISO 8601 opening timestamp chosen from the distribution start/open time. */
177
170
  startsAt?: string;
178
171
  }
179
- /**
180
- * Enterable auction view rendered when the first bid can be placed.
181
- */
182
- export interface AuctionEnterableView {
172
+ /** Facts every enterable auction view carries, whatever the first bid must name. */
173
+ interface AuctionEnterableViewBase {
183
174
  /** Phase discriminator; `bid()` is legal on this view. */
184
175
  phase: "enterable";
185
176
  /** Mechanism discriminator for auction rendering. */
186
177
  mechanism: "auction";
187
- selectionMode?: SelectionMode;
188
178
  /** Open auction distribution facts from the journey projector. */
189
179
  distribution: DistributionSummary & {
190
180
  type: "auction";
@@ -193,20 +183,50 @@ export interface AuctionEnterableView {
193
183
  consumer: AuctionSequenceConsumerState;
194
184
  /** Live auction display facts: the price model, currency, and close time. */
195
185
  display$: ReadableAtom<AuctionDisplayState>;
186
+ }
187
+ /**
188
+ * Enterable auction view rendered when the first bid can be placed, discriminated on whether the
189
+ * server refuses that bid without a product choice.
190
+ *
191
+ * A required arm carries `loadSelectionOptions()` and will not compile without a pair; a
192
+ * not-required arm carries neither and sends none. The pair a first bid records is write-once, so
193
+ * every later raise carries it back rather than asking for it again.
194
+ */
195
+ export type AuctionEnterableView = (AuctionEnterableViewBase & {
196
+ /** The first bid is accepted without a product choice. */
197
+ selection: {
198
+ required: false;
199
+ };
200
+ /**
201
+ * Place the first auction bid.
202
+ *
203
+ * Legal only while this view is current. An English auction requires `input.amount`, a
204
+ * decimal money string; a Dutch auction clinches at the price the server is showing and
205
+ * refuses an amount. The promise rejects if the input does not match the mechanism, if
206
+ * bidding is closed, or if the server rejects the bid.
207
+ */
208
+ bid(input: Omit<AuctionBidInput, "selection">): Promise<void>;
209
+ }) | (AuctionEnterableViewBase & {
210
+ /** The first bid is refused without a product choice. */
211
+ selection: {
212
+ required: true;
213
+ };
196
214
  /** Load the current selection options. */
197
215
  loadSelectionOptions(): Promise<SelectionOptions>;
198
216
  /**
199
- * Place the first auction bid.
217
+ * Place the first auction bid for a chosen product.
200
218
  *
201
- * Legal only while this view is current. An English auction requires `input.amount`, a decimal
202
- * money string; a Dutch auction clinches at the price the server is showing and refuses an
203
- * amount. The promise rejects if the input does not match the mechanism, if bidding is closed,
204
- * or if the server rejects the bid.
205
- * `input.selection` names the product this bid is for on a selection-enabled auction; the server
206
- * rejects a missing required choice with SELECTION_REQUIRED.
219
+ * Legal only while this view is current. An English auction requires `input.amount`, a
220
+ * decimal money string; a Dutch auction clinches at the price the server is showing and
221
+ * refuses an amount. The promise rejects if the input does not match the mechanism, if
222
+ * bidding is closed, or if the server rejects the bid.
223
+ * `input.selection` names the product this bid is for; this auction refuses a bid without one.
207
224
  */
208
- bid(input: AuctionBidInput): Promise<void>;
209
- }
225
+ bid(input: AuctionBidInput & {
226
+ /** The product and variant this bid is for; the bidder's choice is recorded write-once. */
227
+ selection: SelectionChoice;
228
+ }): Promise<void>;
229
+ });
210
230
  /**
211
231
  * Participating auction view rendered while the consumer is bidding.
212
232
  */
@@ -216,7 +236,6 @@ export interface AuctionParticipatingView {
216
236
  phase: "participating";
217
237
  /** Mechanism discriminator for auction rendering. */
218
238
  mechanism: "auction";
219
- selectionMode?: SelectionMode;
220
239
  /** Consumer auction participation facts. */
221
240
  consumer: AuctionSequenceConsumerState;
222
241
  /** Live auction display facts: the price model, currency, and close time. */
@@ -230,10 +249,10 @@ export interface AuctionParticipatingView {
230
249
  * money string at or above the price model's `minNextBid`; a Dutch auction clinches at the price
231
250
  * the server is showing and refuses an amount. The promise rejects if the input does not match
232
251
  * the mechanism, if bidding is closed, or if the server rejects the bid.
233
- * `input.selection` names the product this bid is for on a selection-enabled auction; the server
234
- * rejects a missing required choice with SELECTION_REQUIRED.
252
+ * A raise takes no product choice: the bidder's recorded pair is write-once, and the driver
253
+ * carries it back on every raise.
235
254
  */
236
- bid(input: AuctionBidInput): Promise<void>;
255
+ bid(input: Omit<AuctionBidInput, "selection">): Promise<void>;
237
256
  }
238
257
  /**
239
258
  * Settling auction view rendered while the server computes the auction result.
@@ -243,7 +262,6 @@ export interface AuctionSettlingView {
243
262
  phase: "settling";
244
263
  /** Mechanism discriminator for auction rendering. */
245
264
  mechanism: "auction";
246
- selectionMode?: SelectionMode;
247
265
  /** Settling auction distribution facts from the journey projector. */
248
266
  distribution: DistributionSummary & {
249
267
  type: "auction";
@@ -259,7 +277,6 @@ interface AuctionGrantedViewBase {
259
277
  phase: "granted";
260
278
  /** Mechanism discriminator for auction rendering. */
261
279
  mechanism: "auction";
262
- selectionMode?: SelectionMode;
263
280
  /** Auction distribution facts from the journey projector. */
264
281
  distribution: DistributionSummary & {
265
282
  type: "auction";
@@ -328,7 +345,6 @@ export interface AuctionEndedView {
328
345
  phase: "ended";
329
346
  /** Mechanism discriminator for auction rendering. */
330
347
  mechanism: "auction";
331
- selectionMode?: SelectionMode;
332
348
  /** Consumer auction facts at the terminal outcome. */
333
349
  consumer: AuctionSequenceConsumerState;
334
350
  /** Server-derived terminal outcome for the auction participation. */
@@ -340,7 +356,6 @@ export interface AuctionGrantedAwaitingAssignmentView {
340
356
  phase: "granted";
341
357
  /** Mechanism discriminator. */
342
358
  mechanism: "auction";
343
- selectionMode?: SelectionMode;
344
359
  /** Distribution associated with this grant. */
345
360
  distribution: DistributionSummary & {
346
361
  type: "auction";
@@ -362,7 +377,6 @@ export interface AuctionGrantedSelectionRequiredView {
362
377
  phase: "granted";
363
378
  /** Mechanism discriminator. */
364
379
  mechanism: "auction";
365
- selectionMode?: SelectionMode;
366
380
  /** Distribution associated with this grant. */
367
381
  distribution: DistributionSummary & {
368
382
  type: "auction";
@@ -1 +1 @@
1
- import{DrawConsumerStatuses as e}from"@fanfare-io/fanfare-sdk-contracts/consumer-me";import{createError as t}from"../core/errors.js";import{selectionModeFields as i,buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as s,checkoutViewFields as r,isEntryActionRequired as o,canReenter as a,isPreAuthMisconfigured as d}from"../payment/checkout-contract.js";import{isClaimableSettlement as c}from"../payment/settlement.js";import{isUnresolvedDrawConsumer as u}from"./draw.sequence.js";import{drawSelectionFromResponse as p}from"./types.js";function l(e){return d(s(e.details))}function m(e){return a(e.distribution.lifecycle,s(e.distribution.details))}function h(e){return new y(e)}const w=new Set(e);function f(e){const n=function(e){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:a,outcome:d}=e;if(!i)return{phase:"unavailable"};const c=function(e){if("draw"!==e.type)throw t.validationError("Draw driver received a non-draw distribution");return e}(i),p=n&&"draw"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):v(i);if(s)return"completed"===d?.type?g(c,p,d,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===c.lifecycle?l(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:v(c)}:g(c,p,{type:"expired"}):o&&a?{phase:"granted",mechanism:"draw",distribution:c,consumer:p,grant:s,settlement:o,selection:a}:{phase:"unavailable"};if(!function(e){return w.has(e.status)}(p))return{phase:"unavailable",reason:"unrecognized_standing"};if(!d&&"draw"===n?.mechanism&&"closed"===c.lifecycle)return g(c,p,{type:"lost"});const m=d??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:void 0}(p);if(m)return g(c,p,m,r);if("settling"===c.lifecycle)return{phase:"settling",mechanism:"draw",distribution:c,consumer:p};if(u(p))return{phase:"participating",mechanism:"draw",distribution:c,consumer:p};if("scheduled"===c.lifecycle)return{phase:"scheduled",mechanism:"draw",distribution:c};if("open"===c.lifecycle)return l(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:p};return g(c,p,{type:"closed"})}(e);return"unavailable"===n.phase?n:{...n,...i(e)}}function b(e,t){return e&&"draw"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:"won"===t.type?{...e,status:"won"}:{...e,status:"not_entered"}:e}class y{constructor(e){this.deps=e,this.mechanism="draw",this.settlementCanStartWhileActive=!0}project(e){return f(e)}buildView(e,s){if("unavailable"===e.phase)return{phase:"unavailable",reason:e.reason};const r=function(e){if(!("mechanism"in e)||"draw"!==e.mechanism)throw t.validationError("Draw driver received a non-draw sequence");return e}(e);switch(r.phase){case"scheduled":return{phase:"scheduled",mechanism:"draw",...i(r),distribution:r.distribution,startsAt:r.distribution.startsAt??r.distribution.opensAt};case"enterable":return this.buildEnterableView(r,s);case"participating":return{phase:"participating",mechanism:"draw",...i(r),consumer:r.consumer,display$:s.displayAtom,loadSelectionOptions:s.loadSelectionOptions,select:s.select,leave:()=>this.leave()};case"settling":return{phase:"settling",mechanism:"draw",...i(r),distribution:r.distribution,consumer:r.consumer};case"granted":{const e={phase:"granted",mechanism:"draw",...i(r),distribution:r.distribution,consumer:r.consumer,grant:r.grant},{settlement:t}=r,o=r.selection;if("awaiting_assignment"===o.status)return{...e,settlement:t,selection:o};if("required"===o.status)return{...e,settlement:t,selection:o,select:s.select,loadSelectionOptions:s.loadSelectionOptions};if("internal"===t.processor&&"at_end"===t.mode){const i=n(t,r.pendingAction,s);return i?{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim(),payment:i}:{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}}return c(t)?{...e,settlement:t,selection:o,loadSelectionOptions:s.loadSelectionOptions,select:s.select,claim:()=>s.claim()}:{...e,settlement:t,selection:o}}case"ended":return this.buildEndedView(r)}}buildEnterableView(e,t){const n=s(e.distribution.details),o=r(n);return"pre_auth"===o.checkoutMode?{phase:"enterable",mechanism:"draw",...i(e),...o,distribution:e.distribution,consumer:e.consumer,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{},loadSelectionOptions:t.loadSelectionOptions,enter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{phase:"enterable",mechanism:"draw",...i(e),...o,distribution:e.distribution,consumer:e.consumer,loadSelectionOptions:t.loadSelectionOptions,enter:e=>this.enter({selection:e})}}buildEndedView(e){const t={phase:"ended",mechanism:"draw",...i(e),consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!m(e))return t;const n=s(e.distribution.details),o=r(n);return"pre_auth"===o.checkoutMode?{...t,...o,reenter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{...t,...o,reenter:e=>this.enter({selection:e})}}startMonitoring(e){this.activeMonitorId=e.participation.id;const t=this.deps.getCurrentSequence(),i=t&&("participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"draw"===t.mechanism&&"draw"===t.distribution.details?.type?t.distribution.details.drawTime:void 0;this.deps.draws.startMonitoring(e.participation.id,{displayAtom:e.displayAtom,drawTime:i,phase:"settling"===t?.phase?"settling":"participating"},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.draws.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const i=this.currentDrawSequence("enterable","No open draw to enter"),n=i.distribution,r=s(n.details),a=e?.paymentInput;if("pre_auth"===r.mode&&!a)throw t.validationError("Payment input is required for pre-auth distributions");const d=e?.selection?await this.deps.draws.enter(n.id,void 0,void 0,a,e.selection):a?await this.deps.draws.enter(n.id,void 0,void 0,a):await this.deps.draws.enter(n.id,void 0);if(o(d))return this.deps.commit({...i,pendingAction:d.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:n.id,processor:d.nextAction.processor});const c=function(e){if("ENTERED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("WON"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("LEFT"===e.status)return{type:"ended",outcome:{type:"left"}};return{type:"ended",outcome:{type:"DENIED"===e.status?"denied":"lost",reason:"reason"in e?e.reason:void 0}}}(d);if(c)return void this.deps.applyMonitorUpdate(c);const u=p(d),l={...(m=n.id,{mechanism:"draw",status:"entered",id:m,distributionId:m}),...u?{selection:u}:{}};var m;this.deps.ensureDisplayAtom({id:n.id,type:"draw"}),this.deps.commit(f({distribution:n,consumer:l})),this.deps.emitEvent("sequence_change","success","user","Entered draw",{distributionId:n.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentDrawSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;await this.deps.draws.leave(t),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"draw"})}currentDrawSequence(e,i="Not participating in a draw"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"draw"!==n.mechanism)throw t.validationError(i);if("enterable"===e&&"ended"===n.phase&&m(n))return{phase:"enterable",mechanism:"draw",distribution:n.distribution,consumer:v(n.distribution)};if(n.phase!==e)throw t.validationError(i);return n}}function v(e){return{status:"not_entered",distributionId:e.id}}function g(e,t,i,n){return{phase:"ended",mechanism:"draw",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}export{h as createDrawDriver,f as projectDrawSequence,b as withDrawTerminalConsumer};
1
+ import{DrawConsumerStatuses as e}from"@fanfare-io/fanfare-sdk-contracts/consumer-me";import{createError as t}from"../core/errors.js";import{readEntrySelectionRequirement as i}from"../experiences/selection-requirement.js";import{buildGrantPaymentAffordance as n}from"../experiences/sequence-driver.js";import{resolveCheckoutContract as s,checkoutViewFields as r,isEntryActionRequired as o,canReenter as a,isPreAuthMisconfigured as d}from"../payment/checkout-contract.js";import{isClaimableSettlement as c}from"../payment/settlement.js";import{isUnresolvedDrawConsumer as u}from"./draw.sequence.js";import{drawSelectionFromResponse as l}from"./types.js";function p(e){return d(s(e.details))}function m(e){return a(e.distribution.lifecycle,s(e.distribution.details))}function h(e){return new y(e)}const w=new Set(e);function f(e){const{distribution:i,consumer:n,grant:s,checkout:r,settlement:o,selection:a,outcome:d}=e;if(!i)return{phase:"unavailable"};const c=function(e){if("draw"!==e.type)throw t.validationError("Draw driver received a non-draw distribution");return e}(i),l=n&&"draw"===n.mechanism?function(e){const{mechanism:t,...i}=e;return i}(n):v(i);if(s)return"completed"===d?.type?g(c,l,d,r):s.expiresAt&&Date.now()>new Date(s.expiresAt).getTime()?"open"===c.lifecycle?p(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:v(c)}:g(c,l,{type:"expired"}):o&&a?{phase:"granted",mechanism:"draw",distribution:c,consumer:l,grant:s,settlement:o,selection:a}:{phase:"unavailable"};if(!function(e){return w.has(e.status)}(l))return{phase:"unavailable",reason:"unrecognized_standing"};if(!d&&"draw"===n?.mechanism&&"closed"===c.lifecycle)return g(c,l,{type:"lost"});const m=d??function(e){return"completed"===e.status?{type:"completed"}:"denied"===e.status?{type:"denied",reason:e.deniedReason}:void 0}(l);return m?g(c,l,m,r):"settling"===c.lifecycle?{phase:"settling",mechanism:"draw",distribution:c,consumer:l}:u(l)?{phase:"participating",mechanism:"draw",distribution:c,consumer:l}:"scheduled"===c.lifecycle?{phase:"scheduled",mechanism:"draw",distribution:c}:"open"===c.lifecycle?p(c)?{phase:"unavailable",reason:"checkout_misconfigured"}:{phase:"enterable",mechanism:"draw",distribution:c,consumer:l}:g(c,l,{type:"closed"})}function b(e,t){return e&&"draw"===e.mechanism&&t?"left"===t.type?{...e,status:"left"}:"denied"===t.type?{...e,status:"denied",deniedReason:t.reason}:"completed"===t.type?{...e,status:"completed"}:"won"===t.type?{...e,status:"won"}:{...e,status:"not_entered"}:e}class y{constructor(e){this.deps=e,this.mechanism="draw",this.settlementCanStartWhileActive=!0}project(e){return f(e)}buildView(e,i){if("unavailable"===e.phase)return{phase:"unavailable",reason:e.reason};const s=function(e){if(!("mechanism"in e)||"draw"!==e.mechanism)throw t.validationError("Draw driver received a non-draw sequence");return e}(e);switch(s.phase){case"scheduled":return{phase:"scheduled",mechanism:"draw",distribution:s.distribution,startsAt:s.distribution.startsAt??s.distribution.opensAt};case"enterable":return this.buildEnterableView(s,i);case"participating":return{phase:"participating",mechanism:"draw",consumer:s.consumer,display$:i.displayAtom,loadSelectionOptions:i.loadSelectionOptions,select:i.select,leave:()=>this.leave()};case"settling":return{phase:"settling",mechanism:"draw",distribution:s.distribution,consumer:s.consumer};case"granted":{const e={phase:"granted",mechanism:"draw",distribution:s.distribution,consumer:s.consumer,grant:s.grant},{settlement:t}=s,r=s.selection;if("awaiting_assignment"===r.status)return{...e,settlement:t,selection:r};if("required"===r.status)return{...e,settlement:t,selection:r,select:i.select,loadSelectionOptions:i.loadSelectionOptions};if("internal"===t.processor&&"at_end"===t.mode){const o=n(t,s.pendingAction,i);return o?{...e,settlement:t,selection:r,loadSelectionOptions:i.loadSelectionOptions,select:i.select,claim:()=>i.claim(),payment:o}:{...e,settlement:t,selection:r,loadSelectionOptions:i.loadSelectionOptions,select:i.select,claim:()=>i.claim()}}return c(t)?{...e,settlement:t,selection:r,loadSelectionOptions:i.loadSelectionOptions,select:i.select,claim:()=>i.claim()}:{...e,settlement:t,selection:r}}case"ended":return this.buildEndedView(s,i)}}buildEnterableView(e,t){const n=s(e.distribution.details),o=r(n),a={phase:"enterable",mechanism:"draw",distribution:e.distribution,consumer:e.consumer},d=i(e.distribution.details);if("pre_auth"===o.checkoutMode){const i={...a,...o,...e.pendingAction?{pendingAction:e.pendingAction}:{},...e.paymentProvider?{paymentProvider:e.paymentProvider}:{}};return d?{...i,selection:{required:!0},loadSelectionOptions:t.loadSelectionOptions,enter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{...i,selection:{required:!1},enter:e=>this.enter({paymentInput:e})}}return d?{...a,...o,selection:{required:!0},loadSelectionOptions:t.loadSelectionOptions,enter:e=>this.enter({selection:e})}:{...a,...o,selection:{required:!1},enter:()=>this.enter({})}}buildEndedView(e,t){const n={phase:"ended",mechanism:"draw",consumer:e.consumer,outcome:e.outcome,...e.checkout?{checkout:e.checkout}:{}};if(!m(e))return n;const o=s(e.distribution.details),a=r(o),d=i(e.distribution.details);return"pre_auth"===a.checkoutMode?d?{...n,...a,selection:{required:!0},loadSelectionOptions:t.loadSelectionOptions,reenter:(e,t)=>this.enter({paymentInput:e,selection:t})}:{...n,...a,selection:{required:!1},reenter:e=>this.enter({paymentInput:e})}:d?{...n,...a,selection:{required:!0},loadSelectionOptions:t.loadSelectionOptions,reenter:e=>this.enter({selection:e})}:{...n,...a,selection:{required:!1},reenter:()=>this.enter({})}}startMonitoring(e){this.activeMonitorId=e.participation.id;const t=this.deps.getCurrentSequence(),i=t&&("participating"===t.phase||"settling"===t.phase)&&"mechanism"in t&&"draw"===t.mechanism&&"draw"===t.distribution.details?.type?t.distribution.details.drawTime:void 0;this.deps.draws.startMonitoring(e.participation.id,{displayAtom:e.displayAtom,drawTime:i,phase:"settling"===t?.phase?"settling":"participating"},e.onUpdate)}stopMonitoring(){this.activeMonitorId&&(this.deps.draws.stopMonitoring(this.activeMonitorId),this.activeMonitorId=void 0)}async enter(e){await this.deps.runSerializedOperation(async()=>{await this.enterWithinOperation(e)})}async enterWithinOperation(e){const n=this.currentDrawSequence("enterable","No open draw to enter"),r=n.distribution,a=s(r.details),d=e?.paymentInput;if("pre_auth"===a.mode&&!d)throw t.validationError("Payment input is required for pre-auth distributions");const c=i(r.details);if(c&&!e?.selection)throw t.validationError("A product selection is required to enter");const u=c?e?.selection:void 0,p=u?await this.deps.draws.enter(r.id,void 0,void 0,d,u):d?await this.deps.draws.enter(r.id,void 0,void 0,d):await this.deps.draws.enter(r.id,void 0);if(o(p))return this.deps.commit({...n,pendingAction:p.nextAction}),void this.deps.emitEvent("sequence_change","info","user","Entry awaiting verification",{distributionId:r.id,processor:p.nextAction.processor});const m=function(e){if("ENTERED"===e.status)return null;if("COMPLETED"===e.status)return{type:"ended",outcome:{type:"completed"}};if("WON"===e.status)return"admissionGrant"in e?{type:"granted",token:e.admissionGrant,expiresAt:e.expiresAt?new Date(e.expiresAt).getTime():void 0}:null;if("LEFT"===e.status)return{type:"ended",outcome:{type:"left"}};return{type:"ended",outcome:{type:"DENIED"===e.status?"denied":"lost",reason:"reason"in e?e.reason:void 0}}}(p);if(m)return void this.deps.applyMonitorUpdate(m);const h=l(p),w={...(b=r.id,{mechanism:"draw",status:"entered",id:b,distributionId:b}),...h?{selection:h}:{}};var b;this.deps.ensureDisplayAtom({id:r.id,type:"draw"}),this.deps.commit(f({distribution:r,consumer:w})),this.deps.emitEvent("sequence_change","success","user","Entered draw",{distributionId:r.id})}async leave(){await this.deps.runSerializedOperation(async()=>{await this.leaveWithinOperation()})}async leaveWithinOperation(){const e=this.currentDrawSequence("participating"),t=e.consumer.distributionId??e.consumer.id??e.distribution.id;await this.deps.draws.leave(t),this.deps.stopRuntimeMonitoring(!0),this.deps.applyMonitorUpdate({type:"ended",outcome:{type:"left"}}),this.deps.emitEvent("sequence_change","info","user","Left participation",{type:"draw"})}currentDrawSequence(e,i="Not participating in a draw"){const n=this.deps.getCurrentSequence();if(!n||!("mechanism"in n)||"draw"!==n.mechanism)throw t.validationError(i);if("enterable"===e&&"ended"===n.phase&&m(n))return{phase:"enterable",mechanism:"draw",distribution:n.distribution,consumer:v(n.distribution)};if(n.phase!==e)throw t.validationError(i);return n}}function v(e){return{status:"not_entered",distributionId:e.id}}function g(e,t,i,n){return{phase:"ended",mechanism:"draw",distribution:e,consumer:t,outcome:{...i,distributionType:i.distributionType??e.type,distributionId:i.distributionId??e.id,at:i.at??/* @__PURE__ */(new Date).toISOString()},...n?{checkout:n}:{}}}export{h as createDrawDriver,f as projectDrawSequence,b as withDrawTerminalConsumer};