@coinlist-co/react 0.0.2 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/{chunk-S56KGI3U.js → chunk-6CG7JT7Q.js} +255 -45
  2. package/dist/chunk-6CG7JT7Q.js.map +1 -0
  3. package/dist/chunk-DLEKT4T4.js +118 -0
  4. package/dist/chunk-DLEKT4T4.js.map +1 -0
  5. package/dist/{chunk-W6ZBUBLA.js → chunk-GRVV7NLV.js} +33 -4
  6. package/dist/chunk-GRVV7NLV.js.map +1 -0
  7. package/dist/chunk-WFA6X7E2.js +76 -0
  8. package/dist/chunk-WFA6X7E2.js.map +1 -0
  9. package/dist/client/components/index.cjs +188 -2
  10. package/dist/client/components/index.cjs.map +1 -1
  11. package/dist/client/components/index.d.cts +41 -1
  12. package/dist/client/components/index.d.ts +41 -1
  13. package/dist/client/components/index.js +149 -4
  14. package/dist/client/components/index.js.map +1 -1
  15. package/dist/client/core/index.cjs +259 -6
  16. package/dist/client/core/index.cjs.map +1 -1
  17. package/dist/client/core/index.d.cts +4 -3
  18. package/dist/client/core/index.d.ts +4 -3
  19. package/dist/client/core/index.js +34 -4
  20. package/dist/client/hooks/index.cjs +136 -2
  21. package/dist/client/hooks/index.cjs.map +1 -1
  22. package/dist/client/hooks/index.d.cts +52 -11
  23. package/dist/client/hooks/index.d.ts +52 -11
  24. package/dist/client/hooks/index.js +13 -5
  25. package/dist/client/index.cjs +315 -6
  26. package/dist/client/index.cjs.map +1 -1
  27. package/dist/client/index.d.cts +6 -4
  28. package/dist/client/index.d.ts +6 -4
  29. package/dist/client/index.js +38 -6
  30. package/dist/client/styles.css +1 -1
  31. package/dist/coinlist-client-BiA8a2yU.d.ts +272 -0
  32. package/dist/coinlist-client-DXKFDGhP.d.cts +272 -0
  33. package/dist/newtype-yKTvFdg_.d.cts +6 -0
  34. package/dist/newtype-yKTvFdg_.d.ts +6 -0
  35. package/dist/{oauth-session-g0OPJNKn.d.ts → oauth-session-DgItaMKN.d.cts} +2 -5
  36. package/dist/{oauth-session-g0OPJNKn.d.cts → oauth-session-DnKDI5ou.d.ts} +2 -5
  37. package/dist/offer-D6p_Ijme.d.cts +30 -0
  38. package/dist/offer-DnFEFJw9.d.ts +30 -0
  39. package/dist/server/index.cjs +30 -1
  40. package/dist/server/index.cjs.map +1 -1
  41. package/dist/server/index.d.cts +3 -2
  42. package/dist/server/index.d.ts +3 -2
  43. package/dist/server/index.js +1 -1
  44. package/dist/useCompleteCoinListOAuth-6Z4DGuiH.d.cts +55 -0
  45. package/dist/useCompleteCoinListOAuth-C3G1Vsf8.d.ts +55 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-CGIPLHD3.js +0 -63
  48. package/dist/chunk-CGIPLHD3.js.map +0 -1
  49. package/dist/chunk-S56KGI3U.js.map +0 -1
  50. package/dist/chunk-W6ZBUBLA.js.map +0 -1
  51. package/dist/coinlist-client-BH_Cn_7u.d.cts +0 -71
  52. package/dist/coinlist-client-fkB3J-2a.d.ts +0 -71
@@ -4,8 +4,23 @@ import {
4
4
  UserId
5
5
  } from "../../chunk-YJQMJFA7.js";
