@eluvio/elv-client-js 3.2.2 → 3.2.4

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.
@@ -1,40 +0,0 @@
1
- let WalletConfiguration = {
2
- demo: {
3
- configUrl: "https://demov3.net955210.contentfabric.io/config",
4
- staging: {
5
- siteId: "iq__2gkNh8CCZqFFnoRpEUmz7P3PaBQG",
6
- purchaseMode: "develop",
7
- appUrl: "https://core.test.contentfabric.io/wallet-demo"
8
- }
9
- },
10
- main: {
11
- configUrl: "https://main.net955305.contentfabric.io/config",
12
- staging: {
13
- siteId: "iq__inauxD1KLyKWPHargCWjdCh2ayr",
14
- purchaseMode: "production",
15
- appUrl: "https://core.test.contentfabric.io/wallet"
16
- },
17
- production: {
18
- siteId: "iq__suqRJUt2vmXsyiWS5ZaSGwtFU9R",
19
- purchaseMode: "production",
20
- appUrl: "https://wallet.contentfabric.io"
21
- }
22
- },
23
- __MARKETPLACE_ORDER: [
24
- "dolly-marketplace",
25
- "oc-marketplace",
26
- "maskverse-marketplace",
27
- "emp-marketplace",
28
- "microsoft",
29
- "indieflix-marketplace",
30
- "angels-airwaves-marketplace"
31
- ]
32
- };
33
-
34
- // No production environment on demo
35
- WalletConfiguration.demo.production = WalletConfiguration.demo.staging;
36
-
37
- // Allow demo to be referred to as demov3
38
- WalletConfiguration.demov3 = WalletConfiguration.demo;
39
-
40
- module.exports = WalletConfiguration;
@@ -1,185 +0,0 @@
1
- # Eluvio Wallet Client
2
-
3
- This is a standalone client for using Eluvio Media Wallet functionality
4
-
5
- For information about the embedded wallet app frame client, see [here](https://eluv-io.github.io/elv-media-wallet/ElvWalletFrameClient.html)
6
-
7
- ## Initializing the Client
8
-
9
- Initializing the client is as simple as calling the static Initialize method with the network (main or demo) and the mode (production or staging) the client should operate upon, as well as (optionally) the marketplace to associate the client with.
10
-
11
- ```javascript
12
- await ElvWalletClient.Initialize({
13
- network: "main | demo",
14
- mode: "production | staging",
15
- marketplaceParams: {
16
- tenantSlug,
17
- marketplaceSlug
18
- }
19
- })
20
- ```
21
-
22
- ## Referencing Marketplaces
23
-
24
- Many methods, including the Initialize method, take a parameter called `marketplaceParams`. This parameter should be specified in one of the following formats:
25
-
26
- Specify the tenant slug and marketplace slug corresponding to your marketplace.
27
- ```javascript
28
- {
29
- tenantSlug: "<tenant-slug>",
30
- marketplaceSlug: "<marketplace-slug>"
31
- }
32
- ```
33
-
34
- Specify the object ID of the marketplace
35
- ```javascript
36
- { marketplaceId: "iq__abc123" }
37
- ```
38
-
39
- Specify a version hash of the marketplace
40
- ```javascript
41
- { marketplaceHash: "hq__abc123" }
42
- ```
43
-
44
- ## Handling Login
45
-
46
- The wallet client make it simple to log in with the Eluvio Media Wallet. However, if you are also using the frame client to embed the wallet application, extra care must be taken to ensure the login flow is handled correctly and the wallet client and frame have parity in their authorization states.
47
-
48
- <div id="wallet-client" />
49
-
50
- ### Wallet Client
51
-
52
- ##### Redirect Flow
53
- ```javascript
54
- walletClient.LogIn({
55
- method: "redirect",
56
- callbackUrl: <https://your-domain.com/callback>
57
- });
58
- ```
59
-
60
- Upon login, the browser will return to the callbackUrl with the authorization token as a url parameter (`elvToken`). **Initializing the client will automatically pull the token out of the URL parameters and log in.**
61
-
62
- If you don't want to initialize the client in the callback URL, you can save this token and later set it in the client using the `Authenticate` method.
63
-
64
- ```javascript
65
- const searchParams = new URLSearchParams(window.location.search);
66
- const clientAuthToken = searchParams.get("elvToken");
67
-
68
- ...
69
-
70
- walletClient.Authorize({token: clientAuthToken});
71
-
72
- ```
73
-
74
- ##### Popup Flow
75
- ```javascript
76
- try {
77
- await walletClient.LogIn({
78
- method: "popup"
79
- })
80
- } catch(error) {
81
- // User closed popup
82
- }
83
- ```
84
-
85
- ##### Additional Options
86
-
87
- The `clear` parameter in the LogIn method will ensure that the user does the full log in flow, even if they are already logged in to the Eluvio Media Wallet application. This is important to specify if the user has logged out from your application, as they will otherwise still be logged in to the Media Wallet and the login flow will simply authorize them as the same user.
88
-
89
- The `provider` parameter will automatically proceed to log in with the specified provider instead of presenting the usual login screen and waiting for the user to choose. For example, you can specify that the login flow should automatically prompt for Metamask login or proceed to the OAuth login flow. For the OAuth flow, the `mode` parameter can be used to proceed to the `login` flow or the `create` account flow.
90
-
91
- ##### Saving Authorization
92
-
93
- By default, the client will save the authorization token in localstorage, if available. If you prefer to handle storing the authorization token differently, you can specify that the client should not save the token when initializing the client:
94
-
95
- ```javascript
96
- const walletClient = ElvWalletClient.Initialize({
97
- ...,
98
- storeAuthToken: false
99
- })
100
- ```
101
-
102
- The authorization token can be retrieved using `walletClient.ClientAuthToken()`, which can then be used later in the `Authenticate` method.
103
-
104
-
105
- ### Frame Client
106
-
107
- If you only want to embed the Eluvio Media Wallet application without using the Wallet Client and you don't want to implement a custom login screen, no special effort is needed. The wallet app UI will handle login natively.
108
-
109
- You can use event listeners with the frame client to detect when the user logs in or out:
110
-
111
- ```javascript
112
- frameClient.AddEventListener(frameClient.EVENTS.LOG_IN, ({address}) => { ... });
113
-
114
- frameClient.AddEventListener(frameClient.EVENTS.LOG_OUT, () => { ... });
115
- ```
116
-
117
-
118
- ### Custom Login UI For Embedded Wallet App / Using Both Wallet Client and Frame Client
119
-
120
- If you want to implement a custom login screen for the embedded wallet application, or if you want to use both the wallet and frame clients in the same application, some care must be taken to ensure the login flow is handled correctly and the wallet client and frame have parity in their authorization states.
121
-
122
- First, **login should be handled by the Wallet Client only**. The wallet client does not have to deal with the limitations of iframes, and the wallet client is allowed access to the user's authorization token, which can be passed to the frame client to authorize the embedded application.
123
-
124
- Authorization can be passed to the embedded frame, but **cannot be retrieved** from it. Because of this, logging in via the embedded application would mean the user is logged in in the frame, but the wallet client in the containing application has no access to that user's authorization.
125
-
126
- Here's how to handle this case:
127
-
128
- ##### Perform Login Using the Wallet Client
129
-
130
- See the [Wallet Client](#wallet-client) login section for details about how to handle the login flow with the wallet client.
131
-
132
- ##### Capture Login from the Frame
133
-
134
- When initializing the frame client, specify the `captureLogin` option. This will cause login prompts (e.g. user clicks log in, user tries to perform/access something that requires login, etc.) to emit an event instead of presenting the login form in the frame.
135
-
136
- ```javascript
137
- const frameClient = await ElvWalletFrameClient.InitializeFrame({
138
- ...,
139
- captureLogin: true
140
- })
141
- ```
142
-
143
- You can then listen for that event to present your own login screen, or simply trigger the login flow with the Wallet Client.
144
-
145
- ```javascript
146
- frameClient.AddEventListener(
147
- frameClient.EVENTS.LOG_IN_REQUESTED,
148
- () => {
149
- // Show your login screen or log in with wallet client
150
- // ShowLogin()
151
- // walletClient.LogIn({...});
152
- }
153
- )
154
- ```
155
-
156
- ##### Pass Authorization Token to Frame Client
157
-
158
- When the login flow has completed with the wallet client, pass the authorization token to the embedded application:
159
-
160
- ```javascript
161
- if(walletClient.ClientAuthToken()) {
162
- await frameClient.LogIn({clientAuthToken: walletClient.ClientAuthToken()})
163
- }
164
- ```
165
-
166
- ##### Handle Log Out in Both Clients
167
-
168
- After the user is logged in with the frame client, you can present an option to log out. Be sure this logs out both the wallet client and the frame client:
169
-
170
- ```javascript
171
- function LogOutFromMyApp() {
172
- walletClient.LogOut();
173
- frameClient.LogOut();
174
- }
175
- ```
176
-
177
- Additionally, the user may log out from the embedded application. Use an event listener in the frame client to handle this and log out from the wallet client:
178
-
179
- ```javascript
180
- frameClient.AddEventListener(
181
- frameClient.EVENTS.LOG_OUT,
182
- () => LogOutFromMyApp()
183
- );
184
- ```
185
-
@@ -1,234 +0,0 @@
1
- const Utils = require("../Utils");
2
-
3
- const RarityToPercentage = (rarity) => {
4
- if(!rarity) {
5
- return "";
6
- }
7
-
8
- rarity = rarity.toString();
9
-
10
- if(!rarity.includes("/")) {
11
- return rarity;
12
- }
13
-
14
- const [ numerator, denominator ] = rarity.split("/");
15
- let percentage = 100 * parseInt(numerator) / parseInt(denominator);
16
-
17
- if(percentage < 1) {
18
- percentage = percentage.toFixed(2);
19
- } else {
20
- percentage = percentage.toFixed(1).toString().replace(".0", "");
21
- }
22
-
23
- return percentage;
24
- };
25
-
26
- // Format NFT or listing result into consistent format
27
- const FormatNFTDetails = function(entry) {
28
- const isListing = !!entry.id;
29
-
30
- const metadata = (isListing ? entry.nft : entry.meta) || {};
31
- const info = (isListing ? entry.info : entry);
32
-
33
- let details = {
34
- USDCAccepted: !!(entry.accepts || []).find(entry => entry.type === "sol"),
35
- USDCOnly: ((entry.accepts || []).find(entry => entry.type === "sol") || {}).preferred,
36
- TenantId: entry.tenant || entry.tenant_id,
37
- ContractAddr: info.contract_addr,
38
- ContractId: `ictr${Utils.AddressToHash(info.contract_addr)}`,
39
- ContractName: info.contract_name,
40
- Cap: info.cap,
41
- TokenIdStr: info.token_id_str,
42
- TokenUri: info.token_uri,
43
- TokenOrdinal: info.ordinal,
44
- TokenHold: info.hold,
45
- TokenHoldDate: info.hold ? new Date(parseInt(info.hold) * 1000) : undefined,
46
- TokenOwner: info.token_owner ? Utils.FormatAddress(info.token_owner) : "",
47
- VersionHash: (info.token_uri || "").split("/").find(s => (s || "").startsWith("hq__")),
48
- };
49
-
50
- if(isListing) {
51
- details = {
52
- ...details,
53
- // Listing specific fields
54
- ListingId: entry.id,
55
- CreatedAt: entry.created * 1000,
56
- UpdatedAt: entry.updated * 1000,
57
- CheckoutLockedUntil: entry.checkout ? entry.checkout * 1000 : undefined,
58
- SellerAddress: Utils.FormatAddress(entry.seller),
59
- Price: entry.price,
60
- Fee: entry.fee
61
- };
62
- }
63
-
64
- return {
65
- metadata,
66
- details
67
- };
68
- };
69
-
70
- exports.FormatNFTDetails = FormatNFTDetails;
71
-
72
-
73
- const FormatNFTMetadata = function(nft) {
74
- nft.formatted = true;
75
-
76
- // Surface relevant details to top level
77
- nft.contractAddress = nft.details.ContractAddr;
78
- nft.contractId = nft.details.ContractId;
79
- nft.tokenId = nft.details.TokenIdStr;
80
- nft.name = nft.metadata.display_name;
81
-
82
- if(nft.details.ListingId) {
83
- nft.listingId = nft.details.ListingId;
84
- }
85
-
86
- // Format traits
87
- const FILTERED_ATTRIBUTES = ["Content Fabric Hash", "Creator", "Total Minted Supply"];
88
- nft.metadata.attributes = (nft.metadata.attributes || [])
89
- .filter(attribute => attribute && !FILTERED_ATTRIBUTES.includes(attribute.trait_type))
90
- .map(trait => ({...trait, name: trait.trait_type, rarity_percent: RarityToPercentage(trait.rarity)}));
91
-
92
- // Generate embed URLs for additional media
93
- if(nft.metadata.additional_media) {
94
- nft.metadata.additional_media = nft.metadata.additional_media.map(media => {
95
- try {
96
- // Generate embed URLs for additional media
97
- const mediaType = (media.media_type || "").toLowerCase();
98
-
99
- if(mediaType === "image") {
100
- return {
101
- ...media,
102
- embed_url: media.media_file.url
103
- };
104
- }
105
-
106
- let embedUrl = new URL("https://embed.v3.contentfabric.io");
107
- embedUrl.searchParams.set("p", "");
108
- embedUrl.searchParams.set("net", rootStore.network === "demo" ? "demo" : "main");
109
- embedUrl.searchParams.set("ath", rootStore.authToken);
110
-
111
- if(mediaType === "video") {
112
- embedUrl.searchParams.set("vid", LinkTargetHash(media.media_link));
113
- embedUrl.searchParams.set("ct", "h");
114
- embedUrl.searchParams.set("ap", "");
115
- } else if(mediaType === "ebook") {
116
- embedUrl.searchParams.set("type", "ebook");
117
- embedUrl.searchParams.set("vid", media.media_file["."].container);
118
- embedUrl.searchParams.set("murl", btoa(media.media_file.url));
119
- }
120
-
121
- return {
122
- ...media,
123
- embed_url: embedUrl.toString()
124
- };
125
- } catch(error) {
126
- return media;
127
- }
128
- });
129
- }
130
-
131
- // Generate embed URLs for pack opening animations
132
- ["open_animation", "open_animation__mobile", "reveal_animation", "reveal_animation_mobile"].forEach(key => {
133
- try {
134
- if(nft.metadata.pack_options && nft.metadata.pack_options[key]) {
135
- let embedUrl = new URL("https://embed.v3.contentfabric.io");
136
- embedUrl.searchParams.set("p", "");
137
- embedUrl.searchParams.set("net", rootStore.network === "demo" ? "demo" : "main");
138
- embedUrl.searchParams.set("ath", rootStore.authToken || rootStore.staticToken);
139
- embedUrl.searchParams.set("vid", LinkTargetHash(nft.metadata.pack_options[key]));
140
- embedUrl.searchParams.set("ap", "");
141
-
142
- if(!key.startsWith("reveal")) {
143
- embedUrl.searchParams.set("m", "");
144
- embedUrl.searchParams.set("lp", "");
145
- }
146
-
147
- nft.metadata.pack_options[`${key}_embed_url`] = embedUrl.toString();
148
- }
149
- // eslint-disable-next-line no-empty
150
- } catch(error) {}
151
- });
152
-
153
- return nft;
154
- };
155
-
156
- exports.FormatNFTMetadata = FormatNFTMetadata;
157
-
158
- exports.FormatNFT = function (item) {
159
- return FormatNFTMetadata(FormatNFTDetails(item));
160
- };
161
-
162
-
163
- exports.LinkTargetHash = function(link) {
164
- if(!link) { return; }
165
-
166
- if(link["."] && link["."].source) {
167
- return link["."].source;
168
- }
169
-
170
- if(link["/"] && link["/"].startsWith("/qfab/")) {
171
- return link["/"].split("/").find(segment => segment.startsWith("hq__"));
172
- }
173
-
174
- if(link["."] && link["."].container) {
175
- return link["."].container;
176
- }
177
- };
178
-
179
- // https://stackoverflow.com/questions/4068373/center-a-popup-window-on-screen
180
- const Popup = ({url, title, w, h}) => {
181
- // Fixes dual-screen position
182
- const dualScreenLeft = window.screenLeft || window.screenX;
183
- const dualScreenTop = window.screenTop || window.screenY;
184
-
185
- const width = window.innerWidth || document.documentElement.clientWidth || screen.width;
186
- const height = window.innerHeight || document.documentElement.clientHeight || screen.height;
187
-
188
- const systemZoom = width / window.screen.availWidth;
189
- const left = (width - w) / 2 / systemZoom + dualScreenLeft;
190
- const top = (height - h) / 2 / systemZoom + dualScreenTop;
191
- const newWindow = window.open(url, title,
192
- `
193
- width=${w / systemZoom},
194
- height=${h / systemZoom},
195
- top=${top},
196
- left=${left}
197
- `
198
- );
199
-
200
- if(window.focus) newWindow.focus();
201
-
202
- return newWindow;
203
- };
204
-
205
- exports.ActionPopup = async ({mode="tab", url, onMessage, onCancel}) => {
206
- await new Promise(resolve => {
207
- const newWindow = mode === "popup" ?
208
- Popup({url, title: "Eluvio Media Wallet", w: 500, h: 850}) :
209
- window.open(url);
210
-
211
- const closeCheck = setInterval(async () => {
212
- if(newWindow.closed) {
213
- clearInterval(closeCheck);
214
-
215
- if(onCancel) {
216
- await onCancel();
217
- }
218
-
219
- resolve();
220
- }
221
- }, 1000);
222
-
223
- window.addEventListener("message", async event => {
224
- await onMessage(
225
- event,
226
- () => {
227
- clearInterval(closeCheck);
228
- newWindow.close();
229
- resolve();
230
- }
231
- );
232
- });
233
- });
234
- };