@frak-labs/nexus-sdk 0.0.1-alpha
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/LICENSE +674 -0
- package/README.md +70 -0
- package/dist/chunk-4X75PGSK.cjs +160 -0
- package/dist/chunk-JE64MPH2.js +160 -0
- package/dist/client-SCwoh_kP.d.cts +246 -0
- package/dist/client-SCwoh_kP.d.ts +246 -0
- package/dist/core/actions/index.cjs +77 -0
- package/dist/core/actions/index.d.cts +63 -0
- package/dist/core/actions/index.d.ts +63 -0
- package/dist/core/actions/index.js +77 -0
- package/dist/core/index.cjs +179 -0
- package/dist/core/index.d.cts +83 -0
- package/dist/core/index.d.ts +83 -0
- package/dist/core/index.js +179 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Nexus Wallet SDK
|
|
2
|
+
|
|
3
|
+
This SDK help any dApps, or gated content provider, use the [Nexus Wallet](https://poc-wallet.frak.id/) as a regular wallet, with smoother UX for your end-users (pay for his gas fees, check the paywall options, track his consumption etc.)
|
|
4
|
+
|
|
5
|
+
Checkout our documentation for more informations about the usage:
|
|
6
|
+
- [React client usage](https://docs.frak.id/wallet-sdk/how-to/client-react)
|
|
7
|
+
- [Core client usage](https://docs.frak.id/wallet-sdk/how-to/client-core)
|
|
8
|
+
|
|
9
|
+
To have more info about how does it works under the hood, you can check [this](https://docs.frak.id/wallet-sdk/under-the-hood)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun add viem @frak-labs/nexus-sdk
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import {
|
|
21
|
+
createIframe,
|
|
22
|
+
createIFrameNexusClient,
|
|
23
|
+
} from "@frak-labs/nexus-sdk/core";
|
|
24
|
+
import type { NexusClient, NexusWalletSdkConfig } from "@frak-labs/nexus-sdk/core";
|
|
25
|
+
|
|
26
|
+
// Create the config for the Nexus Wallet SDK
|
|
27
|
+
export const nexusConfig: NexusWalletSdkConfig = {
|
|
28
|
+
// The current url for the wallet sdk
|
|
29
|
+
walletUrl: "https://poc-wallet.frak.id",
|
|
30
|
+
// The content id on which this sdk will be used
|
|
31
|
+
contentId: "0xdeadbeef",
|
|
32
|
+
// The content title, this will be displayed to the user during a few registration steps
|
|
33
|
+
contentTitle: "My dApp content title"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Create the iFrame and the associated NexusClient
|
|
37
|
+
async function createClient(): Promise<NexusClient> {
|
|
38
|
+
// Create the iFrame that will be used for the communication with the nexus wallet
|
|
39
|
+
const iframe = await createIframe(nexusConfig);
|
|
40
|
+
|
|
41
|
+
// Build the client
|
|
42
|
+
const client = createIFrameNexusClient(nexusConfig, iframe);
|
|
43
|
+
|
|
44
|
+
// Wait for it to be ready
|
|
45
|
+
await client.waitForConnection();
|
|
46
|
+
|
|
47
|
+
// And then return it
|
|
48
|
+
return client;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Create the client and use it
|
|
52
|
+
export const nexusClient = await createClient();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Sample usage
|
|
56
|
+
|
|
57
|
+
Sample code to watch the current user wallet status:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { nexusClient } from "./client";
|
|
61
|
+
import { watchWalletStatus } from "@frak-labs/nexus-sdk/actions";
|
|
62
|
+
import type { WalletStatusReturnType } from "@frak-labs/nexus-sdk/core";
|
|
63
|
+
|
|
64
|
+
// Watch the wallet status
|
|
65
|
+
watchWalletStatus(nexusClient, (walletStatus: WalletStatusReturnType) => {
|
|
66
|
+
console.log("Wallet status changed", { walletStatus });
|
|
67
|
+
// You can now use the status to update your UI
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/core/utils/compression/compress.ts
|
|
9
|
+
var _asynclzstring = require('async-lz-string');
|
|
10
|
+
var _jssha256 = require('js-sha256');
|
|
11
|
+
async function hashAndCompressData(data, keyProvider) {
|
|
12
|
+
const keys = keyProvider(data);
|
|
13
|
+
const validationHash = _jssha256.sha256.call(void 0, keys.join("_"));
|
|
14
|
+
const hashProtectedData = {
|
|
15
|
+
...data,
|
|
16
|
+
validationHash
|
|
17
|
+
};
|
|
18
|
+
const compressed = await compressJson(hashProtectedData);
|
|
19
|
+
const compressedHash = _jssha256.sha256.call(void 0, compressed);
|
|
20
|
+
return {
|
|
21
|
+
compressed,
|
|
22
|
+
compressedHash
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function compressJson(data) {
|
|
26
|
+
return _asynclzstring.compressToBase64.call(void 0, JSON.stringify(data));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/core/utils/compression/decompress.ts
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
async function decompressDataAndCheckHash(compressedData, keyAccessor) {
|
|
33
|
+
if (!(_optionalChain([compressedData, 'optionalAccess', _ => _.compressed]) && _optionalChain([compressedData, 'optionalAccess', _2 => _2.compressedHash]))) {
|
|
34
|
+
throw new Error("Missing compressed data");
|
|
35
|
+
}
|
|
36
|
+
const parsedData = await decompressJson(
|
|
37
|
+
compressedData.compressed
|
|
38
|
+
);
|
|
39
|
+
if (!parsedData) {
|
|
40
|
+
throw new Error(`Invalid compressed data: ${parsedData}`);
|
|
41
|
+
}
|
|
42
|
+
if (!_optionalChain([parsedData, 'optionalAccess', _3 => _3.validationHash])) {
|
|
43
|
+
throw new Error("Missing validation hash");
|
|
44
|
+
}
|
|
45
|
+
const expectedCompressedHash = _jssha256.sha256.call(void 0, compressedData.compressed);
|
|
46
|
+
if (expectedCompressedHash !== compressedData.compressedHash) {
|
|
47
|
+
throw new Error("Invalid compressed hash");
|
|
48
|
+
}
|
|
49
|
+
const keys = keyAccessor(parsedData);
|
|
50
|
+
const expectedValidationHash = _jssha256.sha256.call(void 0, keys.join("_"));
|
|
51
|
+
if (expectedValidationHash !== parsedData.validationHash) {
|
|
52
|
+
throw new Error("Invalid data validation hash");
|
|
53
|
+
}
|
|
54
|
+
return parsedData;
|
|
55
|
+
}
|
|
56
|
+
async function decompressJson(data) {
|
|
57
|
+
const decompressed = await _asynclzstring.decompressFromBase64.call(void 0, data);
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(decompressed);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error("Invalid compressed data", e);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/core/utils/compression/iframeRpcKeyProvider.ts
|
|
67
|
+
var iFrameRequestKeyProvider = (args) => {
|
|
68
|
+
if (args.method === "frak_getArticleUnlockOptions") {
|
|
69
|
+
return ["get-price", args.params[0], args.params[1]];
|
|
70
|
+
}
|
|
71
|
+
if (args.method === "frak_listenToWalletStatus") {
|
|
72
|
+
return ["wallet-status"];
|
|
73
|
+
}
|
|
74
|
+
if (args.method === "frak_listenToArticleUnlockStatus") {
|
|
75
|
+
return ["article-unlock-status", args.params[0], args.params[1]];
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`No key provider found for the arguments ${args}`);
|
|
78
|
+
};
|
|
79
|
+
function getIFrameResponseKeyProvider(param) {
|
|
80
|
+
if (param.method === "frak_getArticleUnlockOptions") {
|
|
81
|
+
return (response) => [
|
|
82
|
+
"get-price-response",
|
|
83
|
+
response.prices.length
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
if (param.method === "frak_listenToWalletStatus") {
|
|
87
|
+
return (response) => [
|
|
88
|
+
"wallet-status",
|
|
89
|
+
response.key,
|
|
90
|
+
response.key === "connected" ? response.wallet : "0xdeadbeef"
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
if (param.method === "frak_listenToArticleUnlockStatus") {
|
|
94
|
+
return (response) => [
|
|
95
|
+
"article-unlock-status",
|
|
96
|
+
response.key,
|
|
97
|
+
response.key === "valid" ? response.allowedUntil.toString(16) : "deadbeef"
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`No key provider found for the request ${param}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/core/utils/iframeHelper.ts
|
|
104
|
+
function createIframe({
|
|
105
|
+
walletBaseUrl
|
|
106
|
+
}) {
|
|
107
|
+
const isAlreadyCreated = document.querySelector("#frak-wallet");
|
|
108
|
+
if (isAlreadyCreated) {
|
|
109
|
+
return Promise.resolve(void 0);
|
|
110
|
+
}
|
|
111
|
+
const iframe = document.createElement("iframe");
|
|
112
|
+
iframe.name = "frak-wallet";
|
|
113
|
+
iframe.id = "frak-wallet";
|
|
114
|
+
iframe.style.width = "0";
|
|
115
|
+
iframe.style.height = "0";
|
|
116
|
+
iframe.style.border = "0";
|
|
117
|
+
iframe.style.position = "absolute";
|
|
118
|
+
iframe.style.top = "-1000px";
|
|
119
|
+
iframe.style.left = "-1000px";
|
|
120
|
+
document.body.appendChild(iframe);
|
|
121
|
+
return new Promise((resolve) => {
|
|
122
|
+
_optionalChain([iframe, 'optionalAccess', _4 => _4.addEventListener, 'call', _5 => _5("load", () => resolve(iframe))]);
|
|
123
|
+
iframe.src = `${walletBaseUrl}/listener`;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/core/utils/compression/redirectKeyProvider.ts
|
|
128
|
+
var redirectRequestKeyProvider = (args) => {
|
|
129
|
+
if (args.method === "frak_startArticleUnlock") {
|
|
130
|
+
return [
|
|
131
|
+
"start-unlock",
|
|
132
|
+
args.params.contentId,
|
|
133
|
+
args.params.articleId,
|
|
134
|
+
args.params.price.index.toString()
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`No key provider found for the arguments ${args}`);
|
|
138
|
+
};
|
|
139
|
+
function getRedirectResponseResponseKeyProvider(method) {
|
|
140
|
+
if (method === "frak_startArticleUnlock") {
|
|
141
|
+
return (response) => [
|
|
142
|
+
"start-unlock",
|
|
143
|
+
response.key,
|
|
144
|
+
response.status,
|
|
145
|
+
_nullishCoalesce(response.user, () => ( "0xdeadbeef"))
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
throw new Error(`No key provider found for the method ${method}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
exports.__publicField = __publicField; exports.hashAndCompressData = hashAndCompressData; exports.decompressDataAndCheckHash = decompressDataAndCheckHash; exports.iFrameRequestKeyProvider = iFrameRequestKeyProvider; exports.getIFrameResponseKeyProvider = getIFrameResponseKeyProvider; exports.createIframe = createIframe; exports.redirectRequestKeyProvider = redirectRequestKeyProvider; exports.getRedirectResponseResponseKeyProvider = getRedirectResponseResponseKeyProvider;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => {
|
|
4
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
5
|
+
return value;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/core/utils/compression/compress.ts
|
|
9
|
+
import { compressToBase64 } from "async-lz-string";
|
|
10
|
+
import { sha256 } from "js-sha256";
|
|
11
|
+
async function hashAndCompressData(data, keyProvider) {
|
|
12
|
+
const keys = keyProvider(data);
|
|
13
|
+
const validationHash = sha256(keys.join("_"));
|
|
14
|
+
const hashProtectedData = {
|
|
15
|
+
...data,
|
|
16
|
+
validationHash
|
|
17
|
+
};
|
|
18
|
+
const compressed = await compressJson(hashProtectedData);
|
|
19
|
+
const compressedHash = sha256(compressed);
|
|
20
|
+
return {
|
|
21
|
+
compressed,
|
|
22
|
+
compressedHash
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function compressJson(data) {
|
|
26
|
+
return compressToBase64(JSON.stringify(data));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/core/utils/compression/decompress.ts
|
|
30
|
+
import { decompressFromBase64 } from "async-lz-string";
|
|
31
|
+
import { sha256 as sha2562 } from "js-sha256";
|
|
32
|
+
async function decompressDataAndCheckHash(compressedData, keyAccessor) {
|
|
33
|
+
if (!(compressedData?.compressed && compressedData?.compressedHash)) {
|
|
34
|
+
throw new Error("Missing compressed data");
|
|
35
|
+
}
|
|
36
|
+
const parsedData = await decompressJson(
|
|
37
|
+
compressedData.compressed
|
|
38
|
+
);
|
|
39
|
+
if (!parsedData) {
|
|
40
|
+
throw new Error(`Invalid compressed data: ${parsedData}`);
|
|
41
|
+
}
|
|
42
|
+
if (!parsedData?.validationHash) {
|
|
43
|
+
throw new Error("Missing validation hash");
|
|
44
|
+
}
|
|
45
|
+
const expectedCompressedHash = sha2562(compressedData.compressed);
|
|
46
|
+
if (expectedCompressedHash !== compressedData.compressedHash) {
|
|
47
|
+
throw new Error("Invalid compressed hash");
|
|
48
|
+
}
|
|
49
|
+
const keys = keyAccessor(parsedData);
|
|
50
|
+
const expectedValidationHash = sha2562(keys.join("_"));
|
|
51
|
+
if (expectedValidationHash !== parsedData.validationHash) {
|
|
52
|
+
throw new Error("Invalid data validation hash");
|
|
53
|
+
}
|
|
54
|
+
return parsedData;
|
|
55
|
+
}
|
|
56
|
+
async function decompressJson(data) {
|
|
57
|
+
const decompressed = await decompressFromBase64(data);
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(decompressed);
|
|
60
|
+
} catch (e) {
|
|
61
|
+
console.error("Invalid compressed data", e);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/core/utils/compression/iframeRpcKeyProvider.ts
|
|
67
|
+
var iFrameRequestKeyProvider = (args) => {
|
|
68
|
+
if (args.method === "frak_getArticleUnlockOptions") {
|
|
69
|
+
return ["get-price", args.params[0], args.params[1]];
|
|
70
|
+
}
|
|
71
|
+
if (args.method === "frak_listenToWalletStatus") {
|
|
72
|
+
return ["wallet-status"];
|
|
73
|
+
}
|
|
74
|
+
if (args.method === "frak_listenToArticleUnlockStatus") {
|
|
75
|
+
return ["article-unlock-status", args.params[0], args.params[1]];
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`No key provider found for the arguments ${args}`);
|
|
78
|
+
};
|
|
79
|
+
function getIFrameResponseKeyProvider(param) {
|
|
80
|
+
if (param.method === "frak_getArticleUnlockOptions") {
|
|
81
|
+
return (response) => [
|
|
82
|
+
"get-price-response",
|
|
83
|
+
response.prices.length
|
|
84
|
+
];
|
|
85
|
+
}
|
|
86
|
+
if (param.method === "frak_listenToWalletStatus") {
|
|
87
|
+
return (response) => [
|
|
88
|
+
"wallet-status",
|
|
89
|
+
response.key,
|
|
90
|
+
response.key === "connected" ? response.wallet : "0xdeadbeef"
|
|
91
|
+
];
|
|
92
|
+
}
|
|
93
|
+
if (param.method === "frak_listenToArticleUnlockStatus") {
|
|
94
|
+
return (response) => [
|
|
95
|
+
"article-unlock-status",
|
|
96
|
+
response.key,
|
|
97
|
+
response.key === "valid" ? response.allowedUntil.toString(16) : "deadbeef"
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
throw new Error(`No key provider found for the request ${param}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/core/utils/iframeHelper.ts
|
|
104
|
+
function createIframe({
|
|
105
|
+
walletBaseUrl
|
|
106
|
+
}) {
|
|
107
|
+
const isAlreadyCreated = document.querySelector("#frak-wallet");
|
|
108
|
+
if (isAlreadyCreated) {
|
|
109
|
+
return Promise.resolve(void 0);
|
|
110
|
+
}
|
|
111
|
+
const iframe = document.createElement("iframe");
|
|
112
|
+
iframe.name = "frak-wallet";
|
|
113
|
+
iframe.id = "frak-wallet";
|
|
114
|
+
iframe.style.width = "0";
|
|
115
|
+
iframe.style.height = "0";
|
|
116
|
+
iframe.style.border = "0";
|
|
117
|
+
iframe.style.position = "absolute";
|
|
118
|
+
iframe.style.top = "-1000px";
|
|
119
|
+
iframe.style.left = "-1000px";
|
|
120
|
+
document.body.appendChild(iframe);
|
|
121
|
+
return new Promise((resolve) => {
|
|
122
|
+
iframe?.addEventListener("load", () => resolve(iframe));
|
|
123
|
+
iframe.src = `${walletBaseUrl}/listener`;
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// src/core/utils/compression/redirectKeyProvider.ts
|
|
128
|
+
var redirectRequestKeyProvider = (args) => {
|
|
129
|
+
if (args.method === "frak_startArticleUnlock") {
|
|
130
|
+
return [
|
|
131
|
+
"start-unlock",
|
|
132
|
+
args.params.contentId,
|
|
133
|
+
args.params.articleId,
|
|
134
|
+
args.params.price.index.toString()
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
throw new Error(`No key provider found for the arguments ${args}`);
|
|
138
|
+
};
|
|
139
|
+
function getRedirectResponseResponseKeyProvider(method) {
|
|
140
|
+
if (method === "frak_startArticleUnlock") {
|
|
141
|
+
return (response) => [
|
|
142
|
+
"start-unlock",
|
|
143
|
+
response.key,
|
|
144
|
+
response.status,
|
|
145
|
+
response.user ?? "0xdeadbeef"
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
throw new Error(`No key provider found for the method ${method}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export {
|
|
152
|
+
__publicField,
|
|
153
|
+
hashAndCompressData,
|
|
154
|
+
decompressDataAndCheckHash,
|
|
155
|
+
iFrameRequestKeyProvider,
|
|
156
|
+
getIFrameResponseKeyProvider,
|
|
157
|
+
createIframe,
|
|
158
|
+
redirectRequestKeyProvider,
|
|
159
|
+
getRedirectResponseResponseKeyProvider
|
|
160
|
+
};
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { Hex, Address, RpcSchema } from 'viem';
|
|
2
|
+
import { Prettify } from 'viem/chains';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for the Frak Wallet SDK
|
|
6
|
+
*/
|
|
7
|
+
type FrakWalletSdkConfig = Readonly<{
|
|
8
|
+
walletUrl: string;
|
|
9
|
+
contentId: Hex;
|
|
10
|
+
contentTitle: string;
|
|
11
|
+
}>;
|
|
12
|
+
|
|
13
|
+
type PaidArticleUnlockPrice = Readonly<{
|
|
14
|
+
index: number;
|
|
15
|
+
unlockDurationInSec: number;
|
|
16
|
+
frkAmount: Hex;
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Request to unlock a paid article
|
|
21
|
+
*/
|
|
22
|
+
type StartArticleUnlockParams = Readonly<{
|
|
23
|
+
articleId: Hex;
|
|
24
|
+
contentId: Hex;
|
|
25
|
+
imageUrl: string;
|
|
26
|
+
articleTitle: string;
|
|
27
|
+
contentTitle: string;
|
|
28
|
+
price: PaidArticleUnlockPrice;
|
|
29
|
+
articleUrl: string;
|
|
30
|
+
redirectUrl: string;
|
|
31
|
+
previewUrl?: string;
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* Return type of the unlock request
|
|
35
|
+
*/
|
|
36
|
+
type StartArticleUnlockReturnType = UnlockSuccess | AlreadyUnlocked | UnlockError;
|
|
37
|
+
type UnlockSuccess = {
|
|
38
|
+
key: "success";
|
|
39
|
+
status: "in-progress";
|
|
40
|
+
user: Address;
|
|
41
|
+
userOpHash: Hex;
|
|
42
|
+
};
|
|
43
|
+
type AlreadyUnlocked = {
|
|
44
|
+
key: "already-unlocked";
|
|
45
|
+
status: "unlocked";
|
|
46
|
+
user: Address;
|
|
47
|
+
};
|
|
48
|
+
type UnlockError = {
|
|
49
|
+
key: "error" | "cancelled";
|
|
50
|
+
status: "locked";
|
|
51
|
+
user?: Address;
|
|
52
|
+
reason?: string;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The response to the get unlock options response
|
|
57
|
+
*/
|
|
58
|
+
type UnlockOptionsReturnType = Readonly<{
|
|
59
|
+
prices: {
|
|
60
|
+
index: number;
|
|
61
|
+
unlockDurationInSec: number;
|
|
62
|
+
frkAmount: Hex;
|
|
63
|
+
isUserAccessible: boolean | null;
|
|
64
|
+
}[];
|
|
65
|
+
}>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The different types of response for the current unlock status
|
|
69
|
+
*/
|
|
70
|
+
type ArticleUnlockStatusReturnType = Readonly<UnlockStatusLocked | UnlockStatusProcessing | UnlockStatusValid | UnlockStatusError>;
|
|
71
|
+
/**
|
|
72
|
+
* When the content unlocked was expired a few time ago
|
|
73
|
+
*/
|
|
74
|
+
type UnlockStatusLocked = {
|
|
75
|
+
key: "expired";
|
|
76
|
+
status: "locked";
|
|
77
|
+
expiredAt: number;
|
|
78
|
+
} | {
|
|
79
|
+
key: "not-unlocked";
|
|
80
|
+
status: "locked";
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* When the content unlocked was expired a few time ago
|
|
84
|
+
*/
|
|
85
|
+
type UnlockStatusProcessing = {
|
|
86
|
+
key: "preparing" | "waiting-user-validation";
|
|
87
|
+
} | {
|
|
88
|
+
key: "waiting-transaction-bundling";
|
|
89
|
+
userOpHash: Hex;
|
|
90
|
+
} | {
|
|
91
|
+
key: "waiting-transaction-confirmation";
|
|
92
|
+
userOpHash: Hex;
|
|
93
|
+
txHash: Hex;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* When the content unlocked was expired a few time ago
|
|
97
|
+
*/
|
|
98
|
+
type UnlockStatusValid = {
|
|
99
|
+
key: "valid";
|
|
100
|
+
status: "unlocked";
|
|
101
|
+
allowedUntil: number;
|
|
102
|
+
};
|
|
103
|
+
/**
|
|
104
|
+
* When the content unlocked was expired a few time ago
|
|
105
|
+
*/
|
|
106
|
+
type UnlockStatusError = {
|
|
107
|
+
key: "error";
|
|
108
|
+
status: "locked";
|
|
109
|
+
reason: string;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
type WalletStatusReturnType = Readonly<WalletConnected | WalletNotConnected>;
|
|
113
|
+
type WalletConnected = {
|
|
114
|
+
key: "connected";
|
|
115
|
+
wallet: Address;
|
|
116
|
+
frkBalanceAsHex: Hex;
|
|
117
|
+
};
|
|
118
|
+
type WalletNotConnected = {
|
|
119
|
+
key: "not-connected";
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* RPC interface that's used for the iframe communication
|
|
124
|
+
*/
|
|
125
|
+
type IFrameRpcSchema = [
|
|
126
|
+
/**
|
|
127
|
+
* Method used to fetch an article unlock options
|
|
128
|
+
*/
|
|
129
|
+
{
|
|
130
|
+
Method: "frak_getArticleUnlockOptions";
|
|
131
|
+
Parameters: [contentId: Hex, articleId: Hex];
|
|
132
|
+
ReturnType: UnlockOptionsReturnType;
|
|
133
|
+
},
|
|
134
|
+
/**
|
|
135
|
+
* Method used to listen to the wallet status
|
|
136
|
+
*/
|
|
137
|
+
{
|
|
138
|
+
Method: "frak_listenToWalletStatus";
|
|
139
|
+
Parameters?: undefined;
|
|
140
|
+
ReturnType: WalletStatusReturnType;
|
|
141
|
+
},
|
|
142
|
+
/**
|
|
143
|
+
* Method used to listen to an article unlock status
|
|
144
|
+
*/
|
|
145
|
+
{
|
|
146
|
+
Method: "frak_listenToArticleUnlockStatus";
|
|
147
|
+
Parameters: [contentId: Hex, articleId: Hex];
|
|
148
|
+
ReturnType: ArticleUnlockStatusReturnType;
|
|
149
|
+
}
|
|
150
|
+
];
|
|
151
|
+
/**
|
|
152
|
+
* RPC interface that's used for the redirection communication
|
|
153
|
+
*/
|
|
154
|
+
type RedirectRpcSchema = [
|
|
155
|
+
/**
|
|
156
|
+
* Method used to start the unlock of an article
|
|
157
|
+
*/
|
|
158
|
+
{
|
|
159
|
+
Method: "frak_startArticleUnlock";
|
|
160
|
+
Path: "/paywall";
|
|
161
|
+
Parameters: StartArticleUnlockParams;
|
|
162
|
+
ReturnType: StartArticleUnlockReturnType;
|
|
163
|
+
}
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Type that extract the possible parameters from a RPC Schema
|
|
168
|
+
*/
|
|
169
|
+
type ExtractedParametersFromRpc<TRpcSchema extends RpcSchema | undefined = undefined> = TRpcSchema extends RpcSchema ? {
|
|
170
|
+
[K in keyof TRpcSchema]: Prettify<{
|
|
171
|
+
method: TRpcSchema[K] extends TRpcSchema[number] ? TRpcSchema[K]["Method"] : string;
|
|
172
|
+
} & (TRpcSchema[K] extends TRpcSchema[number] ? TRpcSchema[K]["Parameters"] extends undefined ? {
|
|
173
|
+
params?: never;
|
|
174
|
+
} : {
|
|
175
|
+
params: TRpcSchema[K]["Parameters"];
|
|
176
|
+
} : never)>;
|
|
177
|
+
}[number] : {
|
|
178
|
+
method: string;
|
|
179
|
+
params?: unknown;
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Type that extract the possible return type from a RPC Schema
|
|
183
|
+
*/
|
|
184
|
+
type ExtractedReturnTypeFromRpc<TRpcSchema extends RpcSchema | undefined = undefined, TParameters extends ExtractedParametersFromRpc<TRpcSchema> = ExtractedParametersFromRpc<TRpcSchema>> = TRpcSchema extends RpcSchema ? ExtractedMethodFromRpc<TRpcSchema, TParameters["method"]>["ReturnType"] : unknown;
|
|
185
|
+
/**
|
|
186
|
+
* Type that extract the possible return type from a RPC Schema
|
|
187
|
+
*/
|
|
188
|
+
type ExtractedMethodFromRpc<TRpcSchema extends RpcSchema | undefined = undefined, TMethod extends ExtractedParametersFromRpc<TRpcSchema>["method"] = ExtractedParametersFromRpc<TRpcSchema>["method"]> = TRpcSchema extends RpcSchema ? Extract<TRpcSchema[number], {
|
|
189
|
+
Method: TMethod;
|
|
190
|
+
}> : unknown;
|
|
191
|
+
/**
|
|
192
|
+
* Type used for a one shot request function
|
|
193
|
+
*/
|
|
194
|
+
type RequestFn<TRpcSchema extends RpcSchema | undefined = undefined> = <TParameters extends ExtractedParametersFromRpc<TRpcSchema> = ExtractedParametersFromRpc<TRpcSchema>, _ReturnType = ExtractedReturnTypeFromRpc<TRpcSchema, TParameters>>(args: TParameters) => Promise<_ReturnType>;
|
|
195
|
+
/**
|
|
196
|
+
* Type used for a one shot request function
|
|
197
|
+
*/
|
|
198
|
+
type ListenerRequestFn<TRpcSchema extends RpcSchema | undefined = undefined> = <TParameters extends ExtractedParametersFromRpc<TRpcSchema> = ExtractedParametersFromRpc<TRpcSchema>>(args: TParameters, callback: (result: ExtractedReturnTypeFromRpc<TRpcSchema, TParameters>) => void) => Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* IFrame transport interface
|
|
201
|
+
*/
|
|
202
|
+
type IFrameTransport = {
|
|
203
|
+
/**
|
|
204
|
+
* Wait for the connection to be established
|
|
205
|
+
*/
|
|
206
|
+
waitForConnection: Promise<boolean>;
|
|
207
|
+
/**
|
|
208
|
+
* Function used to perform a single request via the iframe transport
|
|
209
|
+
*/
|
|
210
|
+
request: RequestFn<IFrameRpcSchema>;
|
|
211
|
+
/**
|
|
212
|
+
* Function used to listen to a request response via the iframe transport
|
|
213
|
+
*/
|
|
214
|
+
listenerRequest: ListenerRequestFn<IFrameRpcSchema>;
|
|
215
|
+
/**
|
|
216
|
+
* Function used to destroy the iframe transport
|
|
217
|
+
*/
|
|
218
|
+
destroy: () => Promise<void>;
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Represent an iframe event
|
|
222
|
+
*/
|
|
223
|
+
type IFrameEvent = IFrameRpcEvent | IFrameLifecycleEvent;
|
|
224
|
+
/**
|
|
225
|
+
* Represent an iframe rpc event
|
|
226
|
+
*/
|
|
227
|
+
type IFrameRpcEvent = {
|
|
228
|
+
id: string;
|
|
229
|
+
topic: ExtractedParametersFromRpc<IFrameRpcSchema>["method"];
|
|
230
|
+
data: {
|
|
231
|
+
compressed: string;
|
|
232
|
+
compressedHash: string;
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
type IFrameLifecycleEvent = {
|
|
236
|
+
lifecycle: "connected";
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Representing a Frak client
|
|
241
|
+
*/
|
|
242
|
+
type FrakClient = {
|
|
243
|
+
config: FrakWalletSdkConfig;
|
|
244
|
+
} & IFrameTransport;
|
|
245
|
+
|
|
246
|
+
export type { ArticleUnlockStatusReturnType as A, ExtractedParametersFromRpc as E, FrakClient as F, IFrameRpcSchema as I, PaidArticleUnlockPrice as P, RedirectRpcSchema as R, StartArticleUnlockReturnType as S, UnlockOptionsReturnType as U, WalletStatusReturnType as W, FrakWalletSdkConfig as a, StartArticleUnlockParams as b, ExtractedReturnTypeFromRpc as c, IFrameTransport as d, IFrameRpcEvent as e, IFrameEvent as f };
|