6
6
  import {
7
- createCoinListClient
8
- } from "../../chunk-S56KGI3U.js";
7
+ Cursor,
8
+ FaqItem,
9
+ Link,
10
+ Milestone,
11
+ Offer,
12
+ OfferDetail,
13
+ OfferId,
14
+ OfferOption,
15
+ OfferOptionId,
16
+ OfferOptionSlug,
17
+ OfferSlug,
18
+ PaginatedResponse,
19
+ PaginationParams,
20
+ TermItem,
21
+ createCoinListClient,
22
+ fetchAllPages
23
+ } from "../../chunk-6CG7JT7Q.js";
9
24
  import {
10
25
  OAuthRefreshToken,
11
26
  OAuthSession
@@ -17,19 +32,34 @@ import {
17
32
  CodeChallenge,
18
33
  CodeVerifier,
19
34
  RedirectUri
20
- } from "../../chunk-W6ZBUBLA.js";
35
+ } from "../../chunk-GRVV7NLV.js";
21
36
  export {
22
37
  AuthorizationCode,
23
38
  ClientId,
24
39
  ClientSecret,
25
40
  CodeChallenge,
26
41
  CodeVerifier,
42
+ Cursor,
43
+ FaqItem,
44
+ Link,
45
+ Milestone,
27
46
  OAuthRefreshToken,
28
47
  OAuthSession,
48
+ Offer,
49
+ OfferDetail,
50
+ OfferId,
51
+ OfferOption,
52
+ OfferOptionId,
53
+ OfferOptionSlug,
54
+ OfferSlug,
55
+ PaginatedResponse,
56
+ PaginationParams,
29
57
  RedirectUri,
58
+ TermItem,
30
59
  User,
31
60
  UserEmail,
32
61
  UserId,
33
- createCoinListClient
62
+ createCoinListClient,
63
+ fetchAllPages
34
64
  };
35
65
  //# sourceMappingURL=index.js.map
@@ -20,7 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/client/hooks/index.ts
21
21
  var hooks_exports = {};
22
22
  __export(hooks_exports, {
23
- useCoinList: () => useCoinList
23
+ useCoinList: () => useCoinList,
24
+ useCoinListOfferDetails: () => useCoinListOfferDetails,
25
+ useCoinListOffers: () => useCoinListOffers,
26
+ useCompleteCoinListOAuth: () => useCompleteCoinListOAuth
24
27
  });
25
28
  module.exports = __toCommonJS(hooks_exports);
26
29
 
@@ -29,6 +32,16 @@ var import_react2 = require("react");
29
32
 
30
33
  // src/client/CoinListProvider.tsx
31
34
  var import_react = require("react");
35
+
36
+ // src/shared/types/errors.ts
37
+ var NotAuthenticatedError = class extends Error {
38
+ constructor(message = "The user is not authenticated. Go through the OAuth flow first!") {
39
+ super(message);
40
+ this.name = "NotAuthenticatedError";
41
+ }
42
+ };
43
+
44
+ // src/client/CoinListProvider.tsx
32
45
  var import_jsx_runtime = require("react/jsx-runtime");
33
46
  var CoinListContext = (0, import_react.createContext)(null);
34
47
 
@@ -49,8 +62,129 @@ var CoinListClientInitializationError = class extends Error {
49
62
  this.name = "CoinListClientInitializationError";
50
63
  }
51
64
  };
