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.
- package/CHANGELOG.md +146 -0
- package/LICENSE +21 -0
- package/README.md +504 -2
- package/dist/api.cjs +74 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +193 -0
- package/dist/api.d.ts +193 -0
- package/dist/api.js +74 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-A2ZAFAWC.cjs +1 -0
- package/dist/chunk-A2ZAFAWC.cjs.map +1 -0
- package/dist/chunk-ABFIPCBY.cjs +109 -0
- package/dist/chunk-ABFIPCBY.cjs.map +1 -0
- package/dist/chunk-CJFIOVBA.js +1 -0
- package/dist/chunk-CJFIOVBA.js.map +1 -0
- package/dist/chunk-DBYCRBVS.js +400 -0
- package/dist/chunk-DBYCRBVS.js.map +1 -0
- package/dist/chunk-PKFIMBPW.cjs +444 -0
- package/dist/chunk-PKFIMBPW.cjs.map +1 -0
- package/dist/chunk-ULEBNY2A.cjs +1301 -0
- package/dist/chunk-ULEBNY2A.cjs.map +1 -0
- package/dist/chunk-VDFCMYLR.cjs +400 -0
- package/dist/chunk-VDFCMYLR.cjs.map +1 -0
- package/dist/chunk-VOTYIQAY.js +109 -0
- package/dist/chunk-VOTYIQAY.js.map +1 -0
- package/dist/chunk-XLBO2RSL.js +1301 -0
- package/dist/chunk-XLBO2RSL.js.map +1 -0
- package/dist/chunk-Z23B5TY6.js +444 -0
- package/dist/chunk-Z23B5TY6.js.map +1 -0
- package/dist/index.cjs +105 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +361 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +315 -0
- package/dist/react.d.ts +315 -0
- package/dist/react.js +333 -0
- package/dist/react.js.map +1 -0
- package/dist/thesis.cjs +76 -0
- package/dist/thesis.cjs.map +1 -0
- package/dist/thesis.d.cts +221 -0
- package/dist/thesis.d.ts +221 -0
- package/dist/thesis.js +76 -0
- package/dist/thesis.js.map +1 -0
- package/dist/types-UZeY9n1e.d.cts +689 -0
- package/dist/types-UZeY9n1e.d.ts +689 -0
- package/dist/users-3DAw88_U.d.cts +767 -0
- package/dist/users-B4r33i4O.d.ts +767 -0
- package/dist/widget.cjs +233 -0
- package/dist/widget.cjs.map +1 -0
- package/dist/widget.d.cts +226 -0
- package/dist/widget.d.ts +226 -0
- package/dist/widget.js +233 -0
- package/dist/widget.js.map +1 -0
- package/package.json +145 -4
package/dist/react.d.cts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Response shapes of the CabalSpy ID Data API, derived from the server source.
|
|
6
|
+
*
|
|
7
|
+
* Every object type keeps an index signature-free shape for editor help, but
|
|
8
|
+
* the server may add fields later; nothing is stripped at runtime.
|
|
9
|
+
*
|
|
10
|
+
* Timestamps are ISO 8601 UTC strings ("2026-10-12T08:00:00Z"), except
|
|
11
|
+
* `PnlCalendarDay.date`, which is "DD-MM-YY" like the CabalSpy API.
|
|
12
|
+
*/
|
|
13
|
+
declare const CHAINS: readonly ["solana", "bnb", "base", "eth", "rh"];
|
|
14
|
+
/** solana, bnb (BNB Chain), base, eth (Ethereum), rh (Robinhood Chain). */
|
|
15
|
+
type Chain = (typeof CHAINS)[number];
|
|
16
|
+
/**
|
|
17
|
+
* `thesis` lets your app post theses and replies, react and report in the
|
|
18
|
+
* user's name (Data API writes with `csid_id`, or the public thesis API and
|
|
19
|
+
* the thesis widget with the user's access token).
|
|
20
|
+
*/
|
|
21
|
+
type OidcScope = 'openid' | 'profile' | 'wallets' | 'onchain' | 'thesis' | 'offline_access';
|
|
22
|
+
interface XProfileClaim {
|
|
23
|
+
id: string;
|
|
24
|
+
username: string;
|
|
25
|
+
followers: number | null;
|
|
26
|
+
following: number | null;
|
|
27
|
+
posts: number | null;
|
|
28
|
+
listed: number | null;
|
|
29
|
+
verified: boolean | null;
|
|
30
|
+
verified_type: string | null;
|
|
31
|
+
created_at: string | null;
|
|
32
|
+
fetched_at: string;
|
|
33
|
+
}
|
|
34
|
+
interface WalletClaim {
|
|
35
|
+
address: string;
|
|
36
|
+
family: string;
|
|
37
|
+
chains: Chain[];
|
|
38
|
+
verified_at: string | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Claims of an ID token or a userinfo response.
|
|
42
|
+
*
|
|
43
|
+
* When the platform is over its plan's user limit, `sub` is an anonymous
|
|
44
|
+
* `anon_…` id, `limited` is true and no profile or wallet data is included.
|
|
45
|
+
*/
|
|
46
|
+
interface CabalSpyIDClaims {
|
|
47
|
+
sub: string;
|
|
48
|
+
iss?: string;
|
|
49
|
+
aud?: string;
|
|
50
|
+
azp?: string;
|
|
51
|
+
exp?: number;
|
|
52
|
+
iat?: number;
|
|
53
|
+
auth_time?: number;
|
|
54
|
+
nonce?: string;
|
|
55
|
+
name?: string | null;
|
|
56
|
+
/** X handle; for people without X `tg.<telegram name>` (signed in with Telegram) or `id.<hex>` (signed in with Google). X handles never contain a dot. */
|
|
57
|
+
preferred_username?: string;
|
|
58
|
+
picture?: string | null;
|
|
59
|
+
/** https://id.cabalspy.xyz/u/<username> */
|
|
60
|
+
profile?: string;
|
|
61
|
+
kol_badge?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Full X profile, userinfo only (scope `profile`). `null` for people who signed
|
|
64
|
+
* in with Telegram or Google and have not connected X. See hasX().
|
|
65
|
+
*/
|
|
66
|
+
x?: XProfileClaim | null;
|
|
67
|
+
/** Verified wallets, userinfo only (scope `wallets`). */
|
|
68
|
+
wallets?: WalletClaim[];
|
|
69
|
+
/** Latest 7-day on-chain volume, userinfo only (scope `onchain`). */
|
|
70
|
+
onchain?: {
|
|
71
|
+
volume_7d_usd: number;
|
|
72
|
+
checked_at: string;
|
|
73
|
+
} | null;
|
|
74
|
+
/** A made-up sandbox identity; never trust it in production. */
|
|
75
|
+
sandbox?: boolean;
|
|
76
|
+
/** True when the platform is over its plan's user limit. */
|
|
77
|
+
limited?: boolean;
|
|
78
|
+
reason?: 'plan_user_limit' | string;
|
|
79
|
+
message?: string;
|
|
80
|
+
[claim: string]: unknown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* CabalSpy ID widgets for any web page (browser only, no framework):
|
|
85
|
+
* the "Sign in with CabalSpy ID" button and the token theses widget.
|
|
86
|
+
*
|
|
87
|
+
* import { mountLoginButton, mountTheses } from 'cabalspy-id/widget';
|
|
88
|
+
*
|
|
89
|
+
* mountLoginButton('#login', { clientId: 'csid_…', onLogin: ({ idToken }) => sendToBackend(idToken) });
|
|
90
|
+
* mountTheses('#theses', { chain: 'solana', mint, clientId: 'csid_…', theme: 'dark' });
|
|
91
|
+
*
|
|
92
|
+
* Loads https://id.cabalspy.xyz/widget.js once and maps options to its data-*
|
|
93
|
+
* attributes. React components: `cabalspy-id/react` (also `cabalspy-id/widget/react`).
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
declare const WIDGET_SRC = "https://id.cabalspy.xyz/widget.js";
|
|
97
|
+
/** Detail of the widget's `csid:login` event. */
|
|
98
|
+
interface CabalSpyIDLogin {
|
|
99
|
+
/** userinfo claims; `limited: true` (anonymous sub) when the platform is over its plan's user limit. */
|
|
100
|
+
user: CabalSpyIDClaims;
|
|
101
|
+
/** Send this to your backend and verify it there. */
|
|
102
|
+
idToken: string;
|
|
103
|
+
accessToken: string;
|
|
104
|
+
/** Seconds. */
|
|
105
|
+
expiresIn: number;
|
|
106
|
+
}
|
|
107
|
+
interface CabalSpyIDLogoutEvent {
|
|
108
|
+
clientId: string;
|
|
109
|
+
}
|
|
110
|
+
interface CabalSpyIDErrorEvent {
|
|
111
|
+
error: string;
|
|
112
|
+
description?: string;
|
|
113
|
+
}
|
|
114
|
+
/** The signed-in person as the widget remembers them on this device. */
|
|
115
|
+
interface CabalSpyIDUserSummary {
|
|
116
|
+
sub: string;
|
|
117
|
+
username?: string;
|
|
118
|
+
name?: string | null;
|
|
119
|
+
picture?: string | null;
|
|
120
|
+
kol_badge?: boolean;
|
|
121
|
+
limited?: boolean;
|
|
122
|
+
}
|
|
123
|
+
/** The global the widget defines (window.CSID). */
|
|
124
|
+
interface CSIDGlobal {
|
|
125
|
+
__loaded: true;
|
|
126
|
+
user: CabalSpyIDLogin | null;
|
|
127
|
+
mount(): void;
|
|
128
|
+
login(opts: {
|
|
129
|
+
clientId: string;
|
|
130
|
+
redirectUri?: string;
|
|
131
|
+
scope?: string;
|
|
132
|
+
}): Promise<void>;
|
|
133
|
+
setUser(clientId: string, user: CabalSpyIDUserSummary | CabalSpyIDClaims): void;
|
|
134
|
+
signOut(clientId: string): void;
|
|
135
|
+
onLogin(cb: (r: CabalSpyIDLogin) => void): void;
|
|
136
|
+
/** Thesis widgets on the page (data-csid-thesis). */
|
|
137
|
+
thesis?: {
|
|
138
|
+
/** Lets thesis widgets write as this user (access token with the scope "thesis"). */
|
|
139
|
+
setAccessToken(token: string | null): void;
|
|
140
|
+
/**
|
|
141
|
+
* Your own sign-in for the widget's "Sign in to write" (null removes it).
|
|
142
|
+
* See {@link setThesisSignInHandler}.
|
|
143
|
+
*/
|
|
144
|
+
setSignInHandler?(handler: ThesisSignInHandler | null): void;
|
|
145
|
+
clear(): void;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Your page's sign-in for thesis widgets: obtain a thesis-capable access token
|
|
150
|
+
* for the person (e.g. your platform's own CabalSpy ID access token with the
|
|
151
|
+
* scope "thesis", from your backend), call `setThesisAccessToken(token)` (or
|
|
152
|
+
* `CSID.thesis.setAccessToken(token)`) and resolve `true`; resolve `false` when
|
|
153
|
+
* the person is not signed in.
|
|
154
|
+
*/
|
|
155
|
+
type ThesisSignInHandler = () => Promise<boolean> | boolean;
|
|
156
|
+
declare global {
|
|
157
|
+
interface Window {
|
|
158
|
+
CSID?: CSIDGlobal;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Loads widget.js once per page. Resolves with window.CSID. */
|
|
162
|
+
declare function loadCabalSpyIDWidget(src?: string): Promise<CSIDGlobal>;
|
|
163
|
+
/** Design and behaviour of the login button. */
|
|
164
|
+
interface LoginButtonOptions {
|
|
165
|
+
/** Your instance's client_id (`csid_…`). */
|
|
166
|
+
clientId: string;
|
|
167
|
+
/** Button design overrides; defaults come from the dashboard's button builder. */
|
|
168
|
+
theme?: 'dark' | 'light' | (string & {});
|
|
169
|
+
color?: string;
|
|
170
|
+
textColor?: string;
|
|
171
|
+
shape?: 'square' | 'rounded' | 'pill';
|
|
172
|
+
size?: 'sm' | 'md' | 'lg';
|
|
173
|
+
label?: string;
|
|
174
|
+
fullWidth?: boolean;
|
|
175
|
+
showLogo?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Server-side apps: your own login route that starts the OIDC flow with your
|
|
178
|
+
* client secret. Without it, a public client runs PKCE in the browser.
|
|
179
|
+
*/
|
|
180
|
+
href?: string;
|
|
181
|
+
/** Browser apps: redirect URI (default: the current page). */
|
|
182
|
+
redirectUri?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Browser apps: requested scopes (default: openid profile). Add `thesis` so
|
|
185
|
+
* the person can write in thesis widgets on your page right after sign-in.
|
|
186
|
+
*/
|
|
187
|
+
scope?: string | OidcScope[];
|
|
188
|
+
/** Server-side apps: the signed-in person's `sub`, to show the avatar menu. */
|
|
189
|
+
user?: string;
|
|
190
|
+
/** Server-side apps: where "Sign out" goes. */
|
|
191
|
+
logoutHref?: string;
|
|
192
|
+
}
|
|
193
|
+
/** Design and data of the token theses widget. */
|
|
194
|
+
interface ThesisWidgetOptions {
|
|
195
|
+
/** solana | bnb | base | eth | rh */
|
|
196
|
+
chain: Chain;
|
|
197
|
+
/** Token mint / contract address. */
|
|
198
|
+
mint: string;
|
|
199
|
+
/**
|
|
200
|
+
* Required. Your instance's PUBLIC client_id (`csid_...`, shown in the
|
|
201
|
+
* dashboard next to the API key; not the API key). The widget sends it on
|
|
202
|
+
* every thesis API call; it also loads the design saved in the dashboard (the
|
|
203
|
+
* options below override it), credits posts to your app and enables `scope: 'instance'`.
|
|
204
|
+
*/
|
|
205
|
+
clientId: string;
|
|
206
|
+
/** Default: dark */
|
|
207
|
+
theme?: 'dark' | 'light';
|
|
208
|
+
/** `global` (default): theses from every platform. `instance`: only the ones written on your instance. */
|
|
209
|
+
scope?: 'global' | 'instance';
|
|
210
|
+
/** Initial order. Default: new */
|
|
211
|
+
sort?: 'new' | 'top';
|
|
212
|
+
/** Font family, e.g. "Inter". */
|
|
213
|
+
font?: string;
|
|
214
|
+
/** Corner radius in px. Default: 12 */
|
|
215
|
+
radius?: number;
|
|
216
|
+
/** Colors (CSS colors, e.g. "#0d0f12"). */
|
|
217
|
+
bg?: string;
|
|
218
|
+
card?: string;
|
|
219
|
+
text?: string;
|
|
220
|
+
muted?: string;
|
|
221
|
+
border?: string;
|
|
222
|
+
accent?: string;
|
|
223
|
+
accentText?: string;
|
|
224
|
+
bull?: string;
|
|
225
|
+
bear?: string;
|
|
226
|
+
/** Show the token header. Default: true */
|
|
227
|
+
showHeader?: boolean;
|
|
228
|
+
/** Show the bull/bear sentiment bar. */
|
|
229
|
+
showSentiment?: boolean;
|
|
230
|
+
/** Denser layout. Default: false */
|
|
231
|
+
compact?: boolean;
|
|
232
|
+
/** Initial height in px; the widget then sizes itself to its content. Default: 520 */
|
|
233
|
+
height?: number;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface CabalSpyLoginProps extends LoginButtonOptions {
|
|
237
|
+
/** Fired after a browser-app login (window event `csid:login`). */
|
|
238
|
+
onLogin?: (result: CabalSpyIDLogin) => void;
|
|
239
|
+
/** Fired when the person signs out from the menu (window event `csid:logout`). */
|
|
240
|
+
onLogout?: (event: CabalSpyIDLogoutEvent) => void;
|
|
241
|
+
/** Fired when the browser flow fails (window event `csid:error`). */
|
|
242
|
+
onError?: (event: CabalSpyIDErrorEvent) => void;
|
|
243
|
+
/** Override the widget URL (e.g. for a self-hosted copy). */
|
|
244
|
+
scriptSrc?: string;
|
|
245
|
+
className?: string;
|
|
246
|
+
style?: CSSProperties;
|
|
247
|
+
id?: string;
|
|
248
|
+
}
|
|
249
|
+
/** "Sign in with CabalSpy ID" button (the official widget). */
|
|
250
|
+
declare function CabalSpyLogin(props: CabalSpyLoginProps): react.DetailedReactHTMLElement<{
|
|
251
|
+
id: string | undefined;
|
|
252
|
+
className: string | undefined;
|
|
253
|
+
style: CSSProperties | undefined;
|
|
254
|
+
}, HTMLElement>;
|
|
255
|
+
interface CabalSpyThesesProps extends ThesisWidgetOptions {
|
|
256
|
+
/**
|
|
257
|
+
* The signed-in user's CabalSpy ID access token (scope `thesis`), so they
|
|
258
|
+
* write without signing in again inside the widget. After a browser login
|
|
259
|
+
* through the widget this is set automatically. `null` signs the widget out.
|
|
260
|
+
*/
|
|
261
|
+
accessToken?: string | null;
|
|
262
|
+
/**
|
|
263
|
+
* Your own sign-in for the widget's "Sign in to write" (instead of the page's
|
|
264
|
+
* login button / popup): get a thesis-capable access token for the person,
|
|
265
|
+
* pass it on (the `accessToken` prop or `setThesisAccessToken`) and resolve
|
|
266
|
+
* `true`; resolve `false` when they are not signed in. While set, the page is
|
|
267
|
+
* the source of truth for sign-in. Removed on unmount.
|
|
268
|
+
*/
|
|
269
|
+
onSignIn?: ThesisSignInHandler;
|
|
270
|
+
scriptSrc?: string;
|
|
271
|
+
className?: string;
|
|
272
|
+
style?: CSSProperties;
|
|
273
|
+
id?: string;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Token theses widget: holders' theses on a token with their real position,
|
|
277
|
+
* replies, reactions, live updates.
|
|
278
|
+
*
|
|
279
|
+
* <CabalSpyTheses chain="solana" mint={mint} clientId="csid_..." theme="dark" accessToken={accessToken} />
|
|
280
|
+
*/
|
|
281
|
+
declare function CabalSpyTheses(props: CabalSpyThesesProps): react.DetailedReactHTMLElement<{
|
|
282
|
+
id: string | undefined;
|
|
283
|
+
className: string | undefined;
|
|
284
|
+
style: CSSProperties | undefined;
|
|
285
|
+
key: string;
|
|
286
|
+
}, HTMLElement>;
|
|
287
|
+
interface UseCabalSpyIDOptions {
|
|
288
|
+
/** Your client_id; needed for login(), signOut() and the remembered user. */
|
|
289
|
+
clientId?: string;
|
|
290
|
+
/** Load widget.js on mount (so a returning OAuth redirect completes). Default: true */
|
|
291
|
+
load?: boolean;
|
|
292
|
+
scriptSrc?: string;
|
|
293
|
+
}
|
|
294
|
+
interface UseCabalSpyIDResult {
|
|
295
|
+
/** userinfo claims from this page's login, else the person remembered on this device. */
|
|
296
|
+
user: CabalSpyIDClaims | CabalSpyIDUserSummary | null;
|
|
297
|
+
/** Only right after a browser login on this page. Verify it on your backend. */
|
|
298
|
+
idToken: string | null;
|
|
299
|
+
accessToken: string | null;
|
|
300
|
+
/** True when the platform is over its plan's user limit for this person. */
|
|
301
|
+
limited: boolean;
|
|
302
|
+
/** widget.js is loaded. */
|
|
303
|
+
ready: boolean;
|
|
304
|
+
/** Starts the browser (public client) login flow. */
|
|
305
|
+
login: (opts?: {
|
|
306
|
+
redirectUri?: string;
|
|
307
|
+
scope?: string | OidcScope[];
|
|
308
|
+
}) => Promise<void>;
|
|
309
|
+
/** Forgets the person on this device and fires `csid:logout`. */
|
|
310
|
+
signOut: () => void;
|
|
311
|
+
}
|
|
312
|
+
/** Login state from the CabalSpy ID widget. */
|
|
313
|
+
declare function useCabalSpyID(options?: UseCabalSpyIDOptions): UseCabalSpyIDResult;
|
|
314
|
+
|
|
315
|
+
export { type CSIDGlobal, type CabalSpyIDErrorEvent, type CabalSpyIDLogin, type CabalSpyIDLogoutEvent, type CabalSpyIDUserSummary, CabalSpyLogin, type CabalSpyLoginProps, CabalSpyTheses, type CabalSpyThesesProps, type LoginButtonOptions, type ThesisSignInHandler, type ThesisWidgetOptions, type UseCabalSpyIDOptions, type UseCabalSpyIDResult, WIDGET_SRC, loadCabalSpyIDWidget, useCabalSpyID };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { CSSProperties } from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Response shapes of the CabalSpy ID Data API, derived from the server source.
|
|
6
|
+
*
|
|
7
|
+
* Every object type keeps an index signature-free shape for editor help, but
|
|
8
|
+
* the server may add fields later; nothing is stripped at runtime.
|
|
9
|
+
*
|
|
10
|
+
* Timestamps are ISO 8601 UTC strings ("2026-10-12T08:00:00Z"), except
|
|
11
|
+
* `PnlCalendarDay.date`, which is "DD-MM-YY" like the CabalSpy API.
|
|
12
|
+
*/
|
|
13
|
+
declare const CHAINS: readonly ["solana", "bnb", "base", "eth", "rh"];
|
|
14
|
+
/** solana, bnb (BNB Chain), base, eth (Ethereum), rh (Robinhood Chain). */
|
|
15
|
+
type Chain = (typeof CHAINS)[number];
|
|
16
|
+
/**
|
|
17
|
+
* `thesis` lets your app post theses and replies, react and report in the
|
|
18
|
+
* user's name (Data API writes with `csid_id`, or the public thesis API and
|
|
19
|
+
* the thesis widget with the user's access token).
|
|
20
|
+
*/
|
|
21
|
+
type OidcScope = 'openid' | 'profile' | 'wallets' | 'onchain' | 'thesis' | 'offline_access';
|
|
22
|
+
interface XProfileClaim {
|
|
23
|
+
id: string;
|
|
24
|
+
username: string;
|
|
25
|
+
followers: number | null;
|
|
26
|
+
following: number | null;
|
|
27
|
+
posts: number | null;
|
|
28
|
+
listed: number | null;
|
|
29
|
+
verified: boolean | null;
|
|
30
|
+
verified_type: string | null;
|
|
31
|
+
created_at: string | null;
|
|
32
|
+
fetched_at: string;
|
|
33
|
+
}
|
|
34
|
+
interface WalletClaim {
|
|
35
|
+
address: string;
|
|
36
|
+
family: string;
|
|
37
|
+
chains: Chain[];
|
|
38
|
+
verified_at: string | null;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Claims of an ID token or a userinfo response.
|
|
42
|
+
*
|
|
43
|
+
* When the platform is over its plan's user limit, `sub` is an anonymous
|
|
44
|
+
* `anon_…` id, `limited` is true and no profile or wallet data is included.
|
|
45
|
+
*/
|
|
46
|
+
interface CabalSpyIDClaims {
|
|
47
|
+
sub: string;
|
|
48
|
+
iss?: string;
|
|
49
|
+
aud?: string;
|
|
50
|
+
azp?: string;
|
|
51
|
+
exp?: number;
|
|
52
|
+
iat?: number;
|
|
53
|
+
auth_time?: number;
|
|
54
|
+
nonce?: string;
|
|
55
|
+
name?: string | null;
|
|
56
|
+
/** X handle; for people without X `tg.<telegram name>` (signed in with Telegram) or `id.<hex>` (signed in with Google). X handles never contain a dot. */
|
|
57
|
+
preferred_username?: string;
|
|
58
|
+
picture?: string | null;
|
|
59
|
+
/** https://id.cabalspy.xyz/u/<username> */
|
|
60
|
+
profile?: string;
|
|
61
|
+
kol_badge?: boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Full X profile, userinfo only (scope `profile`). `null` for people who signed
|
|
64
|
+
* in with Telegram or Google and have not connected X. See hasX().
|
|
65
|
+
*/
|
|
66
|
+
x?: XProfileClaim | null;
|
|
67
|
+
/** Verified wallets, userinfo only (scope `wallets`). */
|
|
68
|
+
wallets?: WalletClaim[];
|
|
69
|
+
/** Latest 7-day on-chain volume, userinfo only (scope `onchain`). */
|
|
70
|
+
onchain?: {
|
|
71
|
+
volume_7d_usd: number;
|
|
72
|
+
checked_at: string;
|
|
73
|
+
} | null;
|
|
74
|
+
/** A made-up sandbox identity; never trust it in production. */
|
|
75
|
+
sandbox?: boolean;
|
|
76
|
+
/** True when the platform is over its plan's user limit. */
|
|
77
|
+
limited?: boolean;
|
|
78
|
+
reason?: 'plan_user_limit' | string;
|
|
79
|
+
message?: string;
|
|
80
|
+
[claim: string]: unknown;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* CabalSpy ID widgets for any web page (browser only, no framework):
|
|
85
|
+
* the "Sign in with CabalSpy ID" button and the token theses widget.
|
|
86
|
+
*
|
|
87
|
+
* import { mountLoginButton, mountTheses } from 'cabalspy-id/widget';
|
|
88
|
+
*
|
|
89
|
+
* mountLoginButton('#login', { clientId: 'csid_…', onLogin: ({ idToken }) => sendToBackend(idToken) });
|
|
90
|
+
* mountTheses('#theses', { chain: 'solana', mint, clientId: 'csid_…', theme: 'dark' });
|
|
91
|
+
*
|
|
92
|
+
* Loads https://id.cabalspy.xyz/widget.js once and maps options to its data-*
|
|
93
|
+
* attributes. React components: `cabalspy-id/react` (also `cabalspy-id/widget/react`).
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
declare const WIDGET_SRC = "https://id.cabalspy.xyz/widget.js";
|
|
97
|
+
/** Detail of the widget's `csid:login` event. */
|
|
98
|
+
interface CabalSpyIDLogin {
|
|
99
|
+
/** userinfo claims; `limited: true` (anonymous sub) when the platform is over its plan's user limit. */
|
|
100
|
+
user: CabalSpyIDClaims;
|
|
101
|
+
/** Send this to your backend and verify it there. */
|
|
102
|
+
idToken: string;
|
|
103
|
+
accessToken: string;
|
|
104
|
+
/** Seconds. */
|
|
105
|
+
expiresIn: number;
|
|
106
|
+
}
|
|
107
|
+
interface CabalSpyIDLogoutEvent {
|
|
108
|
+
clientId: string;
|
|
109
|
+
}
|
|
110
|
+
interface CabalSpyIDErrorEvent {
|
|
111
|
+
error: string;
|
|
112
|
+
description?: string;
|
|
113
|
+
}
|
|
114
|
+
/** The signed-in person as the widget remembers them on this device. */
|
|
115
|
+
interface CabalSpyIDUserSummary {
|
|
116
|
+
sub: string;
|
|
117
|
+
username?: string;
|
|
118
|
+
name?: string | null;
|
|
119
|
+
picture?: string | null;
|
|
120
|
+
kol_badge?: boolean;
|
|
121
|
+
limited?: boolean;
|
|
122
|
+
}
|
|
123
|
+
/** The global the widget defines (window.CSID). */
|
|
124
|
+
interface CSIDGlobal {
|
|
125
|
+
__loaded: true;
|
|
126
|
+
user: CabalSpyIDLogin | null;
|
|
127
|
+
mount(): void;
|
|
128
|
+
login(opts: {
|
|
129
|
+
clientId: string;
|
|
130
|
+
redirectUri?: string;
|
|
131
|
+
scope?: string;
|
|
132
|
+
}): Promise<void>;
|
|
133
|
+
setUser(clientId: string, user: CabalSpyIDUserSummary | CabalSpyIDClaims): void;
|
|
134
|
+
signOut(clientId: string): void;
|
|
135
|
+
onLogin(cb: (r: CabalSpyIDLogin) => void): void;
|
|
136
|
+
/** Thesis widgets on the page (data-csid-thesis). */
|
|
137
|
+
thesis?: {
|
|
138
|
+
/** Lets thesis widgets write as this user (access token with the scope "thesis"). */
|
|
139
|
+
setAccessToken(token: string | null): void;
|
|
140
|
+
/**
|
|
141
|
+
* Your own sign-in for the widget's "Sign in to write" (null removes it).
|
|
142
|
+
* See {@link setThesisSignInHandler}.
|
|
143
|
+
*/
|
|
144
|
+
setSignInHandler?(handler: ThesisSignInHandler | null): void;
|
|
145
|
+
clear(): void;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Your page's sign-in for thesis widgets: obtain a thesis-capable access token
|
|
150
|
+
* for the person (e.g. your platform's own CabalSpy ID access token with the
|
|
151
|
+
* scope "thesis", from your backend), call `setThesisAccessToken(token)` (or
|
|
152
|
+
* `CSID.thesis.setAccessToken(token)`) and resolve `true`; resolve `false` when
|
|
153
|
+
* the person is not signed in.
|
|
154
|
+
*/
|
|
155
|
+
type ThesisSignInHandler = () => Promise<boolean> | boolean;
|
|
156
|
+
declare global {
|
|
157
|
+
interface Window {
|
|
158
|
+
CSID?: CSIDGlobal;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
/** Loads widget.js once per page. Resolves with window.CSID. */
|
|
162
|
+
declare function loadCabalSpyIDWidget(src?: string): Promise<CSIDGlobal>;
|
|
163
|
+
/** Design and behaviour of the login button. */
|
|
164
|
+
interface LoginButtonOptions {
|
|
165
|
+
/** Your instance's client_id (`csid_…`). */
|
|
166
|
+
clientId: string;
|
|
167
|
+
/** Button design overrides; defaults come from the dashboard's button builder. */
|
|
168
|
+
theme?: 'dark' | 'light' | (string & {});
|
|
169
|
+
color?: string;
|
|
170
|
+
textColor?: string;
|
|
171
|
+
shape?: 'square' | 'rounded' | 'pill';
|
|
172
|
+
size?: 'sm' | 'md' | 'lg';
|
|
173
|
+
label?: string;
|
|
174
|
+
fullWidth?: boolean;
|
|
175
|
+
showLogo?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* Server-side apps: your own login route that starts the OIDC flow with your
|
|
178
|
+
* client secret. Without it, a public client runs PKCE in the browser.
|
|
179
|
+
*/
|
|
180
|
+
href?: string;
|
|
181
|
+
/** Browser apps: redirect URI (default: the current page). */
|
|
182
|
+
redirectUri?: string;
|
|
183
|
+
/**
|
|
184
|
+
* Browser apps: requested scopes (default: openid profile). Add `thesis` so
|
|
185
|
+
* the person can write in thesis widgets on your page right after sign-in.
|
|
186
|
+
*/
|
|
187
|
+
scope?: string | OidcScope[];
|
|
188
|
+
/** Server-side apps: the signed-in person's `sub`, to show the avatar menu. */
|
|
189
|
+
user?: string;
|
|
190
|
+
/** Server-side apps: where "Sign out" goes. */
|
|
191
|
+
logoutHref?: string;
|
|
192
|
+
}
|
|
193
|
+
/** Design and data of the token theses widget. */
|
|
194
|
+
interface ThesisWidgetOptions {
|
|
195
|
+
/** solana | bnb | base | eth | rh */
|
|
196
|
+
chain: Chain;
|
|
197
|
+
/** Token mint / contract address. */
|
|
198
|
+
mint: string;
|
|
199
|
+
/**
|
|
200
|
+
* Required. Your instance's PUBLIC client_id (`csid_...`, shown in the
|
|
201
|
+
* dashboard next to the API key; not the API key). The widget sends it on
|
|
202
|
+
* every thesis API call; it also loads the design saved in the dashboard (the
|
|
203
|
+
* options below override it), credits posts to your app and enables `scope: 'instance'`.
|
|
204
|
+
*/
|
|
205
|
+
clientId: string;
|
|
206
|
+
/** Default: dark */
|
|
207
|
+
theme?: 'dark' | 'light';
|
|
208
|
+
/** `global` (default): theses from every platform. `instance`: only the ones written on your instance. */
|
|
209
|
+
scope?: 'global' | 'instance';
|
|
210
|
+
/** Initial order. Default: new */
|
|
211
|
+
sort?: 'new' | 'top';
|
|
212
|
+
/** Font family, e.g. "Inter". */
|
|
213
|
+
font?: string;
|
|
214
|
+
/** Corner radius in px. Default: 12 */
|
|
215
|
+
radius?: number;
|
|
216
|
+
/** Colors (CSS colors, e.g. "#0d0f12"). */
|
|
217
|
+
bg?: string;
|
|
218
|
+
card?: string;
|
|
219
|
+
text?: string;
|
|
220
|
+
muted?: string;
|
|
221
|
+
border?: string;
|
|
222
|
+
accent?: string;
|
|
223
|
+
accentText?: string;
|
|
224
|
+
bull?: string;
|
|
225
|
+
bear?: string;
|
|
226
|
+
/** Show the token header. Default: true */
|
|
227
|
+
showHeader?: boolean;
|
|
228
|
+
/** Show the bull/bear sentiment bar. */
|
|
229
|
+
showSentiment?: boolean;
|
|
230
|
+
/** Denser layout. Default: false */
|
|
231
|
+
compact?: boolean;
|
|
232
|
+
/** Initial height in px; the widget then sizes itself to its content. Default: 520 */
|
|
233
|
+
height?: number;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
interface CabalSpyLoginProps extends LoginButtonOptions {
|
|
237
|
+
/** Fired after a browser-app login (window event `csid:login`). */
|
|
238
|
+
onLogin?: (result: CabalSpyIDLogin) => void;
|
|
239
|
+
/** Fired when the person signs out from the menu (window event `csid:logout`). */
|
|
240
|
+
onLogout?: (event: CabalSpyIDLogoutEvent) => void;
|
|
241
|
+
/** Fired when the browser flow fails (window event `csid:error`). */
|
|
242
|
+
onError?: (event: CabalSpyIDErrorEvent) => void;
|
|
243
|
+
/** Override the widget URL (e.g. for a self-hosted copy). */
|
|
244
|
+
scriptSrc?: string;
|
|
245
|
+
className?: string;
|
|
246
|
+
style?: CSSProperties;
|
|
247
|
+
id?: string;
|
|
248
|
+
}
|
|
249
|
+
/** "Sign in with CabalSpy ID" button (the official widget). */
|
|
250
|
+
declare function CabalSpyLogin(props: CabalSpyLoginProps): react.DetailedReactHTMLElement<{
|
|
251
|
+
id: string | undefined;
|
|
252
|
+
className: string | undefined;
|
|
253
|
+
style: CSSProperties | undefined;
|
|
254
|
+
}, HTMLElement>;
|
|
255
|
+
interface CabalSpyThesesProps extends ThesisWidgetOptions {
|
|
256
|
+
/**
|
|
257
|
+
* The signed-in user's CabalSpy ID access token (scope `thesis`), so they
|
|
258
|
+
* write without signing in again inside the widget. After a browser login
|
|
259
|
+
* through the widget this is set automatically. `null` signs the widget out.
|
|
260
|
+
*/
|
|
261
|
+
accessToken?: string | null;
|
|
262
|
+
/**
|
|
263
|
+
* Your own sign-in for the widget's "Sign in to write" (instead of the page's
|
|
264
|
+
* login button / popup): get a thesis-capable access token for the person,
|
|
265
|
+
* pass it on (the `accessToken` prop or `setThesisAccessToken`) and resolve
|
|
266
|
+
* `true`; resolve `false` when they are not signed in. While set, the page is
|
|
267
|
+
* the source of truth for sign-in. Removed on unmount.
|
|
268
|
+
*/
|
|
269
|
+
onSignIn?: ThesisSignInHandler;
|
|
270
|
+
scriptSrc?: string;
|
|
271
|
+
className?: string;
|
|
272
|
+
style?: CSSProperties;
|
|
273
|
+
id?: string;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Token theses widget: holders' theses on a token with their real position,
|
|
277
|
+
* replies, reactions, live updates.
|
|
278
|
+
*
|
|
279
|
+
* <CabalSpyTheses chain="solana" mint={mint} clientId="csid_..." theme="dark" accessToken={accessToken} />
|
|
280
|
+
*/
|
|
281
|
+
declare function CabalSpyTheses(props: CabalSpyThesesProps): react.DetailedReactHTMLElement<{
|
|
282
|
+
id: string | undefined;
|
|
283
|
+
className: string | undefined;
|
|
284
|
+
style: CSSProperties | undefined;
|
|
285
|
+
key: string;
|
|
286
|
+
}, HTMLElement>;
|
|
287
|
+
interface UseCabalSpyIDOptions {
|
|
288
|
+
/** Your client_id; needed for login(), signOut() and the remembered user. */
|
|
289
|
+
clientId?: string;
|
|
290
|
+
/** Load widget.js on mount (so a returning OAuth redirect completes). Default: true */
|
|
291
|
+
load?: boolean;
|
|
292
|
+
scriptSrc?: string;
|
|
293
|
+
}
|
|
294
|
+
interface UseCabalSpyIDResult {
|
|
295
|
+
/** userinfo claims from this page's login, else the person remembered on this device. */
|
|
296
|
+
user: CabalSpyIDClaims | CabalSpyIDUserSummary | null;
|
|
297
|
+
/** Only right after a browser login on this page. Verify it on your backend. */
|
|
298
|
+
idToken: string | null;
|
|
299
|
+
accessToken: string | null;
|
|
300
|
+
/** True when the platform is over its plan's user limit for this person. */
|
|
301
|
+
limited: boolean;
|
|
302
|
+
/** widget.js is loaded. */
|
|
303
|
+
ready: boolean;
|
|
304
|
+
/** Starts the browser (public client) login flow. */
|
|
305
|
+
login: (opts?: {
|
|
306
|
+
redirectUri?: string;
|
|
307
|
+
scope?: string | OidcScope[];
|
|
308
|
+
}) => Promise<void>;
|
|
309
|
+
/** Forgets the person on this device and fires `csid:logout`. */
|
|
310
|
+
signOut: () => void;
|
|
311
|
+
}
|
|
312
|
+
/** Login state from the CabalSpy ID widget. */
|
|
313
|
+
declare function useCabalSpyID(options?: UseCabalSpyIDOptions): UseCabalSpyIDResult;
|
|
314
|
+
|
|
315
|
+
export { type CSIDGlobal, type CabalSpyIDErrorEvent, type CabalSpyIDLogin, type CabalSpyIDLogoutEvent, type CabalSpyIDUserSummary, CabalSpyLogin, type CabalSpyLoginProps, CabalSpyTheses, type CabalSpyThesesProps, type LoginButtonOptions, type ThesisSignInHandler, type ThesisWidgetOptions, type UseCabalSpyIDOptions, type UseCabalSpyIDResult, WIDGET_SRC, loadCabalSpyIDWidget, useCabalSpyID };
|