@campnetwork/origin 1.2.0-0 → 1.2.0-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/README.md CHANGED
@@ -1,1073 +1,1300 @@
1
- <p align="center">
2
- <img src="https://imgur.com/7nLZezD.png" height="200px"/>
3
- </p>
4
- <br/>
5
-
6
- <p align="center">
7
- <a href="https://www.npmjs.com/package/@campnetwork/origin"><img src="https://img.shields.io/npm/v/@campnetwork/origin?style=for-the-badge" alt="npm version"/></a>
8
- <img alt="GitHub License" src="https://img.shields.io/github/license/campaign-layer/camp-sdk?style=for-the-badge">
9
- <img src="https://img.shields.io/npm/last-update/%40campnetwork%2Forigin?style=for-the-badge" alt="npm last update"/>
10
- <img alt="NPM Downloads" src="https://img.shields.io/npm/d18m/%40campnetwork%2Forigin?style=for-the-badge">
11
- </p>
12
-
13
- # Origin SDK
14
-
15
- The Origin SDK currently exposes the following modules:
16
-
17
- - `"@campnetwork/origin"` - The main entry point for the SDK, exposes the following classes:
18
- - `TwitterAPI` - For fetching user Twitter data from Origin
19
- - `SpotifyAPI` - For fetching user Spotify data from Origin
20
- - `Auth` - For authenticating users with the Origin SDK
21
- - `"@campnetwork/origin/react"` - Exposes the CampProvider and CampContext, as well as React components and hooks for authentication and fetching user data via Origin
22
-
23
- # Installation
24
-
25
- ```bash
26
- npm install @campnetwork/origin
27
- ```
28
-
29
- # Core
30
-
31
- The core modules can be imported either as a CommonJS module or as an ES6 module.
32
-
33
- ### CommonJS
34
-
35
- ```js
36
- const { TwitterAPI, SpotifyAPI, Auth } = require("@campnetwork/origin");
37
- ```
38
-
39
- ### ES6
40
-
41
- ```js
42
- import { TwitterAPI, SpotifyAPI, Auth } from "@campnetwork/origin";
43
- ```
44
-
45
- ## Socials
46
-
47
- ### TwitterAPI
48
-
49
- The TwitterAPI class is the entry point for fetching user Twitter data from Origin. It requires an API key to be instantiated.
50
-
51
- **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
52
-
53
- #### Constructor
54
-
55
- `apiKey` - The API key of your app.
56
-
57
- ```js
58
- const twitter = new TwitterAPI({
59
- apiKey: string,
60
- });
61
- ```
62
-
63
- #### Methods
64
-
65
- ##### fetchUserByUsername
66
-
67
- `fetchUserByUsername(twitterUserName: string)`
68
-
69
- ```js
70
- const user = await twitter.fetchUserByUsername("jack");
71
- ```
72
-
73
- ##### fetchTweetsByUsername
74
-
75
- `fetchTweetsByUsername(twitterUserName: string, page: number, limit: number)`
76
-
77
- ```js
78
- const tweets = await twitter.fetchTweetsByUsername("jack", 1, 10);
79
- ```
80
-
81
- ##### fetchFollowersByUsername
82
-
83
- `fetchFollowersByUsername(twitterUserName: string, page: number, limit: number)`
84
-
85
- ```js
86
- const followers = await twitter.fetchFollowersByUsername("jack", 1, 10);
87
- ```
88
-
89
- ##### fetchFollowingByUsername
90
-
91
- `fetchFollowingByUsername(twitterUserName: string, page: number, limit: number)`
92
-
93
- ```js
94
- const following = await twitter.fetchFollowingByUsername("jack", 1, 10);
95
- ```
96
-
97
- ##### fetchTweetById
98
-
99
- `fetchTweetById(tweetId: string)`
100
-
101
- ```js
102
- const tweet = await twitter.fetchTweetById("1234567890");
103
- ```
104
-
105
- ##### fetchUserByWalletAddress
106
-
107
- `fetchUserByWalletAddress(walletAddress: string, page: number, limit: number)`
108
-
109
- ```js
110
- const user = await twitter.fetchUserByWalletAddress("0x1234567890", 1, 10);
111
- ```
112
-
113
- ##### fetchRepostedByUsername
114
-
115
- `fetchRepostedByUsername(twitterUserName: string, page: number, limit: number)`
116
-
117
- ```js
118
- const reposts = await twitter.fetchRepostedByUsername("jack", 1, 10);
119
- ```
120
-
121
- ##### fetchRepliesByUsername
122
-
123
- `fetchRepliesByUsername(twitterUserName: string, page: number, limit: number)`
124
-
125
- ```js
126
- const replies = await twitter.fetchRepliesByUsername("jack", 1, 10);
127
- ```
128
-
129
- ##### fetchLikesByUsername
130
-
131
- `fetchLikesByUsername(twitterUserName: string, page: number, limit: number)`
132
-
133
- ```js
134
- const likes = await twitter.fetchLikesByUsername("jack", 1, 10);
135
- ```
136
-
137
- ##### fetchFollowsByUsername
138
-
139
- `fetchFollowsByUsername(twitterUserName: string, page: number, limit: number)`
140
-
141
- ```js
142
- const follows = await twitter.fetchFollowsByUsername("jack", 1, 10);
143
- ```
144
-
145
- ##### fetchViewedTweetsByUsername
146
-
147
- `fetchViewedTweetsByUsername(twitterUserName: string, page: number, limit: number)`
148
-
149
- ```js
150
- const viewedTweets = await twitter.fetchViewedTweetsByUsername("jack", 1, 10);
151
- ```
152
-
153
- ### SpotifyAPI
154
-
155
- The SpotifyAPI class is the entry point for fetching user Spotify data from Origin. It requires an API key to be instantiated.
156
-
157
- **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
158
-
159
- #### Constructor
160
-
161
- `apiKey` - The API key of your app.
162
-
163
- ```js
164
- const spotify = new SpotifyAPI({
165
- apiKey: string,
166
- });
167
- ```
168
-
169
- #### Methods
170
-
171
- ##### fetchSavedTracksById
172
-
173
- `fetchSavedTracksById(spotifyId: string)`
174
-
175
- ```js
176
- const savedTracks = await spotify.fetchSavedTracksById("1234567890");
177
- ```
178
-
179
- ##### fetchPlayedTracksById
180
-
181
- `fetchPlayedTracksById(spotifyId: string)`
182
-
183
- ```js
184
- const playedTracks = await spotify.fetchPlayedTracksById("1234567890");
185
- ```
186
-
187
- ##### fetchSavedAlbumsById
188
-
189
- `fetchSavedAlbumsById(spotifyId: string)`
190
-
191
- ```js
192
- const savedAlbums = await spotify.fetchSavedAlbumsById("1234567890");
193
- ```
194
-
195
- ##### fetchSavedPlaylistsById
196
-
197
- `fetchSavedPlaylistsById(spotifyId: string)`
198
-
199
- ```js
200
- const savedPlaylists = await spotify.fetchSavedPlaylistsById("1234567890");
201
- ```
202
-
203
- ##### fetchTracksInAlbum
204
-
205
- `fetchTracksInAlbum(spotifyId: string, albumId: string)`
206
-
207
- ```js
208
- const tracks = await spotify.fetchTracksInAlbum("1234567890", "1234567890");
209
- ```
210
-
211
- ##### fetchTracksInPlaylist
212
-
213
- `fetchTracksInPlaylist(spotifyId: string, playlistId: string)`
214
-
215
- ```js
216
- const tracks = await spotify.fetchTracksInPlaylist("1234567890", "1234567890");
217
- ```
218
-
219
- ##### fetchUserByWalletAddress
220
-
221
- `fetchUserByWalletAddress(walletAddress: string)`
222
-
223
- ```js
224
- const user = await spotify.fetchUserByWalletAddress("0x1234567890");
225
- ```
226
-
227
- ### TikTokAPI
228
-
229
- The TikTokAPI class is the entry point for fetching user TikTok data from Origin. It requires an API key to be instantiated.
230
-
231
- **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
232
-
233
- #### Constructor
234
-
235
- `apiKey` - The API key of your app.
236
-
237
- ```js
238
- const tiktok = new TikTokAPI({
239
- apiKey: string,
240
- });
241
- ```
242
-
243
- #### Methods
244
-
245
- ##### fetchUserByUsername
246
-
247
- `fetchUserByUsername(tiktokUserName: string)`
248
-
249
- ```js
250
- const user = await tiktok.fetchUserByUsername("jack");
251
- ```
252
-
253
- ##### fetchVideoById
254
-
255
- `fetchVideoById(userHandle: string, videoId: string)`
256
-
257
- ```js
258
- const video = await tiktok.fetchVideo("jack", "1234567890");
259
- ```
260
-
261
- ## Auth
262
-
263
- The Auth class is the entry point for authenticating users with the Origin SDK. It requires a clientId to be instantiated.
264
-
265
- **Note: The Auth class is only to be used on the client side.**
266
-
267
- ### Constructor
268
-
269
- - `clientId` - The client ID of your app. This is required to authenticate users with the Origin SDK.
270
- - `redirectUri` - The URI to redirect to after the user completes oauth for any of the socials. Defaults to `window.location.href`.
271
- The `redirectUri` can also be an object with the following optional properties:
272
- - `twitter` - The URI to redirect to after the user completes oauth for Twitter.
273
- - `spotify` - The URI to redirect to after the user completes oauth for Spotify.
274
-
275
- You may use the `redirectUri` object to redirect the user to different pages based on the social they are linking.
276
- You may only define the URIs for the socials you are using, the rest will default to `window.location.href`.
277
-
278
- ```js
279
- import { Auth } from "@campnetwork/origin";
280
-
281
- const auth = new Auth({
282
- clientId: string,
283
- redirectUri: string | object,
284
- allowAnalytics: boolean,
285
- });
286
- ```
287
-
288
- ```js
289
- const auth = new Auth({
290
- clientId: "your-client-id",
291
- redirectUri: {
292
- twitter: "https://your-website.com/twitter",
293
- spotify: "https://your-website.com/spotify",
294
- },
295
- });
296
- ```
297
-
298
- ### Methods
299
-
300
- #### connect
301
-
302
- `connect() => void`
303
-
304
- The `connect` method prompts the user to sign a message with their wallet in order to authenticate with the Origin SDK.
305
- The wallet provider can be set by calling the `setProvider` method on the Auth instance beforehand. The default provider used is `window.ethereum`.
306
-
307
- ```js
308
- auth.connect();
309
- ```
310
-
311
- #### disconnect
312
-
313
- `disconnect() => void`
314
-
315
- The `disconnect` method logs the user out of the Origin SDK on the client side.
316
-
317
- ```js
318
- auth.disconnect();
319
- ```
320
-
321
- #### setProvider
322
-
323
- `setProvider(provider: { provider: EIP1193Provider, info: EIP6963ProviderInfo, address?: string }) => void`
324
-
325
- _Read more about the [EIP1193Provider](https://eips.ethereum.org/EIPS/eip-1193) and [EIP6963ProviderInfo](https://eips.ethereum.org/EIPS/eip-6963) interfaces._
326
-
327
- The `setProvider` method sets the wallet provider to be used for authentication.
328
-
329
- ```js
330
- auth.setProvider({
331
- provider: window.ethereum,
332
- info: { name: "MetaMask", icon: "https://..." },
333
- });
334
- ```
335
-
336
- #### setWalletAddress
337
-
338
- `setWalletAddress(walletAddress: string) => void`
339
-
340
- The `setWalletAddress` method sets the wallet address to be used for authentication (via the `connect` method).
341
-
342
- **This is only needed if the provider does not support the `eth_requestAccounts` method. Only use this method if you are sure you need to set the wallet address manually.**
343
-
344
- ```js
345
- auth.setWalletAddress("0x1234567890");
346
- ```
347
-
348
- #### on
349
-
350
- `on(event: string, callback: (data: any) => void) => void`
351
-
352
- The `on` method listens for events emitted by the Auth module of the Origin SDK.
353
-
354
- The following events are emitted:
355
-
356
- ##### "state"
357
-
358
- Possible states:
359
-
360
- - `authenticated` - The user has successfully authenticated.
361
- - `unauthenticated` - The user has been logged out.
362
- - `loading` - The user is in the process of authenticating.
363
-
364
- ```js
365
- auth.on("state", (data) => {
366
- console.log(data); // "authenticated" | "unauthenticated" | "loading"
367
- });
368
- ```
369
-
370
- ##### "provider"
371
-
372
- Returns the provider that has been set via the `setProvider` method.
373
- If using the Origin SDK React components, this event is emitted when the user selects a provider in the Auth modal.
374
-
375
- ```js
376
- auth.on("provider", (data) => {
377
- console.log(data); // { provider: EIP1193Provider, info: EIP6963ProviderInfo }
378
- });
379
- ```
380
-
381
- ##### "providers"
382
-
383
- Returns the list of providers that have been injected via EIP6963 and that the user can select from.
384
-
385
- ```js
386
- auth.on("providers", (data) => {
387
- console.log(data); // [{ provider: EIP1193Provider, info: EIP6963ProviderInfo }]
388
- });
389
- ```
390
-
391
- You may use this event to update the UI with the available providers. The user can then select a provider to authenticate with, and the `setProvider` method can be called with the selected provider. The `connect` method can then be called to authenticate the user.
392
-
393
- ```js
394
- auth.on("providers", (data) => {
395
- // Update UI with providers
396
- // User selects a provider
397
- const selectedProvider = data[0];
398
-
399
- auth.setProvider(selectedProvider);
400
-
401
- auth.connect();
402
- });
403
- ```
404
-
405
- #### off
406
-
407
- `off(event: string, callback: (data: any) => void) => void`
408
-
409
- The `off` method unsubscribes from events emitted by the Auth module of the Origin SDK.
410
-
411
- ```js
412
- auth.off("state", callback);
413
- ```
414
-
415
- #### getLinkedSocials
416
-
417
- `getLinkedSocials() => Promise<{ twitter: boolean, tiktok: boolean, spotify: boolean }>`
418
-
419
- The `getLinkedSocials` method returns a promise that resolves to an object containing the possible socials that the user can link and whether they are linked or not.
420
-
421
- ```js
422
- const linkedSocials = await auth.getLinkedSocials();
423
-
424
- console.log(linkedSocials); // { twitter: true, tiktok: false, spotify: true }
425
- ```
426
-
427
- ---
428
-
429
- After the user has authenticated, the following methods can be used to link and unlink social accounts.
430
- When linking a social account, the user will be redirected to the OAuth flow for that social platform.
431
- Afterwards, the user will be redirected back to the `redirectUri` specified in the Auth constructor.
432
-
433
- #### linkTwitter
434
-
435
- `linkTwitter() => void`
436
-
437
- The `linkTwitter` method redirects the user to the Twitter OAuth flow to link their Twitter account to Origin.
438
-
439
- ```js
440
- auth.linkTwitter();
441
- ```
442
-
443
- #### linkSpotify
444
-
445
- `linkSpotify() => void`
446
-
447
- The `linkSpotify` method redirects the user to the Spotify OAuth flow to link their Spotify account to Origin.
448
-
449
- ```js
450
- auth.linkSpotify();
451
- ```
452
-
453
- #### linkTikTok
454
-
455
- `linkTikTok(handle: string) => Promise<void>`
456
-
457
- The `linkTikTok` method links the provided TikTok handle to Origin.
458
-
459
- ```js
460
- auth.linkTikTok("tiktokhandle");
461
- ```
462
-
463
- ---
464
-
465
- #### unlinkTwitter
466
-
467
- `unlinkTwitter() => Promise<void>`
468
-
469
- The `unlinkTwitter` method unlinks the user's Twitter account from Origin.
470
-
471
- ```js
472
- await auth.unlinkTwitter();
473
- ```
474
-
475
- #### unlinkSpotify
476
-
477
- `unlinkSpotify() => Promise<void>`
478
-
479
- The `unlinkSpotify` method unlinks the user's Spotify account from Origin.
480
-
481
- ```js
482
- await auth.unlinkSpotify();
483
- ```
484
-
485
- #### unlinkTikTok
486
-
487
- `unlinkTikTok() => Promise<void>`
488
-
489
- The `unlinkTikTok` method unlinks the user's TikTok account from Origin.
490
-
491
- ```js
492
- await auth.unlinkTikTok();
493
- ```
494
-
495
- # React
496
-
497
- The React components and hooks can be imported as ES6 modules. The example below shows how to set up the `CampProvider` component and subsequently use the provided hooks and components.
498
-
499
- ```js
500
- // main.jsx
501
- import { StrictMode } from "react";
502
- import { createRoot } from "react-dom/client";
503
- import { CampProvider } from "@campnetwork/origin/react";
504
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
505
- import App from "./App.jsx";
506
-
507
- const queryClient = new QueryClient();
508
-
509
- createRoot(document.getElementById("root")).render(
510
- <StrictMode>
511
- <QueryClientProvider client={queryClient}>
512
- <CampProvider clientId="your-client-id">
513
- <App />
514
- </CampProvider>
515
- </QueryClientProvider>
516
- </StrictMode>
517
- );
518
- ```
519
-
520
- ## CampProvider
521
-
522
- The `CampProvider` component requires a `clientId` prop to be passed in order link the users to your app.
523
- It can also take the following optional props:
524
-
525
- - `redirectUri` - `string | object` - Either a string that will be used as the redirect URI for all socials, or an object with the following optional properties: `twitter`, `spotify`. This is used to redirect the user to different pages after they have completed the OAuth flow for a social.
526
- - `environment` - `string` - The environment to use. Can be either `DEVELOPMENT` or `PRODUCTION`. Defaults to `DEVELOPMENT`.
527
- - - the `DEVELOPMENT` environment uses the Camp Testnet while the `PRODUCTION` environment uses the Camp Mainnet.
528
-
529
- ```jsx
530
- import { CampProvider } from "@campnetwork/origin/react";
531
- // ...
532
- function App() {
533
- return (
534
- <CampProvider
535
- clientId="your-client-id"
536
- redirectUri="https://your-website.com"
537
- environment="DEVELOPMENT"
538
- >
539
- <div>Your app</div>
540
- </CampProvider>
541
- );
542
- }
543
- ```
544
-
545
- Or, with an object for the `redirectUri`:
546
-
547
- ```jsx
548
- import { CampProvider } from "@campnetwork/origin/react";
549
- // ...
550
- function App() {
551
- return (
552
- <CampProvider
553
- clientId="your-client-id"
554
- redirectUri={{
555
- twitter: "https://your-website.com/twitter",
556
- spotify: "https://your-website.com/spotify",
557
- }}
558
- environment="DEVELOPMENT"
559
- >
560
- <div>Your app</div>
561
- </CampProvider>
562
- );
563
- }
564
- ```
565
-
566
- The `CampProvider` component sets up the context for the Origin SDK and provides the Auth instance to the rest of the app.
567
-
568
- ## CampModal
569
-
570
- ![@campnetwork/origin](https://imgur.com/AFmorL4.png)
571
-
572
- The **CampModal** is a one-line\* solution for authenticating users with the Origin SDK. It can be used to connect users to Origin, link and unlink social accounts, mint IPNFTs, and view the user's Origin stats.
573
-
574
- It works as follows:
575
-
576
- The **CampModal** component displays a button with the text "**Connect**" that the user can click on in order to summon the modal. The modal shows a list of available providers that the user can select from. After a provider has been selected, the `connect` method is called on the Auth instance to authenticate the user.
577
-
578
- If the user is already authenticated, the button will instead say "**My Origin**" and the modal will display the user's Origin profile information and allow them to link and unlink social accounts.
579
-
580
- The **CampModal** can take the following props:
581
-
582
- - `wcProjectId` - `string` - The WalletConnect project ID to use for authentication. Allows the users to authenticate via WalletConnect.
583
- - `injectButton` - `boolean` - Whether to inject the button into the DOM or not. Defaults to `true`. If set to `false`, the button will not be rendered and the modal can be opened programmatically via the `openModal` function returned by the `useModal` hook.
584
- - `onlyWagmi` - `boolean` - Whether to only show the provider that the user is currently authenticated with. Defaults to `false`.
585
- - `defaultProvider` - `{ provider: EIP1193Provider, info: EIP6963ProviderInfo, exclusive: boolean }` - Custom provider to set as the highlighted provider in the modal. If not set, the wagmi provider will be highlighted if it is available. The `exclusive` property can be set to `true` to only show this provider in the modal.
586
-
587
- ### Usage
588
-
589
- Basic usage of the **CampModal** component:
590
-
591
- ```jsx
592
- import { CampModal } from "@campnetwork/origin/react";
593
-
594
- function App() {
595
- return (
596
- <div>
597
- <CampModal />
598
- </div>
599
- );
600
- }
601
- ```
602
-
603
- With custom props:
604
-
605
- ```jsx
606
- import { CampModal } from "@campnetwork/origin/react";
607
-
608
- function App() {
609
- return (
610
- <div>
611
- <CampModal
612
- wcProjectId="your-wc-project-id"
613
- defaultProvider={{
614
- provider: window.ethereum,
615
- info: { name: "MetaMask", icon: "https://..." },
616
- exclusive: false,
617
- }}
618
- />
619
- </div>
620
- );
621
- }
622
- ```
623
-
624
- You can find more [examples here](./examples/client-side/react/providers-configuration).
625
-
626
- Only show the provider that the user is currently authenticated with (if using wagmi):
627
-
628
- ```jsx
629
- import { CampModal } from "@campnetwork/origin/react";
630
-
631
- function App() {
632
- return (
633
- <div>
634
- <CampModal onlyWagmi />
635
- </div>
636
- );
637
- }
638
- ```
639
-
640
- Users can be authenticated either via the Camp Modal as outlined above or programmatically by calling the `connect` method on the Auth instance.
641
-
642
- ### Usage with third party providers (Privy, Appkit, Magic, etc.)
643
-
644
- The Camp Modal can be used in conjunction with providers such as Privy and Appkit to create a seamless authentication experience for users. When using wagmi, it will automatically detect if the user is authenticated via a third party provider and give them the option to connect to Origin using that provider. Otherwise, you can set up the default provider to be whatever provider you are using.
645
-
646
- [Example usage with Privy](./examples/client-side/react/privy-connector/)
647
-
648
- [Example usage with Appkit](./examples/client-side/react/appkit-connector/)
649
-
650
- [Example usage with magic.link](./examples/client-side/react/magic-link-connector/)
651
-
652
- After the user has authenticated, you can use the provided hooks to fetch user data and listen for events.
653
-
654
- ## LinkButton
655
-
656
- The **LinkButton** component is a button that can be used to link and unlink social accounts. Under the hood it uses the `useLinkModal` hook to open the Link Socials modal.
657
-
658
- The **LinkButton** can take the following props:
659
-
660
- - `social` - `string` - The social account to link or unlink. Can be one of: `twitter`, `tiktok`, `spotify`.
661
- - `variant` - `string` - The variant of the button. Can be one of: `default`, `icon`. Defaults to `default`.
662
- - `theme` - `string` - The theme of the button. Can be one of: `default`, `camp`. Defaults to `default`.
663
-
664
- **Note: The `<CampModal/>` component must be rendered in the component tree for the buttons to work.**
665
-
666
- ### Usage
667
-
668
- Basic usage of the **LinkButton** component:
669
-
670
- ```jsx
671
- import { LinkButton, CampModal } from "@campnetwork/origin/react";
672
-
673
- function App() {
674
- return (
675
- <div>
676
- <CampModal />
677
- <LinkButton social="twitter" />
678
- <LinkButton social="spotify" theme="camp" />
679
- <LinkButton social="tiktok" variant="icon" theme="camp" />
680
- </div>
681
- );
682
- }
683
- ```
684
-
685
- ## CampButton
686
-
687
- The **CampButton** component allows you to render a button that opens the Auth or My Origin modal when clicked. It can be used as an alternative to the button that is injected by the **CampModal** component. It allows you to have multiple buttons in your app that open the modal, or to have the button in a different location than where the **CampModal** component is rendered.
688
-
689
- ```jsx
690
- import { CampButton, CampModal } from "@campnetwork/origin/react";
691
-
692
- function App() {
693
- return (
694
- <div>
695
- <CampModal injectButton={false} />
696
- <CampButton />
697
- </div>
698
- );
699
- }
700
- ```
701
-
702
- ## Hooks
703
-
704
- ### useAuth
705
-
706
- The `useAuth` hook returns the instance of the Auth class that is provided by the CampProvider.
707
- It can be used as outlined in the Core section in order to build custom authentication flows, listen for events, and fetch user data.
708
-
709
- ```jsx
710
- import { useAuth } from "@campnetwork/origin/react";
711
-
712
- function App() {
713
- const auth = useAuth();
714
-
715
- return (
716
- <div>
717
- <button onClick={auth.connect}>Connect</button>
718
- </div>
719
- );
720
- }
721
- ```
722
-
723
- ### useAuthState
724
-
725
- The `useAuthState` hook returns the current authentication state of the user.
726
-
727
- ```jsx
728
- import { useAuthState } from "@campnetwork/origin/react";
729
-
730
- function App() {
731
- const { authenticated, loading } = useAuthState();
732
-
733
- return (
734
- <div>
735
- {loading && <div>Loading...</div>}
736
- {authenticated && <div>Authenticated</div>}
737
- </div>
738
- );
739
- }
740
- ```
741
-
742
- ### useProvider
743
-
744
- The `useProvider` hook returns the provider that has been set via the `setProvider` method, as well as a `setProvider` function that can be used to update the provider.
745
-
746
- ```jsx
747
- import { useProvider } from "@campnetwork/origin/react";
748
-
749
- function App() {
750
- const { provider, setProvider } = useProvider();
751
-
752
- return (
753
- <div>
754
- <div>Current provider: {provider.info.name}</div>
755
- <button
756
- onClick={() =>
757
- setProvider({ provider: window.ethereum, info: { name: "Metamask" } })
758
- }
759
- >
760
- Set Provider
761
- </button>
762
- </div>
763
- );
764
- }
765
- ```
766
-
767
- ### useProviders
768
-
769
- The `useProviders` hook returns the list of providers that have been injected via EIP6963 and that the user or app can select from.
770
-
771
- ```jsx
772
- import { useProviders, useProvider } from "@campnetwork/origin/react";
773
-
774
- function App() {
775
- const providers = useProviders();
776
- const { setProvider } = useProvider();
777
-
778
- return (
779
- <div>
780
- {providers.map((provider) => (
781
- <button key={provider.info.name} onClick={() => setProvider(provider)}>
782
- {provider.info.name}
783
- </button>
784
- ))}
785
- </div>
786
- );
787
- }
788
- ```
789
-
790
- ### useConnect
791
-
792
- The `useConnect` hook returns functions that can be used to connect and disconnect the user.
793
-
794
- ```jsx
795
- import { useConnect, useAuthState } from "@campnetwork/origin/react";
796
-
797
- function App() {
798
- const { connect, disconnect } = useConnect();
799
- const { authenticated } = useAuthState();
800
-
801
- return (
802
- <div>
803
- {authenticated ? (
804
- <button onClick={disconnect}>Disconnect</button>
805
- ) : (
806
- <button onClick={connect}>Connect</button>
807
- )}
808
- </div>
809
- );
810
- }
811
- ```
812
-
813
- ### useSocials
814
-
815
- The `useSocials` hook returns the state of the user's linked social accounts.
816
-
817
- ```jsx
818
- import { useSocials } from "@campnetwork/origin/react";
819
-
820
- function App() {
821
- const { data, error, isLoading } = useSocials();
822
-
823
- if (loading) return <div>Loading...</div>;
824
- if (error) return <div>Error: {error.message}</div>;
825
-
826
- return (
827
- <div>
828
- <div>Twitter: {data.twitter ? "Linked" : "Not linked"}</div>
829
- <div>Tiktok: {data.tiktok ? "Linked" : "Not linked"}</div>
830
- <div>Spotify: {data.spotify ? "Linked" : "Not linked"}</div>
831
- </div>
832
- );
833
- }
834
- ```
835
-
836
- ### useLinkSocials
837
-
838
- The `useLinkSocials` hook returns functions that can be used to link and unlink social accounts.
839
-
840
- ```jsx
841
- import { useLinkSocials } from "@campnetwork/origin/react";
842
-
843
- function App() {
844
- const {
845
- linkTwitter,
846
- linkSpotify,
847
- linkTiktok,
848
- unlinkTwitter,
849
- unlinkSpotify,
850
- unlinkTiktok,
851
- } = useLinkSocials();
852
-
853
- return (
854
- <div>
855
- <button onClick={linkTwitter}>Link Twitter</button>
856
- <button onClick={linkSpotify}>Link Spotify</button>
857
- <button onClick={() => linkTiktok("tiktokhandle")}>Link TikTok</button>
858
- </button>
859
- <button onClick={unlinkTwitter}>Unlink Twitter</button>
860
- <button onClick={unlinkTiktok}>Unlink TikTok</button>
861
- <button onClick={unlinkSpotify}>Unlink Spotify</button>
862
- </div>
863
- );
864
- }
865
- ```
866
-
867
- ### useModal
868
-
869
- The `useModal` hook returns the state of the Auth and My Origin modals, as well as functions to show and hide them.
870
-
871
- **Note: The `<CampModal/>` component must be rendered in the component tree for the modals to be displayed.**
872
-
873
- ```jsx
874
- import { useModal, CampModal } from "@campnetwork/origin/react";
875
-
876
- function App() {
877
- const { isOpen, openModal, closeModal } = useModal();
878
-
879
- return (
880
- <div>
881
- <button onClick={openModal}>Open Modal</button>
882
- <button onClick={closeModal}>Close Modal</button>
883
- <CampModal injectButton={false} />
884
- </div>
885
- );
886
- }
887
- ```
888
-
889
- The state and functions returned by the `useModal` hook can be used to show and hide the Auth and My Origin modals, as well as to check if they are currently open. The modal being controlled is dictated by the user's authentication state.
890
-
891
- ### useLinkModal
892
-
893
- The `useLinkModal` hook returns the state of the Link Socials modal, as well as functions to show and hide it.
894
-
895
- **Note: The `<CampModal/>` component must be rendered in the component tree for the modal to be displayed.**
896
-
897
- ```jsx
898
- import { useLinkModal, CampModal } from "@campnetwork/origin/react";
899
-
900
- function App() {
901
- const { isLinkingOpen, openTwitterModal } = useLinkModal();
902
-
903
- return (
904
- <div>
905
- <CampModal />
906
- <button onClick={openTwitterModal}>Link Twitter</button>
907
- </div>
908
- );
909
- }
910
- ```
911
-
912
- It returns the following properties and functions:
913
-
914
- - `isLinkingOpen` - `boolean` - Whether the Link Socials modal is open or not.
915
- - `openTwitterModal` - `() => void`
916
- - `openSpotifyModal` - `() => void`
917
- - `openTiktokModal` - `() => void`
918
- - `linkTwitter` - `() => void`
919
- - `linkSpotify` - `() => void`
920
- - `linkTiktok` - `() => void`
921
- - `linkTelegram` - `() => void`
922
- - `unlinkTwitter` - `() => void`
923
- - `unlinkSpotify` - `() => void`
924
- - `unlinkTiktok` - `() => void`
925
- - `closeModal` - `() => void`
926
-
927
- The difference between the `openXModal` functions and the `linkX / unlinkX` functions is that the former opens the modal regardless of the user's linking state, allowing them to either link or unlink their account, while the latter only opens the specified modal if the user's linking state allows for it.
928
-
929
- For example, if the user is linked to Twitter, calling `openTwitterModal` will open the modal to _unlink_ their Twitter account, while calling `linkTwitter` will not do anything, and calling `unlinkTwitter` will open the modal to unlink their Twitter account.
930
-
931
- ## Origin Methods (`auth.origin`)
932
-
933
- The `Origin` class provides blockchain and API methods for interacting with Origin IpNFTs, uploading files, managing user stats, and more. Access these via `auth.origin` after authentication.
934
-
935
- ### Types
936
-
937
- #### `LicenseTerms`
938
-
939
- The license terms object used in minting and updating methods:
940
-
941
- ```typescript
942
- type LicenseTerms = {
943
- price: bigint; // Price in wei
944
- duration: number; // Duration in seconds
945
- royaltyBps: number; // Royalty in basis points (1-10000)
946
- paymentToken: Address; // Payment token address (address(0) for native currency)
947
- };
948
- ```
949
-
950
- ### Minting Constraints
951
-
952
- When minting or updating an IpNFT, the following constraints apply to the `LicenseTerms`:
953
-
954
- - The price must be at least `1000000000000000` wei (0.001 $CAMP).
955
- - The royaltyBps must be between `1` and `10000` (0.01% to 100%).
956
- - The duration must be between `86400` seconds and `2628000` seconds (1 day to 30 days).
957
-
958
- ### File Upload & Minting
959
-
960
- #### `mintFile(file, metadata, license, parents?, options?)`
961
-
962
- Uploads a file and mints an IpNFT for it.
963
-
964
- - `file`: File to upload and mint
965
- - `metadata`: Additional metadata for the IpNFT
966
- - `name`: Name of the IpNFT
967
- - `description`: Description of the IpNFT
968
- - `image`: Optional image URL for the IpNFT
969
- - `attributes`: Optional array of attributes
970
- - `license`: LicenseTerms object
971
- - `parents`: Optional array of parent token IDs for derivatives
972
- - `options.progressCallback`: Optional progress callback
973
- - **Returns:** Minted token ID as a string, or throws on failure
974
-
975
- #### `mintSocial(source, metadata, license)`
976
-
977
- Mints an IpNFT for a connected social account.
978
-
979
- - `source`: Social platform (`"spotify" | "twitter" | "tiktok"`)
980
- - `metadata`: Additional metadata for the IpNFT
981
- - `license`: LicenseTerms object
982
- - **Returns:** Minted token ID as a string, or throws on failure
983
-
984
- ### IpNFT & Marketplace Methods
985
-
986
- Most methods mirror smart contract functions and require appropriate permissions.
987
-
988
- #### Core IpNFT Methods
989
-
990
- - `mintWithSignature(account, tokenId, parents, creatorContentHash, uri, license, deadline, signature)`
991
- - `registerIpNFT(source, deadline, license, metadata, fileKey?, parents?)`
992
- - `updateTerms(tokenId, license)`
993
- - `finalizeDelete(tokenId)`
994
- - `getOrCreateRoyaltyVault(tokenId)`
995
- - `getTerms(tokenId)`
996
- - `ownerOf(tokenId)`
997
- - `balanceOf(owner)`
998
- - `tokenURI(tokenId)`
999
- - `dataStatus(tokenId)`
1000
- - `isApprovedForAll(owner, operator)`
1001
- - `transferFrom(from, to, tokenId)`
1002
- - `safeTransferFrom(from, to, tokenId)`
1003
- - `approve(to, tokenId)`
1004
- - `setApprovalForAll(operator, approved)`
1005
-
1006
- #### Marketplace Methods
1007
-
1008
- - `buyAccess(buyer, tokenId, expectedPrice, expectedDuration, expectedPaymentToken, value?)`
1009
- - `hasAccess(tokenId, user)`
1010
- - `subscriptionExpiry(tokenId, user)`
1011
-
1012
- #### Utility & Royalty Methods
1013
-
1014
- - `getRoyalties(token?, owner?)` — Get royalty vault and balance
1015
- - `claimRoyalties(token?, owner?)` Claim royalties
1016
-
1017
- #### Smart Access & Data
1018
-
1019
- - `buyAccessSmart(tokenId)` — Buys access, handles payment approval and license details - **Recommended in place of buyAccess**
1020
- - `getData(tokenId)` Fetches the underlying IP for a given IPNFT if the user has purchased access to it
1021
-
1022
- ### User Data & Stats
1023
-
1024
- - `getOriginUploads()` — Fetch user's Origin file uploads (returns array or null)
1025
- - `getOriginUsage()` Fetch user's Origin stats (returns object with multiplier, points, active, teams, dataSources)
1026
- - `setOriginConsent(consent: boolean)` Set user's consent for Origin usage
1027
-
1028
- ### Utility Methods
1029
-
1030
- - `getJwt()` — Get current JWT token
1031
- - `setViemClient(client)` — Set viem wallet client for blockchain interactions
1032
-
1033
- ---
1034
-
1035
- Call these methods as `await auth.origin.methodName(...)` after authenticating. See inline code documentation for full details and parameter types.
1036
-
1037
- ---
1038
-
1039
- # Contributing
1040
-
1041
- Install the dependencies.
1042
-
1043
- ```bash
1044
- npm install
1045
- ```
1046
-
1047
- Build the SDK.
1048
-
1049
- ```bash
1050
- npm run build
1051
- ```
1052
-
1053
- This will generate the SDK in the `dist` folder.
1054
-
1055
- You can also run the following command to watch for changes and rebuild the SDK automatically:
1056
-
1057
- ```bash
1058
- npm run dev
1059
- ```
1060
-
1061
- In order to use the sdk in a local project, you can link the sdk to the project.
1062
-
1063
- ```bash
1064
- npm link .
1065
- ```
1066
-
1067
- Then, in the project you want to use the sdk in, run:
1068
-
1069
- ```bash
1070
- npm link @campnetwork/origin
1071
- ```
1072
-
1073
- This will link the local sdk to the project.
1
+ <p align="center">
2
+ <img src="https://imgur.com/7nLZezD.png" height="200px"/>
3
+ </p>
4
+ <br/>
5
+
6
+ <p align="center">
7
+ <a href="https://www.npmjs.com/package/@campnetwork/origin"><img src="https://img.shields.io/npm/v/@campnetwork/origin?style=for-the-badge" alt="npm version"/></a>
8
+ <img alt="GitHub License" src="https://img.shields.io/github/license/campaign-layer/camp-sdk?style=for-the-badge">
9
+ <img src="https://img.shields.io/npm/last-update/%40campnetwork%2Forigin?style=for-the-badge" alt="npm last update"/>
10
+ <img alt="NPM Downloads" src="https://img.shields.io/npm/d18m/%40campnetwork%2Forigin?style=for-the-badge">
11
+ </p>
12
+
13
+ # Origin SDK
14
+
15
+ The Origin SDK currently exposes the following modules:
16
+
17
+ - `"@campnetwork/origin"` - The main entry point for the SDK, exposes the following classes:
18
+ - `TwitterAPI` - For fetching user Twitter data from Origin
19
+ - `SpotifyAPI` - For fetching user Spotify data from Origin
20
+ - `Auth` - For authenticating users with the Origin SDK (browser and Node.js)
21
+ - Signer adapters and utilities for Node.js support (ethers, viem, custom signers)
22
+ - Camp Network chain configurations (`campMainnet`, `campTestnet`)
23
+ - Origin utilities (`createLicenseTerms`, `LicenseTerms`, `DataStatus`)
24
+ - `"@campnetwork/origin/react"` - Exposes the CampProvider and CampContext, as well as React components and hooks for authentication and fetching user data via Origin
25
+
26
+ ## Features
27
+
28
+ - 🌐 **Browser & Node.js Support** - Use in client-side and server-side applications
29
+ - 🔐 **Multiple Signer Types** - Works with ethers, viem, or custom signers
30
+ - 🔗 **Social Account Linking** - Connect Twitter, Spotify, Discord, TikTok, and Telegram
31
+ - ⚛️ **React Components** - Pre-built UI components and hooks
32
+ - 📦 **TypeScript Support** - Full type definitions included
33
+ - 🛠️ **Flexible Storage** - Custom storage adapters for session persistence
34
+
35
+ # Installation
36
+
37
+ ```bash
38
+ npm install @campnetwork/origin
39
+ ```
40
+
41
+ # Core
42
+
43
+ The core modules can be imported either as a CommonJS module or as an ES6 module.
44
+
45
+ ### CommonJS
46
+
47
+ ```js
48
+ const { TwitterAPI, SpotifyAPI, Auth } = require("@campnetwork/origin");
49
+ ```
50
+
51
+ ### ES6
52
+
53
+ ```js
54
+ import { TwitterAPI, SpotifyAPI, Auth } from "@campnetwork/origin";
55
+ ```
56
+
57
+ ## Socials
58
+
59
+ ### TwitterAPI
60
+
61
+ The TwitterAPI class is the entry point for fetching user Twitter data from Origin. It requires an API key to be instantiated.
62
+
63
+ **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
64
+
65
+ #### Constructor
66
+
67
+ `apiKey` - The API key of your app.
68
+
69
+ ```js
70
+ const twitter = new TwitterAPI({
71
+ apiKey: string,
72
+ });
73
+ ```
74
+
75
+ #### Methods
76
+
77
+ ##### fetchUserByUsername
78
+
79
+ `fetchUserByUsername(twitterUserName: string)`
80
+
81
+ ```js
82
+ const user = await twitter.fetchUserByUsername("jack");
83
+ ```
84
+
85
+ ##### fetchTweetsByUsername
86
+
87
+ `fetchTweetsByUsername(twitterUserName: string, page: number, limit: number)`
88
+
89
+ ```js
90
+ const tweets = await twitter.fetchTweetsByUsername("jack", 1, 10);
91
+ ```
92
+
93
+ ##### fetchFollowersByUsername
94
+
95
+ `fetchFollowersByUsername(twitterUserName: string, page: number, limit: number)`
96
+
97
+ ```js
98
+ const followers = await twitter.fetchFollowersByUsername("jack", 1, 10);
99
+ ```
100
+
101
+ ##### fetchFollowingByUsername
102
+
103
+ `fetchFollowingByUsername(twitterUserName: string, page: number, limit: number)`
104
+
105
+ ```js
106
+ const following = await twitter.fetchFollowingByUsername("jack", 1, 10);
107
+ ```
108
+
109
+ ##### fetchTweetById
110
+
111
+ `fetchTweetById(tweetId: string)`
112
+
113
+ ```js
114
+ const tweet = await twitter.fetchTweetById("1234567890");
115
+ ```
116
+
117
+ ##### fetchUserByWalletAddress
118
+
119
+ `fetchUserByWalletAddress(walletAddress: string, page: number, limit: number)`
120
+
121
+ ```js
122
+ const user = await twitter.fetchUserByWalletAddress("0x1234567890", 1, 10);
123
+ ```
124
+
125
+ ##### fetchRepostedByUsername
126
+
127
+ `fetchRepostedByUsername(twitterUserName: string, page: number, limit: number)`
128
+
129
+ ```js
130
+ const reposts = await twitter.fetchRepostedByUsername("jack", 1, 10);
131
+ ```
132
+
133
+ ##### fetchRepliesByUsername
134
+
135
+ `fetchRepliesByUsername(twitterUserName: string, page: number, limit: number)`
136
+
137
+ ```js
138
+ const replies = await twitter.fetchRepliesByUsername("jack", 1, 10);
139
+ ```
140
+
141
+ ##### fetchLikesByUsername
142
+
143
+ `fetchLikesByUsername(twitterUserName: string, page: number, limit: number)`
144
+
145
+ ```js
146
+ const likes = await twitter.fetchLikesByUsername("jack", 1, 10);
147
+ ```
148
+
149
+ ##### fetchFollowsByUsername
150
+
151
+ `fetchFollowsByUsername(twitterUserName: string, page: number, limit: number)`
152
+
153
+ ```js
154
+ const follows = await twitter.fetchFollowsByUsername("jack", 1, 10);
155
+ ```
156
+
157
+ ##### fetchViewedTweetsByUsername
158
+
159
+ `fetchViewedTweetsByUsername(twitterUserName: string, page: number, limit: number)`
160
+
161
+ ```js
162
+ const viewedTweets = await twitter.fetchViewedTweetsByUsername("jack", 1, 10);
163
+ ```
164
+
165
+ ### SpotifyAPI
166
+
167
+ The SpotifyAPI class is the entry point for fetching user Spotify data from Origin. It requires an API key to be instantiated.
168
+
169
+ **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
170
+
171
+ #### Constructor
172
+
173
+ `apiKey` - The API key of your app.
174
+
175
+ ```js
176
+ const spotify = new SpotifyAPI({
177
+ apiKey: string,
178
+ });
179
+ ```
180
+
181
+ #### Methods
182
+
183
+ ##### fetchSavedTracksById
184
+
185
+ `fetchSavedTracksById(spotifyId: string)`
186
+
187
+ ```js
188
+ const savedTracks = await spotify.fetchSavedTracksById("1234567890");
189
+ ```
190
+
191
+ ##### fetchPlayedTracksById
192
+
193
+ `fetchPlayedTracksById(spotifyId: string)`
194
+
195
+ ```js
196
+ const playedTracks = await spotify.fetchPlayedTracksById("1234567890");
197
+ ```
198
+
199
+ ##### fetchSavedAlbumsById
200
+
201
+ `fetchSavedAlbumsById(spotifyId: string)`
202
+
203
+ ```js
204
+ const savedAlbums = await spotify.fetchSavedAlbumsById("1234567890");
205
+ ```
206
+
207
+ ##### fetchSavedPlaylistsById
208
+
209
+ `fetchSavedPlaylistsById(spotifyId: string)`
210
+
211
+ ```js
212
+ const savedPlaylists = await spotify.fetchSavedPlaylistsById("1234567890");
213
+ ```
214
+
215
+ ##### fetchTracksInAlbum
216
+
217
+ `fetchTracksInAlbum(spotifyId: string, albumId: string)`
218
+
219
+ ```js
220
+ const tracks = await spotify.fetchTracksInAlbum("1234567890", "1234567890");
221
+ ```
222
+
223
+ ##### fetchTracksInPlaylist
224
+
225
+ `fetchTracksInPlaylist(spotifyId: string, playlistId: string)`
226
+
227
+ ```js
228
+ const tracks = await spotify.fetchTracksInPlaylist("1234567890", "1234567890");
229
+ ```
230
+
231
+ ##### fetchUserByWalletAddress
232
+
233
+ `fetchUserByWalletAddress(walletAddress: string)`
234
+
235
+ ```js
236
+ const user = await spotify.fetchUserByWalletAddress("0x1234567890");
237
+ ```
238
+
239
+ ### TikTokAPI
240
+
241
+ The TikTokAPI class is the entry point for fetching user TikTok data from Origin. It requires an API key to be instantiated.
242
+
243
+ **Note: The methods for fetching data will only return data for users who have authenticated to your app via the Origin SDK.**
244
+
245
+ #### Constructor
246
+
247
+ `apiKey` - The API key of your app.
248
+
249
+ ```js
250
+ const tiktok = new TikTokAPI({
251
+ apiKey: string,
252
+ });
253
+ ```
254
+
255
+ #### Methods
256
+
257
+ ##### fetchUserByUsername
258
+
259
+ `fetchUserByUsername(tiktokUserName: string)`
260
+
261
+ ```js
262
+ const user = await tiktok.fetchUserByUsername("jack");
263
+ ```
264
+
265
+ ##### fetchVideoById
266
+
267
+ `fetchVideoById(userHandle: string, videoId: string)`
268
+
269
+ ```js
270
+ const video = await tiktok.fetchVideo("jack", "1234567890");
271
+ ```
272
+
273
+ ## Auth
274
+
275
+ The Auth class is the entry point for authenticating users with the Origin SDK. It requires a clientId to be instantiated.
276
+
277
+ **Note: The Auth class is only to be used on the client side.**
278
+
279
+ ### Constructor
280
+
281
+ - `clientId` - The client ID of your app. This is required to authenticate users with the Origin SDK.
282
+ - `redirectUri` - The URI to redirect to after the user completes oauth for any of the socials. Defaults to `window.location.href`.
283
+ The `redirectUri` can also be an object with the following optional properties:
284
+ - `twitter` - The URI to redirect to after the user completes oauth for Twitter.
285
+ - `spotify` - The URI to redirect to after the user completes oauth for Spotify.
286
+
287
+ You may use the `redirectUri` object to redirect the user to different pages based on the social they are linking.
288
+ You may only define the URIs for the socials you are using, the rest will default to `window.location.href`.
289
+
290
+ ```js
291
+ import { Auth } from "@campnetwork/origin";
292
+
293
+ const auth = new Auth({
294
+ clientId: string,
295
+ redirectUri: string | object,
296
+ allowAnalytics: boolean,
297
+ });
298
+ ```
299
+
300
+ ```js
301
+ const auth = new Auth({
302
+ clientId: "your-client-id",
303
+ redirectUri: {
304
+ twitter: "https://your-website.com/twitter",
305
+ spotify: "https://your-website.com/spotify",
306
+ },
307
+ });
308
+ ```
309
+
310
+ ### Methods
311
+
312
+ #### connect
313
+
314
+ `connect() => void`
315
+
316
+ The `connect` method prompts the user to sign a message with their wallet in order to authenticate with the Origin SDK.
317
+ The wallet provider can be set by calling the `setProvider` method on the Auth instance beforehand. The default provider used is `window.ethereum`.
318
+
319
+ ```js
320
+ auth.connect();
321
+ ```
322
+
323
+ #### disconnect
324
+
325
+ `disconnect() => void`
326
+
327
+ The `disconnect` method logs the user out of the Origin SDK on the client side.
328
+
329
+ ```js
330
+ auth.disconnect();
331
+ ```
332
+
333
+ #### setProvider
334
+
335
+ `setProvider(provider: { provider: EIP1193Provider, info: EIP6963ProviderInfo, address?: string }) => void`
336
+
337
+ _Read more about the [EIP1193Provider](https://eips.ethereum.org/EIPS/eip-1193) and [EIP6963ProviderInfo](https://eips.ethereum.org/EIPS/eip-6963) interfaces._
338
+
339
+ The `setProvider` method sets the wallet provider to be used for authentication.
340
+
341
+ ```js
342
+ auth.setProvider({
343
+ provider: window.ethereum,
344
+ info: { name: "MetaMask", icon: "https://..." },
345
+ });
346
+ ```
347
+
348
+ #### setWalletAddress
349
+
350
+ `setWalletAddress(walletAddress: string) => void`
351
+
352
+ The `setWalletAddress` method sets the wallet address to be used for authentication (via the `connect` method).
353
+
354
+ **This is only needed if the provider does not support the `eth_requestAccounts` method. Only use this method if you are sure you need to set the wallet address manually.**
355
+
356
+ ```js
357
+ auth.setWalletAddress("0x1234567890");
358
+ ```
359
+
360
+ #### on
361
+
362
+ `on(event: string, callback: (data: any) => void) => void`
363
+
364
+ The `on` method listens for events emitted by the Auth module of the Origin SDK.
365
+
366
+ The following events are emitted:
367
+
368
+ ##### "state"
369
+
370
+ Possible states:
371
+
372
+ - `authenticated` - The user has successfully authenticated.
373
+ - `unauthenticated` - The user has been logged out.
374
+ - `loading` - The user is in the process of authenticating.
375
+
376
+ ```js
377
+ auth.on("state", (data) => {
378
+ console.log(data); // "authenticated" | "unauthenticated" | "loading"
379
+ });
380
+ ```
381
+
382
+ ##### "provider"
383
+
384
+ Returns the provider that has been set via the `setProvider` method.
385
+ If using the Origin SDK React components, this event is emitted when the user selects a provider in the Auth modal.
386
+
387
+ ```js
388
+ auth.on("provider", (data) => {
389
+ console.log(data); // { provider: EIP1193Provider, info: EIP6963ProviderInfo }
390
+ });
391
+ ```
392
+
393
+ ##### "providers"
394
+
395
+ Returns the list of providers that have been injected via EIP6963 and that the user can select from.
396
+
397
+ ```js
398
+ auth.on("providers", (data) => {
399
+ console.log(data); // [{ provider: EIP1193Provider, info: EIP6963ProviderInfo }]
400
+ });
401
+ ```
402
+
403
+ You may use this event to update the UI with the available providers. The user can then select a provider to authenticate with, and the `setProvider` method can be called with the selected provider. The `connect` method can then be called to authenticate the user.
404
+
405
+ ```js
406
+ auth.on("providers", (data) => {
407
+ // Update UI with providers
408
+ // User selects a provider
409
+ const selectedProvider = data[0];
410
+
411
+ auth.setProvider(selectedProvider);
412
+
413
+ auth.connect();
414
+ });
415
+ ```
416
+
417
+ #### off
418
+
419
+ `off(event: string, callback: (data: any) => void) => void`
420
+
421
+ The `off` method unsubscribes from events emitted by the Auth module of the Origin SDK.
422
+
423
+ ```js
424
+ auth.off("state", callback);
425
+ ```
426
+
427
+ #### getLinkedSocials
428
+
429
+ `getLinkedSocials() => Promise<{ twitter: boolean, tiktok: boolean, spotify: boolean }>`
430
+
431
+ The `getLinkedSocials` method returns a promise that resolves to an object containing the possible socials that the user can link and whether they are linked or not.
432
+
433
+ ```js
434
+ const linkedSocials = await auth.getLinkedSocials();
435
+
436
+ console.log(linkedSocials); // { twitter: true, tiktok: false, spotify: true }
437
+ ```
438
+
439
+ ---
440
+
441
+ After the user has authenticated, the following methods can be used to link and unlink social accounts.
442
+ When linking a social account, the user will be redirected to the OAuth flow for that social platform.
443
+ Afterwards, the user will be redirected back to the `redirectUri` specified in the Auth constructor.
444
+
445
+ #### linkTwitter
446
+
447
+ `linkTwitter() => void`
448
+
449
+ The `linkTwitter` method redirects the user to the Twitter OAuth flow to link their Twitter account to Origin.
450
+
451
+ ```js
452
+ auth.linkTwitter();
453
+ ```
454
+
455
+ #### linkSpotify
456
+
457
+ `linkSpotify() => void`
458
+
459
+ The `linkSpotify` method redirects the user to the Spotify OAuth flow to link their Spotify account to Origin.
460
+
461
+ ```js
462
+ auth.linkSpotify();
463
+ ```
464
+
465
+ #### linkTikTok
466
+
467
+ `linkTikTok(handle: string) => Promise<void>`
468
+
469
+ The `linkTikTok` method links the provided TikTok handle to Origin.
470
+
471
+ ```js
472
+ auth.linkTikTok("tiktokhandle");
473
+ ```
474
+
475
+ ---
476
+
477
+ #### unlinkTwitter
478
+
479
+ `unlinkTwitter() => Promise<void>`
480
+
481
+ The `unlinkTwitter` method unlinks the user's Twitter account from Origin.
482
+
483
+ ```js
484
+ await auth.unlinkTwitter();
485
+ ```
486
+
487
+ #### unlinkSpotify
488
+
489
+ `unlinkSpotify() => Promise<void>`
490
+
491
+ The `unlinkSpotify` method unlinks the user's Spotify account from Origin.
492
+
493
+ ```js
494
+ await auth.unlinkSpotify();
495
+ ```
496
+
497
+ #### unlinkTikTok
498
+
499
+ `unlinkTikTok() => Promise<void>`
500
+
501
+ The `unlinkTikTok` method unlinks the user's TikTok account from Origin.
502
+
503
+ ```js
504
+ await auth.unlinkTikTok();
505
+ ```
506
+
507
+ ## Node.js Support
508
+
509
+ The Origin SDK supports Node.js environments, allowing you to authenticate and interact with Origin using server-side signers like ethers or viem.
510
+
511
+ ### Installation for Node.js
512
+
513
+ ```bash
514
+ # With ethers
515
+ npm install @campnetwork/origin ethers
516
+
517
+ # With viem
518
+ npm install @campnetwork/origin viem
519
+ ```
520
+
521
+ ### Key Differences from Browser Usage
522
+
523
+ 1. **No Browser Provider Detection**: In Node.js, you explicitly provide a signer instead of detecting browser wallets
524
+ 2. **Storage**: By default, Node.js uses in-memory storage (not persisted). You can provide a custom storage adapter
525
+ 3. **OAuth Social Linking**: Social account linking requires browser environment for OAuth flow
526
+ 4. **SIWE Domain/URI**: You must provide domain and URI for SIWE messages
527
+
528
+ ### Using with ethers
529
+
530
+ ```js
531
+ import { Auth, campMainnet } from "@campnetwork/origin";
532
+ import { ethers } from "ethers";
533
+
534
+ // Setup ethers provider and signer
535
+ const provider = new ethers.JsonRpcProvider(
536
+ process.env.RPC_URL || campMainnet.rpcUrls.default.http[0]
537
+ );
538
+ const signer = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
539
+
540
+ // Create Auth instance
541
+ const auth = new Auth({
542
+ clientId: process.env.CLIENT_ID,
543
+ redirectUri: "https://myapp.com/callback",
544
+ environment: "PRODUCTION",
545
+ });
546
+
547
+ // Connect using ethers signer
548
+ const result = await auth.connectWithSigner(signer, {
549
+ domain: "myapp.com",
550
+ uri: "https://myapp.com",
551
+ });
552
+
553
+ console.log("Connected!", result.walletAddress);
554
+
555
+ // Use origin methods
556
+ if (auth.origin) {
557
+ const terms = await auth.origin.getTerms(tokenId);
558
+ console.log("Terms:", terms);
559
+ }
560
+ ```
561
+
562
+ ### Using with viem
563
+
564
+ ```js
565
+ import { Auth, createNodeWalletClient, campMainnet } from "@campnetwork/origin";
566
+ import { privateKeyToAccount } from "viem/accounts";
567
+
568
+ // Create viem account from private key
569
+ const account = privateKeyToAccount(process.env.PRIVATE_KEY);
570
+
571
+ // Create wallet client for Node.js using Camp Network chain
572
+ const client = createNodeWalletClient(
573
+ account,
574
+ campMainnet,
575
+ process.env.RPC_URL || campMainnet.rpcUrls.default.http[0]
576
+ );
577
+
578
+ // Create Auth instance
579
+ const auth = new Auth({
580
+ clientId: process.env.CLIENT_ID,
581
+ redirectUri: "https://myapp.com/callback",
582
+ environment: "PRODUCTION",
583
+ });
584
+
585
+ // Connect using viem client
586
+ await auth.connectWithSigner(client, {
587
+ domain: "myapp.com",
588
+ uri: "https://myapp.com",
589
+ });
590
+
591
+ console.log("Authenticated:", auth.isAuthenticated);
592
+ ```
593
+
594
+ ### Exported Chain Configurations
595
+
596
+ The SDK exports Camp Network chain configurations for easy use:
597
+
598
+ ```js
599
+ import { campMainnet, campTestnet } from "@campnetwork/origin";
600
+
601
+ // campMainnet - Chain ID: 484 (Production)
602
+ // campTestnet - Chain ID: 123420001114 (Basecamp testnet)
603
+
604
+ console.log(campMainnet.rpcUrls.default.http[0]); // RPC URL
605
+ console.log(campMainnet.blockExplorers.default.url); // Block explorer
606
+ ```
607
+
608
+ ### Custom Storage Adapter
609
+
610
+ By default, Node.js uses in-memory storage. You can provide a custom storage adapter for persistence:
611
+
612
+ ```js
613
+ import { Auth, MemoryStorage } from "@campnetwork/origin";
614
+
615
+ // Custom file-based storage
616
+ class FileStorage {
617
+ async getItem(key) {
618
+ /* read from file */
619
+ }
620
+ async setItem(key, value) {
621
+ /* write to file */
622
+ }
623
+ async removeItem(key) {
624
+ /* delete from file */
625
+ }
626
+ }
627
+
628
+ const auth = new Auth({
629
+ clientId: process.env.CLIENT_ID,
630
+ redirectUri: "https://myapp.com/callback",
631
+ environment: "PRODUCTION",
632
+ storage: new FileStorage(), // Custom storage
633
+ });
634
+ ```
635
+
636
+ ### Methods
637
+
638
+ #### connectWithSigner
639
+
640
+ `connectWithSigner(signer: any, options?: { domain?: string, uri?: string }) => Promise<{ success: boolean, message: string, walletAddress: string }>`
641
+
642
+ Connect with a custom signer (viem WalletClient, ethers Signer, or custom signer implementation).
643
+
644
+ ```js
645
+ await auth.connectWithSigner(signer, {
646
+ domain: "myapp.com", // Required: Your application domain
647
+ uri: "https://myapp.com", // Required: Your application URI
648
+ });
649
+ ```
650
+
651
+ **Supported Signer Types:**
652
+
653
+ - **viem WalletClient** - Automatically detected and used
654
+ - **ethers Signer** (v5 or v6) - Works with both versions
655
+ - **Custom Signer** - Must implement `getAddress()`, `signMessage()`, and `getChainId()` methods
656
+
657
+ ### Exported Types and Utilities
658
+
659
+ ```js
660
+ import {
661
+ // Auth class
662
+ Auth,
663
+
664
+ // Signer adapters
665
+ ViemSignerAdapter,
666
+ EthersSignerAdapter,
667
+ CustomSignerAdapter,
668
+ createSignerAdapter,
669
+
670
+ // Storage adapters
671
+ BrowserStorage,
672
+ MemoryStorage,
673
+
674
+ // Viem helpers
675
+ createNodeWalletClient,
676
+
677
+ // Chain configs
678
+ campMainnet,
679
+ campTestnet,
680
+ } from "@campnetwork/origin";
681
+ ```
682
+
683
+ ### Examples
684
+
685
+ See the [examples/server-side](./examples/server-side) directory for complete Node.js examples including:
686
+
687
+ - `connect-with-ethers.js` - Using ethers v6 Signer
688
+ - `connect-with-viem.js` - Using viem WalletClient
689
+ - `connect-with-custom-signer.js` - Custom signer implementation
690
+ - `query-origin-data.js` - Querying blockchain data
691
+
692
+ # React
693
+
694
+ The React components and hooks can be imported as ES6 modules. The example below shows how to set up the `CampProvider` component and subsequently use the provided hooks and components.
695
+
696
+ ```js
697
+ // main.jsx
698
+ import { StrictMode } from "react";
699
+ import { createRoot } from "react-dom/client";
700
+ import { CampProvider } from "@campnetwork/origin/react";
701
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
702
+ import App from "./App.jsx";
703
+
704
+ const queryClient = new QueryClient();
705
+
706
+ createRoot(document.getElementById("root")).render(
707
+ <StrictMode>
708
+ <QueryClientProvider client={queryClient}>
709
+ <CampProvider clientId="your-client-id">
710
+ <App />
711
+ </CampProvider>
712
+ </QueryClientProvider>
713
+ </StrictMode>
714
+ );
715
+ ```
716
+
717
+ ## CampProvider
718
+
719
+ The `CampProvider` component requires a `clientId` prop to be passed in order link the users to your app.
720
+ It can also take the following optional props:
721
+
722
+ - `redirectUri` - `string | object` - Either a string that will be used as the redirect URI for all socials, or an object with the following optional properties: `twitter`, `spotify`. This is used to redirect the user to different pages after they have completed the OAuth flow for a social.
723
+ - `environment` - `string` - The environment to use. Can be either `DEVELOPMENT` or `PRODUCTION`. Defaults to `DEVELOPMENT`.
724
+ - - the `DEVELOPMENT` environment uses the Camp Testnet while the `PRODUCTION` environment uses the Camp Mainnet.
725
+
726
+ ```jsx
727
+ import { CampProvider } from "@campnetwork/origin/react";
728
+ // ...
729
+ function App() {
730
+ return (
731
+ <CampProvider
732
+ clientId="your-client-id"
733
+ redirectUri="https://your-website.com"
734
+ environment="DEVELOPMENT"
735
+ >
736
+ <div>Your app</div>
737
+ </CampProvider>
738
+ );
739
+ }
740
+ ```
741
+
742
+ Or, with an object for the `redirectUri`:
743
+
744
+ ```jsx
745
+ import { CampProvider } from "@campnetwork/origin/react";
746
+ // ...
747
+ function App() {
748
+ return (
749
+ <CampProvider
750
+ clientId="your-client-id"
751
+ redirectUri={{
752
+ twitter: "https://your-website.com/twitter",
753
+ spotify: "https://your-website.com/spotify",
754
+ }}
755
+ environment="DEVELOPMENT"
756
+ >
757
+ <div>Your app</div>
758
+ </CampProvider>
759
+ );
760
+ }
761
+ ```
762
+
763
+ The `CampProvider` component sets up the context for the Origin SDK and provides the Auth instance to the rest of the app.
764
+
765
+ ## CampModal
766
+
767
+ ![@campnetwork/origin](https://imgur.com/AFmorL4.png)
768
+
769
+ The **CampModal** is a one-line\* solution for authenticating users with the Origin SDK. It can be used to connect users to Origin, link and unlink social accounts, mint IPNFTs, and view the user's Origin stats.
770
+
771
+ It works as follows:
772
+
773
+ The **CampModal** component displays a button with the text "**Connect**" that the user can click on in order to summon the modal. The modal shows a list of available providers that the user can select from. After a provider has been selected, the `connect` method is called on the Auth instance to authenticate the user.
774
+
775
+ If the user is already authenticated, the button will instead say "**My Origin**" and the modal will display the user's Origin profile information and allow them to link and unlink social accounts.
776
+
777
+ The **CampModal** can take the following props:
778
+
779
+ - `wcProjectId` - `string` - The WalletConnect project ID to use for authentication. Allows the users to authenticate via WalletConnect.
780
+ - `injectButton` - `boolean` - Whether to inject the button into the DOM or not. Defaults to `true`. If set to `false`, the button will not be rendered and the modal can be opened programmatically via the `openModal` function returned by the `useModal` hook.
781
+ - `onlyWagmi` - `boolean` - Whether to only show the provider that the user is currently authenticated with. Defaults to `false`.
782
+ - `defaultProvider` - `{ provider: EIP1193Provider, info: EIP6963ProviderInfo, exclusive: boolean }` - Custom provider to set as the highlighted provider in the modal. If not set, the wagmi provider will be highlighted if it is available. The `exclusive` property can be set to `true` to only show this provider in the modal.
783
+
784
+ ### Usage
785
+
786
+ Basic usage of the **CampModal** component:
787
+
788
+ ```jsx
789
+ import { CampModal } from "@campnetwork/origin/react";
790
+
791
+ function App() {
792
+ return (
793
+ <div>
794
+ <CampModal />
795
+ </div>
796
+ );
797
+ }
798
+ ```
799
+
800
+ With custom props:
801
+
802
+ ```jsx
803
+ import { CampModal } from "@campnetwork/origin/react";
804
+
805
+ function App() {
806
+ return (
807
+ <div>
808
+ <CampModal
809
+ wcProjectId="your-wc-project-id"
810
+ defaultProvider={{
811
+ provider: window.ethereum,
812
+ info: { name: "MetaMask", icon: "https://..." },
813
+ exclusive: false,
814
+ }}
815
+ />
816
+ </div>
817
+ );
818
+ }
819
+ ```
820
+
821
+ You can find more [examples here](./examples/client-side/react/providers-configuration).
822
+
823
+ Only show the provider that the user is currently authenticated with (if using wagmi):
824
+
825
+ ```jsx
826
+ import { CampModal } from "@campnetwork/origin/react";
827
+
828
+ function App() {
829
+ return (
830
+ <div>
831
+ <CampModal onlyWagmi />
832
+ </div>
833
+ );
834
+ }
835
+ ```
836
+
837
+ Users can be authenticated either via the Camp Modal as outlined above or programmatically by calling the `connect` method on the Auth instance.
838
+
839
+ ### Usage with third party providers (Privy, Appkit, Magic, etc.)
840
+
841
+ The Camp Modal can be used in conjunction with providers such as Privy and Appkit to create a seamless authentication experience for users. When using wagmi, it will automatically detect if the user is authenticated via a third party provider and give them the option to connect to Origin using that provider. Otherwise, you can set up the default provider to be whatever provider you are using.
842
+
843
+ [Example usage with Privy](./examples/client-side/react/privy-connector/)
844
+
845
+ [Example usage with Appkit](./examples/client-side/react/appkit-connector/)
846
+
847
+ [Example usage with magic.link](./examples/client-side/react/magic-link-connector/)
848
+
849
+ After the user has authenticated, you can use the provided hooks to fetch user data and listen for events.
850
+
851
+ ## LinkButton
852
+
853
+ The **LinkButton** component is a button that can be used to link and unlink social accounts. Under the hood it uses the `useLinkModal` hook to open the Link Socials modal.
854
+
855
+ The **LinkButton** can take the following props:
856
+
857
+ - `social` - `string` - The social account to link or unlink. Can be one of: `twitter`, `tiktok`, `spotify`.
858
+ - `variant` - `string` - The variant of the button. Can be one of: `default`, `icon`. Defaults to `default`.
859
+ - `theme` - `string` - The theme of the button. Can be one of: `default`, `camp`. Defaults to `default`.
860
+
861
+ **Note: The `<CampModal/>` component must be rendered in the component tree for the buttons to work.**
862
+
863
+ ### Usage
864
+
865
+ Basic usage of the **LinkButton** component:
866
+
867
+ ```jsx
868
+ import { LinkButton, CampModal } from "@campnetwork/origin/react";
869
+
870
+ function App() {
871
+ return (
872
+ <div>
873
+ <CampModal />
874
+ <LinkButton social="twitter" />
875
+ <LinkButton social="spotify" theme="camp" />
876
+ <LinkButton social="tiktok" variant="icon" theme="camp" />
877
+ </div>
878
+ );
879
+ }
880
+ ```
881
+
882
+ ## CampButton
883
+
884
+ The **CampButton** component allows you to render a button that opens the Auth or My Origin modal when clicked. It can be used as an alternative to the button that is injected by the **CampModal** component. It allows you to have multiple buttons in your app that open the modal, or to have the button in a different location than where the **CampModal** component is rendered.
885
+
886
+ ```jsx
887
+ import { CampButton, CampModal } from "@campnetwork/origin/react";
888
+
889
+ function App() {
890
+ return (
891
+ <div>
892
+ <CampModal injectButton={false} />
893
+ <CampButton />
894
+ </div>
895
+ );
896
+ }
897
+ ```
898
+
899
+ ## Hooks
900
+
901
+ ### useAuth
902
+
903
+ The `useAuth` hook returns the instance of the Auth class that is provided by the CampProvider.
904
+ It can be used as outlined in the Core section in order to build custom authentication flows, listen for events, and fetch user data.
905
+
906
+ ```jsx
907
+ import { useAuth } from "@campnetwork/origin/react";
908
+
909
+ function App() {
910
+ const auth = useAuth();
911
+
912
+ return (
913
+ <div>
914
+ <button onClick={auth.connect}>Connect</button>
915
+ </div>
916
+ );
917
+ }
918
+ ```
919
+
920
+ ### useAuthState
921
+
922
+ The `useAuthState` hook returns the current authentication state of the user.
923
+
924
+ ```jsx
925
+ import { useAuthState } from "@campnetwork/origin/react";
926
+
927
+ function App() {
928
+ const { authenticated, loading } = useAuthState();
929
+
930
+ return (
931
+ <div>
932
+ {loading && <div>Loading...</div>}
933
+ {authenticated && <div>Authenticated</div>}
934
+ </div>
935
+ );
936
+ }
937
+ ```
938
+
939
+ ### useProvider
940
+
941
+ The `useProvider` hook returns the provider that has been set via the `setProvider` method, as well as a `setProvider` function that can be used to update the provider.
942
+
943
+ ```jsx
944
+ import { useProvider } from "@campnetwork/origin/react";
945
+
946
+ function App() {
947
+ const { provider, setProvider } = useProvider();
948
+
949
+ return (
950
+ <div>
951
+ <div>Current provider: {provider.info.name}</div>
952
+ <button
953
+ onClick={() =>
954
+ setProvider({ provider: window.ethereum, info: { name: "Metamask" } })
955
+ }
956
+ >
957
+ Set Provider
958
+ </button>
959
+ </div>
960
+ );
961
+ }
962
+ ```
963
+
964
+ ### useProviders
965
+
966
+ The `useProviders` hook returns the list of providers that have been injected via EIP6963 and that the user or app can select from.
967
+
968
+ ```jsx
969
+ import { useProviders, useProvider } from "@campnetwork/origin/react";
970
+
971
+ function App() {
972
+ const providers = useProviders();
973
+ const { setProvider } = useProvider();
974
+
975
+ return (
976
+ <div>
977
+ {providers.map((provider) => (
978
+ <button key={provider.info.name} onClick={() => setProvider(provider)}>
979
+ {provider.info.name}
980
+ </button>
981
+ ))}
982
+ </div>
983
+ );
984
+ }
985
+ ```
986
+
987
+ ### useConnect
988
+
989
+ The `useConnect` hook returns functions that can be used to connect and disconnect the user.
990
+
991
+ ```jsx
992
+ import { useConnect, useAuthState } from "@campnetwork/origin/react";
993
+
994
+ function App() {
995
+ const { connect, disconnect } = useConnect();
996
+ const { authenticated } = useAuthState();
997
+
998
+ return (
999
+ <div>
1000
+ {authenticated ? (
1001
+ <button onClick={disconnect}>Disconnect</button>
1002
+ ) : (
1003
+ <button onClick={connect}>Connect</button>
1004
+ )}
1005
+ </div>
1006
+ );
1007
+ }
1008
+ ```
1009
+
1010
+ ### useSocials
1011
+
1012
+ The `useSocials` hook returns the state of the user's linked social accounts.
1013
+
1014
+ ```jsx
1015
+ import { useSocials } from "@campnetwork/origin/react";
1016
+
1017
+ function App() {
1018
+ const { data, error, isLoading } = useSocials();
1019
+
1020
+ if (loading) return <div>Loading...</div>;
1021
+ if (error) return <div>Error: {error.message}</div>;
1022
+
1023
+ return (
1024
+ <div>
1025
+ <div>Twitter: {data.twitter ? "Linked" : "Not linked"}</div>
1026
+ <div>Tiktok: {data.tiktok ? "Linked" : "Not linked"}</div>
1027
+ <div>Spotify: {data.spotify ? "Linked" : "Not linked"}</div>
1028
+ </div>
1029
+ );
1030
+ }
1031
+ ```
1032
+
1033
+ ### useLinkSocials
1034
+
1035
+ The `useLinkSocials` hook returns functions that can be used to link and unlink social accounts.
1036
+
1037
+ ```jsx
1038
+ import { useLinkSocials } from "@campnetwork/origin/react";
1039
+
1040
+ function App() {
1041
+ const {
1042
+ linkTwitter,
1043
+ linkSpotify,
1044
+ linkTiktok,
1045
+ unlinkTwitter,
1046
+ unlinkSpotify,
1047
+ unlinkTiktok,
1048
+ } = useLinkSocials();
1049
+
1050
+ return (
1051
+ <div>
1052
+ <button onClick={linkTwitter}>Link Twitter</button>
1053
+ <button onClick={linkSpotify}>Link Spotify</button>
1054
+ <button onClick={() => linkTiktok("tiktokhandle")}>Link TikTok</button>
1055
+ </button>
1056
+ <button onClick={unlinkTwitter}>Unlink Twitter</button>
1057
+ <button onClick={unlinkTiktok}>Unlink TikTok</button>
1058
+ <button onClick={unlinkSpotify}>Unlink Spotify</button>
1059
+ </div>
1060
+ );
1061
+ }
1062
+ ```
1063
+
1064
+ ### useModal
1065
+
1066
+ The `useModal` hook returns the state of the Auth and My Origin modals, as well as functions to show and hide them.
1067
+
1068
+ **Note: The `<CampModal/>` component must be rendered in the component tree for the modals to be displayed.**
1069
+
1070
+ ```jsx
1071
+ import { useModal, CampModal } from "@campnetwork/origin/react";
1072
+
1073
+ function App() {
1074
+ const { isOpen, openModal, closeModal } = useModal();
1075
+
1076
+ return (
1077
+ <div>
1078
+ <button onClick={openModal}>Open Modal</button>
1079
+ <button onClick={closeModal}>Close Modal</button>
1080
+ <CampModal injectButton={false} />
1081
+ </div>
1082
+ );
1083
+ }
1084
+ ```
1085
+
1086
+ The state and functions returned by the `useModal` hook can be used to show and hide the Auth and My Origin modals, as well as to check if they are currently open. The modal being controlled is dictated by the user's authentication state.
1087
+
1088
+ ### useLinkModal
1089
+
1090
+ The `useLinkModal` hook returns the state of the Link Socials modal, as well as functions to show and hide it.
1091
+
1092
+ **Note: The `<CampModal/>` component must be rendered in the component tree for the modal to be displayed.**
1093
+
1094
+ ```jsx
1095
+ import { useLinkModal, CampModal } from "@campnetwork/origin/react";
1096
+
1097
+ function App() {
1098
+ const { isLinkingOpen, openTwitterModal } = useLinkModal();
1099
+
1100
+ return (
1101
+ <div>
1102
+ <CampModal />
1103
+ <button onClick={openTwitterModal}>Link Twitter</button>
1104
+ </div>
1105
+ );
1106
+ }
1107
+ ```
1108
+
1109
+ It returns the following properties and functions:
1110
+
1111
+ - `isLinkingOpen` - `boolean` - Whether the Link Socials modal is open or not.
1112
+ - `openTwitterModal` - `() => void`
1113
+ - `openSpotifyModal` - `() => void`
1114
+ - `openTiktokModal` - `() => void`
1115
+ - `linkTwitter` - `() => void`
1116
+ - `linkSpotify` - `() => void`
1117
+ - `linkTiktok` - `() => void`
1118
+ - `linkTelegram` - `() => void`
1119
+ - `unlinkTwitter` - `() => void`
1120
+ - `unlinkSpotify` - `() => void`
1121
+ - `unlinkTiktok` - `() => void`
1122
+ - `closeModal` - `() => void`
1123
+
1124
+ The difference between the `openXModal` functions and the `linkX / unlinkX` functions is that the former opens the modal regardless of the user's linking state, allowing them to either link or unlink their account, while the latter only opens the specified modal if the user's linking state allows for it.
1125
+
1126
+ For example, if the user is linked to Twitter, calling `openTwitterModal` will open the modal to _unlink_ their Twitter account, while calling `linkTwitter` will not do anything, and calling `unlinkTwitter` will open the modal to unlink their Twitter account.
1127
+
1128
+ ## Origin Methods (`auth.origin`)
1129
+
1130
+ The `Origin` class provides blockchain and API methods for interacting with Origin IpNFTs, uploading files, managing user stats, and more. Access these via `auth.origin` after authentication.
1131
+
1132
+ ### Types
1133
+
1134
+ #### `LicenseTerms`
1135
+
1136
+ The license terms object used in minting and updating methods:
1137
+
1138
+ ```typescript
1139
+ type LicenseTerms = {
1140
+ price: bigint; // Price in wei
1141
+ duration: number; // Duration in seconds
1142
+ royaltyBps: number; // Royalty in basis points (1-10000)
1143
+ paymentToken: Address; // Payment token address (address(0) for native currency)
1144
+ };
1145
+ ```
1146
+
1147
+ ### Minting Constraints
1148
+
1149
+ When minting or updating an IpNFT, the following constraints apply to the `LicenseTerms`:
1150
+
1151
+ - The price must be at least `1000000000000000` wei (0.001 $CAMP).
1152
+ - The royaltyBps must be between `1` and `10000` (0.01% to 100%).
1153
+ - The duration must be between `86400` seconds and `2628000` seconds (1 day to 30 days).
1154
+
1155
+ ### `createLicenseTerms(price, duration, royaltyBps, paymentToken)`
1156
+
1157
+ A utility function to create properly validated license terms for minting and updating IpNFTs.
1158
+
1159
+ - `price`: Price in wei (bigint) - must be at least `1000000000000000` wei
1160
+ - `duration`: Duration in seconds (number) - must be between `86400` and `2628000` seconds
1161
+ - `royaltyBps`: Royalty in basis points (number) - must be between `1` and `10000`
1162
+ - `paymentToken`: Payment token address (Address) - use `zeroAddress` from viem for native currency
1163
+ - **Returns:** A validated `LicenseTerms` object
1164
+ - **Throws:** Error if any parameter violates the constraints
1165
+
1166
+ **Example:**
1167
+
1168
+ ```typescript
1169
+ import { createLicenseTerms } from "@campnetwork/origin";
1170
+ import { zeroAddress } from "viem";
1171
+
1172
+ // Create license terms with validation
1173
+ const license = createLicenseTerms(
1174
+ BigInt("1000000000000000"), // 0.001 CAMP in wei
1175
+ 86400, // 1 day in seconds
1176
+ 1000, // 10% royalty (1000 basis points)
1177
+ zeroAddress // Native currency (CAMP)
1178
+ );
1179
+
1180
+ // Use with minting functions
1181
+ await auth.origin.mintFile(file, metadata, license);
1182
+ await auth.origin.mintSocial("twitter", metadata, license);
1183
+ ```
1184
+
1185
+ ### File Upload & Minting
1186
+
1187
+ #### `mintFile(file, metadata, license, parents?, options?)`
1188
+
1189
+ Uploads a file and mints an IpNFT for it.
1190
+
1191
+ - `file`: File to upload and mint
1192
+ - `metadata`: Additional metadata for the IpNFT
1193
+ - `name`: Name of the IpNFT
1194
+ - `description`: Description of the IpNFT
1195
+ - `image`: Optional image URL for the IpNFT
1196
+ - `attributes`: Optional array of attributes
1197
+ - `license`: LicenseTerms object
1198
+ - `parents`: Optional array of parent token IDs for derivatives
1199
+ - `options.progressCallback`: Optional progress callback
1200
+ - **Returns:** Minted token ID as a string, or throws on failure
1201
+
1202
+ #### `mintSocial(source, metadata, license)`
1203
+
1204
+ Mints an IpNFT for a connected social account.
1205
+
1206
+ - `source`: Social platform (`"spotify" | "twitter" | "tiktok"`)
1207
+ - `metadata`: Additional metadata for the IpNFT
1208
+ - `license`: LicenseTerms object
1209
+ - **Returns:** Minted token ID as a string, or throws on failure
1210
+
1211
+ ### IpNFT & Marketplace Methods
1212
+
1213
+ Most methods mirror smart contract functions and require appropriate permissions.
1214
+
1215
+ #### Core IpNFT Methods
1216
+
1217
+ - `mintWithSignature(account, tokenId, parents, creatorContentHash, uri, license, deadline, signature)`
1218
+ - `registerIpNFT(source, deadline, license, metadata, fileKey?, parents?)`
1219
+ - `updateTerms(tokenId, license)`
1220
+ - `finalizeDelete(tokenId)`
1221
+ - `getOrCreateRoyaltyVault(tokenId)`
1222
+ - `getTerms(tokenId)`
1223
+ - `ownerOf(tokenId)`
1224
+ - `balanceOf(owner)`
1225
+ - `tokenURI(tokenId)`
1226
+ - `dataStatus(tokenId)`
1227
+ - `isApprovedForAll(owner, operator)`
1228
+ - `transferFrom(from, to, tokenId)`
1229
+ - `safeTransferFrom(from, to, tokenId)`
1230
+ - `approve(to, tokenId)`
1231
+ - `setApprovalForAll(operator, approved)`
1232
+
1233
+ #### Marketplace Methods
1234
+
1235
+ - `buyAccess(buyer, tokenId, expectedPrice, expectedDuration, expectedPaymentToken, value?)`
1236
+ - `hasAccess(tokenId, user)`
1237
+ - `subscriptionExpiry(tokenId, user)`
1238
+
1239
+ #### Utility & Royalty Methods
1240
+
1241
+ - `getRoyalties(token?, owner?)` — Get royalty vault and balance
1242
+ - `claimRoyalties(token?, owner?)` — Claim royalties
1243
+
1244
+ #### Smart Access & Data
1245
+
1246
+ - `buyAccessSmart(tokenId)` — Buys access, handles payment approval and license details - **Recommended in place of buyAccess**
1247
+ - `getData(tokenId)` — Fetches the underlying IP for a given IPNFT if the user has purchased access to it
1248
+
1249
+ ### User Data & Stats
1250
+
1251
+ - `getOriginUploads()` — Fetch user's Origin file uploads (returns array or null)
1252
+ - `getOriginUsage()` — Fetch user's Origin stats (returns object with multiplier, points, active, teams, dataSources)
1253
+ - `setOriginConsent(consent: boolean)` — Set user's consent for Origin usage
1254
+
1255
+ ### Utility Methods
1256
+
1257
+ - `getJwt()` — Get current JWT token
1258
+ - `setViemClient(client)` — Set viem wallet client for blockchain interactions
1259
+
1260
+ ---
1261
+
1262
+ Call these methods as `await auth.origin.methodName(...)` after authenticating. See inline code documentation for full details and parameter types.
1263
+
1264
+ ---
1265
+
1266
+ # Contributing
1267
+
1268
+ Install the dependencies.
1269
+
1270
+ ```bash
1271
+ npm install
1272
+ ```
1273
+
1274
+ Build the SDK.
1275
+
1276
+ ```bash
1277
+ npm run build
1278
+ ```
1279
+
1280
+ This will generate the SDK in the `dist` folder.
1281
+
1282
+ You can also run the following command to watch for changes and rebuild the SDK automatically:
1283
+
1284
+ ```bash
1285
+ npm run dev
1286
+ ```
1287
+
1288
+ In order to use the sdk in a local project, you can link the sdk to the project.
1289
+
1290
+ ```bash
1291
+ npm link .
1292
+ ```
1293
+
1294
+ Then, in the project you want to use the sdk in, run:
1295
+
1296
+ ```bash
1297
+ npm link @campnetwork/origin
1298
+ ```
1299
+
1300
+ This will link the local sdk to the project.