cabalspy-id 0.0.0-stage → 0.5.2

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 (58) hide show
  1. package/CHANGELOG.md +146 -0
  2. package/LICENSE +21 -0
  3. package/README.md +504 -2
  4. package/dist/api.cjs +74 -0
  5. package/dist/api.cjs.map +1 -0
  6. package/dist/api.d.cts +193 -0
  7. package/dist/api.d.ts +193 -0
  8. package/dist/api.js +74 -0
  9. package/dist/api.js.map +1 -0
  10. package/dist/chunk-A2ZAFAWC.cjs +1 -0
  11. package/dist/chunk-A2ZAFAWC.cjs.map +1 -0
  12. package/dist/chunk-ABFIPCBY.cjs +109 -0
  13. package/dist/chunk-ABFIPCBY.cjs.map +1 -0
  14. package/dist/chunk-CJFIOVBA.js +1 -0
  15. package/dist/chunk-CJFIOVBA.js.map +1 -0
  16. package/dist/chunk-DBYCRBVS.js +400 -0
  17. package/dist/chunk-DBYCRBVS.js.map +1 -0
  18. package/dist/chunk-PKFIMBPW.cjs +444 -0
  19. package/dist/chunk-PKFIMBPW.cjs.map +1 -0
  20. package/dist/chunk-ULEBNY2A.cjs +1301 -0
  21. package/dist/chunk-ULEBNY2A.cjs.map +1 -0
  22. package/dist/chunk-VDFCMYLR.cjs +400 -0
  23. package/dist/chunk-VDFCMYLR.cjs.map +1 -0
  24. package/dist/chunk-VOTYIQAY.js +109 -0
  25. package/dist/chunk-VOTYIQAY.js.map +1 -0
  26. package/dist/chunk-XLBO2RSL.js +1301 -0
  27. package/dist/chunk-XLBO2RSL.js.map +1 -0
  28. package/dist/chunk-Z23B5TY6.js +444 -0
  29. package/dist/chunk-Z23B5TY6.js.map +1 -0
  30. package/dist/index.cjs +105 -0
  31. package/dist/index.cjs.map +1 -0
  32. package/dist/index.d.cts +21 -0
  33. package/dist/index.d.ts +21 -0
  34. package/dist/index.js +105 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/react.cjs +361 -0
  37. package/dist/react.cjs.map +1 -0
  38. package/dist/react.d.cts +315 -0
  39. package/dist/react.d.ts +315 -0
  40. package/dist/react.js +333 -0
  41. package/dist/react.js.map +1 -0
  42. package/dist/thesis.cjs +76 -0
  43. package/dist/thesis.cjs.map +1 -0
  44. package/dist/thesis.d.cts +221 -0
  45. package/dist/thesis.d.ts +221 -0
  46. package/dist/thesis.js +76 -0
  47. package/dist/thesis.js.map +1 -0
  48. package/dist/types-UZeY9n1e.d.cts +689 -0
  49. package/dist/types-UZeY9n1e.d.ts +689 -0
  50. package/dist/users-3DAw88_U.d.cts +767 -0
  51. package/dist/users-B4r33i4O.d.ts +767 -0
  52. package/dist/widget.cjs +233 -0
  53. package/dist/widget.cjs.map +1 -0
  54. package/dist/widget.d.cts +226 -0
  55. package/dist/widget.d.ts +226 -0
  56. package/dist/widget.js +233 -0
  57. package/dist/widget.js.map +1 -0
  58. package/package.json +145 -4
