@fanfare-io/fanfare-sdk-core 0.1.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/LICENSE +202 -0
- package/README.md +44 -0
- package/dist/adapters/google-analytics.d.ts +12 -0
- package/dist/adapters/google-analytics.js +1 -0
- package/dist/adapters/index.d.ts +9 -0
- package/dist/adapters/index.js +1 -0
- package/dist/adapters/types.d.ts +9 -0
- package/dist/appointments/appointment.module.d.ts +32 -0
- package/dist/appointments/appointment.module.js +1 -0
- package/dist/appointments/index.d.ts +2 -0
- package/dist/appointments/public.d.ts +1 -0
- package/dist/appointments/public.js +1 -0
- package/dist/appointments/types.d.ts +47 -0
- package/dist/auctions/auction.module.d.ts +58 -0
- package/dist/auctions/auction.module.js +1 -0
- package/dist/auctions/index.d.ts +5 -0
- package/dist/auctions/public.d.ts +5 -0
- package/dist/auctions/public.js +1 -0
- package/dist/auctions/types.d.ts +97 -0
- package/dist/auth/auth.module.d.ts +71 -0
- package/dist/auth/auth.module.js +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/types.d.ts +112 -0
- package/dist/beacon/batching.d.ts +52 -0
- package/dist/beacon/batching.js +1 -0
- package/dist/beacon/beacon.module.d.ts +58 -0
- package/dist/beacon/beacon.module.js +1 -0
- package/dist/beacon/enrichment.d.ts +16 -0
- package/dist/beacon/enrichment.js +1 -0
- package/dist/beacon/index.d.ts +12 -0
- package/dist/beacon/public.d.ts +9 -0
- package/dist/beacon/public.js +1 -0
- package/dist/beacon/types.d.ts +103 -0
- package/dist/beacon/validation.d.ts +24 -0
- package/dist/beacon/validation.js +1 -0
- package/dist/challenges/challenge.module.d.ts +9 -0
- package/dist/challenges/challenge.module.js +1 -0
- package/dist/challenges/index.d.ts +3 -0
- package/dist/challenges/public.d.ts +9 -0
- package/dist/challenges/public.js +1 -0
- package/dist/challenges/types.d.ts +33 -0
- package/dist/config/index.d.ts +44 -0
- package/dist/config/index.js +1 -0
- package/dist/core/client.d.ts +15 -0
- package/dist/core/client.js +2 -0
- package/dist/core/errors.d.ts +175 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/http.d.ts +87 -0
- package/dist/core/http.js +1 -0
- package/dist/core/logger.d.ts +46 -0
- package/dist/core/logger.js +1 -0
- package/dist/core/money.d.ts +10 -0
- package/dist/core/money.js +1 -0
- package/dist/core/parse-response.d.ts +62 -0
- package/dist/core/parse-response.js +1 -0
- package/dist/core/utils.d.ts +67 -0
- package/dist/core/utils.js +1 -0
- package/dist/draws/draw.module.d.ts +40 -0
- package/dist/draws/draw.module.js +1 -0
- package/dist/draws/index.d.ts +5 -0
- package/dist/draws/public.d.ts +6 -0
- package/dist/draws/public.js +1 -0
- package/dist/draws/types.d.ts +90 -0
- package/dist/draws/types.js +1 -0
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +1 -0
- package/dist/events.d.ts +5 -0
- package/dist/events.js +1 -0
- package/dist/experiences/distribution-monitor.runtime.d.ts +12 -0
- package/dist/experiences/distribution-monitor.runtime.js +1 -0
- package/dist/experiences/distribution-monitor.types.d.ts +62 -0
- package/dist/experiences/experience.module.d.ts +88 -0
- package/dist/experiences/experience.module.js +1 -0
- package/dist/experiences/index.d.ts +3 -0
- package/dist/experiences/index.js +1 -0
- package/dist/experiences/journey-contract.fixtures.d.ts +9 -0
- package/dist/experiences/journey-view.d.ts +22 -0
- package/dist/experiences/journey-view.js +1 -0
- package/dist/experiences/journey.d.ts +89 -0
- package/dist/experiences/journey.js +1 -0
- package/dist/experiences/journey.machine.d.ts +79 -0
- package/dist/experiences/journey.machine.js +1 -0
- package/dist/experiences/journey.types.d.ts +395 -0
- package/dist/experiences/public.d.ts +13 -0
- package/dist/experiences/public.js +1 -0
- package/dist/experiences/types.d.ts +161 -0
- package/dist/handoff/handoff.module.d.ts +184 -0
- package/dist/handoff/handoff.module.js +1 -0
- package/dist/handoff/index.d.ts +5 -0
- package/dist/handoff/index.js +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -0
- package/dist/internals.d.ts +11 -0
- package/dist/internals.js +1 -0
- package/dist/queues/index.d.ts +5 -0
- package/dist/queues/index.js +1 -0
- package/dist/queues/qualitative-bucket.d.ts +12 -0
- package/dist/queues/qualitative-bucket.js +1 -0
- package/dist/queues/queue.module.d.ts +42 -0
- package/dist/queues/queue.module.js +1 -0
- package/dist/queues/types.d.ts +112 -0
- package/dist/queues/types.js +1 -0
- package/dist/security/admission-proof.d.ts +15 -0
- package/dist/security/admission-proof.js +1 -0
- package/dist/state/capability-token-registry.d.ts +44 -0
- package/dist/state/capability-token-registry.js +1 -0
- package/dist/state/events.d.ts +342 -0
- package/dist/state/events.js +1 -0
- package/dist/state/store.d.ts +48 -0
- package/dist/state/store.js +1 -0
- package/dist/sync/broadcast-transport.d.ts +19 -0
- package/dist/sync/broadcast-transport.js +1 -0
- package/dist/sync/cross-tab-coordinator.d.ts +44 -0
- package/dist/sync/cross-tab-coordinator.js +1 -0
- package/dist/sync/index.d.ts +8 -0
- package/dist/sync/localstorage-transport.d.ts +32 -0
- package/dist/sync/localstorage-transport.js +1 -0
- package/dist/sync/protocol-transport.d.ts +51 -0
- package/dist/sync/protocol-transport.js +1 -0
- package/dist/sync/protocol.d.ts +254 -0
- package/dist/sync/protocol.js +1 -0
- package/dist/sync/recovery.d.ts +68 -0
- package/dist/sync/transport-factory.d.ts +16 -0
- package/dist/sync/transport-factory.js +1 -0
- package/dist/sync/transport-interface.d.ts +33 -0
- package/dist/sync/transport.d.ts +49 -0
- package/dist/sync/transport.js +1 -0
- package/dist/test-utils/harness-scenarios.d.ts +71 -0
- package/dist/test-utils/harness-scenarios.js +1 -0
- package/dist/test-utils/index.d.ts +12 -0
- package/dist/test-utils/index.js +1 -0
- package/dist/test-utils/mock-journey.d.ts +63 -0
- package/dist/test-utils/mock-journey.js +1 -0
- package/dist/test-utils/mock-sdk-vitest.d.ts +80 -0
- package/dist/test-utils/mock-sdk-vitest.js +1 -0
- package/dist/test-utils/mock-sdk.d.ts +22 -0
- package/dist/test-utils/mock-sdk.js +1 -0
- package/dist/test-utils/mock-server.d.ts +105 -0
- package/dist/test-utils/mock-server.js +1 -0
- package/dist/test-utils/sdk-factory.d.ts +3 -0
- package/dist/test-utils/sdk-factory.js +1 -0
- package/dist/test-utils/verification-scenarios.d.ts +43 -0
- package/dist/test-utils/verification-scenarios.js +1 -0
- package/dist/test-utils/verification-state.d.ts +1 -0
- package/dist/test-utils/verification-state.js +1 -0
- package/dist/theme.d.ts +8 -0
- package/dist/theme.js +1 -0
- package/dist/timed-releases/index.d.ts +6 -0
- package/dist/timed-releases/public.d.ts +6 -0
- package/dist/timed-releases/public.js +1 -0
- package/dist/timed-releases/timed-release.module.d.ts +31 -0
- package/dist/timed-releases/timed-release.module.js +1 -0
- package/dist/timed-releases/types.d.ts +70 -0
- package/dist/timed-releases/types.js +1 -0
- package/dist/types/distribution-type.d.ts +45 -0
- package/dist/types/index.d.ts +178 -0
- package/dist/utils/fingerprint.module.d.ts +27 -0
- package/dist/utils/fingerprint.module.js +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/version.d.ts +5 -0
- package/dist/version.js +1 -0
- package/dist/waitlists/index.d.ts +2 -0
- package/dist/waitlists/public.d.ts +6 -0
- package/dist/waitlists/public.js +1 -0
- package/dist/waitlists/types.d.ts +50 -0
- package/dist/waitlists/types.js +1 -0
- package/dist/waitlists/waitlist.module.d.ts +17 -0
- package/dist/waitlists/waitlist.module.js +1 -0
- package/package.json +205 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { HttpClient } from '../core/http';
|
|
2
|
+
import { AuthenticatedSession, AuthModule, AuthStatus, ExternalExchange, GuestSession, LoginOptions, OtpRequest, OtpVerify, Session } from './types';
|
|
3
|
+
export declare class AuthenticationModule implements AuthModule {
|
|
4
|
+
private http;
|
|
5
|
+
private beaconHttp;
|
|
6
|
+
private logger;
|
|
7
|
+
private store;
|
|
8
|
+
private events;
|
|
9
|
+
private refreshTimer?;
|
|
10
|
+
private refreshPromise?;
|
|
11
|
+
constructor(http: HttpClient, beaconHttp: HttpClient);
|
|
12
|
+
/**
|
|
13
|
+
* Check current authentication status
|
|
14
|
+
*/
|
|
15
|
+
check(): AuthStatus;
|
|
16
|
+
/**
|
|
17
|
+
* Create a guest session
|
|
18
|
+
*/
|
|
19
|
+
guest(): Promise<GuestSession>;
|
|
20
|
+
/**
|
|
21
|
+
* Request OTP for email login
|
|
22
|
+
*/
|
|
23
|
+
requestOtp(options: OtpRequest | string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Verify OTP and login
|
|
26
|
+
*/
|
|
27
|
+
verifyOtp(options: OtpVerify | {
|
|
28
|
+
email: string;
|
|
29
|
+
code: string;
|
|
30
|
+
}): Promise<AuthenticatedSession>;
|
|
31
|
+
/**
|
|
32
|
+
* Exchange a one-time external auth code for an authenticated session
|
|
33
|
+
*/
|
|
34
|
+
exchangeExternal(options: ExternalExchange | string): Promise<AuthenticatedSession>;
|
|
35
|
+
/**
|
|
36
|
+
* Login with email (combined OTP flow)
|
|
37
|
+
*/
|
|
38
|
+
login(options: LoginOptions): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Logout current session
|
|
41
|
+
*/
|
|
42
|
+
logout(): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Get current session
|
|
45
|
+
*/
|
|
46
|
+
getSession(): Session | null;
|
|
47
|
+
/**
|
|
48
|
+
* Refresh the access token
|
|
49
|
+
*/
|
|
50
|
+
refresh(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Internal refresh implementation
|
|
53
|
+
*/
|
|
54
|
+
private _doRefresh;
|
|
55
|
+
/**
|
|
56
|
+
* Handle 401 responses
|
|
57
|
+
*/
|
|
58
|
+
private handleUnauthorized;
|
|
59
|
+
/**
|
|
60
|
+
* Schedule token refresh 5 minutes before expiry
|
|
61
|
+
*/
|
|
62
|
+
private scheduleTokenRefresh;
|
|
63
|
+
/**
|
|
64
|
+
* Cancel scheduled token refresh
|
|
65
|
+
*/
|
|
66
|
+
private cancelTokenRefresh;
|
|
67
|
+
/**
|
|
68
|
+
* Clean up resources
|
|
69
|
+
*/
|
|
70
|
+
destroy(): void;
|
|
71
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getLogger as e}from"../core/logger.js";import{getEventBus as t}from"../state/events.js";import{getSDKStore as s}from"../state/store.js";class r{constructor(r,o){this.logger=e(),this.store=s(),this.events=t(),this.http=r,this.beaconHttp=o,this.http.updateConfig({...this.http.getConfig(),onUnauthorized:async()=>{await this.handleUnauthorized()}});const i=this.store.beaconToken;i&&this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":i}})}check(){const e=this.store.session;return e?{isAuthenticated:!0,session:e,isGuest:"guest"===e.type}:{isAuthenticated:!1}}async guest(){try{this.logger.info("Creating guest session");const{session:e,accessToken:t,refreshToken:s,beaconToken:r}=await this.http.post("/auth/guest");return this.store.setSession(e),this.store.setRefreshToken(s??null),this.store.setBeaconToken(r),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${t}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":r}}),this.scheduleTokenRefresh(e.expiresAt),this.events.emit("auth:authenticated",{session:e,isNew:!0}),e}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Failed to create guest session",t),this.events.emit("auth:error",{error:t,context:"guest"}),t}}async requestOtp(e){try{this.logger.info("Requesting OTP");const t="string"==typeof e?{email:e}:e;await this.http.post("/auth/otp/request",t)}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to request OTP",e),this.events.emit("auth:error",{error:e,context:"requestOtp"}),e}}async verifyOtp(e){try{const t=e;this.logger.info("Verifying OTP",{email:t.email,phone:t.phone});const{session:s,accessToken:r,refreshToken:o,beaconToken:i}=await this.http.post("/auth/otp/verify",t);return this.store.setSession(s),this.store.setRefreshToken(o??null),this.store.setBeaconToken(i),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${r}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":i}}),this.scheduleTokenRefresh(s.expiresAt),this.events.emit("auth:authenticated",{session:s,isNew:!0}),s}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to verify OTP",e),this.events.emit("auth:error",{error:e,context:"verifyOtp"}),e}}async exchangeExternal(e){try{const t="string"==typeof e?{exchangeCode:e}:e;this.logger.info("Exchanging external auth code");const{session:s,accessToken:r,refreshToken:o,beaconToken:i}=await this.http.post("/auth/external/exchange",t);return this.store.setSession(s),this.store.setRefreshToken(o??null),this.store.setBeaconToken(i),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${r}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":i}}),this.scheduleTokenRefresh(s.expiresAt),this.events.emit("auth:authenticated",{session:s,isNew:!0}),s}catch(t){const e=t instanceof Error?t:new Error(String(t));throw this.logger.error("Failed to exchange external auth code",e),this.events.emit("auth:error",{error:e,context:"exchangeExternal"}),e}}async login(e){await this.requestOtp({email:e.email})}async logout(){try{if(!this.store.session)return;this.cancelTokenRefresh(),await this.http.post("/auth/logout",{},{skipUnauthorizedHandler:!0}).catch(()=>{}),this.store.clearAll();const e=this.http.getConfig(),{Authorization:t,...s}=e.headers||{};this.http.updateConfig({...e,headers:s});const r=this.beaconHttp.getConfig(),{"X-Beacon-Token":o,...i}=r.headers||{};this.beaconHttp.updateConfig({...r,headers:i}),this.events.emit("auth:logout",{reason:"user"})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Error during logout",t),this.store.clearAll(),t}}getSession(){return this.store.session}async refresh(){return this.refreshPromise?(this.logger.debug("Refresh already in progress, returning existing promise"),this.refreshPromise):(this.refreshPromise=this._doRefresh().finally(()=>{this.refreshPromise=void 0}),this.refreshPromise)}async _doRefresh(){try{this.logger.info("Refreshing access token");const{accessToken:e,refreshToken:t,beaconToken:s}=await this.http.post("/auth/refresh",{});this.store.setRefreshToken(t??null),this.store.setBeaconToken(s),this.http.updateConfig({...this.http.getConfig(),headers:{...this.http.getConfig().headers,Authorization:`Bearer ${e}`}}),this.beaconHttp.updateConfig({...this.beaconHttp.getConfig(),headers:{...this.beaconHttp.getConfig().headers,"X-Beacon-Token":s}});const r=this.store.session;r&&r.expiresAt&&this.scheduleTokenRefresh(r.expiresAt),this.store.session&&this.events.emit("auth:refreshed",{session:this.store.session})}catch(e){const t=e instanceof Error?e:new Error(String(e));throw this.logger.error("Failed to refresh token",t),await this.logout(),t}}async handleUnauthorized(){this.logger.warn("Received 401, attempting to refresh token");try{await this.refresh()}catch(e){const t=e instanceof Error?e:new Error(String(e));this.logger.error("Failed to handle 401",t),this.events.emit("auth:error",{error:new Error("Session expired"),context:"unauthorized"})}}scheduleTokenRefresh(e){this.cancelTokenRefresh();const t=Date.now(),s=new Date(e).getTime()-3e5,r=s-t;r<=0?this.refresh().catch(e=>{this.logger.error("Failed to refresh expired token",e)}):(this.logger.debug("Scheduling token refresh",{expiresAt:new Date(e).toISOString(),refreshAt:new Date(s).toISOString(),delayMs:r}),this.refreshTimer=setTimeout(()=>{this.refresh().catch(e=>{this.logger.error("Scheduled token refresh failed",e)})},r))}cancelTokenRefresh(){this.refreshTimer&&(clearTimeout(this.refreshTimer),this.refreshTimer=void 0,this.logger.debug("Cancelled token refresh timer"))}destroy(){this.cancelTokenRefresh(),this.refreshPromise=void 0}}export{r as AuthenticationModule};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { AuthModule, AuthStatus, AuthenticatedSession, Consumer, ExternalExchange, GuestSession, LoginOptions, OtpRequest, OtpVerify, Session, } from './types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication type definitions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Authentication module interface
|
|
6
|
+
*/
|
|
7
|
+
export interface AuthModule {
|
|
8
|
+
/**
|
|
9
|
+
* Check current authentication status
|
|
10
|
+
*/
|
|
11
|
+
check(): AuthStatus;
|
|
12
|
+
/**
|
|
13
|
+
* Create a guest session
|
|
14
|
+
*/
|
|
15
|
+
guest(): Promise<GuestSession>;
|
|
16
|
+
/**
|
|
17
|
+
* Request OTP for email authentication
|
|
18
|
+
*/
|
|
19
|
+
requestOtp(options: OtpRequest | string): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Verify OTP and authenticate
|
|
22
|
+
*/
|
|
23
|
+
verifyOtp(options: OtpVerify | {
|
|
24
|
+
email: string;
|
|
25
|
+
code: string;
|
|
26
|
+
}): Promise<AuthenticatedSession>;
|
|
27
|
+
/**
|
|
28
|
+
* Exchange a one-time external auth code for an authenticated session
|
|
29
|
+
*/
|
|
30
|
+
exchangeExternal(options: ExternalExchange | string): Promise<AuthenticatedSession>;
|
|
31
|
+
/**
|
|
32
|
+
* Login with email (combined OTP flow)
|
|
33
|
+
*/
|
|
34
|
+
login(options: LoginOptions): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Logout and clear session
|
|
37
|
+
*/
|
|
38
|
+
logout(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Get current session
|
|
41
|
+
*/
|
|
42
|
+
getSession(): Session | null;
|
|
43
|
+
/**
|
|
44
|
+
* Refresh the access token
|
|
45
|
+
*/
|
|
46
|
+
refresh(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Login options
|
|
50
|
+
*/
|
|
51
|
+
export interface LoginOptions {
|
|
52
|
+
email: string;
|
|
53
|
+
}
|
|
54
|
+
export interface OtpRequest {
|
|
55
|
+
email?: string;
|
|
56
|
+
phone?: string;
|
|
57
|
+
defaultCountry?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface OtpVerify {
|
|
61
|
+
email?: string;
|
|
62
|
+
phone?: string;
|
|
63
|
+
code: string;
|
|
64
|
+
defaultCountry?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ExternalExchange {
|
|
67
|
+
exchangeCode: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Current authentication status
|
|
71
|
+
*/
|
|
72
|
+
export interface AuthStatus {
|
|
73
|
+
isAuthenticated: boolean;
|
|
74
|
+
isGuest?: boolean;
|
|
75
|
+
session?: Session;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Base session interface
|
|
79
|
+
*/
|
|
80
|
+
export interface Session {
|
|
81
|
+
type: "guest" | "authenticated";
|
|
82
|
+
consumerId: string;
|
|
83
|
+
email?: string;
|
|
84
|
+
phone?: string;
|
|
85
|
+
expiresAt: string;
|
|
86
|
+
deviceFingerprint?: string;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Guest session
|
|
90
|
+
*/
|
|
91
|
+
export interface GuestSession extends Session {
|
|
92
|
+
type: "guest";
|
|
93
|
+
guestId: string;
|
|
94
|
+
email: undefined;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Authenticated session
|
|
98
|
+
*/
|
|
99
|
+
export interface AuthenticatedSession extends Session {
|
|
100
|
+
type: "authenticated";
|
|
101
|
+
email?: string;
|
|
102
|
+
phone?: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Consumer information
|
|
106
|
+
*/
|
|
107
|
+
export interface Consumer {
|
|
108
|
+
id: string;
|
|
109
|
+
email?: string;
|
|
110
|
+
createdAt: string;
|
|
111
|
+
metadata?: Record<string, unknown>;
|
|
112
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BeaconConfig, BeaconEventInput } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Smart event batcher with requestIdleCallback and visibility change support
|
|
4
|
+
*
|
|
5
|
+
* Features:
|
|
6
|
+
* - Batches events in memory
|
|
7
|
+
* - Auto-flushes when batch size threshold reached
|
|
8
|
+
* - Auto-flushes after time threshold
|
|
9
|
+
* - Uses requestIdleCallback for smart batching during idle time
|
|
10
|
+
* - Auto-flushes on visibility change (tab hidden)
|
|
11
|
+
* - Auto-flushes on page unload (beforeunload/pagehide)
|
|
12
|
+
*
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
export declare class EventBatcher {
|
|
16
|
+
private queue;
|
|
17
|
+
private flushTimer;
|
|
18
|
+
private config;
|
|
19
|
+
private flushCallback;
|
|
20
|
+
private visibilityHandler;
|
|
21
|
+
private beforeUnloadHandler;
|
|
22
|
+
private pageHideHandler;
|
|
23
|
+
constructor(config: BeaconConfig, flushCallback: (events: BeaconEventInput[]) => Promise<void>);
|
|
24
|
+
/**
|
|
25
|
+
* Add an event to the batch queue
|
|
26
|
+
*
|
|
27
|
+
* @param event - Event to queue
|
|
28
|
+
*/
|
|
29
|
+
add(event: BeaconEventInput): void;
|
|
30
|
+
/**
|
|
31
|
+
* Schedule a flush using requestIdleCallback for smart batching
|
|
32
|
+
*
|
|
33
|
+
* @private
|
|
34
|
+
*/
|
|
35
|
+
private scheduleFlush;
|
|
36
|
+
/**
|
|
37
|
+
* Flush all pending events immediately
|
|
38
|
+
*
|
|
39
|
+
* @returns Promise that resolves when flush completes
|
|
40
|
+
*/
|
|
41
|
+
flush(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Set up event listeners for auto-flush behavior
|
|
44
|
+
*
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
private setupListeners;
|
|
48
|
+
/**
|
|
49
|
+
* Remove event listeners and flush pending events
|
|
50
|
+
*/
|
|
51
|
+
destroy(): void;
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class e{constructor(e,i){this.queue=[],this.flushTimer=null,this.visibilityHandler=null,this.beforeUnloadHandler=null,this.pageHideHandler=null,this.config={maxBatchSize:e.maxBatchSize??50,maxBatchTime:e.maxBatchTime??5e3,flushOnVisibilityChange:e.flushOnVisibilityChange??!0,flushOnUnload:e.flushOnUnload??!0,disablePageContext:e.disablePageContext??!1,disableMarketingParams:e.disableMarketingParams??!1},this.flushCallback=i,this.setupListeners()}add(e){this.queue.push(e),this.queue.length>=this.config.maxBatchSize?this.flush():this.flushTimer||this.scheduleFlush()}scheduleFlush(){"undefined"!=typeof requestIdleCallback?requestIdleCallback(()=>{this.flushTimer=setTimeout(()=>this.flush(),this.config.maxBatchTime)},{timeout:this.config.maxBatchTime}):this.flushTimer=setTimeout(()=>this.flush(),this.config.maxBatchTime)}async flush(){if(this.flushTimer&&(clearTimeout(this.flushTimer),this.flushTimer=null),0===this.queue.length)return;const e=[...this.queue];this.queue=[],await this.flushCallback(e)}setupListeners(){"undefined"!=typeof window&&"undefined"!=typeof document&&(this.config.flushOnVisibilityChange&&(this.visibilityHandler=()=>{"hidden"===document.visibilityState&&this.flush()},document.addEventListener("visibilitychange",this.visibilityHandler)),this.config.flushOnUnload&&(this.pageHideHandler=()=>{this.flush()},window.addEventListener("pagehide",this.pageHideHandler),this.beforeUnloadHandler=()=>{this.flush()},window.addEventListener("beforeunload",this.beforeUnloadHandler)))}destroy(){"undefined"!=typeof window&&"undefined"!=typeof document&&(this.visibilityHandler&&document.removeEventListener("visibilitychange",this.visibilityHandler),this.beforeUnloadHandler&&window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.pageHideHandler&&window.removeEventListener("pagehide",this.pageHideHandler)),this.flushTimer&&clearTimeout(this.flushTimer),this.flush()}}export{e as EventBatcher};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { HttpClient } from '../core/http';
|
|
2
|
+
import { BeaconConfig, BeaconEventInput, BeaconModule } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Beacon tracking module for client-side event tracking
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
export declare class BeaconTrackingModule implements BeaconModule {
|
|
9
|
+
private http;
|
|
10
|
+
private logger;
|
|
11
|
+
private events;
|
|
12
|
+
private store;
|
|
13
|
+
private batcher;
|
|
14
|
+
private config;
|
|
15
|
+
constructor(http: HttpClient, config?: BeaconConfig);
|
|
16
|
+
/**
|
|
17
|
+
* Track a single event
|
|
18
|
+
*
|
|
19
|
+
* Events are enriched with auto-generated fields and browser context,
|
|
20
|
+
* then queued for batching. The batch is sent when size/time thresholds
|
|
21
|
+
* are reached or on visibility change/page unload.
|
|
22
|
+
*
|
|
23
|
+
* @param event - Event to track
|
|
24
|
+
*/
|
|
25
|
+
track(event: BeaconEventInput): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Track multiple events in a batch
|
|
28
|
+
*
|
|
29
|
+
* Events are enriched and validated, then sent immediately
|
|
30
|
+
* (bypassing the batching queue).
|
|
31
|
+
*
|
|
32
|
+
* @param events - Events to track
|
|
33
|
+
*/
|
|
34
|
+
trackBatch(events: BeaconEventInput[]): Promise<void>;
|
|
35
|
+
/**
|
|
36
|
+
* Flush pending events immediately
|
|
37
|
+
*
|
|
38
|
+
* Forces all queued events to be sent to the beacon endpoint.
|
|
39
|
+
*/
|
|
40
|
+
flush(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Send events to beacon endpoint
|
|
43
|
+
*
|
|
44
|
+
* Uses single event endpoint for one event, batch endpoint for multiple.
|
|
45
|
+
* Gracefully degrades on errors (tracking failures don't break app).
|
|
46
|
+
*
|
|
47
|
+
* @param events - Events to send
|
|
48
|
+
* @returns true if sent successfully, false if failed
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
private sendBatch;
|
|
52
|
+
/**
|
|
53
|
+
* Cleanup and destroy the module
|
|
54
|
+
*
|
|
55
|
+
* Removes event listeners and flushes pending events.
|
|
56
|
+
*/
|
|
57
|
+
destroy(): void;
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getLogger as t}from"../core/logger.js";import{getEventBus as e}from"../state/events.js";import{getSDKStore as r}from"../state/store.js";import{EventBatcher as s}from"./batching.js";import{enrichEvent as n}from"./enrichment.js";import{validateEvent as o}from"./validation.js";class i{constructor(n,o={}){this.logger=t(),this.events=e(),this.store=r(),this.http=n,this.config=o,this.batcher=new s(o,async t=>{await this.sendBatch(t)}),this.logger.debug("Beacon tracking module initialized",{config:o})}async track(t){try{const e=n(t,this.config);o(e),this.batcher.add(e),this.events.emit("beacon:queued",{event:e}),this.logger.debug("Event queued for tracking",{event:e})}catch(e){throw this.logger.error("Failed to queue event",{error:e,event:t}),this.events.emit("beacon:error",{error:e,event:t}),e}}async trackBatch(t){try{const e=t.map(t=>{const e=n(t,this.config);return o(e),e}),r=await this.sendBatch(e);this.logger[r?"info":"warn"](r?"Batch tracked successfully":"Batch queued but send failed",{count:e.length})}catch(e){throw this.logger.error("Failed to track batch",{error:e,count:t.length}),this.events.emit("beacon:error",{error:e,events:t}),e}}async flush(){await this.batcher.flush()}async sendBatch(t){if(0===t.length)return!0;try{const e=1===t.length?"/events":"/events/batch",r=1===t.length?t[0]:t,s=this.http.getConfig().headers?.["X-Organization-Id"],n="string"==typeof s?s:void 0,o=this.store.session?.consumerId,i=t=>({...t,...n?{organizationId:n}:{},...o?{consumerId:o}:{}}),a=Array.isArray(r)?r.map(i):i(r);return await this.http.post(e,a),this.events.emit("beacon:sent",{count:t.length}),this.logger.info("Events sent to beacon",{count:t.length}),!0}catch(e){return this.logger.error("Failed to send events",{error:e,count:t.length}),this.events.emit("beacon:error",{error:e,events:t}),!1}}destroy(){this.batcher.destroy()}}export{i as BeaconTrackingModule};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { BeaconConfig, BeaconEventInput } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Auto-enrich beacon event with generated fields and browser context
|
|
4
|
+
*
|
|
5
|
+
* Adds the following if not already present:
|
|
6
|
+
* - eventId (UUID v7 for time-based sorting)
|
|
7
|
+
* - eventTimestamp (ISO 8601, canonical event time)
|
|
8
|
+
* - eventProperties (empty object)
|
|
9
|
+
* - Page context (url, title, referrer)
|
|
10
|
+
* - Marketing parameters (UTM params from URL)
|
|
11
|
+
*
|
|
12
|
+
* @param event - Original event to enrich
|
|
13
|
+
* @param config - Beacon configuration
|
|
14
|
+
* @returns Enriched event
|
|
15
|
+
*/
|
|
16
|
+
export declare function enrichEvent(event: BeaconEventInput, config: BeaconConfig): BeaconEventInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{v7 as e}from"uuid";const t=1e6;function n(n,r){const o={...n};if(o.eventId||(o.eventId=e()),!o.eventTimestamp){const e=function(){const e=Date.now(),n=new Date(e).toISOString(),r=`${e}${function(){if("undefined"==typeof performance||"function"!=typeof performance.now)return"000000";return Math.floor(performance.now()%1*t).toString().padStart(6,"0")}()}`;return{eventTime:n,eventTimeNs:r}}();o.eventTimestamp=e.eventTime,o.eventTimestampNs=e.eventTimeNs}if(o.eventProperties||(o.eventProperties={}),!r.disablePageContext&&"undefined"!=typeof window&&(o.pageUrl||(o.pageUrl=window.location.href),o.pagePath||(o.pagePath=window.location.pathname),o.pageTitle||"undefined"==typeof document||(o.pageTitle=document.title),"undefined"!=typeof document&&document.referrer&&(o.referrerUrl||(o.referrerUrl=document.referrer),!o.referringDomain)))try{const e=new URL(document.referrer);o.referringDomain=e.hostname}catch{}if(!r.disableMarketingParams&&"undefined"!=typeof window)try{const e=new URLSearchParams(window.location.search);if(!o.utmSource){const t=e.get("utm_source");t&&(o.utmSource=t)}if(!o.utmMedium){const t=e.get("utm_medium");t&&(o.utmMedium=t)}if(!o.utmCampaign){const t=e.get("utm_campaign");t&&(o.utmCampaign=t)}if(!o.utmTerm){const t=e.get("utm_term");t&&(o.utmTerm=t)}if(!o.utmContent){const t=e.get("utm_content");t&&(o.utmContent=t)}}catch{}return o}export{n as enrichEvent};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Beacon Event Tracking Module
|
|
3
|
+
*
|
|
4
|
+
* Provides client-side event tracking with automatic enrichment,
|
|
5
|
+
* smart batching, and lightweight validation.
|
|
6
|
+
*
|
|
7
|
+
* @module beacon
|
|
8
|
+
*/
|
|
9
|
+
export { BeaconTrackingModule } from './beacon.module';
|
|
10
|
+
export { enrichEvent } from './enrichment';
|
|
11
|
+
export type { BeaconConfig, BeaconEvent, BeaconEventInput, BeaconModule } from './types';
|
|
12
|
+
export { ValidationError, validateEvent } from './validation';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public beacon type surface.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors exactly the beacon symbols on the root barrel — the runtime
|
|
5
|
+
* `BeaconTrackingModule`/`enrichEvent`/`validateEvent` are deliberately not
|
|
6
|
+
* re-exported here. `ValidationError` is kept because it is on the root barrel.
|
|
7
|
+
*/
|
|
8
|
+
export type { BeaconConfig, BeaconEvent, BeaconEventInput, BeaconModule } from './types';
|
|
9
|
+
export { ValidationError } from './validation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ValidationError as o}from"./validation.js";export{o as ValidationError};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { BeaconEvent, BeaconEventInput } from '@fanfare-io/fanfare-sdk-contracts/beacon';
|
|
2
|
+
export type { BeaconEvent, BeaconEventInput };
|
|
3
|
+
/**
|
|
4
|
+
* Beacon tracking module interface
|
|
5
|
+
*/
|
|
6
|
+
export interface BeaconModule {
|
|
7
|
+
/**
|
|
8
|
+
* Track a single event
|
|
9
|
+
*
|
|
10
|
+
* Events are automatically enriched with eventId, timestamp, page context,
|
|
11
|
+
* and marketing parameters before being queued for batch sending.
|
|
12
|
+
*
|
|
13
|
+
* @param event - Event to track
|
|
14
|
+
* @returns Promise that resolves when event is queued (not sent)
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* await fanfare.beacon.track({
|
|
19
|
+
* eventName: "pageView",
|
|
20
|
+
* eventProperties: {
|
|
21
|
+
* pageType: "home"
|
|
22
|
+
* }
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
track(event: BeaconEventInput): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Track multiple events in a batch
|
|
29
|
+
*
|
|
30
|
+
* Sends events immediately, bypassing the batching queue.
|
|
31
|
+
* Useful for tracking multiple related events atomically.
|
|
32
|
+
*
|
|
33
|
+
* @param events - Events to track
|
|
34
|
+
* @returns Promise that resolves when batch is sent
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ```typescript
|
|
38
|
+
* await fanfare.beacon.trackBatch([
|
|
39
|
+
* { eventName: "pageView" },
|
|
40
|
+
* { eventName: "productImpression", eventProperties: { productId: "123" } }
|
|
41
|
+
* ]);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
trackBatch(events: BeaconEventInput[]): Promise<void>;
|
|
45
|
+
/**
|
|
46
|
+
* Flush pending events immediately
|
|
47
|
+
*
|
|
48
|
+
* Forces all queued events to be sent to the beacon endpoint.
|
|
49
|
+
* Automatically called on visibility change and page unload.
|
|
50
|
+
*
|
|
51
|
+
* @returns Promise that resolves when flush completes
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* await fanfare.beacon.flush();
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
flush(): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Beacon module configuration
|
|
62
|
+
*/
|
|
63
|
+
export interface BeaconConfig {
|
|
64
|
+
/**
|
|
65
|
+
* Base URL for beacon API
|
|
66
|
+
* When not specified, uses the environment-specific beacon URL
|
|
67
|
+
* @example "http://localhost:4803" (development)
|
|
68
|
+
* @example "https://beacon.fanfare.io" (production)
|
|
69
|
+
*/
|
|
70
|
+
baseUrl?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Maximum events to batch before auto-flush
|
|
73
|
+
* @default 50
|
|
74
|
+
*/
|
|
75
|
+
maxBatchSize?: number;
|
|
76
|
+
/**
|
|
77
|
+
* Maximum time (ms) to wait before auto-flush
|
|
78
|
+
* @default 5000
|
|
79
|
+
*/
|
|
80
|
+
maxBatchTime?: number;
|
|
81
|
+
/**
|
|
82
|
+
* Enable auto-flush on visibility change (tab hidden)
|
|
83
|
+
* @default true
|
|
84
|
+
*/
|
|
85
|
+
flushOnVisibilityChange?: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Enable auto-flush on page unload
|
|
88
|
+
* @default true
|
|
89
|
+
*/
|
|
90
|
+
flushOnUnload?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Disable automatic page context enrichment
|
|
93
|
+
* When true, pageUrl, pageTitle, referrer, etc. will not be auto-populated
|
|
94
|
+
* @default false
|
|
95
|
+
*/
|
|
96
|
+
disablePageContext?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Disable automatic UTM parameter extraction
|
|
99
|
+
* When true, utm_* fields will not be auto-extracted from URL
|
|
100
|
+
* @default false
|
|
101
|
+
*/
|
|
102
|
+
disableMarketingParams?: boolean;
|
|
103
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { BeaconEventName } from '@fanfare-io/fanfare-sdk-contracts/beacon/names';
|
|
2
|
+
import { BeaconEventInput } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Validation error for beacon events
|
|
5
|
+
*/
|
|
6
|
+
export declare class ValidationError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Lightweight validation for beacon events
|
|
11
|
+
*
|
|
12
|
+
* Only validates essential fields:
|
|
13
|
+
* - eventName is required and non-empty
|
|
14
|
+
* - eventId exists after enrichment
|
|
15
|
+
* - eventTimestamp exists after enrichment
|
|
16
|
+
* - eventProperties is an object if provided
|
|
17
|
+
*
|
|
18
|
+
* Server-side validation handles comprehensive validation.
|
|
19
|
+
*
|
|
20
|
+
* @param event - Event to validate
|
|
21
|
+
* @throws {ValidationError} If validation fails
|
|
22
|
+
*/
|
|
23
|
+
export declare function validateEvent(event: BeaconEventInput): void;
|
|
24
|
+
export declare function isBeaconEventName(eventName: string): eventName is BeaconEventName;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{BeaconEventNames as e}from"@fanfare-io/fanfare-sdk-contracts/beacon/names";const t=new Set(e);class n extends Error{constructor(e){super(e),this.name="ValidationError"}}function r(r){if(!r.eventName||"string"!=typeof r.eventName)throw new n("eventName is required and must be a string");if(0===r.eventName.trim().length)throw new n("eventName cannot be empty");if(!t.has(r.eventName))throw new n(`eventName must be one of: ${e.join(", ")}`);if(!r.eventId)throw new n("eventId is required");if(!r.eventTimestamp)throw new n("eventTimestamp is required");if(void 0!==r.eventProperties&&"object"!=typeof r.eventProperties)throw new n("eventProperties must be an object");if(null===r.eventProperties)throw new n("eventProperties cannot be null")}export{n as ValidationError,r as validateEvent};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { HttpClient } from '../core/http';
|
|
2
|
+
import { ChallengeInitiateRequest, ChallengeInitiateResponse, ChallengeModule, ChallengeVerifyRequest, ChallengeVerifyResponse } from './types';
|
|
3
|
+
export declare class ChallengeManagementModule implements ChallengeModule {
|
|
4
|
+
private http;
|
|
5
|
+
private logger;
|
|
6
|
+
constructor(http: HttpClient);
|
|
7
|
+
initiate(input?: ChallengeInitiateRequest): Promise<ChallengeInitiateResponse>;
|
|
8
|
+
verify(input: ChallengeVerifyRequest): Promise<ChallengeVerifyResponse>;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getLogger as t}from"../core/logger.js";class r{constructor(r){this.logger=t(),this.http=r}async initiate(t={}){try{return await this.http.post("/challenges/initiate",t)}catch(r){throw this.logger.error("Failed to initiate challenge",{error:r}),r}}async verify(t){try{return await this.http.post("/challenges/verify",t)}catch(r){throw this.logger.error("Failed to verify challenge",{error:r}),r}}}export{r as ChallengeManagementModule};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { ChallengeManagementModule } from './challenge.module';
|
|
2
|
+
export { ChallengeProvider, ChallengePurpose, ChallengeType } from './types';
|
|
3
|
+
export type { BotMitigationState, ChallengeInitiateRequest, ChallengeInitiateResponse, ChallengeModule, ChallengeVerifyRequest, ChallengeVerifyResponse, RoutingChallenge, } from './types';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public challenge type surface.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors exactly the challenge symbols on the root barrel — the runtime
|
|
5
|
+
* `ChallengeManagementModule` from `challenge.module` is deliberately not
|
|
6
|
+
* re-exported here.
|
|
7
|
+
*/
|
|
8
|
+
export { ChallengeProvider, ChallengePurpose, ChallengeType } from './types';
|
|
9
|
+
export type { BotMitigationState, ChallengeInitiateRequest, ChallengeInitiateResponse, ChallengeModule, ChallengeVerifyRequest, ChallengeVerifyResponse, RoutingChallenge, } from './types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{ChallengeProvider as a,ChallengePurpose as r,ChallengeType as e}from"@fanfare-io/fanfare-sdk-contracts/challenges";export{a as ChallengeProvider,r as ChallengePurpose,e as ChallengeType};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { BotMitigationState, ChallengePurpose, ChallengeType, RoutingChallenge } from '@fanfare-io/fanfare-sdk-contracts/challenges';
|
|
2
|
+
export { ChallengeProvider, ChallengePurpose, ChallengeType } from '@fanfare-io/fanfare-sdk-contracts/challenges';
|
|
3
|
+
export type { BotMitigationState, RoutingChallenge } from '@fanfare-io/fanfare-sdk-contracts/challenges';
|
|
4
|
+
export type ChallengeInitiateRequest = {
|
|
5
|
+
purpose?: ChallengePurpose;
|
|
6
|
+
type?: ChallengeType;
|
|
7
|
+
};
|
|
8
|
+
export type ChallengeInitiateResponse = {
|
|
9
|
+
challenge?: RoutingChallenge;
|
|
10
|
+
botMitigation?: BotMitigationState;
|
|
11
|
+
};
|
|
12
|
+
export type ChallengeVerifyRequest = {
|
|
13
|
+
challengeId: string;
|
|
14
|
+
token: string;
|
|
15
|
+
};
|
|
16
|
+
export type ChallengeVerifyResponse = {
|
|
17
|
+
status: "passed";
|
|
18
|
+
passedUntil: string;
|
|
19
|
+
} | {
|
|
20
|
+
status: "failed";
|
|
21
|
+
attemptsRemaining: number;
|
|
22
|
+
message?: string;
|
|
23
|
+
errorCodes?: string[];
|
|
24
|
+
} | {
|
|
25
|
+
status: "blocked";
|
|
26
|
+
blockedUntil: string;
|
|
27
|
+
message: string;
|
|
28
|
+
errorCodes?: string[];
|
|
29
|
+
};
|
|
30
|
+
export interface ChallengeModule {
|
|
31
|
+
initiate(input?: ChallengeInitiateRequest): Promise<ChallengeInitiateResponse>;
|
|
32
|
+
verify(input: ChallengeVerifyRequest): Promise<ChallengeVerifyResponse>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { FanfareConfig } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* API URLs by environment
|
|
4
|
+
*/
|
|
5
|
+
export declare const API_URLS: {
|
|
6
|
+
readonly production: "https://consumer.fanfare.io/api";
|
|
7
|
+
readonly development: "http://localhost:4802";
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Beacon API URLs by environment
|
|
11
|
+
*/
|
|
12
|
+
export declare const BEACON_URLS: {
|
|
13
|
+
readonly production: "https://beacon.fanfare.io";
|
|
14
|
+
readonly development: "http://localhost:4803";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Default configuration values
|
|
18
|
+
*/
|
|
19
|
+
export declare const DEFAULT_CONFIG: Partial<FanfareConfig>;
|
|
20
|
+
/**
|
|
21
|
+
* Configuration manager
|
|
22
|
+
*/
|
|
23
|
+
export declare class Config {
|
|
24
|
+
private readonly config;
|
|
25
|
+
constructor(userConfig: FanfareConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Get the API URL for the current environment
|
|
28
|
+
*/
|
|
29
|
+
get apiUrl(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Get the Beacon API URL for the current environment
|
|
32
|
+
*/
|
|
33
|
+
get beaconUrl(): string;
|
|
34
|
+
/**
|
|
35
|
+
* Get the full configuration
|
|
36
|
+
*/
|
|
37
|
+
get(): FanfareConfig & {
|
|
38
|
+
apiUrl?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Get a specific configuration value
|
|
42
|
+
*/
|
|
43
|
+
getValue<K extends keyof FanfareConfig>(key: K): K extends "apiUrl" ? string | undefined : Required<FanfareConfig>[K];
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createError as i}from"../core/errors.js";const n={production:"https://consumer.fanfare.io/api",development:"http://localhost:4802"},o={production:"https://beacon.fanfare.io",development:"http://localhost:4803"},t=/* @__PURE__ */new Set(["https://consumer.fanfare.io"]),e=/* @__PURE__ */new Set(["https://beacon.fanfare.io"]),r={environment:"production",auth:{persistSession:!0,sessionDuration:3600},logging:{level:"error"}};class a{constructor(n){if(this.config={organizationId:n.organizationId,publishableKey:n.publishableKey,environment:n.environment??r.environment??"production",apiUrl:n.apiUrl,credentials:n.credentials??"include",debug:n.debug??!1,auth:{...r.auth,...n.auth},logging:{...r.logging,...n.logging},sync:n.sync,beacon:n.beacon,features:{fingerprinting:n.features?.fingerprinting??!0}},!this.config.organizationId)throw i.invalidConfig("organizationId is required");if(!this.config.publishableKey)throw i.invalidConfig("publishableKey is required");"production"===this.config.environment&&(s("apiUrl",this.apiUrl,t),s("beacon.baseUrl",this.beaconUrl,e))}get apiUrl(){return this.config.apiUrl||n[this.config.environment]}get beaconUrl(){return this.config.beacon?.baseUrl||o[this.config.environment]}get(){return this.config}getValue(i){return this.config[i]}}function s(n,o,t){let e;try{e=new URL(o)}catch{throw i.invalidConfig(`${n} must be a valid URL in production`)}if("https:"!==e.protocol)throw i.invalidConfig(`${n} must use HTTPS in production`);if(!t.has(e.origin))throw i.invalidConfig(`${n} must use a trusted Fanfare destination in production`)}export{n as API_URLS,o as BEACON_URLS,a as Config,r as DEFAULT_CONFIG};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FanfareConfig, FanfareSDK } from '../types';
|
|
2
|
+
/** @internal Reset active instance guard (for testing only) */
|
|
3
|
+
export declare function resetActiveInstance(): void;
|
|
4
|
+
/**
|
|
5
|
+
* Initialize the Fanfare SDK
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const fanfare = await Fanfare.init({
|
|
10
|
+
* organizationId: 'org_123',
|
|
11
|
+
* publishableKey: 'pk_live_xyz789'
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export declare function init(config: FanfareConfig): Promise<FanfareSDK>;
|