@campnetwork/origin 1.4.0-alpha.4 → 1.4.0-alpha.6

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.
@@ -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
@@ -8412,7 +8413,7 @@ function bulkBuyAccessSmart(tokenIds, options) {
8412
8413
  * creatorContentHash: "0x...",
8413
8414
  * uri: "ipfs://...",
8414
8415
  * licenseTerms: { price: 1000n, duration: 86400, royaltyBps: 500, paymentToken: zeroAddress, licenseType: 0 },
8415
- * deadline: BigInt(Date.now() + 600000),
8416
+ * deadline: BigInt(Math.floor(Date.now() / 1000) + 600),
8416
8417
  * parents: [],
8417
8418
  * isIP: true,
8418
8419
  * appId: "myApp",
@@ -8443,6 +8444,312 @@ function bulkMintTolerant(mints) {
8443
8444
  return this.callContractMethod(this.environment.BATCH_OPERATIONS_CONTRACT_ADDRESS, this.environment.BATCH_OPERATIONS_ABI, "bulkMintTolerant", [mints], { waitForReceipt: true });
8444
8445
  }
8445
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
+ const result = yield response.json();
8537
+ return result.data;
8538
+ });
8539
+ }
8540
+ /**
8541
+ * Delete saved IPFS credentials.
8542
+ * @throws {APIError} If deletion fails.
8543
+ */
8544
+ function deleteIpfsCredentials() {
8545
+ return __awaiter(this, void 0, void 0, function* () {
8546
+ if (!this.jwt) {
8547
+ throw new APIError("JWT token required for IPFS credentials management");
8548
+ }
8549
+ const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials`, {
8550
+ method: "DELETE",
8551
+ headers: {
8552
+ Authorization: `Bearer ${this.jwt}`,
8553
+ },
8554
+ });
8555
+ if (!response.ok) {
8556
+ const errorData = yield response.json().catch(() => ({}));
8557
+ throw new APIError(errorData.message ||
8558
+ `Failed to delete IPFS credentials (HTTP ${response.status})`, response.status);
8559
+ }
8560
+ });
8561
+ }
8562
+ /**
8563
+ * Check if user has IPFS credentials configured.
8564
+ * @returns True if credentials are configured, false otherwise.
8565
+ */
8566
+ function hasIpfsCredentials() {
8567
+ return __awaiter(this, void 0, void 0, function* () {
8568
+ var _a;
8569
+ if (!this.jwt) {
8570
+ return false;
8571
+ }
8572
+ try {
8573
+ const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/credentials`, {
8574
+ method: "GET",
8575
+ headers: {
8576
+ Authorization: `Bearer ${this.jwt}`,
8577
+ },
8578
+ });
8579
+ if (!response.ok) {
8580
+ return false;
8581
+ }
8582
+ const data = yield response.json();
8583
+ return ((_a = data.data) === null || _a === void 0 ? void 0 : _a.hasCredentials) || false;
8584
+ }
8585
+ catch (_b) {
8586
+ return false;
8587
+ }
8588
+ });
8589
+ }
8590
+ /**
8591
+ * Get IPFS upload config for client-side uploads.
8592
+ * @returns IPFS config or null if not configured.
8593
+ */
8594
+ function getIpfsUploadConfig() {
8595
+ return __awaiter(this, void 0, void 0, function* () {
8596
+ if (!this.jwt) {
8597
+ return null;
8598
+ }
8599
+ try {
8600
+ const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/upload-config`, {
8601
+ method: "GET",
8602
+ headers: {
8603
+ Authorization: `Bearer ${this.jwt}`,
8604
+ },
8605
+ });
8606
+ if (!response.ok) {
8607
+ return null;
8608
+ }
8609
+ const result = yield response.json();
8610
+ return result.data || null;
8611
+ }
8612
+ catch (_a) {
8613
+ return null;
8614
+ }
8615
+ });
8616
+ }
8617
+ /**
8618
+ * Upload a file to user's IPFS pinning service.
8619
+ * @param file The file to upload.
8620
+ * @param config The IPFS upload config.
8621
+ * @param progressCallback Optional progress callback with intermediate upload progress.
8622
+ * @returns The IPFS CID of the uploaded file.
8623
+ */
8624
+ function uploadToUserIPFS(file, config, progressCallback) {
8625
+ return __awaiter(this, void 0, void 0, function* () {
8626
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
8627
+ // Validate file input
8628
+ if (!file || !(file instanceof File)) {
8629
+ throw new ValidationError("Invalid file: must be a File object");
8630
+ }
8631
+ if (file.size === 0) {
8632
+ throw new ValidationError("Cannot upload empty file");
8633
+ }
8634
+ progressCallback === null || progressCallback === void 0 ? void 0 : progressCallback(0);
8635
+ const onUploadProgress = progressCallback
8636
+ ? (progressEvent) => {
8637
+ if (progressEvent.total) {
8638
+ const percent = Math.round((progressEvent.loaded / progressEvent.total) * 100);
8639
+ progressCallback(percent);
8640
+ }
8641
+ }
8642
+ : undefined;
8643
+ let cid;
8644
+ switch (config.provider) {
8645
+ case "pinata": {
8646
+ const formData = new FormData();
8647
+ formData.append("file", file);
8648
+ const headers = {};
8649
+ if ((_a = config.pinata) === null || _a === void 0 ? void 0 : _a.jwt) {
8650
+ headers["Authorization"] = `Bearer ${config.pinata.jwt}`;
8651
+ }
8652
+ else if (((_b = config.pinata) === null || _b === void 0 ? void 0 : _b.apiKey) && ((_c = config.pinata) === null || _c === void 0 ? void 0 : _c.apiSecret)) {
8653
+ headers["pinata_api_key"] = config.pinata.apiKey;
8654
+ headers["pinata_secret_api_key"] = config.pinata.apiSecret;
8655
+ }
8656
+ try {
8657
+ const response = yield axios.post("https://api.pinata.cloud/pinning/pinFileToIPFS", formData, { headers, onUploadProgress, timeout: 600000 });
8658
+ cid = response.data.IpfsHash;
8659
+ }
8660
+ catch (error) {
8661
+ const status = (_d = error.response) === null || _d === void 0 ? void 0 : _d.status;
8662
+ 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) ||
8663
+ ((_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.message) ||
8664
+ error.message;
8665
+ throw new APIError(`Pinata IPFS upload failed: ${message}`, status);
8666
+ }
8667
+ break;
8668
+ }
8669
+ case "infura": {
8670
+ if (!config.infura) {
8671
+ throw new Error("Infura config missing");
8672
+ }
8673
+ const formData = new FormData();
8674
+ formData.append("file", file);
8675
+ const auth = btoa(`${config.infura.projectId}:${config.infura.projectSecret}`);
8676
+ try {
8677
+ const response = yield axios.post(`${config.infura.endpoint}/api/v0/add`, formData, {
8678
+ headers: { Authorization: `Basic ${auth}` },
8679
+ onUploadProgress,
8680
+ timeout: 600000,
8681
+ });
8682
+ cid = response.data.Hash;
8683
+ }
8684
+ catch (error) {
8685
+ const status = (_k = error.response) === null || _k === void 0 ? void 0 : _k.status;
8686
+ const message = ((_m = (_l = error.response) === null || _l === void 0 ? void 0 : _l.data) === null || _m === void 0 ? void 0 : _m.Message) || error.message;
8687
+ throw new APIError(`Infura IPFS upload failed: ${message}`, status);
8688
+ }
8689
+ break;
8690
+ }
8691
+ case "web3storage": {
8692
+ if (!((_o = config.web3storage) === null || _o === void 0 ? void 0 : _o.token)) {
8693
+ throw new Error("web3.storage config missing");
8694
+ }
8695
+ try {
8696
+ const response = yield axios.post("https://api.web3.storage/upload", file, {
8697
+ headers: {
8698
+ Authorization: `Bearer ${config.web3storage.token}`,
8699
+ "X-Name": file.name,
8700
+ },
8701
+ onUploadProgress,
8702
+ timeout: 600000,
8703
+ });
8704
+ cid = response.data.cid;
8705
+ }
8706
+ catch (error) {
8707
+ const status = (_p = error.response) === null || _p === void 0 ? void 0 : _p.status;
8708
+ const message = ((_r = (_q = error.response) === null || _q === void 0 ? void 0 : _q.data) === null || _r === void 0 ? void 0 : _r.message) || error.message;
8709
+ throw new APIError(`web3.storage IPFS upload failed: ${message}`, status);
8710
+ }
8711
+ break;
8712
+ }
8713
+ default:
8714
+ throw new ValidationError(`Unsupported IPFS provider: ${config.provider}. Supported providers: pinata, infura, web3storage`);
8715
+ }
8716
+ if (!cid || typeof cid !== "string") {
8717
+ throw new APIError(`IPFS upload to ${config.provider} succeeded but returned no CID`);
8718
+ }
8719
+ progressCallback === null || progressCallback === void 0 ? void 0 : progressCallback(100);
8720
+ return cid;
8721
+ });
8722
+ }
8723
+ /**
8724
+ * Register an IPFS file with the backend after client-side upload.
8725
+ * @param cid The IPFS CID of the uploaded file.
8726
+ * @param fileName The original file name.
8727
+ * @param fileType The file MIME type.
8728
+ * @returns The registered file key.
8729
+ */
8730
+ function registerIpfsFile(cid, fileName, fileType) {
8731
+ return __awaiter(this, void 0, void 0, function* () {
8732
+ if (!this.jwt) {
8733
+ throw new APIError("JWT token required for IPFS file registration");
8734
+ }
8735
+ const response = yield fetch(`${this.environment.AUTH_HUB_BASE_API}/ipfs/register-file`, {
8736
+ method: "POST",
8737
+ headers: {
8738
+ Authorization: `Bearer ${this.jwt}`,
8739
+ "Content-Type": "application/json",
8740
+ },
8741
+ body: JSON.stringify({ cid, fileName, fileType }),
8742
+ });
8743
+ if (!response.ok) {
8744
+ const errorData = yield response.json().catch(() => ({}));
8745
+ throw new APIError(errorData.message ||
8746
+ `Failed to register IPFS file (HTTP ${response.status})`, response.status);
8747
+ }
8748
+ const result = yield response.json();
8749
+ return { fileKey: result.data.fileKey };
8750
+ });
8751
+ }
8752
+
8446
8753
  var _Origin_instances, _Origin_generateURL, _Origin_setOriginStatus, _Origin_uploadToIPFS, _Origin_uploadFile, _Origin_waitForTxReceipt, _Origin_ensureChainId, _Origin_getCurrentAccount, _Origin_getProtocolFeeBps, _Origin_getAppFeeBpsForToken, _Origin_resolveWalletAddress;
8447
8754
  /**
8448
8755
  * The Origin class
@@ -8516,6 +8823,14 @@ class Origin {
8516
8823
  this.getRoyaltyTokenBalance = getRoyaltyTokenBalance.bind(this);
8517
8824
  // AppRegistry module methods
8518
8825
  this.getAppInfo = getAppInfo.bind(this);
8826
+ // IPFS credentials methods
8827
+ this.saveIpfsCredentials = saveIpfsCredentials.bind(this);
8828
+ this.verifyIpfsCredentials = verifyIpfsCredentials.bind(this);
8829
+ this.deleteIpfsCredentials = deleteIpfsCredentials.bind(this);
8830
+ this.hasIpfsCredentials = hasIpfsCredentials.bind(this);
8831
+ this.getIpfsUploadConfig = getIpfsUploadConfig.bind(this);
8832
+ this.uploadToUserIPFS = uploadToUserIPFS.bind(this);
8833
+ this.registerIpfsFile = registerIpfsFile.bind(this);
8519
8834
  }
8520
8835
  getJwt() {
8521
8836
  return this.jwt;
@@ -8569,7 +8884,7 @@ class Origin {
8569
8884
  * @param metadata The metadata associated with the file.
8570
8885
  * @param license The license terms for the IpNFT.
8571
8886
  * @param parents Optional parent token IDs for lineage tracking.
8572
- * @param options Optional parameters including progress callback, preview image, and use asset as preview flag.
8887
+ * @param options Optional parameters including progress callback, preview image, use asset as preview flag, and forceIpfs.
8573
8888
  * @returns The token ID of the minted IpNFT as a string, or null if minting failed.
8574
8889
  */
8575
8890
  mintFile(file, metadata, license, parents, options) {
@@ -8581,17 +8896,37 @@ class Origin {
8581
8896
  catch (error) {
8582
8897
  throw new WalletError(`Cannot mint file "${file.name}": wallet not connected. Please connect a wallet first.`);
8583
8898
  }
8899
+ // Check if we should use IPFS for this file
8900
+ const shouldUseIpfs = (options === null || options === void 0 ? void 0 : options.forceIpfs) || file.size > constants.MAX_FILE_SIZE;
8584
8901
  let info;
8585
- try {
8586
- info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, options);
8587
- if (!info || !info.key) {
8588
- throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
8902
+ if (shouldUseIpfs) {
8903
+ // Large file - use user's IPFS pinning service
8904
+ const ipfsConfig = yield this.getIpfsUploadConfig();
8905
+ if (!ipfsConfig) {
8906
+ throw new APIError(`File "${file.name}" exceeds 20MB limit. Please configure your IPFS pinning service in Settings to upload large files.`);
8907
+ }
8908
+ try {
8909
+ const cid = yield this.uploadToUserIPFS(file, ipfsConfig, options === null || options === void 0 ? void 0 : options.progressCallback);
8910
+ const { fileKey } = yield this.registerIpfsFile(cid, file.name, file.type);
8911
+ info = { key: fileKey, uploadId: "" };
8912
+ }
8913
+ catch (error) {
8914
+ throw new APIError(`Failed to upload file "${file.name}" to IPFS: ${getErrorMessage(error)}`);
8589
8915
  }
8590
8916
  }
8591
- catch (error) {
8592
- if (error instanceof APIError || error instanceof WalletError)
8593
- throw error;
8594
- throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
8917
+ else {
8918
+ // Normal file - use S3
8919
+ try {
8920
+ info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, options);
8921
+ if (!info || !info.key) {
8922
+ throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
8923
+ }
8924
+ }
8925
+ catch (error) {
8926
+ if (error instanceof APIError || error instanceof WalletError)
8927
+ throw error;
8928
+ throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
8929
+ }
8595
8930
  }
8596
8931
  if (file.type) {
8597
8932
  metadata.mimetype = file.type;
@@ -8607,7 +8942,7 @@ class Origin {
8607
8942
  if (previewImageIpfsHash) {
8608
8943
  metadata.image = `ipfs://${previewImageIpfsHash}`;
8609
8944
  }
8610
- const deadline = BigInt(Date.now() + 600000); // 10 minutes from now
8945
+ const deadline = BigInt(Math.floor(Date.now() / 1000) + 600); // 10 minutes from now
8611
8946
  if (this.baseParentId) {
8612
8947
  if (!parents) {
8613
8948
  parents = [];
@@ -8621,7 +8956,10 @@ class Origin {
8621
8956
  parents, this.appId);
8622
8957
  }
8623
8958
  catch (error) {
8624
- yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8959
+ // Only update S3 status if we have an uploadId (non-IPFS flow)
8960
+ if (info.uploadId) {
8961
+ yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8962
+ }
8625
8963
  throw new Error(`Failed to register IpNFT: ${error instanceof Error ? error.message : String(error)}`);
8626
8964
  }
8627
8965
  const { tokenId, signerAddress, creatorContentHash, signature, uri } = registration;
@@ -8635,12 +8973,18 @@ class Origin {
8635
8973
  try {
8636
8974
  const mintResult = yield this.mintWithSignature(account, tokenId, parents || [], true, creatorContentHash, uri, license, deadline, signature, this.appId);
8637
8975
  if (["0x1", "success"].indexOf(mintResult.receipt.status) === -1) {
8638
- yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8976
+ // Only update S3 status if we have an uploadId (non-IPFS flow)
8977
+ if (info.uploadId) {
8978
+ yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8979
+ }
8639
8980
  throw new Error(`Minting failed with status: ${mintResult.receipt.status}`);
8640
8981
  }
8641
8982
  }
8642
8983
  catch (error) {
8643
- yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8984
+ // Only update S3 status if we have an uploadId (non-IPFS flow)
8985
+ if (info.uploadId) {
8986
+ yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8987
+ }
8644
8988
  throw new Error(`Minting transaction failed: ${error instanceof Error ? error.message : String(error)}`);
8645
8989
  }
8646
8990
  return tokenId.toString();
@@ -8687,10 +9031,15 @@ class Origin {
8687
9031
  const { file, metadata, license } = entry;
8688
9032
  let { parents } = entry;
8689
9033
  // Upload file
9034
+ const shouldUseIpfs = (options === null || options === void 0 ? void 0 : options.forceIpfs) || file.size > constants.MAX_FILE_SIZE;
8690
9035
  let info;
8691
- try {
8692
- info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, {
8693
- progressCallback: (percent) => {
9036
+ if (shouldUseIpfs) {
9037
+ const ipfsConfig = yield this.getIpfsUploadConfig();
9038
+ if (!ipfsConfig) {
9039
+ throw new APIError(`File "${file.name}" exceeds 20MB limit. Please configure your IPFS pinning service in Settings to upload large files.`);
9040
+ }
9041
+ try {
9042
+ const cid = yield this.uploadToUserIPFS(file, ipfsConfig, (percent) => {
8694
9043
  var _a;
8695
9044
  (_a = options === null || options === void 0 ? void 0 : options.progressCallback) === null || _a === void 0 ? void 0 : _a.call(options, {
8696
9045
  fileIndex: i,
@@ -8698,16 +9047,38 @@ class Origin {
8698
9047
  stage: "uploading",
8699
9048
  percent,
8700
9049
  });
8701
- },
8702
- });
8703
- if (!info || !info.key) {
8704
- throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
9050
+ });
9051
+ const { fileKey } = yield this.registerIpfsFile(cid, file.name, file.type);
9052
+ info = { key: fileKey, uploadId: "" };
9053
+ }
9054
+ catch (error) {
9055
+ if (error instanceof APIError)
9056
+ throw error;
9057
+ throw new APIError(`Failed to upload file "${file.name}" to IPFS: ${getErrorMessage(error)}`);
8705
9058
  }
8706
9059
  }
8707
- catch (error) {
8708
- if (error instanceof APIError || error instanceof WalletError)
8709
- throw error;
8710
- throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
9060
+ else {
9061
+ try {
9062
+ info = yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_uploadFile).call(this, file, {
9063
+ progressCallback: (percent) => {
9064
+ var _a;
9065
+ (_a = options === null || options === void 0 ? void 0 : options.progressCallback) === null || _a === void 0 ? void 0 : _a.call(options, {
9066
+ fileIndex: i,
9067
+ fileCount: entries.length,
9068
+ stage: "uploading",
9069
+ percent,
9070
+ });
9071
+ },
9072
+ });
9073
+ if (!info || !info.key) {
9074
+ throw new APIError(`Failed to upload file "${file.name}": no upload info returned from server`);
9075
+ }
9076
+ }
9077
+ catch (error) {
9078
+ if (error instanceof APIError || error instanceof WalletError)
9079
+ throw error;
9080
+ throw new APIError(`Failed to upload file "${file.name}": ${getErrorMessage(error)}`);
9081
+ }
8711
9082
  }
8712
9083
  uploadInfos.push(info);
8713
9084
  // Set mimetype
@@ -8725,7 +9096,7 @@ class Origin {
8725
9096
  if (previewImageIpfsHash) {
8726
9097
  metadata.image = `ipfs://${previewImageIpfsHash}`;
8727
9098
  }
8728
- const deadline = BigInt(Date.now() + 600000); // 10 minutes from now
9099
+ const deadline = BigInt(Math.floor(Date.now() / 1000) + 600); // 10 minutes from now
8729
9100
  // Prepare parents
8730
9101
  if (this.baseParentId) {
8731
9102
  if (!parents) {
@@ -8747,12 +9118,16 @@ class Origin {
8747
9118
  parents, this.appId);
8748
9119
  }
8749
9120
  catch (error) {
8750
- yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
9121
+ if (info.uploadId) {
9122
+ yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
9123
+ }
8751
9124
  throw new Error(`Failed to register IpNFT for file "${file.name}": ${error instanceof Error ? error.message : String(error)}`);
8752
9125
  }
8753
9126
  const { tokenId, creatorContentHash, signature, uri } = registration;
8754
9127
  if (!tokenId || !creatorContentHash || signature === undefined || !uri) {
8755
- yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
9128
+ if (info.uploadId) {
9129
+ yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
9130
+ }
8756
9131
  throw new Error(`Failed to register IpNFT for file "${file.name}": Missing required fields in registration response.`);
8757
9132
  }
8758
9133
  tokenIds.push(tokenId.toString());
@@ -8781,8 +9156,10 @@ class Origin {
8781
9156
  return { tokenIds, result };
8782
9157
  }
8783
9158
  catch (error) {
8784
- // Mark all uploads as failed
9159
+ // Mark all S3 uploads as failed (skip IPFS entries with no uploadId)
8785
9160
  for (const info of uploadInfos) {
9161
+ if (!info.uploadId)
9162
+ continue;
8786
9163
  try {
8787
9164
  yield __classPrivateFieldGet(this, _Origin_instances, "m", _Origin_setOriginStatus).call(this, info.key, info.uploadId, []);
8788
9165
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campnetwork/origin",
3
- "version": "1.4.0-alpha.4",
3
+ "version": "1.4.0-alpha.6",
4
4
  "main": "dist/core.cjs",
5
5
  "exports": {
6
6
  ".": {