65
+
66
+ // src/client/hooks/useCoinListOfferDetails.ts
67
+ var import_react3 = require("react");
68
+ var LOADING_STATE = { type: "LOADING" };
69
+ function useCoinListOfferDetails(offerId) {
70
+ const { coinlist, isReady } = useCoinList();
71
+ const [offerDetailsState, setOfferDetailsState] = (0, import_react3.useState)(LOADING_STATE);
72
+ (0, import_react3.useEffect)(() => {
73
+ let isCancelled = false;
74
+ if (!isReady) {
75
+ setOfferDetailsState(LOADING_STATE);
76
+ return () => {
77
+ isCancelled = true;
78
+ };
79
+ }
80
+ setOfferDetailsState(LOADING_STATE);
81
+ coinlist.fetchOfferDetails(offerId).then((offerDetail) => {
82
+ if (!isCancelled) {
83
+ setOfferDetailsState({ type: "CONTENT", offerDetail });
84
+ }
85
+ }).catch((error) => {
86
+ if (!isCancelled) {
87
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
88
+ setOfferDetailsState({ type: "ERROR", reason });
89
+ }
90
+ });
91
+ return () => {
92
+ isCancelled = true;
93
+ };
94
+ }, [coinlist, isReady, offerId]);
95
+ return { offerDetailsState };
96
+ }
97
+
98
+ // src/client/hooks/useCoinListOffers.ts
99
+ var import_react4 = require("react");
100
+ var LOADING_STATE2 = { type: "LOADING" };
101
+ function useCoinListOffers() {
102
+ const { coinlist, isReady } = useCoinList();
103
+ const [offersState, setOffersState] = (0, import_react4.useState)(LOADING_STATE2);
104
+ (0, import_react4.useEffect)(() => {
105
+ let isCancelled = false;
106
+ if (!isReady) {
107
+ setOffersState(LOADING_STATE2);
108
+ return () => {
109
+ isCancelled = true;
110
+ };
111
+ }
112
+ setOffersState(LOADING_STATE2);
113
+ coinlist.fetchAllOffers().then((offers) => {
114
+ if (!isCancelled) {
115
+ setOffersState({ type: "CONTENT", offers });
116
+ }
117
+ }).catch((error) => {
118
+ if (!isCancelled) {
119
+ const reason = error instanceof NotAuthenticatedError ? "not-authenticated" : "generic-error";
120
+ setOffersState({ type: "ERROR", reason });
121
+ }
122
+ });
123
+ return () => {
124
+ isCancelled = true;
125
+ };
126
+ }, [coinlist, isReady]);
127
+ return { offersState };
128
+ }
129
+
130
+ // src/client/hooks/useCompleteCoinListOAuth.ts
131
+ var import_react5 = require("react");
132
+ function useCompleteCoinListOAuth(options) {
133
+ const { coinlist } = useCoinList();
134
+ const postOAuthCompleteRef = (0, import_react5.useRef)(options.postOAuthComplete);
135
+ const onFailureRef = (0, import_react5.useRef)(options.onFailure);
136
+ const onSuccessRef = (0, import_react5.useRef)(options.onSuccess);
137
+ postOAuthCompleteRef.current = options.postOAuthComplete;
138
+ onFailureRef.current = options.onFailure;
139
+ onSuccessRef.current = options.onSuccess;
140
+ const hasStartedExchangeRef = (0, import_react5.useRef)(false);
141
+ (0, import_react5.useEffect)(() => {
142
+ if (typeof window === "undefined") return;
143
+ const params = new URLSearchParams(window.location.search);
144
+ if (!params.has("code") && !params.has("error")) return;
145
+ if (hasStartedExchangeRef.current) return;
146
+ const oauthResult = coinlist.completeOAuth();
147
+ if (oauthResult.type === "error") {
148
+ void Promise.resolve(onFailureRef.current(oauthResult.reason)).catch(
149
+ () => {
150
+ }
151
+ );
152
+ return;
153
+ }
154
+ hasStartedExchangeRef.current = true;
155
+ let cancelled = false;
156
+ void (async () => {
157
+ try {
158
+ const ok = await postOAuthCompleteRef.current({
159
+ code: oauthResult.code,
160
+ codeVerifier: oauthResult.codeVerifier
161
+ });
162
+ if (cancelled) return;
163
+ if (!ok) {
164
+ hasStartedExchangeRef.current = false;
165
+ await onFailureRef.current("complete_request_failed");
166
+ return;
167
+ }
168
+ await coinlist.init();
169
+ if (cancelled) return;
170
+ await onSuccessRef.current();
171
+ } catch {
172
+ if (cancelled) return;
173
+ hasStartedExchangeRef.current = false;
174
+ await onFailureRef.current("complete_request_failed");
175
+ }
176
+ })();
177
+ return () => {
178
+ cancelled = true;
179
+ hasStartedExchangeRef.current = false;
180
+ };
181
+ }, [coinlist]);
182
+ }
52
183
  // Annotate the CommonJS export names for ESM import in node:
53
184
  0 && (module.exports = {
54
- useCoinList
185
+ useCoinList,
186
+ useCoinListOfferDetails,
187
+ useCoinListOffers,
188
+ useCompleteCoinListOAuth
55
189
  });
