@campnetwork/origin 1.4.0-alpha.3 → 1.4.0-alpha.5
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/dist/core.cjs +230 -154
- package/dist/core.d.ts +124 -12
- package/dist/core.esm.d.ts +124 -12
- package/dist/core.esm.js +239 -163
- package/dist/react/index.esm.d.ts +124 -12
- package/dist/react/index.esm.js +431 -67
- package/package.json +1 -1
package/dist/react/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import React, { createContext, useState, useContext, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';
|
|
3
|
-
import { custom, createWalletClient, createPublicClient, http, zeroAddress, erc20Abi as erc20Abi$1,
|
|
3
|
+
import { custom, createWalletClient, createPublicClient, http, zeroAddress, erc20Abi as erc20Abi$1, getAbiItem, formatEther, formatUnits, encodeFunctionData, checksumAddress, parseEther } from 'viem';
|
|
4
4
|
import { toAccount } from 'viem/accounts';
|
|
5
5
|
import { createSiweMessage } from 'viem/siwe';
|
|
6
6
|
import axios from 'axios';
|
|
@@ -6599,6 +6599,7 @@ var constants = {
|
|
|
6599
6599
|
SUPPORTED_VIDEO_FORMATS: ["video/mp4", "video/webm"],
|
|
6600
6600
|
SUPPORTED_AUDIO_FORMATS: ["audio/mpeg", "audio/wav", "audio/ogg"],
|
|
6601
6601
|
SUPPORTED_TEXT_FORMATS: ["text/plain"],
|
|
6602
|
+
MAX_FILE_SIZE: 20 * 1024 * 1024, // 20 MB
|
|
6602
6603
|
AVAILABLE_SOCIALS: ["twitter", "spotify"], // tiktok disabled
|
|
6603
6604
|
MAX_LICENSE_DURATION: 2628000, // 30 days in seconds
|
|
6604
6605
|
MIN_LICENSE_DURATION: 86400, // 1 day in seconds
|
|
@@ -8032,17 +8033,17 @@ function getVaultRevenueTokens(tokenId) {
|
|
|
8032
8033
|
|
|
8033
8034
|
/**
|
|
8034
8035
|
* Returns the amount of revenue claimable by a holder for a given token and revenue token.
|
|
8035
|
-
* If no holder is provided, the
|
|
8036
|
-
* since RT tokens are
|
|
8036
|
+
* If no holder is provided, the connected wallet address is used,
|
|
8037
|
+
* since RT tokens are sent directly to the wallet.
|
|
8037
8038
|
*
|
|
8038
8039
|
* @param tokenId The token ID whose vault to query.
|
|
8039
8040
|
* @param revenueToken The ERC20 revenue token address.
|
|
8040
|
-
* @param holder Optional holder address. Defaults to the
|
|
8041
|
+
* @param holder Optional holder address. Defaults to the connected wallet.
|
|
8041
8042
|
* @returns The claimable amount in the revenue token's smallest unit.
|
|
8042
8043
|
*/
|
|
8043
8044
|
function claimableRevenue(tokenId, revenueToken, holder) {
|
|
8044
8045
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8045
|
-
const holderAddress = holder || (yield this.
|
|
8046
|
+
const holderAddress = holder || (yield this.getWalletAddress());
|
|
8046
8047
|
const amount = yield this.callContractMethod(this.environment.MARKETPLACE_CONTRACT_ADDRESS, this.environment.MARKETPLACE_ABI, "claimableRevenue", [tokenId, holderAddress, revenueToken]);
|
|
8047
8048
|
return amount;
|
|
8048
8049
|
});
|
|
@@ -8050,8 +8051,8 @@ function claimableRevenue(tokenId, revenueToken, holder) {
|
|
|
8050
8051
|
|
|
8051
8052
|
/**
|
|
8052
8053
|
* Claims accumulated revenue for a token from a specific revenue token.
|
|
8053
|
-
*
|
|
8054
|
-
*
|
|
8054
|
+
* The connected wallet must hold Royalty Tokens for the given token.
|
|
8055
|
+
* Revenue is sent directly to the connected wallet.
|
|
8055
8056
|
*
|
|
8056
8057
|
* @param tokenId The token ID whose vault to claim from.
|
|
8057
8058
|
* @param revenueToken The ERC20 revenue token address to claim.
|
|
@@ -8059,25 +8060,14 @@ function claimableRevenue(tokenId, revenueToken, holder) {
|
|
|
8059
8060
|
*/
|
|
8060
8061
|
function claimRevenue(tokenId, revenueToken) {
|
|
8061
8062
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8062
|
-
|
|
8063
|
-
const data = encodeFunctionData({
|
|
8064
|
-
abi: this.environment.MARKETPLACE_ABI,
|
|
8065
|
-
functionName: "claimRevenue",
|
|
8066
|
-
args: [tokenId, revenueToken],
|
|
8067
|
-
});
|
|
8068
|
-
return this.callContractMethod(tokenBoundAccount, this.environment.TBA_ABI, "execute", [
|
|
8069
|
-
this.environment.MARKETPLACE_CONTRACT_ADDRESS,
|
|
8070
|
-
BigInt(0),
|
|
8071
|
-
data,
|
|
8072
|
-
0,
|
|
8073
|
-
], { waitForReceipt: true, value: BigInt(0) });
|
|
8063
|
+
return this.callContractMethod(this.environment.MARKETPLACE_CONTRACT_ADDRESS, this.environment.MARKETPLACE_ABI, "claimRevenue", [tokenId, revenueToken], { waitForReceipt: true });
|
|
8074
8064
|
});
|
|
8075
8065
|
}
|
|
8076
8066
|
|
|
8077
8067
|
/**
|
|
8078
8068
|
* Claims accumulated revenue for a token from multiple revenue tokens in a single transaction.
|
|
8079
|
-
*
|
|
8080
|
-
*
|
|
8069
|
+
* The connected wallet must hold Royalty Tokens for the given token.
|
|
8070
|
+
* Revenue is sent directly to the connected wallet.
|
|
8081
8071
|
*
|
|
8082
8072
|
* @param tokenId The token ID whose vault to claim from.
|
|
8083
8073
|
* @param revenueTokens Array of ERC20 revenue token addresses to claim.
|
|
@@ -8085,18 +8075,7 @@ function claimRevenue(tokenId, revenueToken) {
|
|
|
8085
8075
|
*/
|
|
8086
8076
|
function claimRevenueBatch(tokenId, revenueTokens) {
|
|
8087
8077
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8088
|
-
|
|
8089
|
-
const data = encodeFunctionData({
|
|
8090
|
-
abi: this.environment.MARKETPLACE_ABI,
|
|
8091
|
-
functionName: "claimRevenueBatch",
|
|
8092
|
-
args: [tokenId, revenueTokens],
|
|
8093
|
-
});
|
|
8094
|
-
return this.callContractMethod(tokenBoundAccount, this.environment.TBA_ABI, "execute", [
|
|
8095
|
-
this.environment.MARKETPLACE_CONTRACT_ADDRESS,
|
|
8096
|
-
BigInt(0),
|
|
8097
|
-
data,
|
|
8098
|
-
0,
|
|
8099
|
-
], { waitForReceipt: true, value: BigInt(0) });
|
|
8078
|
+
return this.callContractMethod(this.environment.MARKETPLACE_CONTRACT_ADDRESS, this.environment.MARKETPLACE_ABI, "claimRevenueBatch", [tokenId, revenueTokens], { waitForReceipt: true });
|
|
8100
8079
|
});
|
|
8101
8080
|
}
|
|
8102
8081
|
|
|
@@ -8138,17 +8117,17 @@ const erc20Abi = [
|
|
|
8138
8117
|
];
|
|
8139
8118
|
/**
|
|
8140
8119
|
* Gets the Royalty Token balance for a holder in a token's vault.
|
|
8141
|
-
* If no holder is provided, the
|
|
8142
|
-
* since RT tokens are
|
|
8120
|
+
* If no holder is provided, the connected wallet address is used,
|
|
8121
|
+
* since RT tokens are sent directly to the wallet.
|
|
8143
8122
|
*
|
|
8144
8123
|
* @param tokenId The token ID whose vault to query.
|
|
8145
|
-
* @param holder Optional holder address. Defaults to the
|
|
8124
|
+
* @param holder Optional holder address. Defaults to the connected wallet.
|
|
8146
8125
|
* @returns The royalty token balance info including vault address, balance, total supply, percentage, and decimals.
|
|
8147
8126
|
*/
|
|
8148
8127
|
function getRoyaltyTokenBalance(tokenId, holder) {
|
|
8149
8128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8150
|
-
// Default to the
|
|
8151
|
-
const holderAddress = holder || (yield this.
|
|
8129
|
+
// Default to the connected wallet, since RT tokens are sent there directly
|
|
8130
|
+
const holderAddress = holder || (yield this.getWalletAddress());
|
|
8152
8131
|
// Get vault address
|
|
8153
8132
|
const vaultAddress = yield this.callContractMethod(this.environment.DATANFT_CONTRACT_ADDRESS, this.environment.IPNFT_ABI, "getRoyaltyVault", [tokenId]);
|
|
8154
8133
|
if (!vaultAddress || vaultAddress === zeroAddress) {
|
|
@@ -8434,7 +8413,7 @@ function bulkBuyAccessSmart(tokenIds, options) {
|
|
|
8434
8413
|
* creatorContentHash: "0x...",
|
|
8435
8414
|
* uri: "ipfs://...",
|
|
8436
8415
|
* licenseTerms: { price: 1000n, duration: 86400, royaltyBps: 500, paymentToken: zeroAddress, licenseType: 0 },
|
|
8437
|
-
* deadline: BigInt(Date.now() +
|
|
8416
|
+
* deadline: BigInt(Math.floor(Date.now() / 1000) + 600),
|
|
8438
8417
|
* parents: [],
|
|
8439
8418
|
* isIP: true,
|
|
8440
8419
|
* appId: "myApp",
|
|
@@ -8465,6 +8444,311 @@ function bulkMintTolerant(mints) {
|
|
|
8465
8444
|
return this.callContractMethod(this.environment.BATCH_OPERATIONS_CONTRACT_ADDRESS, this.environment.BATCH_OPERATIONS_ABI, "bulkMintTolerant", [mints], { waitForReceipt: true });
|
|
8466
8445
|
}
|
|
8467
8446
|
|
|
8447
|
+
function validateIpfsCredentials(credentials) {
|
|
8448
|
+
switch (credentials.provider) {
|
|
8449
|
+
case "pinata":
|
|
8450
|
+
if (!credentials.jwt && !(credentials.apiKey && credentials.apiSecret)) {
|
|
8451
|
+
throw new ValidationError("Pinata requires either 'jwt' or both 'apiKey' and 'apiSecret'");
|
|
8452
|
+
}
|
|
8453
|
+
break;
|
|
8454
|
+
case "infura":
|
|
8455
|
+
if (!credentials.projectId || !credentials.projectSecret) {
|
|
8456
|
+
throw new ValidationError("Infura requires both 'projectId' and 'projectSecret'");
|
|
8457
|
+
}
|
|
8458
|
+
break;
|
|
8459
|
+
case "web3storage":
|
|
8460
|
+
if (!credentials.token) {
|
|
8461
|
+
throw new ValidationError("web3.storage requires 'token'");
|
|
8462
|
+
}
|
|
8463
|
+
break;
|
|
8464
|
+
default:
|
|
8465
|
+
throw new ValidationError(`Unsupported IPFS provider: ${credentials.provider}`);
|
|
8466
|
+
}
|
|
8467
|
+
}
|
|
8468
|
+
/**
|
|
8469
|
+
* Save IPFS credentials for large file uploads.
|
|
8470
|
+
* Users can configure their own IPFS pinning service (Pinata, Infura, or web3.storage).
|
|
8471
|
+
* @param credentials The IPFS credentials to save.
|
|
8472
|
+
* @throws {APIError} If saving credentials fails.
|
|
8473
|
+
* @example
|
|
8474
|
+
* ```typescript
|
|
8475
|
+
* // Save Pinata credentials
|
|
8476
|
+
* await origin.saveIpfsCredentials({
|
|
8477
|
+
* provider: 'pinata',
|
|
8478
|
+
* jwt: 'your-pinata-jwt-token'
|
|
8479
|
+
* });
|
|
8480
|
+
*
|
|
8481
|
+
* // Save Infura credentials
|
|
8482
|
+
* await origin.saveIpfsCredentials({
|
|
8483
|
+
* provider: 'infura',
|
|
8484
|
+
* projectId: 'your-project-id',
|
|
8485
|
+
* projectSecret: 'your-project-secret'
|
|
8486
|
+
* });
|
|
8487
|
+
* ```
|
|
8488
|
+
*/
|
|
8489
|
+
function saveIpfsCredentials(credentials) {
|
|
8490
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8491
|
+
if (!this.jwt) {
|
|
8492
|
+
throw new APIError("JWT token required for IPFS credentials management");
|
|
8493
|
+
}
|
|
8494
|
+
// Validate credentials before sending
|
|
8495
|
+
validateIpfsCredentials(credentials);
|
|
8496
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials`, {
|
|
8497
|
+
method: "POST",
|
|
8498
|
+
headers: {
|
|
8499
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8500
|
+
"Content-Type": "application/json",
|
|
8501
|
+
},
|
|
8502
|
+
body: JSON.stringify(credentials),
|
|
8503
|
+
});
|
|
8504
|
+
if (!response.ok) {
|
|
8505
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
8506
|
+
throw new APIError(errorData.message ||
|
|
8507
|
+
`Failed to save IPFS credentials (HTTP ${response.status})`, response.status);
|
|
8508
|
+
}
|
|
8509
|
+
});
|
|
8510
|
+
}
|
|
8511
|
+
/**
|
|
8512
|
+
* Verify that saved IPFS credentials are valid.
|
|
8513
|
+
* @returns Object with valid boolean and optional error message.
|
|
8514
|
+
* @throws {APIError} If verification request fails.
|
|
8515
|
+
*/
|
|
8516
|
+
function verifyIpfsCredentials() {
|
|
8517
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8518
|
+
if (!this.jwt) {
|
|
8519
|
+
throw new APIError("JWT token required for IPFS credentials management");
|
|
8520
|
+
}
|
|
8521
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials/verify`, {
|
|
8522
|
+
method: "POST",
|
|
8523
|
+
headers: {
|
|
8524
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8525
|
+
"Content-Type": "application/json",
|
|
8526
|
+
},
|
|
8527
|
+
});
|
|
8528
|
+
if (!response.ok) {
|
|
8529
|
+
if (response.status === 404) {
|
|
8530
|
+
return { valid: false, error: "No IPFS credentials configured" };
|
|
8531
|
+
}
|
|
8532
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
8533
|
+
throw new APIError(errorData.message ||
|
|
8534
|
+
`Failed to verify IPFS credentials (HTTP ${response.status})`, response.status);
|
|
8535
|
+
}
|
|
8536
|
+
return response.json();
|
|
8537
|
+
});
|
|
8538
|
+
}
|
|
8539
|
+
/**
|
|
8540
|
+
* Delete saved IPFS credentials.
|
|
8541
|
+
* @throws {APIError} If deletion fails.
|
|
8542
|
+
*/
|
|
8543
|
+
function deleteIpfsCredentials() {
|
|
8544
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8545
|
+
if (!this.jwt) {
|
|
8546
|
+
throw new APIError("JWT token required for IPFS credentials management");
|
|
8547
|
+
}
|
|
8548
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials`, {
|
|
8549
|
+
method: "DELETE",
|
|
8550
|
+
headers: {
|
|
8551
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8552
|
+
},
|
|
8553
|
+
});
|
|
8554
|
+
if (!response.ok) {
|
|
8555
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
8556
|
+
throw new APIError(errorData.message ||
|
|
8557
|
+
`Failed to delete IPFS credentials (HTTP ${response.status})`, response.status);
|
|
8558
|
+
}
|
|
8559
|
+
});
|
|
8560
|
+
}
|
|
8561
|
+
/**
|
|
8562
|
+
* Check if user has IPFS credentials configured.
|
|
8563
|
+
* @returns True if credentials are configured, false otherwise.
|
|
8564
|
+
*/
|
|
8565
|
+
function hasIpfsCredentials() {
|
|
8566
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8567
|
+
var _a;
|
|
8568
|
+
if (!this.jwt) {
|
|
8569
|
+
return false;
|
|
8570
|
+
}
|
|
8571
|
+
try {
|
|
8572
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials`, {
|
|
8573
|
+
method: "GET",
|
|
8574
|
+
headers: {
|
|
8575
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8576
|
+
},
|
|
8577
|
+
});
|
|
8578
|
+
if (!response.ok) {
|
|
8579
|
+
return false;
|
|
8580
|
+
}
|
|
8581
|
+
const data = yield response.json();
|
|
8582
|
+
return ((_a = data.data) === null || _a === void 0 ? void 0 : _a.hasCredentials) || false;
|
|
8583
|
+
}
|
|
8584
|
+
catch (_b) {
|
|
8585
|
+
return false;
|
|
8586
|
+
}
|
|
8587
|
+
});
|
|
8588
|
+
}
|
|
8589
|
+
/**
|
|
8590
|
+
* Get IPFS upload config for client-side uploads.
|
|
8591
|
+
* @returns IPFS config or null if not configured.
|
|
8592
|
+
*/
|
|
8593
|
+
function getIpfsUploadConfig() {
|
|
8594
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8595
|
+
if (!this.jwt) {
|
|
8596
|
+
return null;
|
|
8597
|
+
}
|
|
8598
|
+
try {
|
|
8599
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/upload-config`, {
|
|
8600
|
+
method: "GET",
|
|
8601
|
+
headers: {
|
|
8602
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8603
|
+
},
|
|
8604
|
+
});
|
|
8605
|
+
if (!response.ok) {
|
|
8606
|
+
return null;
|
|
8607
|
+
}
|
|
8608
|
+
const result = yield response.json();
|
|
8609
|
+
return result.data || null;
|
|
8610
|
+
}
|
|
8611
|
+
catch (_a) {
|
|
8612
|
+
return null;
|
|
8613
|
+
}
|
|
8614
|
+
});
|
|
8615
|
+
}
|
|
8616
|
+
/**
|
|
8617
|
+
* Upload a file to user's IPFS pinning service.
|
|
8618
|
+
* @param file The file to upload.
|
|
8619
|
+
* @param config The IPFS upload config.
|
|
8620
|
+
* @param progressCallback Optional progress callback with intermediate upload progress.
|
|
8621
|
+
* @returns The IPFS CID of the uploaded file.
|
|
8622
|
+
*/
|
|
8623
|
+
function uploadToUserIPFS(file, config, progressCallback) {
|
|
8624
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8625
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
8626
|
+
// Validate file input
|
|
8627
|
+
if (!file || !(file instanceof File)) {
|
|
8628
|
+
throw new ValidationError("Invalid file: must be a File object");
|
|
8629
|
+
}
|
|
8630
|
+
if (file.size === 0) {
|
|
8631
|
+
throw new ValidationError("Cannot upload empty file");
|
|
8632
|
+
}
|
|
8633
|
+
progressCallback === null || progressCallback === void 0 ? void 0 : progressCallback(0);
|
|
8634
|
+
const onUploadProgress = progressCallback
|
|
8635
|
+
? (progressEvent) => {
|
|
8636
|
+
if (progressEvent.total) {
|
|
8637
|
+
const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
|
|
8638
|
+
progressCallback(percent);
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8641
|
+
: undefined;
|
|
8642
|
+
let cid;
|
|
8643
|
+
switch (config.provider) {
|
|
8644
|
+
case "pinata": {
|
|
8645
|
+
const formData = new FormData();
|
|
8646
|
+
formData.append("file", file);
|
|
8647
|
+
const headers = {};
|
|
8648
|
+
if ((_a = config.pinata) === null || _a === void 0 ? void 0 : _a.jwt) {
|
|
8649
|
+
headers["Authorization"] = `Bearer ${config.pinata.jwt}`;
|
|
8650
|
+
}
|
|
8651
|
+
else if (((_b = config.pinata) === null || _b === void 0 ? void 0 : _b.apiKey) && ((_c = config.pinata) === null || _c === void 0 ? void 0 : _c.apiSecret)) {
|
|
8652
|
+
headers["pinata_api_key"] = config.pinata.apiKey;
|
|
8653
|
+
headers["pinata_secret_api_key"] = config.pinata.apiSecret;
|
|
8654
|
+
}
|
|
8655
|
+
try {
|
|
8656
|
+
const response = yield axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, { headers, onUploadProgress, timeout: 600000 });
|
|
8657
|
+
cid = response.data.IpfsHash;
|
|
8658
|
+
}
|
|
8659
|
+
catch (error) {
|
|
8660
|
+
const status = (_d = error.response) === null || _d === void 0 ? void 0 : _d.status;
|
|
8661
|
+
const message = ((_g = (_f = (_e = error.response) === null || _e === void 0 ? void 0 : _e.data) === null || _f === void 0 ? void 0 : _f.error) === null || _g === void 0 ? void 0 : _g.details) ||
|
|
8662
|
+
((_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.message) ||
|
|
8663
|
+
error.message;
|
|
8664
|
+
throw new APIError(`Pinata IPFS upload failed: ${message}`, status);
|
|
8665
|
+
}
|
|
8666
|
+
break;
|
|
8667
|
+
}
|
|
8668
|
+
case "infura": {
|
|
8669
|
+
if (!config.infura) {
|
|
8670
|
+
throw new Error("Infura config missing");
|
|
8671
|
+
}
|
|
8672
|
+
const formData = new FormData();
|
|
8673
|
+
formData.append("file", file);
|
|
8674
|
+
const auth = btoa(`${config.infura.projectId}:${config.infura.projectSecret}`);
|
|
8675
|
+
try {
|
|
8676
|
+
const response = yield axios.post(`${config.infura.endpoint}/api/v0/add`, formData, {
|
|
8677
|
+
headers: { Authorization: `Basic ${auth}` },
|
|
8678
|
+
onUploadProgress,
|
|
8679
|
+
timeout: 600000,
|
|
8680
|
+
});
|
|
8681
|
+
cid = response.data.Hash;
|
|
8682
|
+
}
|
|
8683
|
+
catch (error) {
|
|
8684
|
+
const status = (_k = error.response) === null || _k === void 0 ? void 0 : _k.status;
|
|
8685
|
+
const message = ((_m = (_l = error.response) === null || _l === void 0 ? void 0 : _l.data) === null || _m === void 0 ? void 0 : _m.Message) || error.message;
|
|
8686
|
+
throw new APIError(`Infura IPFS upload failed: ${message}`, status);
|
|
8687
|
+
}
|
|
8688
|
+
break;
|
|
8689
|
+
}
|
|
8690
|
+
case "web3storage": {
|
|
8691
|
+
if (!((_o = config.web3storage) === null || _o === void 0 ? void 0 : _o.token)) {
|
|
8692
|
+
throw new Error("web3.storage config missing");
|
|
8693
|
+
}
|
|
8694
|
+
try {
|
|
8695
|
+
const response = yield axios.post("https://api.web3.storage/upload", file, {
|
|
8696
|
+
headers: {
|
|
8697
|
+
Authorization: `Bearer ${config.web3storage.token}`,
|
|
8698
|
+
"X-Name": file.name,
|
|
8699
|
+
},
|
|
8700
|
+
onUploadProgress,
|
|
8701
|
+
timeout: 600000,
|
|
8702
|
+
});
|
|
8703
|
+
cid = response.data.cid;
|
|
8704
|
+
}
|
|
8705
|
+
catch (error) {
|
|
8706
|
+
const status = (_p = error.response) === null || _p === void 0 ? void 0 : _p.status;
|
|
8707
|
+
const message = ((_r = (_q = error.response) === null || _q === void 0 ? void 0 : _q.data) === null || _r === void 0 ? void 0 : _r.message) || error.message;
|
|
8708
|
+
throw new APIError(`web3.storage IPFS upload failed: ${message}`, status);
|
|
8709
|
+
}
|
|
8710
|
+
break;
|
|
8711
|
+
}
|
|
8712
|
+
default:
|
|
8713
|
+
throw new ValidationError(`Unsupported IPFS provider: ${config.provider}. Supported providers: pinata, infura, web3storage`);
|
|
8714
|
+
}
|
|
8715
|
+
if (!cid || typeof cid !== "string") {
|
|
8716
|
+
throw new APIError(`IPFS upload to ${config.provider} succeeded but returned no CID`);
|
|
8717
|
+
}
|
|
8718
|
+
progressCallback === null || progressCallback === void 0 ? void 0 : progressCallback(100);
|
|
8719
|
+
return cid;
|
|
8720
|
+
});
|
|
8721
|
+
}
|
|
8722
|
+
/**
|
|
8723
|
+
* Register an IPFS file with the backend after client-side upload.
|
|
8724
|
+
* @param cid The IPFS CID of the uploaded file.
|
|
8725
|
+
* @param fileName The original file name.
|
|
8726
|
+
* @param fileType The file MIME type.
|
|
8727
|
+
* @returns The registered file key.
|
|
8728
|
+
*/
|
|
8729
|
+
function registerIpfsFile(cid, fileName, fileType) {
|
|
8730
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
8731
|
+
if (!this.jwt) {
|
|
8732
|
+
throw new APIError("JWT token required for IPFS file registration");
|
|
8733
|
+
}
|
|
8734
|
+
const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/register-file`, {
|
|
8735
|
+
method: "POST",
|
|
8736
|
+
headers: {
|
|
8737
|
+
Authorization: `Bearer ${this.jwt}`,
|
|
8738
|
+
"Content-Type": "application/json",
|
|
8739
|
+
},
|
|
8740
|
+
body: JSON.stringify({ cid, fileName, fileType }),
|
|
8741
|
+
});
|
|
8742
|
+
if (!response.ok) {
|
|
8743
|
+
const errorData = yield response.json().catch(() => ({}));
|
|
8744
|
+
throw new APIError(errorData.message ||
|
|
8745
|
+
`Failed to register IPFS file (HTTP ${response.status})`, response.status);
|
|
8746
|
+
}
|
|
8747
|
+
const result = yield response.json();
|
|
8748
|
+
return { fileKey: result.data.fileKey };
|
|
8749
|
+
});
|
|
8750
|
+
}
|
|
8751
|
+
|
|
8468
8752
|
var _Origin_instances, _Origin_generateURL, _Origin_setOriginStatus, _Origin_uploadToIPFS, _Origin_uploadFile, _Origin_waitForTxReceipt, _Origin_ensureChainId, _Origin_getCurrentAccount, _Origin_getProtocolFeeBps, _Origin_getAppFeeBpsForToken, _Origin_resolveWalletAddress;
|
|
8469
8753
|
/**
|
|
8470
8754
|
* The Origin class
|
|
@@ -8538,6 +8822,14 @@ class Origin {
|
|
|
8538
8822
|
this.getRoyaltyTokenBalance = getRoyaltyTokenBalance.bind(this);
|
|
8539
8823
|
// AppRegistry module methods
|
|
8540
8824
|
this.getAppInfo = getAppInfo.bind(this);
|
|
8825
|
+
// IPFS credentials methods
|
|
8826
|
+
this.saveIpfsCredentials = saveIpfsCredentials.bind(this);
|
|
8827
|
+
this.verifyIpfsCredentials = verifyIpfsCredentials.bind(this);
|
|
8828
|
+
this.deleteIpfsCredentials = deleteIpfsCredentials.bind(this);
|
|
8829
|
+
this.hasIpfsCredentials = hasIpfsCredentials.bind(this);
|
|
8830
|
+
this.getIpfsUploadConfig = getIpfsUploadConfig.bind(this);
|
|
8831
|
+
this.uploadToUserIPFS = uploadToUserIPFS.bind(this);
|
|
8832
|
+
this.registerIpfsFile = registerIpfsFile.bind(this);
|
|
8541
8833
|
}
|
|
8542
8834
|
getJwt() {
|
|
8543
8835
|
return this.jwt;
|
|
@@ -8591,7 +8883,7 @@ class Origin {
|
|
|
8591
8883
|
* @param metadata The metadata associated with the file.
|
|
8592
8884
|
* @param license The license terms for the IpNFT.
|
|
8593
8885
|
* @param parents Optional parent token IDs for lineage tracking.
|
|
8594
|
-
* @param options Optional parameters including progress callback, preview image,
|
|
8886
|
+
* @param options Optional parameters including progress callback, preview image, use asset as preview flag, and forceIpfs.
|
|
8595
8887
|
* @returns The token ID of the minted IpNFT as a string, or null if minting failed.
|
|
8596
8888
|
*/
|
|
8597
8889
|
mintFile(file, metadata, license, parents, options) {
|
|
@@ -8603,17 +8895,37 @@ class Origin {
|
|
|
8603
8895
|
catch (error) {
|
|
8604
8896
|
throw new WalletError(`Cannot mint file "${file.name}": wallet not connected. Please connect a wallet first.`);
|
|
8605
8897
|
}
|
|
8898
|
+
// Check if we should use IPFS for this file
|
|
8899
|
+
const shouldUseIpfs = (options === null || options === void 0 ? void 0 : options.forceIpfs) || file.size > constants.MAX_FILE_SIZE;
|
|
8606
8900
|
let info;
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8901
|
+
if (shouldUseIpfs) {
|
|
8902
|
+
// Large file - use user's IPFS pinning service
|
|
8903
|
+
const ipfsConfig = yield this.getIpfsUploadConfig();
|
|
8904
|
+
if (!ipfsConfig) {
|
|
8905
|
+
throw new APIError(`File "${file.name}" exceeds 20MB limit. Please configure your IPFS pinning service in Settings to upload large files.`);
|
|
8906
|
+
}
|
|
8907
|
+
try {
|
|
8908
|
+
const cid = yield this.uploadToUserIPFS(file, ipfsConfig, options === null || options === void 0 ? void 0 : options.progressCallback);
|
|
8909
|
+
const { fileKey } = yield this.registerIpfsFile(cid, file.name, file.type);
|
|
8910
|
+
info = { key: fileKey, uploadId: "" };
|
|
8911
|
+
}
|
|
8912
|
+
catch (error) {
|
|
8913
|
+
throw new APIError(`Failed to upload file "${file.name}" to IPFS: ${getErrorMessage(error)}`);
|
|
8611
8914
|
}
|
|
8612
8915
|
}
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8916
|
+
else {
|
|
8917
|
+
// Normal file - use S3
|
|
8918
|
+
try {
|
|
8919
|
+
info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, options);
|
|
8920
|
+
if (!info || !info.key) {
|
|
8921
|
+
throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
|
|
8922
|
+
}
|
|
8923
|
+
}
|
|
8924
|
+
catch (error) {
|
|
8925
|
+
if (error instanceof APIError || error instanceof WalletError)
|
|
8926
|
+
throw error;
|
|
8927
|
+
throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
|
|
8928
|
+
}
|
|
8617
8929
|
}
|
|
8618
8930
|
if (file.type) {
|
|
8619
8931
|
metadata.mimetype = file.type;
|
|
@@ -8629,7 +8941,7 @@ class Origin {
|
|
|
8629
8941
|
if (previewImageIpfsHash) {
|
|
8630
8942
|
metadata.image = `ipfs://${previewImageIpfsHash}`;
|
|
8631
8943
|
}
|
|
8632
|
-
const deadline = BigInt(Date.now() +
|
|
8944
|
+
const deadline = BigInt(Math.floor(Date.now() / 1000) + 600); // 10 minutes from now
|
|
8633
8945
|
if (this.baseParentId) {
|
|
8634
8946
|
if (!parents) {
|
|
8635
8947
|
parents = [];
|
|
@@ -8643,7 +8955,10 @@ class Origin {
|
|
|
8643
8955
|
parents, this.appId);
|
|
8644
8956
|
}
|
|
8645
8957
|
catch (error) {
|
|
8646
|
-
|
|
8958
|
+
// Only update S3 status if we have an uploadId (non-IPFS flow)
|
|
8959
|
+
if (info.uploadId) {
|
|
8960
|
+
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
8961
|
+
}
|
|
8647
8962
|
throw new Error(`Failed to register IpNFT: ${error instanceof Error ? error.message : String(error)}`);
|
|
8648
8963
|
}
|
|
8649
8964
|
const { tokenId, signerAddress, creatorContentHash, signature, uri } = registration;
|
|
@@ -8657,12 +8972,18 @@ class Origin {
|
|
|
8657
8972
|
try {
|
|
8658
8973
|
const mintResult = yield this.mintWithSignature(account, tokenId, parents || [], true, creatorContentHash, uri, license, deadline, signature, this.appId);
|
|
8659
8974
|
if (["0x1", "success"].indexOf(mintResult.receipt.status) === -1) {
|
|
8660
|
-
|
|
8975
|
+
// Only update S3 status if we have an uploadId (non-IPFS flow)
|
|
8976
|
+
if (info.uploadId) {
|
|
8977
|
+
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
8978
|
+
}
|
|
8661
8979
|
throw new Error(`Minting failed with status: ${mintResult.receipt.status}`);
|
|
8662
8980
|
}
|
|
8663
8981
|
}
|
|
8664
8982
|
catch (error) {
|
|
8665
|
-
|
|
8983
|
+
// Only update S3 status if we have an uploadId (non-IPFS flow)
|
|
8984
|
+
if (info.uploadId) {
|
|
8985
|
+
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
8986
|
+
}
|
|
8666
8987
|
throw new Error(`Minting transaction failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
8667
8988
|
}
|
|
8668
8989
|
return tokenId.toString();
|
|
@@ -8709,10 +9030,15 @@ class Origin {
|
|
|
8709
9030
|
const { file, metadata, license } = entry;
|
|
8710
9031
|
let { parents } = entry;
|
|
8711
9032
|
// Upload file
|
|
9033
|
+
const shouldUseIpfs = (options === null || options === void 0 ? void 0 : options.forceIpfs) || file.size > constants.MAX_FILE_SIZE;
|
|
8712
9034
|
let info;
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
9035
|
+
if (shouldUseIpfs) {
|
|
9036
|
+
const ipfsConfig = yield this.getIpfsUploadConfig();
|
|
9037
|
+
if (!ipfsConfig) {
|
|
9038
|
+
throw new APIError(`File "${file.name}" exceeds 20MB limit. Please configure your IPFS pinning service in Settings to upload large files.`);
|
|
9039
|
+
}
|
|
9040
|
+
try {
|
|
9041
|
+
const cid = yield this.uploadToUserIPFS(file, ipfsConfig, (percent) => {
|
|
8716
9042
|
var _a;
|
|
8717
9043
|
(_a = options === null || options === void 0 ? void 0 : options.progressCallback) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
8718
9044
|
fileIndex: i,
|
|
@@ -8720,16 +9046,38 @@ class Origin {
|
|
|
8720
9046
|
stage: "uploading",
|
|
8721
9047
|
percent,
|
|
8722
9048
|
});
|
|
8723
|
-
}
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
9049
|
+
});
|
|
9050
|
+
const { fileKey } = yield this.registerIpfsFile(cid, file.name, file.type);
|
|
9051
|
+
info = { key: fileKey, uploadId: "" };
|
|
9052
|
+
}
|
|
9053
|
+
catch (error) {
|
|
9054
|
+
if (error instanceof APIError)
|
|
9055
|
+
throw error;
|
|
9056
|
+
throw new APIError(`Failed to upload file "${file.name}" to IPFS: ${getErrorMessage(error)}`);
|
|
8727
9057
|
}
|
|
8728
9058
|
}
|
|
8729
|
-
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
|
|
9059
|
+
else {
|
|
9060
|
+
try {
|
|
9061
|
+
info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, {
|
|
9062
|
+
progressCallback: (percent) => {
|
|
9063
|
+
var _a;
|
|
9064
|
+
(_a = options === null || options === void 0 ? void 0 : options.progressCallback) === null || _a === void 0 ? void 0 : _a.call(options, {
|
|
9065
|
+
fileIndex: i,
|
|
9066
|
+
fileCount: entries.length,
|
|
9067
|
+
stage: "uploading",
|
|
9068
|
+
percent,
|
|
9069
|
+
});
|
|
9070
|
+
},
|
|
9071
|
+
});
|
|
9072
|
+
if (!info || !info.key) {
|
|
9073
|
+
throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
|
|
9074
|
+
}
|
|
9075
|
+
}
|
|
9076
|
+
catch (error) {
|
|
9077
|
+
if (error instanceof APIError || error instanceof WalletError)
|
|
9078
|
+
throw error;
|
|
9079
|
+
throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
|
|
9080
|
+
}
|
|
8733
9081
|
}
|
|
8734
9082
|
uploadInfos.push(info);
|
|
8735
9083
|
// Set mimetype
|
|
@@ -8747,7 +9095,7 @@ class Origin {
|
|
|
8747
9095
|
if (previewImageIpfsHash) {
|
|
8748
9096
|
metadata.image = `ipfs://${previewImageIpfsHash}`;
|
|
8749
9097
|
}
|
|
8750
|
-
const deadline = BigInt(Date.now() +
|
|
9098
|
+
const deadline = BigInt(Math.floor(Date.now() / 1000) + 600); // 10 minutes from now
|
|
8751
9099
|
// Prepare parents
|
|
8752
9100
|
if (this.baseParentId) {
|
|
8753
9101
|
if (!parents) {
|
|
@@ -8769,12 +9117,16 @@ class Origin {
|
|
|
8769
9117
|
parents, this.appId);
|
|
8770
9118
|
}
|
|
8771
9119
|
catch (error) {
|
|
8772
|
-
|
|
9120
|
+
if (info.uploadId) {
|
|
9121
|
+
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
9122
|
+
}
|
|
8773
9123
|
throw new Error(`Failed to register IpNFT for file "${file.name}": ${error instanceof Error ? error.message : String(error)}`);
|
|
8774
9124
|
}
|
|
8775
9125
|
const { tokenId, creatorContentHash, signature, uri } = registration;
|
|
8776
9126
|
if (!tokenId || !creatorContentHash || signature === undefined || !uri) {
|
|
8777
|
-
|
|
9127
|
+
if (info.uploadId) {
|
|
9128
|
+
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
9129
|
+
}
|
|
8778
9130
|
throw new Error(`Failed to register IpNFT for file "${file.name}": Missing required fields in registration response.`);
|
|
8779
9131
|
}
|
|
8780
9132
|
tokenIds.push(tokenId.toString());
|
|
@@ -8803,8 +9155,10 @@ class Origin {
|
|
|
8803
9155
|
return { tokenIds, result };
|
|
8804
9156
|
}
|
|
8805
9157
|
catch (error) {
|
|
8806
|
-
// Mark all uploads as failed
|
|
9158
|
+
// Mark all S3 uploads as failed (skip IPFS entries with no uploadId)
|
|
8807
9159
|
for (const info of uploadInfos) {
|
|
9160
|
+
if (!info.uploadId)
|
|
9161
|
+
continue;
|
|
8808
9162
|
try {
|
|
8809
9163
|
yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
|
|
8810
9164
|
}
|
|
@@ -9242,6 +9596,16 @@ class Origin {
|
|
|
9242
9596
|
{ waitForReceipt: true, value: BigInt(0) });
|
|
9243
9597
|
});
|
|
9244
9598
|
}
|
|
9599
|
+
/**
|
|
9600
|
+
* Get the connected wallet address.
|
|
9601
|
+
* @returns {Promise<Address>} The connected wallet address.
|
|
9602
|
+
* @throws {WalletError} Throws if no wallet is connected.
|
|
9603
|
+
*/
|
|
9604
|
+
getWalletAddress() {
|
|
9605
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
9606
|
+
return __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_resolveWalletAddress).call(this);
|
|
9607
|
+
});
|
|
9608
|
+
}
|
|
9245
9609
|
}
|
|
9246
9610
|
_Origin_instances = new WeakSet(), _Origin_generateURL = function _Origin_generateURL(file, partCount) {
|
|
9247
9611
|
return __awaiter(this, void 0, void 0, function* () {
|