@coinlist-co/react 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/RequirementItem-B-MvcxSr.d.cts +37 -0
- package/dist/RequirementItem-DcYot2uC.d.ts +37 -0
- package/dist/chunk-EHZ6PIGN.js +414 -0
- package/dist/chunk-EHZ6PIGN.js.map +1 -0
- package/dist/chunk-NC45IO63.js +777 -0
- package/dist/chunk-NC45IO63.js.map +1 -0
- package/dist/chunk-RIFATQB5.js +257 -0
- package/dist/chunk-RIFATQB5.js.map +1 -0
- package/dist/chunk-UGJUTRXC.js +304 -0
- package/dist/chunk-UGJUTRXC.js.map +1 -0
- package/dist/client/components/index.cjs +473 -10
- package/dist/client/components/index.cjs.map +1 -1
- package/dist/client/components/index.d.cts +80 -12
- package/dist/client/components/index.d.ts +80 -12
- package/dist/client/components/index.js +243 -243
- package/dist/client/components/index.js.map +1 -1
- package/dist/client/core/index.cjs +349 -202
- package/dist/client/core/index.cjs.map +1 -1
- package/dist/client/core/index.d.cts +4 -4
- package/dist/client/core/index.d.ts +4 -4
- package/dist/client/core/index.js +16 -14
- package/dist/client/hooks/index.cjs +133 -16
- package/dist/client/hooks/index.cjs.map +1 -1
- package/dist/client/hooks/index.d.cts +102 -8
- package/dist/client/hooks/index.d.ts +102 -8
- package/dist/client/hooks/index.js +11 -9
- package/dist/client/index.cjs +591 -210
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +7 -6
- package/dist/client/index.d.ts +7 -6
- package/dist/client/index.js +41 -17
- package/dist/client/styles.css +1 -1
- package/dist/coinlist-client-BSxpqylo.d.ts +158 -0
- package/dist/coinlist-client-Cah5c_aF.d.cts +158 -0
- package/dist/participation-DMMEDxON.d.cts +185 -0
- package/dist/participation-E-bT-GXJ.d.ts +185 -0
- package/dist/requirement-XWT0T_zO.d.cts +205 -0
- package/dist/requirement-XWT0T_zO.d.ts +205 -0
- package/dist/server/index.cjs +519 -14
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +73 -4
- package/dist/server/index.d.ts +73 -4
- package/dist/server/index.js +116 -20
- package/dist/server/index.js.map +1 -1
- package/dist/useCoinListRequirements-B5-ZPOMz.d.ts +80 -0
- package/dist/useCoinListRequirements-Cuc32Tqw.d.cts +80 -0
- package/package.json +4 -4
- package/dist/chunk-32GOUV3L.js +0 -118
- package/dist/chunk-32GOUV3L.js.map +0 -1
- package/dist/chunk-G3B4RLXP.js +0 -76
- package/dist/chunk-G3B4RLXP.js.map +0 -1
- package/dist/chunk-GRVV7NLV.js +0 -282
- package/dist/chunk-GRVV7NLV.js.map +0 -1
- package/dist/chunk-Z5RFQOMS.js +0 -560
- package/dist/chunk-Z5RFQOMS.js.map +0 -1
- package/dist/coinlist-client-20v7fJSW.d.ts +0 -394
- package/dist/coinlist-client-Ds86ycAg.d.cts +0 -394
- package/dist/newtype-yKTvFdg_.d.cts +0 -6
- package/dist/newtype-yKTvFdg_.d.ts +0 -6
- package/dist/oauth-session-DgItaMKN.d.cts +0 -56
- package/dist/oauth-session-DnKDI5ou.d.ts +0 -56
- package/dist/offer-D6p_Ijme.d.cts +0 -30
- package/dist/offer-DnFEFJw9.d.ts +0 -30
- package/dist/useCoinListOffers-DIdOb5hB.d.ts +0 -27
- package/dist/useCoinListOffers-DvJxu6qj.d.cts +0 -27
- package/dist/useCompleteCoinListOAuth-C359mp_k.d.cts +0 -55
- package/dist/useCompleteCoinListOAuth-wZX3o8r2.d.ts +0 -55
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/api/api.server.ts","../../src/server/coinlist.server.ts"],"sourcesContent":["import {\n type HttpClientConfig,\n HttpError,\n type HttpRequest,\n} from '@/shared/api/http';\nimport { HttpClient } from '@/shared/api/http-client';\nimport { requestRetryMiddleware } from '@/shared/api/middleware/request-retry';\n\nexport class Api {\n private readonly httpClient: HttpClient;\n\n constructor(private readonly config: HttpClientConfig) {\n this.httpClient = new HttpClient(this.config, {\n beforeRequest: [],\n afterRequest: [requestRetryMiddleware],\n });\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n const response = await this.httpClient.send<TResponse>(request);\n if (response.status >= 200 && response.status < 300) {\n return response.body as TResponse;\n } else {\n throw new HttpError(response);\n }\n }\n}\n","import { Api } from '@/server/api/api.server';\nimport { API_VERSION, PUBLIC_API_BASE_URL } from '@/shared/api/frontline';\nimport { HttpError } from '@/shared/api/http';\nimport type { Config } from '@/shared/types/config';\nimport type { OAuthSessionDto } from '@/shared/types/dto/oauth-session';\nimport type {\n AuthorizationCode,\n ClientSecret,\n CodeVerifier,\n} from '@/shared/types/oauth';\nimport {\n type OAuthAccessToken,\n OAuthSession,\n} from '@/shared/types/oauth-session';\n\n/** Buffer in seconds before expiry to consider token expired for refresh. */\nconst ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;\n\nexport interface SessionStore {\n getSession(): Promise<OAuthSession | null>;\n setSession(session: OAuthSession | null): Promise<void>;\n}\n\nexport interface ServerConfig extends Config {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Buffer in seconds before expiry to consider token expired for refresh. */\n readonly accessTokenExpiryBufferSeconds?: number;\n /**\n * Whether SDK will throw an exception in cases it can be silent.\n * For example, if token revokation on logout fails.\n */\n readonly strict?: boolean;\n}\n\nexport interface CoinListServer {\n completeOAuth(\n code: AuthorizationCode,\n codeVerifier: CodeVerifier\n ): Promise<OAuthSession>;\n\n /**\n * Responsible for:\n * 1. Returning a securely stored access token from Cookies\n * 2. Renewing the session if it's expired (or about to expire)\n *\n * @returns a valid access token or null if the user is not authentication.\n * On error rejects the Promise and throws.\n */\n accessToken(): Promise<OAuthAccessToken | null>;\n\n /**\n * Revokes the current token via POST /oauth/revoke and clears the session.\n */\n logout(): Promise<void>;\n}\n\nclass CoinListServerImpl implements CoinListServer {\n private readonly api: Api;\n private readonly baseUrl: string;\n\n private readonly accessTokenExpiryBufferSeconds: number;\n private readonly strict: boolean;\n\n constructor(private readonly _config: ServerConfig) {\n this.baseUrl = _config.baseUrl ?? PUBLIC_API_BASE_URL;\n this.accessTokenExpiryBufferSeconds =\n _config.accessTokenExpiryBufferSeconds ??\n ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS;\n this.strict = _config.strict ?? false;\n this.api = new Api({\n baseUrl: this.baseUrl,\n xApiVersion: API_VERSION,\n });\n }\n\n async completeOAuth(\n code: AuthorizationCode,\n codeVerifier: CodeVerifier\n ): Promise<OAuthSession> {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'authorization_code',\n code,\n redirect_uri: this._config.redirectUri,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n code_verifier: codeVerifier,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n this._config.sessionStore.setSession(session);\n return session;\n }\n\n async accessToken(): Promise<OAuthAccessToken | null> {\n const session = await this._config.sessionStore.getSession();\n if (session == null) return null;\n\n const now = Date.now();\n const expiresAt = session.accessToken.expiresAt.getTime();\n const bufferMs = this.accessTokenExpiryBufferSeconds * 1000;\n if (expiresAt > now + bufferMs) {\n return session.accessToken;\n }\n\n const refreshToken = session?.refreshToken;\n if (!refreshToken) {\n await this._config.sessionStore.setSession(null);\n return null;\n }\n\n try {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n },\n });\n const newSession = OAuthSession.fromDto(sessionDto);\n await this._config.sessionStore.setSession(newSession);\n return newSession.accessToken;\n } catch {\n await this._config.sessionStore.setSession(null);\n return null;\n }\n }\n\n async logout(): Promise<void> {\n const session = await this._config.sessionStore.getSession();\n if (session != null) {\n const tokenToRevoke = session.accessToken.value;\n try {\n await this.api.send({\n method: 'POST',\n url: `/oauth/revoke`,\n body: {\n token: tokenToRevoke,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n },\n });\n } catch (err) {\n if (err instanceof HttpError) {\n if (this.strict) {\n throw err;\n }\n } else {\n throw err;\n }\n }\n await this._config.sessionStore.setSession(null);\n }\n }\n}\n\nexport function createCoinListServer(config: ServerConfig): CoinListServer {\n return new CoinListServerImpl(config);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/api/api.server.ts","../../src/server/coinlist.server.ts"],"sourcesContent":["import { AuthenticatedApiClient } from '@/shared/api/authenticated-api-client';\nimport type { HttpClientConfig, HttpRequest } from '@/shared/api/http';\nimport type { OAuthAccessToken } from '@/shared/types/oauth-session';\n\nexport class Api {\n private readonly client: AuthenticatedApiClient;\n\n constructor(\n config: HttpClientConfig,\n fetchAccessToken: (refresh: boolean) => Promise<OAuthAccessToken | null>\n ) {\n this.client = new AuthenticatedApiClient(config, fetchAccessToken);\n }\n\n async send<TResponse>(request: HttpRequest): Promise<TResponse> {\n return this.client.send<TResponse>(request);\n }\n}\n","import { Api } from '@/server/api/api.server';\nimport { API_VERSION, PUBLIC_API_BASE_URL } from '@/shared/api/frontline';\nimport * as offersApi from '@/shared/api/frontline/offers';\nimport * as participationsApi from '@/shared/api/frontline/participations';\nimport * as requirementsApi from '@/shared/api/frontline/requirements';\nimport { HttpError } from '@/shared/api/http';\nimport type {\n PaginatedResponse,\n PaginationParams,\n} from '@/shared/api/pagination';\nimport type { Config } from '@/shared/types/config';\nimport type { OAuthSessionDto } from '@/shared/types/dto/oauth-session';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type {\n AuthorizationCode,\n ClientSecret,\n CodeVerifier,\n} from '@/shared/types/oauth';\nimport {\n type OAuthAccessToken,\n OAuthSession,\n} from '@/shared/types/oauth-session';\nimport type { Offer, OfferId } from '@/shared/types/offer';\nimport type { OfferDetail, OfferOptionId } from '@/shared/types/offer-detail';\nimport type {\n CreateParticipationParams,\n Participation,\n ParticipationId,\n ParticipationsPaginationParams,\n} from '@/shared/types/participation';\nimport type {\n Requirement,\n RequirementStatusInfo,\n} from '@/shared/types/requirement';\n\n/** Buffer in seconds before expiry to consider token expired for refresh. */\nconst ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS = 60;\n\nexport interface SessionStore {\n getSession(): Promise<OAuthSession | null>;\n setSession(session: OAuthSession | null): Promise<void>;\n}\n\nexport interface ServerConfig extends Config {\n readonly clientSecret: ClientSecret;\n readonly sessionStore: SessionStore;\n /** Buffer in seconds before expiry to consider token expired for refresh. */\n readonly accessTokenExpiryBufferSeconds?: number;\n /**\n * Whether SDK will throw an exception in cases it can be silent.\n * For example, if token revokation on logout fails.\n */\n readonly strict?: boolean;\n}\n\nexport interface CoinListServer {\n completeOAuth(\n code: AuthorizationCode,\n codeVerifier: CodeVerifier\n ): Promise<OAuthSession>;\n\n /**\n * Responsible for:\n * 1. Returning a securely stored access token from Cookies\n * 2. Renewing the session if it's expired (or about to expire)\n *\n * @returns a valid access token or null if the user is not authentication.\n * On error rejects the Promise and throws.\n */\n accessToken(): Promise<OAuthAccessToken | null>;\n\n /**\n * Revokes the current token via POST /oauth/revoke and clears the session.\n */\n logout(): Promise<void>;\n\n /**\n * Fetches all offers by iterating through every paginated response.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchAllOffers(): Promise<Offer[]>;\n\n /**\n * Fetches a single page of offers.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchOffersPage(params: PaginationParams): Promise<PaginatedResponse<Offer>>;\n\n /**\n * Fetches details for a given offer by its id.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchOfferDetails(id: OfferId): Promise<OfferDetail>;\n\n /**\n * Fetches all participations by iterating through every paginated response.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchAllParticipations(offerId?: OfferId): Promise<Participation[]>;\n\n /**\n * Fetches a single page of participations, optionally filtered by offer.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>>;\n\n /**\n * Fetches a participation by id.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchParticipation(id: ParticipationId): Promise<Participation>;\n\n /**\n * Creates a participation.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation>;\n\n /**\n * Fetches the requirements for all options of a given offer, grouped by option ID.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>>;\n\n /**\n * Fetches the user's requirement statuses for a given offer.\n *\n * Throws {@link NotAuthenticatedError} if the user is not authenticated.\n */\n fetchRequirementStatuses(offerId: OfferId): Promise<RequirementStatusInfo[]>;\n}\n\nclass CoinListServerImpl implements CoinListServer {\n private readonly api: Api;\n private readonly baseUrl: string;\n\n private readonly accessTokenExpiryBufferSeconds: number;\n private readonly strict: boolean;\n\n constructor(private readonly _config: ServerConfig) {\n this.baseUrl = _config.baseUrl ?? PUBLIC_API_BASE_URL;\n this.accessTokenExpiryBufferSeconds =\n _config.accessTokenExpiryBufferSeconds ??\n ACCESS_TOKEN_EXPIRY_BUFFER_SECONDS;\n this.strict = _config.strict ?? false;\n this.api = new Api(\n {\n baseUrl: this.baseUrl,\n xApiVersion: API_VERSION,\n },\n (_refresh) => this.accessToken()\n );\n }\n\n async completeOAuth(\n code: AuthorizationCode,\n codeVerifier: CodeVerifier\n ): Promise<OAuthSession> {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'authorization_code',\n code,\n redirect_uri: this._config.redirectUri,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n code_verifier: codeVerifier,\n },\n });\n const session = OAuthSession.fromDto(sessionDto);\n this._config.sessionStore.setSession(session);\n return session;\n }\n\n async accessToken(): Promise<OAuthAccessToken | null> {\n const session = await this._config.sessionStore.getSession();\n if (session == null) return null;\n\n const now = Date.now();\n const expiresAt = session.accessToken.expiresAt.getTime();\n const bufferMs = this.accessTokenExpiryBufferSeconds * 1000;\n if (expiresAt > now + bufferMs) {\n return session.accessToken;\n }\n\n const refreshToken = session?.refreshToken;\n if (!refreshToken) {\n await this._config.sessionStore.setSession(null);\n return null;\n }\n\n try {\n const sessionDto = await this.api.send<OAuthSessionDto>({\n method: 'POST',\n url: `/oauth/token`,\n body: {\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n },\n });\n const newSession = OAuthSession.fromDto(sessionDto);\n await this._config.sessionStore.setSession(newSession);\n return newSession.accessToken;\n } catch {\n await this._config.sessionStore.setSession(null);\n return null;\n }\n }\n\n async logout(): Promise<void> {\n const session = await this._config.sessionStore.getSession();\n if (session != null) {\n const tokenToRevoke = session.accessToken.value;\n try {\n await this.api.send({\n method: 'POST',\n url: `/oauth/revoke`,\n body: {\n token: tokenToRevoke,\n client_id: this._config.clientId,\n client_secret: this._config.clientSecret,\n },\n });\n } catch (err) {\n if (err instanceof HttpError) {\n if (this.strict) {\n throw err;\n }\n } else {\n throw err;\n }\n }\n await this._config.sessionStore.setSession(null);\n }\n }\n\n private async ensureAuthenticated(): Promise<void> {\n const token = await this.accessToken();\n if (token === null) {\n throw new NotAuthenticatedError();\n }\n }\n\n async fetchAllOffers(): Promise<Offer[]> {\n await this.ensureAuthenticated();\n return offersApi.fetchAllOffers(this.api);\n }\n\n async fetchOffersPage(\n params: PaginationParams\n ): Promise<PaginatedResponse<Offer>> {\n await this.ensureAuthenticated();\n return offersApi.fetchOffersPage(this.api, params);\n }\n\n async fetchOfferDetails(id: OfferId): Promise<OfferDetail> {\n await this.ensureAuthenticated();\n return offersApi.fetchOfferDetails(this.api, id);\n }\n\n async fetchAllParticipations(offerId?: OfferId): Promise<Participation[]> {\n await this.ensureAuthenticated();\n return participationsApi.fetchAllParticipations(this.api, offerId);\n }\n\n async fetchParticipationsPage(\n params: ParticipationsPaginationParams\n ): Promise<PaginatedResponse<Participation>> {\n await this.ensureAuthenticated();\n return participationsApi.fetchParticipationsPage(this.api, params);\n }\n\n async fetchParticipation(id: ParticipationId): Promise<Participation> {\n await this.ensureAuthenticated();\n return participationsApi.fetchParticipation(this.api, id);\n }\n\n async createParticipation(\n params: CreateParticipationParams\n ): Promise<Participation> {\n await this.ensureAuthenticated();\n return participationsApi.createParticipation(this.api, params);\n }\n\n async fetchOfferRequirements(\n offerId: OfferId\n ): Promise<Record<OfferOptionId, Requirement[]>> {\n await this.ensureAuthenticated();\n return requirementsApi.fetchOfferRequirements(this.api, offerId);\n }\n\n async fetchRequirementStatuses(\n offerId: OfferId\n ): Promise<RequirementStatusInfo[]> {\n await this.ensureAuthenticated();\n return requirementsApi.fetchRequirementStatuses(this.api, offerId);\n }\n}\n\nexport function createCoinListServer(config: ServerConfig): CoinListServer {\n return new CoinListServerImpl(config);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { O as Offer, d as OfferOptionId, R as Requirement, h as RequirementStatusInfo, b as OfferId } from './requirement-XWT0T_zO.js';
|
|
2
|
+
|
|
3
|
+
type LoadOffersReason = 'not-authenticated' | 'generic-error';
|
|
4
|
+
type LoadOffersState = {
|
|
5
|
+
type: 'LOADING';
|
|
6
|
+
} | {
|
|
7
|
+
type: 'ERROR';
|
|
8
|
+
reason: LoadOffersReason;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'CONTENT';
|
|
11
|
+
offers: Offer[];
|
|
12
|
+
};
|
|
13
|
+
interface UseCoinListOffersOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Offers pre-fetched on the server (e.g. via `CoinListServer.fetchAllOffers()`).
|
|
16
|
+
* When provided, the hook uses this data as-is and skips the client-side fetch entirely.
|
|
17
|
+
*/
|
|
18
|
+
serverOffers?: Offer[];
|
|
19
|
+
}
|
|
20
|
+
interface UseCoinListOffersResult {
|
|
21
|
+
offersState: LoadOffersState;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Loads all CoinList offers for the current user and exposes a UI-friendly state.
|
|
25
|
+
*
|
|
26
|
+
* Pass `serverOffers` (pre-fetched server-side) to use that data as-is and skip
|
|
27
|
+
* the client-side fetch entirely.
|
|
28
|
+
*
|
|
29
|
+
* Returns `LOADING` while CoinList is initializing or while offers are being fetched.
|
|
30
|
+
* Returns `CONTENT` with all offers when `fetchAllOffers()` succeeds.
|
|
31
|
+
* Returns `ERROR` with:
|
|
32
|
+
* - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
|
|
33
|
+
* - `generic-error` for any other failure
|
|
34
|
+
*/
|
|
35
|
+
declare function useCoinListOffers(options?: UseCoinListOffersOptions): UseCoinListOffersResult;
|
|
36
|
+
|
|
37
|
+
type LoadRequirementsReason = 'not-authenticated' | 'generic-error';
|
|
38
|
+
type LoadRequirementsState = {
|
|
39
|
+
type: 'LOADING';
|
|
40
|
+
} | {
|
|
41
|
+
type: 'ERROR';
|
|
42
|
+
reason: LoadRequirementsReason;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'CONTENT';
|
|
45
|
+
requirementsByOptionId: Record<OfferOptionId, Requirement[]>;
|
|
46
|
+
statuses: RequirementStatusInfo[];
|
|
47
|
+
};
|
|
48
|
+
interface UseCoinListRequirementsOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Requirements data pre-fetched on the server (e.g. via
|
|
51
|
+
* `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).
|
|
52
|
+
* When provided, the hook uses this data as-is and skips the initial client-side fetch.
|
|
53
|
+
* Calling `refetch()` will still trigger a fresh fetch.
|
|
54
|
+
*/
|
|
55
|
+
serverData?: {
|
|
56
|
+
requirementsByOptionId: Record<OfferOptionId, Requirement[]>;
|
|
57
|
+
statuses: RequirementStatusInfo[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
interface UseCoinListRequirementsResult {
|
|
61
|
+
requirementsState: LoadRequirementsState;
|
|
62
|
+
/** Triggers a re-fetch of requirements and statuses. */
|
|
63
|
+
refetch: () => void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Loads requirements (grouped by option ID) and requirement statuses for a
|
|
67
|
+
* given offer, then exposes them via a state machine.
|
|
68
|
+
*
|
|
69
|
+
* Pass `serverData` (pre-fetched server-side) to use that data as-is and skip
|
|
70
|
+
* the initial client-side fetch. Calling `refetch()` will still trigger a fresh fetch.
|
|
71
|
+
*
|
|
72
|
+
* Returns `LOADING` while CoinList is initializing or while data is being fetched.
|
|
73
|
+
* Returns `CONTENT` with requirementsByOptionId and statuses on success.
|
|
74
|
+
* Returns `ERROR` with:
|
|
75
|
+
* - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
|
|
76
|
+
* - `generic-error` for any other failure
|
|
77
|
+
*/
|
|
78
|
+
declare function useCoinListRequirements(offerId: OfferId, options?: UseCoinListRequirementsOptions): UseCoinListRequirementsResult;
|
|
79
|
+
|
|
80
|
+
export { type LoadOffersReason as L, type UseCoinListOffersOptions as U, type LoadOffersState as a, type LoadRequirementsReason as b, type LoadRequirementsState as c, type UseCoinListOffersResult as d, type UseCoinListRequirementsOptions as e, type UseCoinListRequirementsResult as f, useCoinListRequirements as g, useCoinListOffers as u };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { O as Offer, d as OfferOptionId, R as Requirement, h as RequirementStatusInfo, b as OfferId } from './requirement-XWT0T_zO.cjs';
|
|
2
|
+
|
|
3
|
+
type LoadOffersReason = 'not-authenticated' | 'generic-error';
|
|
4
|
+
type LoadOffersState = {
|
|
5
|
+
type: 'LOADING';
|
|
6
|
+
} | {
|
|
7
|
+
type: 'ERROR';
|
|
8
|
+
reason: LoadOffersReason;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'CONTENT';
|
|
11
|
+
offers: Offer[];
|
|
12
|
+
};
|
|
13
|
+
interface UseCoinListOffersOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Offers pre-fetched on the server (e.g. via `CoinListServer.fetchAllOffers()`).
|
|
16
|
+
* When provided, the hook uses this data as-is and skips the client-side fetch entirely.
|
|
17
|
+
*/
|
|
18
|
+
serverOffers?: Offer[];
|
|
19
|
+
}
|
|
20
|
+
interface UseCoinListOffersResult {
|
|
21
|
+
offersState: LoadOffersState;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Loads all CoinList offers for the current user and exposes a UI-friendly state.
|
|
25
|
+
*
|
|
26
|
+
* Pass `serverOffers` (pre-fetched server-side) to use that data as-is and skip
|
|
27
|
+
* the client-side fetch entirely.
|
|
28
|
+
*
|
|
29
|
+
* Returns `LOADING` while CoinList is initializing or while offers are being fetched.
|
|
30
|
+
* Returns `CONTENT` with all offers when `fetchAllOffers()` succeeds.
|
|
31
|
+
* Returns `ERROR` with:
|
|
32
|
+
* - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
|
|
33
|
+
* - `generic-error` for any other failure
|
|
34
|
+
*/
|
|
35
|
+
declare function useCoinListOffers(options?: UseCoinListOffersOptions): UseCoinListOffersResult;
|
|
36
|
+
|
|
37
|
+
type LoadRequirementsReason = 'not-authenticated' | 'generic-error';
|
|
38
|
+
type LoadRequirementsState = {
|
|
39
|
+
type: 'LOADING';
|
|
40
|
+
} | {
|
|
41
|
+
type: 'ERROR';
|
|
42
|
+
reason: LoadRequirementsReason;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'CONTENT';
|
|
45
|
+
requirementsByOptionId: Record<OfferOptionId, Requirement[]>;
|
|
46
|
+
statuses: RequirementStatusInfo[];
|
|
47
|
+
};
|
|
48
|
+
interface UseCoinListRequirementsOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Requirements data pre-fetched on the server (e.g. via
|
|
51
|
+
* `CoinListServer.fetchOfferRequirements()` + `fetchRequirementStatuses()`).
|
|
52
|
+
* When provided, the hook uses this data as-is and skips the initial client-side fetch.
|
|
53
|
+
* Calling `refetch()` will still trigger a fresh fetch.
|
|
54
|
+
*/
|
|
55
|
+
serverData?: {
|
|
56
|
+
requirementsByOptionId: Record<OfferOptionId, Requirement[]>;
|
|
57
|
+
statuses: RequirementStatusInfo[];
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
interface UseCoinListRequirementsResult {
|
|
61
|
+
requirementsState: LoadRequirementsState;
|
|
62
|
+
/** Triggers a re-fetch of requirements and statuses. */
|
|
63
|
+
refetch: () => void;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Loads requirements (grouped by option ID) and requirement statuses for a
|
|
67
|
+
* given offer, then exposes them via a state machine.
|
|
68
|
+
*
|
|
69
|
+
* Pass `serverData` (pre-fetched server-side) to use that data as-is and skip
|
|
70
|
+
* the initial client-side fetch. Calling `refetch()` will still trigger a fresh fetch.
|
|
71
|
+
*
|
|
72
|
+
* Returns `LOADING` while CoinList is initializing or while data is being fetched.
|
|
73
|
+
* Returns `CONTENT` with requirementsByOptionId and statuses on success.
|
|
74
|
+
* Returns `ERROR` with:
|
|
75
|
+
* - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
|
|
76
|
+
* - `generic-error` for any other failure
|
|
77
|
+
*/
|
|
78
|
+
declare function useCoinListRequirements(offerId: OfferId, options?: UseCoinListRequirementsOptions): UseCoinListRequirementsResult;
|
|
79
|
+
|
|
80
|
+
export { type LoadOffersReason as L, type UseCoinListOffersOptions as U, type LoadOffersState as a, type LoadRequirementsReason as b, type LoadRequirementsState as c, type UseCoinListOffersResult as d, type UseCoinListRequirementsOptions as e, type UseCoinListRequirementsResult as f, useCoinListRequirements as g, useCoinListOffers as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coinlist-co/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "CoinList Partner SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/client/index.cjs",
|
|
@@ -96,10 +96,10 @@
|
|
|
96
96
|
"storybook:build": "storybook build",
|
|
97
97
|
"typecheck": "tsc --noEmit",
|
|
98
98
|
"biome:check": "biome check .",
|
|
99
|
-
"lint:fix": "biome check . --write --unsafe",
|
|
100
99
|
"deslop": "deslop --check",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
100
|
+
"lint": "npm run biome:check && npm run deslop",
|
|
101
|
+
"lint:fix": "deslop && biome check . --write --unsafe",
|
|
102
|
+
"check": "npm run typecheck && npm run lint && npm run build && npm run storybook:build && npm run test && npm run test:e2e && npm run test:e2e:browser"
|
|
103
103
|
},
|
|
104
104
|
"repository": {
|
|
105
105
|
"type": "git",
|
package/dist/chunk-32GOUV3L.js
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createCoinListClient
|
|
3
|
-
} from "./chunk-Z5RFQOMS.js";
|
|
4
|
-
|
|
5
|
-
// src/client/CoinListProvider.tsx
|
|
6
|
-
import {
|
|
7
|
-
createContext,
|
|
8
|
-
useEffect,
|
|
9
|
-
useMemo,
|
|
10
|
-
useState
|
|
11
|
-
} from "react";
|
|
12
|
-
import { jsx } from "react/jsx-runtime";
|
|
13
|
-
var CoinListContext = createContext(null);
|
|
14
|
-
function CoinListProvider({ config, children }) {
|
|
15
|
-
const [isReady, setIsReady] = useState(false);
|
|
16
|
-
const coinlist = useMemo(() => createCoinListClient(config), [config]);
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
let isCancelled = false;
|
|
19
|
-
if (coinlist.getAuthState() === "unknown") {
|
|
20
|
-
coinlist.init().then(() => {
|
|
21
|
-
if (!isCancelled) {
|
|
22
|
-
setIsReady(true);
|
|
23
|
-
}
|
|
24
|
-
}).catch(() => {
|
|
25
|
-
if (!isCancelled) {
|
|
26
|
-
setIsReady(true);
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
} else {
|
|
30
|
-
setIsReady(true);
|
|
31
|
-
}
|
|
32
|
-
return () => {
|
|
33
|
-
isCancelled = true;
|
|
34
|
-
};
|
|
35
|
-
}, [coinlist]);
|
|
36
|
-
const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);
|
|
37
|
-
return /* @__PURE__ */ jsx(CoinListContext.Provider, { value, children });
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// src/client/hooks/useCoinList.ts
|
|
41
|
-
import { useContext } from "react";
|
|
42
|
-
function useCoinList() {
|
|
43
|
-
const context = useContext(CoinListContext);
|
|
44
|
-
if (context === null) {
|
|
45
|
-
throw new CoinListClientInitializationError();
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
isReady: context.isReady,
|
|
49
|
-
coinlist: context.coinlist
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
var CoinListClientInitializationError = class extends Error {
|
|
53
|
-
constructor(message = "useCoinList() must be used within CoinListProvider. Wrap your app with <CoinListProvider config={...}>.") {
|
|
54
|
-
super(message);
|
|
55
|
-
this.name = "CoinListClientInitializationError";
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// src/client/hooks/useCompleteCoinListOAuth.ts
|
|
60
|
-
import { useEffect as useEffect2, useRef } from "react";
|
|
61
|
-
function useCompleteCoinListOAuth(options) {
|
|
62
|
-
const { coinlist } = useCoinList();
|
|
63
|
-
const postOAuthCompleteRef = useRef(options.postOAuthComplete);
|
|
64
|
-
const onFailureRef = useRef(options.onFailure);
|
|
65
|
-
const onSuccessRef = useRef(options.onSuccess);
|
|
66
|
-
postOAuthCompleteRef.current = options.postOAuthComplete;
|
|
67
|
-
onFailureRef.current = options.onFailure;
|
|
68
|
-
onSuccessRef.current = options.onSuccess;
|
|
69
|
-
const hasStartedExchangeRef = useRef(false);
|
|
70
|
-
useEffect2(() => {
|
|
71
|
-
if (typeof window === "undefined") return;
|
|
72
|
-
const params = new URLSearchParams(window.location.search);
|
|
73
|
-
if (!params.has("code") && !params.has("error")) return;
|
|
74
|
-
if (hasStartedExchangeRef.current) return;
|
|
75
|
-
const oauthResult = coinlist.completeOAuth();
|
|
76
|
-
if (oauthResult.type === "error") {
|
|
77
|
-
void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(
|
|
78
|
-
() => {
|
|
79
|
-
}
|
|
80
|
-
);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
hasStartedExchangeRef.current = true;
|
|
84
|
-
let cancelled = false;
|
|
85
|
-
void (async () => {
|
|
86
|
-
try {
|
|
87
|
-
const ok = await postOAuthCompleteRef.current({
|
|
88
|
-
code: oauthResult.code,
|
|
89
|
-
codeVerifier: oauthResult.codeVerifier
|
|
90
|
-
});
|
|
91
|
-
if (cancelled) return;
|
|
92
|
-
if (!ok) {
|
|
93
|
-
hasStartedExchangeRef.current = false;
|
|
94
|
-
await onFailureRef.current("complete_request_failed");
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
await coinlist.init();
|
|
98
|
-
if (cancelled) return;
|
|
99
|
-
await onSuccessRef.current();
|
|
100
|
-
} catch {
|
|
101
|
-
if (cancelled) return;
|
|
102
|
-
hasStartedExchangeRef.current = false;
|
|
103
|
-
await onFailureRef.current("complete_request_failed");
|
|
104
|
-
}
|
|
105
|
-
})();
|
|
106
|
-
return () => {
|
|
107
|
-
cancelled = true;
|
|
108
|
-
hasStartedExchangeRef.current = false;
|
|
109
|
-
};
|
|
110
|
-
}, [coinlist]);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export {
|
|
114
|
-
CoinListProvider,
|
|
115
|
-
useCoinList,
|
|
116
|
-
useCompleteCoinListOAuth
|
|
117
|
-
};
|
|
118
|
-
//# sourceMappingURL=chunk-32GOUV3L.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/CoinListProvider.tsx","../src/client/hooks/useCoinList.ts","../src/client/hooks/useCompleteCoinListOAuth.ts"],"sourcesContent":["/**\n * Global CoinList initialization for React apps.\n * Wrap your app once at the root; use useCoinList() anywhere below.\n */\n\nimport {\n createContext,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n} from 'react';\nimport {\n type ClientConfig,\n type CoinListClient,\n createCoinListClient,\n} from '@/client/core/coinlist-client';\n\nexport type CoinListContextValue = {\n coinlist: CoinListClient;\n isReady: boolean;\n};\n\nexport const CoinListContext = createContext<CoinListContextValue | null>(null);\n\nexport type CoinListProviderProps = {\n config: ClientConfig;\n children: ReactNode;\n};\n\n/**\n * Provide CoinList (api + config) to the tree. Initialize once at app root with your config.\n */\nexport function CoinListProvider({ config, children }: CoinListProviderProps) {\n const [isReady, setIsReady] = useState(false);\n const coinlist = useMemo(() => createCoinListClient(config), [config]);\n\n useEffect(() => {\n let isCancelled = false;\n if (coinlist.getAuthState() === 'unknown') {\n coinlist\n .init()\n .then(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n })\n .catch(() => {\n if (!isCancelled) {\n setIsReady(true);\n }\n });\n } else {\n setIsReady(true);\n }\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist]);\n\n const value = useMemo(() => ({ coinlist, isReady }), [coinlist, isReady]);\n\n return (\n <CoinListContext.Provider value={value}>\n {children}\n </CoinListContext.Provider>\n );\n}\n","import { useContext } from 'react';\nimport { CoinListContext } from '@/client/CoinListProvider';\nimport type { CoinListClient } from '@/client/core/coinlist-client';\n\nexport interface UseCoinListResult {\n /**\n * Indicates whether the CoinList client has been initialized and ready to use.\n * While isReady is false, then the current user state will be `unknown`.\n */\n isReady: boolean;\n coinlist: CoinListClient;\n}\n\nexport function useCoinList(): UseCoinListResult {\n const context = useContext(CoinListContext);\n if (context === null) {\n throw new CoinListClientInitializationError();\n }\n\n return {\n isReady: context.isReady,\n coinlist: context.coinlist,\n };\n}\n\nexport class CoinListClientInitializationError extends Error {\n constructor(\n message = 'useCoinList() must be used within CoinListProvider. Wrap your app with <CoinListProvider config={...}>.'\n ) {\n super(message);\n this.name = 'CoinListClientInitializationError';\n }\n}\n","import { useEffect, useRef } from 'react';\nimport type { OauthClientErrorReason } from '@/client/core/types/client-types';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport type { AuthorizationCode, CodeVerifier } from '@/shared/types/oauth';\n\n/**\n * Reasons passed to {@link UseCompleteCoinListOAuthOptions.onFailure} when the\n * OAuth callback cannot be completed. Includes PKCE / redirect validation\n * errors from {@link CoinListClient.completeOAuth} and a dedicated value when\n * {@link UseCompleteCoinListOAuthOptions.postOAuthComplete} fails or rejects.\n */\nexport type CompleteCoinListOAuthFailureReason =\n | OauthClientErrorReason\n | 'complete_request_failed';\n\nexport interface UseCompleteCoinListOAuthOptions {\n /**\n * Exchange the authorization code on your backend (e.g. POST to your API).\n * Return `true` when the session was established successfully, `false` when\n * the request completed but signing in failed. Rejections are treated like\n * `false` and reported as {@link CompleteCoinListOAuthFailureReason}\n * `\"complete_request_failed\"`.\n */\n postOAuthComplete: (payload: {\n code: AuthorizationCode;\n codeVerifier: CodeVerifier;\n }) => Promise<boolean>;\n /**\n * Called when the user denied access (`error` query parameter), when\n * {@link CoinListClient.completeOAuth} fails PKCE/state validation, or when\n * {@link UseCompleteCoinListOAuthOptions.postOAuthComplete} fails.\n */\n onFailure: (\n reason: CompleteCoinListOAuthFailureReason\n ) => void | Promise<void>;\n /** Invoked after {@link UseCompleteCoinListOAuthOptions.postOAuthComplete} succeeds and {@link CoinListClient.init} has refreshed the client session. */\n onSuccess: () => void | Promise<void>;\n}\n\n/**\n * Runs the CoinList OAuth callback once on mount: validates the redirect URL via\n * {@link CoinListClient.completeOAuth}, exchanges the code via {@link UseCompleteCoinListOAuthOptions.postOAuthComplete},\n * refreshes tokens with {@link CoinListClient.init}, then calls {@link UseCompleteCoinListOAuthOptions.onSuccess}.\n *\n * Framework-agnostic: reads `window.location` like {@link CoinListClient.completeOAuth}. Supply\n * {@link UseCompleteCoinListOAuthOptions.postOAuthComplete}, {@link UseCompleteCoinListOAuthOptions.onFailure},\n * and {@link UseCompleteCoinListOAuthOptions.onSuccess} to perform redirects or routing in your app.\n *\n * Must be used within {@link CoinListProvider}.\n */\nexport function useCompleteCoinListOAuth(\n options: UseCompleteCoinListOAuthOptions\n): void {\n const { coinlist } = useCoinList();\n\n const postOAuthCompleteRef = useRef(options.postOAuthComplete);\n const onFailureRef = useRef(options.onFailure);\n const onSuccessRef = useRef(options.onSuccess);\n\n postOAuthCompleteRef.current = options.postOAuthComplete;\n onFailureRef.current = options.onFailure;\n onSuccessRef.current = options.onSuccess;\n\n const hasStartedExchangeRef = useRef(false);\n\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const params = new URLSearchParams(window.location.search);\n if (!params.has('code') && !params.has('error')) return;\n\n if (hasStartedExchangeRef.current) return;\n\n const oauthResult = coinlist.completeOAuth();\n if (oauthResult.type === 'error') {\n void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(\n () => {}\n );\n return;\n }\n\n hasStartedExchangeRef.current = true;\n let cancelled = false;\n\n void (async () => {\n try {\n const ok = await postOAuthCompleteRef.current({\n code: oauthResult.code,\n codeVerifier: oauthResult.codeVerifier,\n });\n\n if (cancelled) return;\n\n if (!ok) {\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n return;\n }\n\n await coinlist.init();\n\n if (cancelled) return;\n\n await onSuccessRef.current();\n } catch {\n if (cancelled) return;\n hasStartedExchangeRef.current = false;\n await onFailureRef.current('complete_request_failed');\n }\n })();\n\n return () => {\n cancelled = true;\n hasStartedExchangeRef.current = false;\n };\n }, [coinlist]);\n}\n"],"mappings":"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","names":["useEffect","useEffect"]}
|
package/dist/chunk-G3B4RLXP.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useCoinList
|
|
3
|
-
} from "./chunk-32GOUV3L.js";
|
|
4
|
-
import {
|
|
5
|
-
NotAuthenticatedError
|
|
6
|
-
} from "./chunk-Z5RFQOMS.js";
|
|
7
|
-
|
|
8
|
-
// src/client/hooks/useCoinListOfferDetails.ts
|
|
9
|
-
import { useEffect, useState } from "react";
|
|
10
|
-
var LOADING_STATE = { type: "LOADING" };
|
|
11
|
-
function useCoinListOfferDetails(offerId) {
|
|
12
|
-
const { coinlist, isReady } = useCoinList();
|
|
13
|
-
const [offerDetailsState, setOfferDetailsState] = useState(LOADING_STATE);
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
let isCancelled = false;
|
|
16
|
-
if (!isReady) {
|
|
17
|
-
setOfferDetailsState(LOADING_STATE);
|
|
18
|
-
return () => {
|
|
19
|
-
isCancelled = true;
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
setOfferDetailsState(LOADING_STATE);
|
|
23
|
-
coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
|
|
24
|
-
if (!isCancelled) {
|
|
25
|
-
setOfferDetailsState({ type: "CONTENT", offerDetail });
|
|
26
|
-
}
|
|
27
|
-
}).catch((error) => {
|
|
28
|
-
if (!isCancelled) {
|
|
29
|
-
const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
|
|
30
|
-
setOfferDetailsState({ type: "ERROR", reason });
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
return () => {
|
|
34
|
-
isCancelled = true;
|
|
35
|
-
};
|
|
36
|
-
}, [coinlist, isReady, offerId]);
|
|
37
|
-
return { offerDetailsState };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// src/client/hooks/useCoinListOffers.ts
|
|
41
|
-
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
42
|
-
var LOADING_STATE2 = { type: "LOADING" };
|
|
43
|
-
function useCoinListOffers() {
|
|
44
|
-
const { coinlist, isReady } = useCoinList();
|
|
45
|
-
const [offersState, setOffersState] = useState2(LOADING_STATE2);
|
|
46
|
-
useEffect2(() => {
|
|
47
|
-
let isCancelled = false;
|
|
48
|
-
if (!isReady) {
|
|
49
|
-
setOffersState(LOADING_STATE2);
|
|
50
|
-
return () => {
|
|
51
|
-
isCancelled = true;
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
setOffersState(LOADING_STATE2);
|
|
55
|
-
coinlist.fetchAllOffers().then((offers) => {
|
|
56
|
-
if (!isCancelled) {
|
|
57
|
-
setOffersState({ type: "CONTENT", offers });
|
|
58
|
-
}
|
|
59
|
-
}).catch((error) => {
|
|
60
|
-
if (!isCancelled) {
|
|
61
|
-
const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
|
|
62
|
-
setOffersState({ type: "ERROR", reason });
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
return () => {
|
|
66
|
-
isCancelled = true;
|
|
67
|
-
};
|
|
68
|
-
}, [coinlist, isReady]);
|
|
69
|
-
return { offersState };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export {
|
|
73
|
-
useCoinListOfferDetails,
|
|
74
|
-
useCoinListOffers
|
|
75
|
-
};
|
|
76
|
-
//# sourceMappingURL=chunk-G3B4RLXP.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/hooks/useCoinListOfferDetails.ts","../src/client/hooks/useCoinListOffers.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { OfferId } from '@/shared/types/offer';\nimport type { OfferDetail } from '@/shared/types/offer-detail';\n\nexport type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOfferDetailsState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOfferDetailsReason;\n }\n | {\n type: 'CONTENT';\n offerDetail: OfferDetail;\n };\n\nexport interface UseCoinListOfferDetailsResult {\n offerDetailsState: LoadOfferDetailsState;\n}\n\nconst LOADING_STATE: LoadOfferDetailsState = { type: 'LOADING' };\n\n/**\n * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.\n *\n * Returns `LOADING` while CoinList is initializing or while details are being fetched.\n * Returns `CONTENT` with the offer when `fetchOfferDetails()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useCoinListOfferDetails(\n offerId: OfferId\n): UseCoinListOfferDetailsResult {\n const { coinlist, isReady } = useCoinList();\n const [offerDetailsState, setOfferDetailsState] =\n useState<LoadOfferDetailsState>(LOADING_STATE);\n\n useEffect(() => {\n let isCancelled = false;\n\n if (!isReady) {\n setOfferDetailsState(LOADING_STATE);\n return () => {\n isCancelled = true;\n };\n }\n\n setOfferDetailsState(LOADING_STATE);\n coinlist\n .fetchOfferDetails(offerId)\n .then((offerDetail) => {\n if (!isCancelled) {\n setOfferDetailsState({ type: 'CONTENT', offerDetail });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOfferDetailsReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOfferDetailsState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady, offerId]);\n\n return { offerDetailsState };\n}\n","import { useEffect, useState } from 'react';\nimport { useCoinList } from '@/client/hooks/useCoinList';\nimport { NotAuthenticatedError } from '@/shared/types/errors';\nimport type { Offer } from '@/shared/types/offer';\n\nexport type LoadOffersReason = 'not-authenticated' | 'generic-error';\n\nexport type LoadOffersState =\n | {\n type: 'LOADING';\n }\n | {\n type: 'ERROR';\n reason: LoadOffersReason;\n }\n | {\n type: 'CONTENT';\n offers: Offer[];\n };\n\nexport interface UseCoinListOffersResult {\n offersState: LoadOffersState;\n}\n\nconst LOADING_STATE: LoadOffersState = { type: 'LOADING' };\n\n/**\n * Loads all CoinList offers for the current user and exposes a UI-friendly state.\n *\n * Returns `LOADING` while CoinList is initializing or while offers are being fetched.\n * Returns `CONTENT` with all offers when `fetchAllOffers()` succeeds.\n * Returns `ERROR` with:\n * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}\n * - `generic-error` for any other failure\n */\nexport function useCoinListOffers(): UseCoinListOffersResult {\n const { coinlist, isReady } = useCoinList();\n const [offersState, setOffersState] =\n useState<LoadOffersState>(LOADING_STATE);\n\n useEffect(() => {\n let isCancelled = false;\n\n // Wait until CoinListProvider finishes auth initialization.\n if (!isReady) {\n setOffersState(LOADING_STATE);\n return () => {\n isCancelled = true;\n };\n }\n\n setOffersState(LOADING_STATE);\n coinlist\n .fetchAllOffers()\n .then((offers) => {\n if (!isCancelled) {\n setOffersState({ type: 'CONTENT', offers });\n }\n })\n .catch((error: unknown) => {\n if (!isCancelled) {\n const reason: LoadOffersReason =\n error instanceof NotAuthenticatedError\n ? 'not-authenticated'\n : 'generic-error';\n setOffersState({ type: 'ERROR', reason });\n }\n });\n\n return () => {\n isCancelled = true;\n };\n }, [coinlist, isReady]);\n\n return { offersState };\n}\n"],"mappings":";;;;;;;;AAAA,SAAS,WAAW,gBAAgB;AAyBpC,IAAM,gBAAuC,EAAE,MAAM,UAAU;AAWxD,SAAS,wBACd,SAC+B;AAC/B,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,CAAC,mBAAmB,oBAAoB,IAC5C,SAAgC,aAAa;AAE/C,YAAU,MAAM;AACd,QAAI,cAAc;AAElB,QAAI,CAAC,SAAS;AACZ,2BAAqB,aAAa;AAClC,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,yBAAqB,aAAa;AAClC,aACG,kBAAkB,OAAO,EACzB,KAAK,CAAC,gBAAgB;AACrB,UAAI,CAAC,aAAa;AAChB,6BAAqB,EAAE,MAAM,WAAW,YAAY,CAAC;AAAA,MACvD;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,6BAAqB,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAChD;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,SAAS,OAAO,CAAC;AAE/B,SAAO,EAAE,kBAAkB;AAC7B;;;AC7EA,SAAS,aAAAA,YAAW,YAAAC,iBAAgB;AAwBpC,IAAMC,iBAAiC,EAAE,MAAM,UAAU;AAWlD,SAAS,oBAA6C;AAC3D,QAAM,EAAE,UAAU,QAAQ,IAAI,YAAY;AAC1C,QAAM,CAAC,aAAa,cAAc,IAChCC,UAA0BD,cAAa;AAEzC,EAAAE,WAAU,MAAM;AACd,QAAI,cAAc;AAGlB,QAAI,CAAC,SAAS;AACZ,qBAAeF,cAAa;AAC5B,aAAO,MAAM;AACX,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,mBAAeA,cAAa;AAC5B,aACG,eAAe,EACf,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,aAAa;AAChB,uBAAe,EAAE,MAAM,WAAW,OAAO,CAAC;AAAA,MAC5C;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,CAAC,aAAa;AAChB,cAAM,SACJ,iBAAiB,wBACb,sBACA;AACN,uBAAe,EAAE,MAAM,SAAS,OAAO,CAAC;AAAA,MAC1C;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,oBAAc;AAAA,IAChB;AAAA,EACF,GAAG,CAAC,UAAU,OAAO,CAAC;AAEtB,SAAO,EAAE,YAAY;AACvB;","names":["useEffect","useState","LOADING_STATE","useState","useEffect"]}
|