56
190
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/client/hooks/index.ts","../../../src/client/hooks/useCoinList.ts","../../../src/client/CoinListProvider.tsx"],"sourcesContent":["export { useCoinList } from '@/client/hooks/useCoinList';\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","/**\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"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAA2B;;;ACK3B,mBAMO;AAqDH;AAzCG,IAAM,sBAAkB,4BAA2C,IAAI;;;ADVvE,SAAS,cAAiC;AAC/C,QAAM,cAAU,0BAAW,eAAe;AAC1C,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI,kCAAkC;AAAA,EAC9C;AAEA,SAAO;AAAA,IACL,SAAS,QAAQ;AAAA,IACjB,UAAU,QAAQ;AAAA,EACpB;AACF;AAEO,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAC3D,YACE,UAAU,2GACV;AACA,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":["import_react"]}
1
+ {"version":3,"sources":["../../../src/client/hooks/index.ts","../../../src/client/hooks/useCoinList.ts","../../../src/client/CoinListProvider.tsx","../../../src/shared/types/errors.ts","../../../src/client/hooks/useCoinListOfferDetails.ts","../../../src/client/hooks/useCoinListOffers.ts","../../../src/client/hooks/useCompleteCoinListOAuth.ts"],"sourcesContent":["export { useCoinList } from '@/client/hooks/useCoinList';\nexport { useCoinListOfferDetails } from '@/client/hooks/useCoinListOfferDetails';\nexport { useCoinListOffers } from '@/client/hooks/useCoinListOffers';\nexport {\n type CompleteCoinListOAuthFailureReason,\n type UseCompleteCoinListOAuthOptions,\n useCompleteCoinListOAuth,\n} from '@/client/hooks/useCompleteCoinListOAuth';\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","/**\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","/**\n * Error thrown when a feature or code path is not yet implemented.\n */\nexport class NotImplementedError extends Error {\n constructor(message = 'Not implemented yet') {\n super(message);\n this.name = 'NotImplementedError';\n }\n}\n\n/**\n * Error thrown when accessing a feature that requires authentication\n * without being authenticated.\n */\nexport class NotAuthenticatedError extends Error {\n constructor(\n message = 'The user is not authenticated. Go through the OAuth flow first!'\n ) {\n super(message);\n this.name = 'NotAuthenticatedError';\n }\n}\n","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","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":["import_react","import_react","import_react","LOADING_STATE","import_react"]}
@@ -1,14 +1,55 @@
1
- import { a as CoinListClient } from '../../coinlist-client-BH_Cn_7u.cjs';
2
- import '../../oauth-session-g0OPJNKn.cjs';
1
+ export { C as CompleteCoinListOAuthFailureReason, U as UseCompleteCoinListOAuthOptions, u as useCoinList, a as useCompleteCoinListOAuth } from '../../useCompleteCoinListOAuth-6Z4DGuiH.cjs';
2
+ import { a as OfferId, O as Offer } from '../../offer-D6p_Ijme.cjs';
3
+ import { d as OfferDetail } from '../../coinlist-client-DXKFDGhP.cjs';
4
+ import '../../oauth-session-DgItaMKN.cjs';
5
+ import '../../newtype-yKTvFdg_.cjs';
3
6
 