package/dist/api.d.cts ADDED
@@ -0,0 +1,193 @@
1
+ export { A as ApiErrorBody, a as AuthenticationError, B as BadRequestError, C as CabalSpyID, b as CabalSpyIDError, c as CabalSpyIDErrorOptions, d as CabalSpyIDOptions, e as CabalSpyIDStream, f as CloseEvent, g as ConnectionError, D as DEFAULT_BASE_URL, h as DEFAULT_STREAM_URL, E as Envelope, H as HandleKind, k as HeaderSource, l as HeartbeatEvent, m as HistoryParams, I as InvalidResponseError, n as LatestTransactionsParams, o as LeaderboardParams, N as NotFoundError, O as OAuthError, P as PermissionError, q as PlanUserLimitError, s as ProfileParams, Q as Query, R as RateLimitError, t as RateLimitInfo, v as ReconnectEvent, S as SDK_VERSION, y as ScopedParams, z as ServerError, F as StreamEvent, G as StreamEventMap, J as StreamOptions, K as StreamTopic, T as SubscribedEvent, a3 as TokenVerificationError, a4 as TrackerParams, a5 as UserLike, a7 as UsersParams, a8 as VerifyWebhookOptions, a9 as WalletParams, aa as WebhookVerificationError, ab as handleKind, ac as hasX, ad as signWebhook, ae as verifyWebhook } from './users-3DAw88_U.cjs';
2
+ import { O as OidcScope, D as DiscoveryDocument, a8 as TokenResponse, c as CabalSpyIDClaims } from './types-UZeY9n1e.cjs';
3
+ export { A as ActiveTokens, a as ApiResponse, C as CHAINS, b as CURRENCY_BY_CHAIN, d as Chain, e as Currency, H as HealthResponse, f as HistoryResponse, g as HistoryToken, h as HistoryTrade, i as HoldingToken, j as HoldingsResponse, L as LEADERBOARD_SORTS, k as LeaderboardEntry, l as LeaderboardResponse, m as LeaderboardSort, n as LifetimeStats, M as MeResponse, P as PERIODS, o as Pagination, p as Period, q as PeriodStats, r as PnlCalendarDay, s as PnlCalendarMonth, t as PnlCalendarResponse, u as PnlChartPoint, v as Profile, R as ResponseMeta, S as Scope, a7 as TokenOverview, a9 as TrackerResponse, aa as TrackerTrade, ab as Trade, ac as TradeOwner, ad as TraderProfile, ae as VerifiedWallet, af as WalletClaim, ag as WalletLookupResponse, ah as WebhookEvent, ai as WebhookEventType, aj as WinRateBuckets, ak as WinRateDistribution, al as XProfileClaim } from './types-UZeY9n1e.cjs';
4
+
5
+ /** ES256 JWT verification against a JWKS, with WebCrypto only (no dependencies). */
6
+ interface EcJwk {
7
+ kty: 'EC';
8
+ crv: 'P-256';
9
+ x: string;
10
+ y: string;
11
+ kid?: string;
12
+ alg?: string;
13
+ use?: string;
14
+ }
15
+ interface Jwks {
16
+ keys: EcJwk[];
17
+ }
18
+ interface JwtHeader {
19
+ alg: string;
20
+ kid?: string;
21
+ typ?: string;
22
+ [key: string]: unknown;
23
+ }
24
+ interface DecodedJwt<P = Record<string, unknown>> {
25
+ header: JwtHeader;
26
+ payload: P;
27
+ }
28
+ /** Decodes a JWT without verifying it. Never trust the result. */
29
+ declare function decodeJwt<P = Record<string, unknown>>(token: string): DecodedJwt<P>;
30
+ /**
31
+ * Caches the provider's public keys. An unknown `kid` triggers one refetch
32
+ * (key rotation), at most once per `cooldownMs`.
33
+ */
34
+ declare class JwksCache {
35
+ private readonly load;
36
+ private readonly cooldownMs;
37
+ private keys;
38
+ private loaded;
39
+ private inflight;
40
+ constructor(load: () => Promise<Jwks>, cooldownMs?: number);
41
+ private refresh;
42
+ getKey(kid: string | undefined): Promise<CryptoKey>;
43
+ }
44
+
45
+ declare const DEFAULT_ISSUER = "https://id.cabalspy.xyz";
46
+ type TokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
47
+ interface CabalSpyIDAuthOptions {
48
+ /** Your instance's client_id (`csid_…`). */
49
+ clientId: string;
50
+ /** Client secret (`csid_sk_…`) of a server-side app. Omit for public clients. */
51
+ clientSecret?: string;
52
+ /** Default redirect URI. Must exactly match one registered in the dashboard. */
53
+ redirectUri?: string;
54
+ /** Default: https://id.cabalspy.xyz (env CABALSPY_ID_ISSUER) */
55
+ issuer?: string;
56
+ /** Default: client_secret_basic with a secret, else none. */
57
+ tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
58
+ /** Accepted clock skew in seconds when checking tokens. Default: 60 */
59
+ clockTolerance?: number;
60
+ /** Per-request timeout in milliseconds. Default: 15_000 */
61
+ timeout?: number;
62
+ fetch?: typeof globalThis.fetch;
63
+ }
64
+ interface PkcePair {
65
+ codeVerifier: string;
66
+ codeChallenge: string;
67
+ }
68
+ /** A fresh PKCE verifier (64 chars) and its S256 challenge. */
69
+ declare function generatePkce(): Promise<PkcePair>;
70
+ interface AuthorizationUrlParams {
71
+ /** Default: ['openid', 'profile']. `openid` is added when missing. */
72
+ scope?: OidcScope[] | string;
73
+ redirectUri?: string;
74
+ /** 'none' (silent, live apps only) or 'consent'. */
75
+ prompt?: 'none' | 'consent';
76
+ /** Your own state value; generated when omitted. */
77
+ state?: string;
78
+ /** Your own nonce; generated when omitted. */
79
+ nonce?: string;
80
+ /** Additional query parameters. */
81
+ extraParams?: Record<string, string>;
82
+ }
83
+ /**
84
+ * What you must keep (e.g. in a signed, http-only cookie or the server
85
+ * session) until the user comes back to your redirect URI.
86
+ */
87
+ interface AuthorizationRequest {
88
+ url: string;
89
+ state: string;
90
+ nonce: string;
91
+ codeVerifier: string;
92
+ redirectUri: string;
93
+ }
94
+ interface CallbackChecks {
95
+ state: string;
96
+ nonce: string;
97
+ codeVerifier: string;
98
+ redirectUri?: string;
99
+ }
100
+ interface VerifyIdTokenOptions {
101
+ /** The nonce you sent; required after an authorization request. */
102
+ nonce?: string;
103
+ /** Maximum seconds since the user authenticated (checks auth_time). */
104
+ maxAge?: number;
105
+ }
106
+ interface LoginResult {
107
+ tokens: TokenResponse;
108
+ /** Verified ID token claims. Check `claims.limited` before using profile data. */
109
+ claims: CabalSpyIDClaims;
110
+ }
111
+ /** True when the platform is over its plan's user limit: anonymous sub, no profile data. */
112
+ declare function isLimited(claims: Pick<CabalSpyIDClaims, 'limited' | 'sub'>): boolean;
113
+ /**
114
+ * OpenID Connect client for "Login with CabalSpy ID".
115
+ *
116
+ * const auth = new CabalSpyIDAuth({ clientId, clientSecret, redirectUri });
117
+ * const req = await auth.createAuthorizationUrl({ scope: ['openid', 'profile', 'wallets'] });
118
+ * // store req.state, req.nonce, req.codeVerifier; redirect to req.url
119
+ * const { tokens, claims } = await auth.handleCallback(callbackUrl, stored);
120
+ */
121
+ declare class CabalSpyIDAuth {
122
+ readonly clientId: string;
123
+ readonly issuer: string;
124
+ readonly redirectUri?: string;
125
+ readonly authMethod: TokenEndpointAuthMethod;
126
+ private readonly clientSecret?;
127
+ private readonly clockTolerance;
128
+ private readonly timeout;
129
+ private readonly fetchImpl;
130
+ private discovery;
131
+ private readonly jwks;
132
+ constructor(options: CabalSpyIDAuthOptions);
133
+ private send;
134
+ private fetchJson;
135
+ private clientAuth;
136
+ private postForm;
137
+ /** The provider's discovery document (cached for the life of this object). */
138
+ discover(): Promise<DiscoveryDocument>;
139
+ /** The provider's public signing keys. */
140
+ getJwks(): Promise<Jwks>;
141
+ /**
142
+ * Builds the authorization URL with PKCE (S256), state and nonce.
143
+ * Store `state`, `nonce` and `codeVerifier` until the callback.
144
+ */
145
+ createAuthorizationUrl(params?: AuthorizationUrlParams): Promise<AuthorizationRequest>;
146
+ /**
147
+ * Completes the login on your redirect URI: checks `error`, `state` and
148
+ * `iss`, exchanges the code and verifies the ID token (signature, iss, aud,
149
+ * exp, nonce).
150
+ *
151
+ * @param callback the full callback URL, its query string or URLSearchParams
152
+ */
153
+ handleCallback(callback: string | URL | URLSearchParams, checks: CallbackChecks): Promise<LoginResult>;
154
+ /** POST /oauth/token with grant_type=authorization_code. */
155
+ exchangeCode(params: {
156
+ code: string;
157
+ codeVerifier: string;
158
+ redirectUri?: string;
159
+ }): Promise<TokenResponse>;
160
+ /**
161
+ * POST /oauth/token with grant_type=refresh_token. Refresh tokens rotate:
162
+ * always store the new `refresh_token`. Reusing an old one revokes the whole
163
+ * chain.
164
+ */
165
+ refresh(refreshToken: string): Promise<TokenResponse>;
166
+ /** POST /oauth/revoke (RFC 7009). Revoking a refresh token ends its whole chain. */
167
+ revoke(token: string): Promise<void>;
168
+ /** GET /oauth/userinfo — full claims for the access token's scopes (x, wallets, onchain …). */
169
+ userinfo(accessToken: string): Promise<CabalSpyIDClaims>;
170
+ /**
171
+ * Verifies an ID token: ES256 signature (JWKS), iss, aud, azp, exp, nonce.
172
+ * Use it for tokens from your own callback and for `idToken` sent from the
173
+ * browser widget's `csid:login` event.
174
+ *
175
+ * When the platform is over its plan's user limit, `sub` is `anon_…` and
176
+ * `limited` is true; see isLimited().
177
+ */
178
+ verifyIdToken(idToken: string, options?: VerifyIdTokenOptions): Promise<CabalSpyIDClaims>;
179
+ /**
180
+ * Verifies a CabalSpy ID access token (typ at+jwt) issued to this client,
181
+ * e.g. one your frontend sends to your API. Returns its claims
182
+ * (sub, scope, client_id, exp, jti).
183
+ */
184
+ verifyAccessToken(accessToken: string): Promise<{
185
+ sub: string;
186
+ scope: string;
187
+ client_id: string;
188
+ exp: number;
189
+ jti: string;
190
+ } & Record<string, unknown>>;
191
+ }
192
+
193
+ export { type AuthorizationRequest, type AuthorizationUrlParams, CabalSpyIDAuth, type CabalSpyIDAuthOptions, CabalSpyIDClaims, type CallbackChecks, DEFAULT_ISSUER, type DecodedJwt, DiscoveryDocument, type EcJwk, type Jwks, JwksCache, type JwtHeader, type LoginResult, OidcScope, type PkcePair, type TokenEndpointAuthMethod, TokenResponse, type VerifyIdTokenOptions, decodeJwt, generatePkce, isLimited };
package/dist/api.d.ts ADDED
@@ -0,0 +1,193 @@
1
+ export { A as ApiErrorBody, a as AuthenticationError, B as BadRequestError, C as CabalSpyID, b as CabalSpyIDError, c as CabalSpyIDErrorOptions, d as CabalSpyIDOptions, e as CabalSpyIDStream, f as CloseEvent, g as ConnectionError, D as DEFAULT_BASE_URL, h as DEFAULT_STREAM_URL, E as Envelope, H as HandleKind, k as HeaderSource, l as HeartbeatEvent, m as HistoryParams, I as InvalidResponseError, n as LatestTransactionsParams, o as LeaderboardParams, N as NotFoundError, O as OAuthError, P as PermissionError, q as PlanUserLimitError, s as ProfileParams, Q as Query, R as RateLimitError, t as RateLimitInfo, v as ReconnectEvent, S as SDK_VERSION, y as ScopedParams, z as ServerError, F as StreamEvent, G as StreamEventMap, J as StreamOptions, K as StreamTopic, T as SubscribedEvent, a3 as TokenVerificationError, a4 as TrackerParams, a5 as UserLike, a7 as UsersParams, a8 as VerifyWebhookOptions, a9 as WalletParams, aa as WebhookVerificationError, ab as handleKind, ac as hasX, ad as signWebhook, ae as verifyWebhook } from './users-B4r33i4O.js';
2
+ import { O as OidcScope, D as DiscoveryDocument, a8 as TokenResponse, c as CabalSpyIDClaims } from './types-UZeY9n1e.js';
3
+ export { A as ActiveTokens, a as ApiResponse, C as CHAINS, b as CURRENCY_BY_CHAIN, d as Chain, e as Currency, H as HealthResponse, f as HistoryResponse, g as HistoryToken, h as HistoryTrade, i as HoldingToken, j as HoldingsResponse, L as LEADERBOARD_SORTS, k as LeaderboardEntry, l as LeaderboardResponse, m as LeaderboardSort, n as LifetimeStats, M as MeResponse, P as PERIODS, o as Pagination, p as Period, q as PeriodStats, r as PnlCalendarDay, s as PnlCalendarMonth, t as PnlCalendarResponse, u as PnlChartPoint, v as Profile, R as ResponseMeta, S as Scope, a7 as TokenOverview, a9 as TrackerResponse, aa as TrackerTrade, ab as Trade, ac as TradeOwner, ad as TraderProfile, ae as VerifiedWallet, af as WalletClaim, ag as WalletLookupResponse, ah as WebhookEvent, ai as WebhookEventType, aj as WinRateBuckets, ak as WinRateDistribution, al as XProfileClaim } from './types-UZeY9n1e.js';
4
+
5
+ /** ES256 JWT verification against a JWKS, with WebCrypto only (no dependencies). */
6
+ interface EcJwk {
7
+ kty: 'EC';
8
+ crv: 'P-256';
9
+ x: string;
10
+ y: string;
11
+ kid?: string;
12
+ alg?: string;
13
+ use?: string;
14
+ }
15
+ interface Jwks {
16
+ keys: EcJwk[];
17
+ }
18
+ interface JwtHeader {
19
+ alg: string;
20
+ kid?: string;
21
+ typ?: string;
22
+ [key: string]: unknown;
23
+ }
24
+ interface DecodedJwt<P = Record<string, unknown>> {
25
+ header: JwtHeader;
26
+ payload: P;
27
+ }
28
+ /** Decodes a JWT without verifying it. Never trust the result. */
29
+ declare function decodeJwt<P = Record<string, unknown>>(token: string): DecodedJwt<P>;
30
+ /**
31
+ * Caches the provider's public keys. An unknown `kid` triggers one refetch
32
+ * (key rotation), at most once per `cooldownMs`.
33
+ */
34
+ declare class JwksCache {
35
+ private readonly load;
36
+ private readonly cooldownMs;
37
+ private keys;
38
+ private loaded;
39
+ private inflight;
40
+ constructor(load: () => Promise<Jwks>, cooldownMs?: number);
41
+ private refresh;
42
+ getKey(kid: string | undefined): Promise<CryptoKey>;
43
+ }
44
+
45
+ declare const DEFAULT_ISSUER = "https://id.cabalspy.xyz";
46
+ type TokenEndpointAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
47
+ interface CabalSpyIDAuthOptions {
48
+ /** Your instance's client_id (`csid_…`). */
49
+ clientId: string;
50
+ /** Client secret (`csid_sk_…`) of a server-side app. Omit for public clients. */
51
+ clientSecret?: string;
52
+ /** Default redirect URI. Must exactly match one registered in the dashboard. */
53
+ redirectUri?: string;
54
+ /** Default: https://id.cabalspy.xyz (env CABALSPY_ID_ISSUER) */
55
+ issuer?: string;
56
+ /** Default: client_secret_basic with a secret, else none. */
57
+ tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
58
+ /** Accepted clock skew in seconds when checking tokens. Default: 60 */
59
+ clockTolerance?: number;
60
+ /** Per-request timeout in milliseconds. Default: 15_000 */
61
+ timeout?: number;
62
+ fetch?: typeof globalThis.fetch;
63
+ }
64
+ interface PkcePair {
65
+ codeVerifier: string;
66
+ codeChallenge: string;
67
+ }
68
+ /** A fresh PKCE verifier (64 chars) and its S256 challenge. */
69
+ declare function generatePkce(): Promise<PkcePair>;
70
+ interface AuthorizationUrlParams {
71
+ /** Default: ['openid', 'profile']. `openid` is added when missing. */
72
+ scope?: OidcScope[] | string;
73
+ redirectUri?: string;
74
+ /** 'none' (silent, live apps only) or 'consent'. */
75
+ prompt?: 'none' | 'consent';
76
+ /** Your own state value; generated when omitted. */
77
+ state?: string;
78
+ /** Your own nonce; generated when omitted. */
79
+ nonce?: string;
80
+ /** Additional query parameters. */
81
+ extraParams?: Record<string, string>;
82
+ }
83
+ /**
84
+ * What you must keep (e.g. in a signed, http-only cookie or the server
85
+ * session) until the user comes back to your redirect URI.
86
+ */
87
+ interface AuthorizationRequest {
88
+ url: string;
89
+ state: string;
90
+ nonce: string;
91
+ codeVerifier: string;
92
+ redirectUri: string;
93
+ }
94
+ interface CallbackChecks {
95
+ state: string;
96
+ nonce: string;
97
+ codeVerifier: string;
98
+ redirectUri?: string;
99
+ }
100
+ interface VerifyIdTokenOptions {
101
+ /** The nonce you sent; required after an authorization request. */
102
+ nonce?: string;
103
+ /** Maximum seconds since the user authenticated (checks auth_time). */
104
+ maxAge?: number;
105
+ }
106
+ interface LoginResult {
107
+ tokens: TokenResponse;
108
+ /** Verified ID token claims. Check `claims.limited` before using profile data. */
109
+ claims: CabalSpyIDClaims;
110
+ }
111
+ /** True when the platform is over its plan's user limit: anonymous sub, no profile data. */
112
+ declare function isLimited(claims: Pick<CabalSpyIDClaims, 'limited' | 'sub'>): boolean;
113
+ /**
114
+ * OpenID Connect client for "Login with CabalSpy ID".
115
+ *
116
+ * const auth = new CabalSpyIDAuth({ clientId, clientSecret, redirectUri });
117
+ * const req = await auth.createAuthorizationUrl({ scope: ['openid', 'profile', 'wallets'] });
118
+ * // store req.state, req.nonce, req.codeVerifier; redirect to req.url
119
+ * const { tokens, claims } = await auth.handleCallback(callbackUrl, stored);
120
+ */
121
+ declare class CabalSpyIDAuth {
122
+ readonly clientId: string;
123
+ readonly issuer: string;
124
+ readonly redirectUri?: string;
125
+ readonly authMethod: TokenEndpointAuthMethod;
126
+ private readonly clientSecret?;
127
+ private readonly clockTolerance;
128
+ private readonly timeout;
129
+ private readonly fetchImpl;
130
+ private discovery;
131
+ private readonly jwks;
132
+ constructor(options: CabalSpyIDAuthOptions);
133
+ private send;
134
+ private fetchJson;
135
+ private clientAuth;
136
+ private postForm;
137
+ /** The provider's discovery document (cached for the life of this object). */
138
+ discover(): Promise<DiscoveryDocument>;
139
+ /** The provider's public signing keys. */
140
+ getJwks(): Promise<Jwks>;
141
+ /**
142
+ * Builds the authorization URL with PKCE (S256), state and nonce.
143
+ * Store `state`, `nonce` and `codeVerifier` until the callback.
144
+ */
145
+ createAuthorizationUrl(params?: AuthorizationUrlParams): Promise<AuthorizationRequest>;
146
+ /**
147
+ * Completes the login on your redirect URI: checks `error`, `state` and
148
+ * `iss`, exchanges the code and verifies the ID token (signature, iss, aud,
149
+ * exp, nonce).
150
+ *
151
+ * @param callback the full callback URL, its query string or URLSearchParams
152
+ */
153
+ handleCallback(callback: string | URL | URLSearchParams, checks: CallbackChecks): Promise<LoginResult>;
154
+ /** POST /oauth/token with grant_type=authorization_code. */
155
+ exchangeCode(params: {
156
+ code: string;
157
+ codeVerifier: string;
158
+ redirectUri?: string;
159
+ }): Promise<TokenResponse>;
160
+ /**
161
+ * POST /oauth/token with grant_type=refresh_token. Refresh tokens rotate:
162
+ * always store the new `refresh_token`. Reusing an old one revokes the whole
163
+ * chain.
164
+ */
165
+ refresh(refreshToken: string): Promise<TokenResponse>;
166
+ /** POST /oauth/revoke (RFC 7009). Revoking a refresh token ends its whole chain. */
167
+ revoke(token: string): Promise<void>;
168
+ /** GET /oauth/userinfo — full claims for the access token's scopes (x, wallets, onchain …). */
169
+ userinfo(accessToken: string): Promise<CabalSpyIDClaims>;
170
+ /**
171
+ * Verifies an ID token: ES256 signature (JWKS), iss, aud, azp, exp, nonce.
172
+ * Use it for tokens from your own callback and for `idToken` sent from the
173
+ * browser widget's `csid:login` event.
174
+ *
175
+ * When the platform is over its plan's user limit, `sub` is `anon_…` and
176
+ * `limited` is true; see isLimited().
177
+ */
178
+ verifyIdToken(idToken: string, options?: VerifyIdTokenOptions): Promise<CabalSpyIDClaims>;
179
+ /**
180
+ * Verifies a CabalSpy ID access token (typ at+jwt) issued to this client,
181
+ * e.g. one your frontend sends to your API. Returns its claims
182
+ * (sub, scope, client_id, exp, jti).
183
+ */
184
+ verifyAccessToken(accessToken: string): Promise<{
185
+ sub: string;
186
+ scope: string;
187
+ client_id: string;
188
+ exp: number;
189
+ jti: string;
190
+ } & Record<string, unknown>>;
191
+ }
192
+
193
+ export { type AuthorizationRequest, type AuthorizationUrlParams, CabalSpyIDAuth, type CabalSpyIDAuthOptions, CabalSpyIDClaims, type CallbackChecks, DEFAULT_ISSUER, type DecodedJwt, DiscoveryDocument, type EcJwk, type Jwks, JwksCache, type JwtHeader, type LoginResult, OidcScope, type PkcePair, type TokenEndpointAuthMethod, TokenResponse, type VerifyIdTokenOptions, decodeJwt, generatePkce, isLimited };
package/dist/api.js ADDED
@@ -0,0 +1,74 @@
1
+ import {
2
+ CabalSpyIDAuth,
3
+ DEFAULT_ISSUER,
4
+ JwksCache,
5
+ decodeJwt,
6
+ generatePkce,
7
+ isLimited
8
+ } from "./chunk-DBYCRBVS.js";
9
+ import "./chunk-CJFIOVBA.js";
10
+ import {
11
+ CHAINS,
12
+ CURRENCY_BY_CHAIN,
13
+ CabalSpyID,
14
+ CabalSpyIDStream,
15
+ DEFAULT_BASE_URL,
16
+ DEFAULT_STREAM_URL,
17
+ LEADERBOARD_SORTS,
18
+ PERIODS,
19
+ SDK_VERSION,
20
+ handleKind,
21
+ hasX,
22
+ signWebhook,
23
+ verifyWebhook
24
+ } from "./chunk-XLBO2RSL.js";
25
+ import {
26
+ AuthenticationError,
27
+ BadRequestError,
28
+ CabalSpyIDError,
29
+ ConnectionError,
30
+ InvalidResponseError,
31
+ NotFoundError,
32
+ OAuthError,
33
+ PermissionError,
34
+ PlanUserLimitError,
35
+ RateLimitError,
36
+ ServerError,
37
+ TokenVerificationError,
38
+ WebhookVerificationError
39
+ } from "./chunk-VOTYIQAY.js";
40
+ export {
41
+ AuthenticationError,
42
+ BadRequestError,
43
+ CHAINS,
44
+ CURRENCY_BY_CHAIN,
45
+ CabalSpyID,
46
+ CabalSpyIDAuth,
47
+ CabalSpyIDError,
48
+ CabalSpyIDStream,
49
+ ConnectionError,
50
+ DEFAULT_BASE_URL,
51
+ DEFAULT_ISSUER,
52
+ DEFAULT_STREAM_URL,
53
+ InvalidResponseError,
54
+ JwksCache,
55
+ LEADERBOARD_SORTS,
56
+ NotFoundError,
57
+ OAuthError,
58
+ PERIODS,
59
+ PermissionError,
60
+ PlanUserLimitError,
61
+ RateLimitError,
62
+ SDK_VERSION,
63
+ ServerError,
64
+ TokenVerificationError,
65
+ WebhookVerificationError,
66
+ decodeJwt,
67
+ generatePkce,
68
+ handleKind,
69
+ hasX,
70
+ isLimited,
71
+ signWebhook,
72
+ verifyWebhook
73
+ };
74
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1 @@
1
+ "use strict";//# sourceMappingURL=chunk-A2ZAFAWC.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/cabalspy-id-js/cabalspy-id-js/dist/chunk-A2ZAFAWC.cjs"],"names":[],"mappings":"AAAA","file":"/home/runner/work/cabalspy-id-js/cabalspy-id-js/dist/chunk-A2ZAFAWC.cjs"}
@@ -0,0 +1,109 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/errors.ts
2
+ var EMPTY_RATE_LIMIT = Object.freeze({ limit: null, remaining: null, reset: null });
3
+ var CabalSpyIDError = class extends Error {
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+ /** The parsed response body, when there was one. */
12
+
13
+ constructor(message, opts = {}) {
14
+ super(message);
15
+ this.name = new.target.name;
16
+ this.status = _nullishCoalesce(opts.status, () => ( 0));
17
+ this.code = _nullishCoalesce(opts.code, () => ( "unknown_error"));
18
+ this.requestId = opts.requestId;
19
+ this.docs = opts.docs;
20
+ this.parameter = opts.parameter;
21
+ this.allowed = opts.allowed;
22
+ this.rateLimit = _nullishCoalesce(opts.rateLimit, () => ( { ...EMPTY_RATE_LIMIT }));
23
+ this.body = opts.body;
24
+ Object.setPrototypeOf(this, new.target.prototype);
25
+ }
26
+ };
27
+ var BadRequestError = class extends CabalSpyIDError {
28
+ };
29
+ var AuthenticationError = class extends CabalSpyIDError {
30
+ };
31
+ var PermissionError = class extends CabalSpyIDError {
32
+ };
33
+ var PlanUserLimitError = (_class = class extends PermissionError {constructor(...args) { super(...args); _class.prototype.__init.call(this); }
34
+ __init() {this.limited = true}
35
+ }, _class);
36
+ var NotFoundError = class extends CabalSpyIDError {
37
+ };
38
+ var RateLimitError = class extends CabalSpyIDError {
39
+ /** Seconds until the next request is allowed, taken from Retry-After. */
40
+
41
+ constructor(message, opts = {}) {
42
+ super(message, opts);
43
+ this.retryAfter = _nullishCoalesce(opts.retryAfter, () => ( null));
44
+ }
45
+ };
46
+ var ServerError = class extends CabalSpyIDError {
47
+ };
48
+ var ConnectionError = class extends CabalSpyIDError {
49
+ };
50
+ var InvalidResponseError = class extends CabalSpyIDError {
51
+ };
52
+ var OAuthError = class extends CabalSpyIDError {
53
+
54
+
55
+ constructor(error, description, opts = {}) {
56
+ super(description ? `${error}: ${description}` : error, { ...opts, code: error });
57
+ this.error = error;
58
+ this.errorDescription = description;
59
+ }
60
+ };
61
+ var TokenVerificationError = class extends CabalSpyIDError {
62
+ };
63
+ var WebhookVerificationError = class extends CabalSpyIDError {
64
+ };
65
+ function errorFromStatus(status, body, rateLimit, retryAfter, fallbackMessage) {
66
+ const opts = {
67
+ status,
68
+ code: _nullishCoalesce(_optionalChain([body, 'optionalAccess', _ => _.code]), () => ( `http_${status}`)),
69
+ requestId: _optionalChain([body, 'optionalAccess', _2 => _2.request_id]),
70
+ docs: _optionalChain([body, 'optionalAccess', _3 => _3.docs]),
71
+ parameter: _optionalChain([body, 'optionalAccess', _4 => _4.parameter]),
72
+ allowed: _optionalChain([body, 'optionalAccess', _5 => _5.allowed]),
73
+ rateLimit,
74
+ body: _nullishCoalesce(body, () => ( void 0))
75
+ };
76
+ const msg = _nullishCoalesce(_optionalChain([body, 'optionalAccess', _6 => _6.message]), () => ( fallbackMessage));
77
+ if (status === 400) return new BadRequestError(msg, opts);
78
+ if (status === 401) return new AuthenticationError(msg, opts);
79
+ if (status === 403) {
80
+ return _optionalChain([body, 'optionalAccess', _7 => _7.code]) === "plan_user_limit" ? new PlanUserLimitError(msg, opts) : new PermissionError(msg, opts);
81
+ }
82
+ if (status === 404) return new NotFoundError(msg, opts);
83
+ if (status === 429) return new RateLimitError(msg, { ...opts, retryAfter });
84
+ if (status >= 500) return new ServerError(msg, opts);
85
+ return new CabalSpyIDError(msg, opts);
86
+ }
87
+ function isRetryable(err) {
88
+ return err instanceof RateLimitError || err instanceof ServerError || err instanceof ConnectionError;
89
+ }
90
+
91
+
92
+
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+
102
+
103
+
104
+
105
+
106
+
107
+
108
+ exports.EMPTY_RATE_LIMIT = EMPTY_RATE_LIMIT; exports.CabalSpyIDError = CabalSpyIDError; exports.BadRequestError = BadRequestError; exports.AuthenticationError = AuthenticationError; exports.PermissionError = PermissionError; exports.PlanUserLimitError = PlanUserLimitError; exports.NotFoundError = NotFoundError; exports.RateLimitError = RateLimitError; exports.ServerError = ServerError; exports.ConnectionError = ConnectionError; exports.InvalidResponseError = InvalidResponseError; exports.OAuthError = OAuthError; exports.TokenVerificationError = TokenVerificationError; exports.WebhookVerificationError = WebhookVerificationError; exports.errorFromStatus = errorFromStatus; exports.isRetryable = isRetryable;
109
+ //# sourceMappingURL=chunk-ABFIPCBY.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/cabalspy-id-js/cabalspy-id-js/dist/chunk-ABFIPCBY.cjs","../src/errors.ts"],"names":[],"mappings":"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","file":"/home/runner/work/cabalspy-id-js/cabalspy-id-js/dist/chunk-ABFIPCBY.cjs","sourcesContent":[null,"// ═══════════════════════════════════════════════════════════════════════════\n// ERRORS\n// ═══════════════════════════════════════════════════════════════════════════\n\nexport interface RateLimitInfo {\n /** Requests per second allowed by the plan. `null` when the header is absent. */\n limit: number | null;\n remaining: number | null;\n /** Seconds until the current one-second window resets. */\n reset: number | null;\n}\n\nexport const EMPTY_RATE_LIMIT: RateLimitInfo = Object.freeze({ limit: null, remaining: null, reset: null });\n\n/** Error body of the Data API: `{\"success\": false, \"error\": {...}}`. */\nexport interface ApiErrorBody {\n code: string;\n message: string;\n request_id: string;\n /** Link to the error's documentation, e.g. https://docs.cabalspy.xyz/cabalspy-id/errors#wallet_not_found */\n docs: string;\n parameter?: string;\n allowed?: unknown[];\n /** Set on `plan_user_limit`. */\n limited?: boolean;\n [key: string]: unknown;\n}\n\nexport interface CabalSpyIDErrorOptions {\n status?: number;\n code?: string;\n requestId?: string;\n docs?: string;\n parameter?: string;\n allowed?: unknown[];\n rateLimit?: RateLimitInfo;\n body?: unknown;\n}\n\n/** Base class for every error thrown by this SDK. */\nexport class CabalSpyIDError extends Error {\n readonly status: number;\n readonly code: string;\n readonly requestId?: string;\n readonly docs?: string;\n readonly parameter?: string;\n readonly allowed?: unknown[];\n readonly rateLimit: RateLimitInfo;\n /** The parsed response body, when there was one. */\n readonly body?: unknown;\n\n constructor(message: string, opts: CabalSpyIDErrorOptions = {}) {\n super(message);\n this.name = new.target.name;\n this.status = opts.status ?? 0;\n this.code = opts.code ?? 'unknown_error';\n this.requestId = opts.requestId;\n this.docs = opts.docs;\n this.parameter = opts.parameter;\n this.allowed = opts.allowed;\n this.rateLimit = opts.rateLimit ?? { ...EMPTY_RATE_LIMIT };\n this.body = opts.body;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** 400 — missing_parameter, invalid_parameter, instance_required */\nexport class BadRequestError extends CabalSpyIDError {}\n/** 401 — missing_api_key; thesis API: client_id_required, invalid_client */\nexport class AuthenticationError extends CabalSpyIDError {}\n/** 403 — invalid_api_key, product_not_enabled, no_instance, scope_not_allowed; thesis API: origin_not_allowed */\nexport class PermissionError extends CabalSpyIDError {}\n/**\n * 403 — plan_user_limit. The person signed in beyond the plan's user limit:\n * the platform receives no data for them until it upgrades.\n */\nexport class PlanUserLimitError extends PermissionError {\n readonly limited = true as const;\n}\n/** 404 — profile_not_found, wallet_not_found, instance_not_found */\nexport class NotFoundError extends CabalSpyIDError {}\n/** 429 — rate_limit_exceeded; thesis API: rate_limited (Retry-After 60) */\nexport class RateLimitError extends CabalSpyIDError {\n /** Seconds until the next request is allowed, taken from Retry-After. */\n readonly retryAfter: number | null;\n constructor(message: string, opts: CabalSpyIDErrorOptions & { retryAfter?: number | null } = {}) {\n super(message, opts);\n this.retryAfter = opts.retryAfter ?? null;\n }\n}\n/** 5xx — internal_error, service_unavailable */\nexport class ServerError extends CabalSpyIDError {}\n/** Network failure, timeout or aborted connection. */\nexport class ConnectionError extends CabalSpyIDError {}\n/** Response was not valid JSON, or did not have the expected envelope. */\nexport class InvalidResponseError extends CabalSpyIDError {}\n\n/**\n * An error from the OpenID Connect endpoints (`/oauth/token`, `/oauth/userinfo`,\n * `/oauth/revoke`) or from the authorization redirect, in OAuth's own format:\n * `code` is the OAuth `error` (invalid_grant, invalid_client, access_denied …).\n */\nexport class OAuthError extends CabalSpyIDError {\n readonly error: string;\n readonly errorDescription?: string;\n constructor(error: string, description?: string, opts: CabalSpyIDErrorOptions = {}) {\n super(description ? `${error}: ${description}` : error, { ...opts, code: error });\n this.error = error;\n this.errorDescription = description;\n }\n}\n\n/** An ID or access token failed verification (signature, iss, aud, exp, nonce …). */\nexport class TokenVerificationError extends CabalSpyIDError {}\n\n/** A webhook failed signature or timestamp verification. */\nexport class WebhookVerificationError extends CabalSpyIDError {}\n\n/** Maps an HTTP status and Data API error body onto the right error class. */\nexport function errorFromStatus(\n status: number,\n body: ApiErrorBody | null,\n rateLimit: RateLimitInfo,\n retryAfter: number | null,\n fallbackMessage: string,\n): CabalSpyIDError {\n const opts: CabalSpyIDErrorOptions = {\n status,\n code: body?.code ?? `http_${status}`,\n requestId: body?.request_id,\n docs: body?.docs,\n parameter: body?.parameter,\n allowed: body?.allowed,\n rateLimit,\n body: body ?? undefined,\n };\n const msg = body?.message ?? fallbackMessage;\n\n if (status === 400) return new BadRequestError(msg, opts);\n if (status === 401) return new AuthenticationError(msg, opts);\n if (status === 403) {\n return body?.code === 'plan_user_limit' ? new PlanUserLimitError(msg, opts) : new PermissionError(msg, opts);\n }\n if (status === 404) return new NotFoundError(msg, opts);\n if (status === 429) return new RateLimitError(msg, { ...opts, retryAfter });\n if (status >= 500) return new ServerError(msg, opts);\n return new CabalSpyIDError(msg, opts);\n}\n\nexport function isRetryable(err: unknown): boolean {\n return err instanceof RateLimitError || err instanceof ServerError || err instanceof ConnectionError;\n}\n"]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-CJFIOVBA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}