@fanfare-io/fanfare-sdk-solid 0.24.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -44,6 +44,27 @@ Solid applications can use `FanfareProvider`, `ExperienceWidget`, and `useExperi
44
44
 
45
45
  `slots` override targeted states while keeping the default widget flow. `children` receives `{ journey, view, snapshot, error, start, isStarting }` when you want to render the full state yourself. Solid `ExperienceWidget` accepts both `class` and `className`.
46
46
 
47
+ Marketing consent in `AuthForm` requires both `showMarketingSmsConsent` and a nonempty
48
+ `marketingSmsMerchantName`. The built-in widget reads the merchant name from the public experience
49
+ response, including before an authenticated experience session exists. Custom auth slots receive
50
+ `marketingSmsMerchantName`; pass it through to `AuthForm` or `JourneyGate` to offer consent for that
51
+ merchant. Sign-in remains available when the merchant name is unavailable.
52
+
53
+ `AuthForm` keeps marketing copy off the initial phone screen. Continue opens an optional panel
54
+ with the named merchant, Fanfare sender, phone number and full disclosure before any OTP request.
55
+ Only "Yes, text me" opts in. It captures the displayed merchant, phone, disclosure, legal text,
56
+ policy links and affirmative label in `marketingSmsConsentText`, then preserves that snapshot through
57
+ OTP verification and resend. "No thanks" continues without marketing consent. Change number,
58
+ returning from verification or changing the consent scope clears the choice and snapshot.
59
+ Implicit submission can open the panel but cannot choose consent. Custom auth handlers must
60
+ preserve the received choice and text through verification; a custom consent UI supplies its own
61
+ actual displayed agreement. The server requires a nonblank text snapshot of at most 4,096 characters
62
+ to record consent. Missing or invalid evidence leaves sign-in available without granting consent.
63
+ This is client-reported audit evidence, not proof of what pixels were displayed.
64
+ Release a matching core and adapter together: the built-in panel uses core's shared policy URLs
65
+ and consent-text formatter. Deploy the generated database migration and server support before
66
+ releasing SDK callers that supply the text.
67
+
47
68
  Mounted inside a shadow root, the widget's styleable elements export CSS parts named after their
48
69
  `data-slot`, so a page styles them with `::part()` — `fanfare-host::part(auction-cta)`. The
49
70
  attribution footer and every element that contains its "Powered by Fanfare" row are
@@ -4,6 +4,7 @@ import { AuthInputMode } from './auth-input';
4
4
  export interface AuthFormProps {
5
5
  onSubmit?: (credential: string, type: AuthInputMode, options?: {
6
6
  marketingSmsConsent: boolean;
7
+ marketingSmsConsentText?: string;
7
8
  }) => Promise<void>;
8
9
  onVerify?: (otp: string) => Promise<void>;
9
10
  onSkip?: () => void | Promise<void>;
@@ -16,17 +17,21 @@ export interface AuthFormProps {
16
17
  description?: string;
17
18
  /** When set, renders a countdown above the form. */
18
19
  countdownTo?: Date;
20
+ /** When set and `countdownTo` is not, renders the close time and a sign-in hint above the form. */
21
+ endedAt?: Date;
19
22
  submitLabel?: string;
20
23
  verifyLabel?: string;
21
24
  allowSkip?: boolean;
22
25
  skipLabel?: string;
23
26
  showBranding?: boolean;
24
27
  /**
25
- * Shows the marketing SMS consent checkbox, its disclosure and legal line on the credential step in
26
- * phone mode. Off by default: set it only when `onSubmit` reads its third argument, since a tick
27
- * the handler never reads is a consent silently dropped.
28
+ * Offers a separate optional marketing SMS panel after credential entry in
29
+ * phone mode. Off by default: set it only when `onSubmit` preserves its third argument through
30
+ * verification, so the explicit consent choice and displayed text are not silently dropped.
28
31
  */
29
32
  showMarketingSmsConsent?: boolean;
33
+ /** Merchant named in the consent disclosure. Consent is offered only when this is nonempty. */
34
+ marketingSmsMerchantName?: string;
30
35
  /** Initial step when mounting. Useful for SSR-resume or storybook lanes that need the verify step. */
31
36
  defaultStep?: "credential" | "verify";
32
37
  /** Initial credential (email or E.164 phone) — pairs with `defaultStep="verify"`. */
@@ -5,6 +5,7 @@ export interface JourneyGateProps {
5
5
  stage: JourneyGateStage;
6
6
  onAuthSubmit?: (credential: string, type: AuthInputMode, options?: {
7
7
  marketingSmsConsent: boolean;
8
+ marketingSmsConsentText?: string;
8
9
  }) => Promise<void>;
9
10
  onAuthVerify?: (otp: string) => Promise<void>;
10
11
  onAuthSkip?: () => void | Promise<void>;
@@ -14,12 +15,16 @@ export interface JourneyGateProps {
14
15
  allowAuthSkip?: boolean;
15
16
  authSkipLabel?: string;
16
17
  allowAccessCodeSkip?: boolean;
18
+ /** Merchant identity from the experience for marketing SMS consent. */
19
+ marketingSmsMerchantName?: string;
17
20
  authTitle?: string;
18
21
  authDescription?: string;
19
22
  accessCodeTitle?: string;
20
23
  accessCodeDescription?: string;
21
24
  /** When the upcoming sequence opens — drives the countdown above the form. */
22
25
  startsAt?: Date;
26
+ /** When the drop closed — drives the ended line on the auth stage. */
27
+ endedAt?: Date;
23
28
  class?: string;
24
29
  className?: string;
25
30
  children?: JSX.Element;
@@ -8,6 +8,7 @@ import { OutcomeReason } from '../module';
8
8
  export interface DrawModuleProps {
9
9
  display$?: ReadableAtom<DrawDisplayState>;
10
10
  sequencePhase: "enterable" | "participating" | "settling" | "granted" | "ended";
11
+ loyaltyBiasEnabled?: boolean;
11
12
  canEnter: boolean;
12
13
  canLeave: boolean;
13
14
  /** Enter action handler; carries the entry pick on a selection-bearing draw. */
@@ -10,6 +10,7 @@ export interface QueueModuleProps {
10
10
  sequencePhase: "enterable" | "participating" | "granted" | "ended";
11
11
  /** Hide live rank-derived queue metrics while the canonical queue is still pre-open. */
12
12
  hideQueueMetrics?: boolean;
13
+ loyaltyBiasEnabled?: boolean;
13
14
  canEnter: boolean;
14
15
  canLeave: boolean;
15
16
  onEnter: () => Promise<void>;
@@ -0,0 +1,3 @@
1
+ export declare function FanfairAttribution(props: {
2
+ enabled: boolean;
3
+ }): import("solid-js").JSX.Element;
@@ -33,14 +33,17 @@ export interface StartSlotProps extends SlotProps {
33
33
  export interface AuthSlotProps extends SlotProps {
34
34
  onSubmit: (credential: string, type: AuthInputMode, options?: {
35
35
  marketingSmsConsent: boolean;
36
+ marketingSmsConsentText?: string;
36
37
  }) => Promise<void>;
37
38
  onVerify: (otp: string) => Promise<void>;
38
39
  onSkip?: () => void;
39
40
  /**
40
- * Whether the sign-in should offer the marketing SMS consent checkbox. The widget sets it because its
41
+ * Whether the sign-in should offer the optional marketing SMS panel. The widget sets it because its
41
42
  * `onSubmit` reads the consent from its third argument; pass it to `AuthForm` with `onSubmit`.
42
43
  */
43
44
  showMarketingSmsConsent?: boolean;
45
+ /** Merchant identity to pass to AuthForm beside showMarketingSmsConsent. */
46
+ marketingSmsMerchantName?: string;
44
47
  }
45
48
  export interface AccessCodeSlotProps extends SlotProps {
46
49
  onSubmit: (code: string) => Promise<void>;
@@ -0,0 +1,10 @@
1
+ import { ExperienceTiming } from '@fanfare-io/fanfare-sdk-core/experiences';
2
+ import { Accessor } from 'solid-js';
3
+ /**
4
+ * Auth can gate routing before an experience session exists, so its merchant identity and timing
5
+ * come from the public read until the session's own details name the merchant.
6
+ */
7
+ export declare function useAuthGateExperienceDetails(experienceId: Accessor<string>, sessionName: Accessor<string | undefined>, sessionTiming: Accessor<ExperienceTiming | null | undefined>, enabled: Accessor<boolean>): {
8
+ merchantName: Accessor<string | undefined>;
9
+ timing: Accessor<ExperienceTiming | null | undefined>;
10
+ };