4
- interface UseCoinListResult {
5
- /**
6
- * Indicates whether the CoinList client has been initialized and ready to use.
7
- * While isReady is false, then the current user state will be `unknown`.
8
- */
9
- isReady: boolean;
10
- coinlist: CoinListClient;
7
+ type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';
8
+ type LoadOfferDetailsState = {
9
+ type: 'LOADING';
10
+ } | {
11
+ type: 'ERROR';
12
+ reason: LoadOfferDetailsReason;
13
+ } | {
14
+ type: 'CONTENT';
15
+ offerDetail: OfferDetail;
16
+ };
17
+ interface UseCoinListOfferDetailsResult {
18
+ offerDetailsState: LoadOfferDetailsState;
11
19
  }
12
- declare function useCoinList(): UseCoinListResult;
20
+ /**
21
+ * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.
22
+ *
23
+ * Returns `LOADING` while CoinList is initializing or while details are being fetched.
24
+ * Returns `CONTENT` with the offer when `fetchOfferDetails()` succeeds.
25
+ * Returns `ERROR` with:
26
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
27
+ * - `generic-error` for any other failure
28
+ */
29
+ declare function useCoinListOfferDetails(offerId: OfferId): UseCoinListOfferDetailsResult;
13
30
 
14
- export { useCoinList };
31
+ type LoadOffersReason = 'not-authenticated' | 'generic-error';
32
+ type LoadOffersState = {
33
+ type: 'LOADING';
34
+ } | {
35
+ type: 'ERROR';
36
+ reason: LoadOffersReason;
37
+ } | {
38
+ type: 'CONTENT';
39
+ offers: Offer[];
40
+ };
41
+ interface UseCoinListOffersResult {
42
+ offersState: LoadOffersState;
43
+ }
44
+ /**
45
+ * Loads all CoinList offers for the current user and exposes a UI-friendly state.
46
+ *
47
+ * Returns `LOADING` while CoinList is initializing or while offers are being fetched.
48
+ * Returns `CONTENT` with all offers when `fetchAllOffers()` succeeds.
49
+ * Returns `ERROR` with:
50
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
51
+ * - `generic-error` for any other failure
52
+ */
53
+ declare function useCoinListOffers(): UseCoinListOffersResult;
54
+
55
+ export { useCoinListOfferDetails, useCoinListOffers };
@@ -1,14 +1,55 @@
1
- import { a as CoinListClient } from '../../coinlist-client-fkB3J-2a.js';
2
- import '../../oauth-session-g0OPJNKn.js';
1
+ export { C as CompleteCoinListOAuthFailureReason, U as UseCompleteCoinListOAuthOptions, u as useCoinList, a as useCompleteCoinListOAuth } from '../../useCompleteCoinListOAuth-C3G1Vsf8.js';
2
+ import { a as OfferId, O as Offer } from '../../offer-DnFEFJw9.js';
3
+ import { d as OfferDetail } from '../../coinlist-client-BiA8a2yU.js';
4
+ import '../../oauth-session-DnKDI5ou.js';
5
+ import '../../newtype-yKTvFdg_.js';
3
6
 
4
- interface UseCoinListResult {
5
- /**
6
- * Indicates whether the CoinList client has been initialized and ready to use.
7
- * While isReady is false, then the current user state will be `unknown`.
8
- */
9
- isReady: boolean;
10
- coinlist: CoinListClient;
7
+ type LoadOfferDetailsReason = 'not-authenticated' | 'generic-error';
8
+ type LoadOfferDetailsState = {
9
+ type: 'LOADING';
10
+ } | {
11
+ type: 'ERROR';
12
+ reason: LoadOfferDetailsReason;
13
+ } | {
14
+ type: 'CONTENT';
15
+ offerDetail: OfferDetail;
16
+ };
17
+ interface UseCoinListOfferDetailsResult {
18
+ offerDetailsState: LoadOfferDetailsState;
11
19
  }
12
- declare function useCoinList(): UseCoinListResult;
20
+ /**
21
+ * Loads CoinList offer details for a given offer id and exposes a UI-friendly state.
22
+ *
23
+ * Returns `LOADING` while CoinList is initializing or while details are being fetched.
24
+ * Returns `CONTENT` with the offer when `fetchOfferDetails()` succeeds.
25
+ * Returns `ERROR` with:
26
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
27
+ * - `generic-error` for any other failure
28
+ */
29
+ declare function useCoinListOfferDetails(offerId: OfferId): UseCoinListOfferDetailsResult;
13
30
 
14
- export { useCoinList };
31
+ type LoadOffersReason = 'not-authenticated' | 'generic-error';
32
+ type LoadOffersState = {
33
+ type: 'LOADING';
34
+ } | {
35
+ type: 'ERROR';
36
+ reason: LoadOffersReason;
37
+ } | {
38
+ type: 'CONTENT';
39
+ offers: Offer[];
40
+ };
41
+ interface UseCoinListOffersResult {
42
+ offersState: LoadOffersState;
43
+ }
44
+ /**
45
+ * Loads all CoinList offers for the current user and exposes a UI-friendly state.
46
+ *
47
+ * Returns `LOADING` while CoinList is initializing or while offers are being fetched.
48
+ * Returns `CONTENT` with all offers when `fetchAllOffers()` succeeds.
49
+ * Returns `ERROR` with:
50
+ * - `not-authenticated` when fetching fails with {@link NotAuthenticatedError}
51
+ * - `generic-error` for any other failure
52
+ */
53
+ declare function useCoinListOffers(): UseCoinListOffersResult;
54
+
55
+ export { useCoinListOfferDetails, useCoinListOffers };
@@ -1,9 +1,17 @@
1
1
  import {
2
- useCoinList
3
- } from "../../chunk-CGIPLHD3.js";
4
- import "../../chunk-S56KGI3U.js";
5
- import "../../chunk-W6ZBUBLA.js";
2
+ useCoinListOfferDetails,
3
+ useCoinListOffers
4
+ } from "../../chunk-WFA6X7E2.js";
5
+ import {
6
+ useCoinList,
7
+ useCompleteCoinListOAuth
8
+ } from "../../chunk-DLEKT4T4.js";
9
+ import "../../chunk-6CG7JT7Q.js";
10
+ import "../../chunk-GRVV7NLV.js";
6
11
  export {
7
- useCoinList
12
+ useCoinList,
13
+ useCoinListOfferDetails,
14
+ useCoinListOffers,
15
+ useCompleteCoinListOAuth
8
16
  };
9
17
  //# sourceMappingURL=index.js.map