Skip to content

Commit

Permalink
vercel serverless functions added
Browse files Browse the repository at this point in the history
  • Loading branch information
tempe-techie committed Nov 27, 2023
1 parent f102112 commit 17ec6c3
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
FILE_UPLOAD_SERVICE=
LINK_PREVIEW_SERVICE=
RPC_CUSTOM=
SPHERON_BUCKET_NAME=
SPHERON_STORAGE_TOKEN=
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ dist

# Local Netlify folder
.netlify
.vercel
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ Make sure to use the the `npm run generate` command instead of `npm run build` f

If you want to use optional features such as GIFs and image upload, make sure to enter proper environment variables (see `.env.example`).

Make sure to also select the proper serverless functions services in your environment variables, for example:

```bash
FILE_UPLOAD_SERVICE=netlify
LINK_PREVIEW_SERVICE=netlify
```

You can also set these in the Nuxt config file (`nuxt.config.ts`).

### 4everland

[4everland](https://4everland.org/) is a decentralized hosting provider which stores your website on IPFS.
Expand Down
3 changes: 3 additions & 0 deletions api/_readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Vercel serverless function

This folder contains serverless functions for Vercel.
25 changes: 25 additions & 0 deletions api/imageUploader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { SpheronClient, ProtocolEnum } = require("@spheron/storage");

export default async function handler(request, response) {
try {
const bucketName = process.env.SPHERON_BUCKET_NAME; // enter bucket name in environment variables
const token = process.env.SPHERON_STORAGE_TOKEN; // add spheron storage token in environment variables

const protocol = ProtocolEnum.IPFS;

const client = new SpheronClient({ token });

const { uploadToken } = await client.createSingleUploadToken({
name: bucketName,
protocol,
});

return response.status(200).json({
data: uploadToken
});

} catch (error) {
console.error(error);
next(error);
}
}
199 changes: 199 additions & 0 deletions api/linkPreviews.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
export default async function handler(request, response) {
const ethers = require('ethers');

const metascraper = require('metascraper')([
require('metascraper-description')(),
require('metascraper-image')(),
require('metascraper-title')()
])

const url = request.query.url;

// link previews for specific sites
if (url.startsWith("https://sparklesnft.com/item/flare/")) {
// SPARKLES ITEM
const cleanUrl = url.split("?")[0];
const addrTokenId = cleanUrl.split("https://sparklesnft.com/item/flare/")[1].replace("/", "");
const addr = addrTokenId.split("_")[0];
const tokenId = addrTokenId.split("_")[1];

const provider = new ethers.providers.JsonRpcProvider("https://flare-api.flare.network/ext/C/rpc");

const nftInterface = new ethers.utils.Interface([
"function uri(uint256 _tokenId) external view returns (string memory)",
"function tokenURI(uint256 _tokenId) external view returns (string memory)"
]);

const nftContract = new ethers.Contract(addr, nftInterface, provider);

let nftMetadataUri;

try {
// erc-1155
nftMetadataUri = await nftContract.uri(tokenId);
} catch (error) {
// erc-721
nftMetadataUri = await nftContract.tokenURI(tokenId);
}

let json;

if (
!nftMetadataUri.startsWith("https://") &&
!nftMetadataUri.startsWith("http://") &&
!nftMetadataUri.startsWith("ipfs://")
) {
const result = atob(nftMetadataUri.substring(29));
json = JSON.parse(result);
} else if (nftMetadataUri.startsWith("ipfs://")) {
// ipfs://QmTLJDoCTihqD3AkNkMMQFXLMQFZkdqLFR3Mdcg14Ln7bL/7.json
// https://bafkreiecjcejcg6h5wh2g3wcacy2lnod2mfrvimlr53ikvlsh53mw2zdty.ipfs.w3s.link/
// https://QmTLJDoCTihqD3AkNkMMQFXLMQFZkdqLFR3Mdcg14Ln7bL.ipfs.dweb.link/7.json
// https://bafybeickgncmppcbrhg4cbzw3nxqajxoe2vj7ixmmcshddkyn5itv7ang4.ipfs.dweb.link/7.json

json = {
"name": "Check this NFT on Sparkles",
"description": "Sparkles NFT Marketplace",
"image": "https://bafkreifyx3seviqnnhpcuge72lr7la3yfrvucr3n5aoqijzjul2fyzh64i.ipfs.w3s.link"
}
} else {
const res = await fetch(nftMetadataUri);
json = await res.json();
}

const finalMetadata = {
"url": url,
"title": json["name"],
"description": json["description"],
"image": {
url: json["image"]
}
};

return response.status(200).json({
data: finalMetadata
});
} else if (url.startsWith("https://opensea.io/assets/base/")) {
// OPENSEA ITEM
const cleanUrl = url.split("?")[0];
const addrTokenId = cleanUrl.split("opensea.io/assets/base/")[1];
const addr = addrTokenId.split("/")[0];
const tokenId = addrTokenId.split("/")[1].replace("/", "");

const provider = new ethers.providers.JsonRpcProvider("https://mainnet.base.org");

const nftInterface = new ethers.utils.Interface([
"function uri(uint256 _tokenId) external view returns (string memory)",
"function tokenURI(uint256 _tokenId) external view returns (string memory)"
]);

const nftContract = new ethers.Contract(addr, nftInterface, provider);

let nftMetadataUri;

try {
// erc-1155
nftMetadataUri = await nftContract.uri(tokenId);
} catch (error) {
// erc-721
nftMetadataUri = await nftContract.tokenURI(tokenId);
}

let json;

if (
!nftMetadataUri.startsWith("https://") &&
!nftMetadataUri.startsWith("http://") &&
!nftMetadataUri.startsWith("ipfs://")
) {
const result = atob(nftMetadataUri.substring(29));
json = JSON.parse(result);
} else if (nftMetadataUri.startsWith("ipfs://")) {
// ipfs://QmTLJDoCTihqD3AkNkMMQFXLMQFZkdqLFR3Mdcg14Ln7bL/7.json
// https://bafkreiecjcejcg6h5wh2g3wcacy2lnod2mfrvimlr53ikvlsh53mw2zdty.ipfs.w3s.link/
// https://QmTLJDoCTihqD3AkNkMMQFXLMQFZkdqLFR3Mdcg14Ln7bL.ipfs.dweb.link/7.json
// https://bafybeickgncmppcbrhg4cbzw3nxqajxoe2vj7ixmmcshddkyn5itv7ang4.ipfs.dweb.link/7.json

json = {
"name": "Check this NFT on OpenSea",
"description": "OpenSea is the world's first and largest web3 marketplace for NFTs and crypto collectibles. Browse, create, buy, sell, and auction NFTs using OpenSea today.",
"image": "https://static.opensea.io/og-images/Metadata-Image.png"
}
} else {
const res = await fetch(nftMetadataUri);
json = await res.json();
}

const finalMetadata = {
"url": url,
"title": json["name"],
"description": json["description"],
"image": {
url: json["image"]
}
};

return response.status(200).json({
data: finalMetadata
});
} else if (url.startsWith("https://twitter.com") || url.startsWith("https://x.com")) {
// TWITTER
const finalMetadata = {
"url": url,
"title": "Twitter / X.com",
"description": "Elon's land, Elon's rules. Enter at your own risk.",
"image": {
url: "https://www.newswire.lk/wp-content/uploads/2022/12/elon-musk-twitter.jpg"
}
};

return response.status(200).json({
data: finalMetadata
});
}

// link previews for all other sites
try {
const res = await fetch(url);
const html = await res.text();

const metadata = await metascraper({ html, url });

const finalMetadata = {
"url": url,
"title": metadata.title,
"description": metadata.description,
"image": {
url: metadata.image
}
};

if (finalMetadata?.title) {
if (url.startsWith("https://opensea.io") && (finalMetadata.title == "Access denied" || finalMetadata.title.startsWith("Just a moment"))) {
finalMetadata.title = "OpenSea";
finalMetadata.description = "OpenSea is the world's first and largest web3 marketplace for NFTs and crypto collectibles. Browse, create, buy, sell, and auction NFTs using OpenSea today.";
finalMetadata.image.url = "https://static.opensea.io/og-images/Metadata-Image.png";
} else if (url.startsWith("https://dune.com") && (finalMetadata.title.startsWith("Attention Required") || finalMetadata.title.startsWith("Just a moment"))) {
finalMetadata.title = "Dune";
finalMetadata.description = "Blockchain ecosystem analytics by and for the community. Explore and share data from Ethereum, Polygon, Arbitrum, Optimism, and others for free.";
finalMetadata.image.url = "https://dune.com/assets/poster-1440w.png";
} else if (finalMetadata.title.startsWith("Just a moment...")) {
return response.status(500).json({
error: "Data not fetched yet."
});
}
}

return response.status(200).json({
data: finalMetadata
});

} catch (error) {
console.error('Error fetching link preview metadata:', error);

return response.status(500).json({
error: error
});
}

};
2 changes: 2 additions & 0 deletions components/chat/ChatPost.vue
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,8 @@ export default {
if (this.$config.linkPreviews === "netlify") {
fetcherService = thisAppUrl + "/.netlify/functions/linkPreviews?url=" + this.firstLink;
} else if (this.$config.linkPreviews === "vercel") {
fetcherService = thisAppUrl + "/api/linkPreviews?url=" + this.firstLink;
} else if (this.$config.linkPreviews === "microlink") {
fetcherService = "https://api.microlink.io/?url=" + this.firstLink;
}
Expand Down
3 changes: 1 addition & 2 deletions components/storage/FileUploadInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ export default {
if (this.$config.fileUploadTokenService === "netlify") {
fetcherService = thisAppUrl + "/.netlify/functions/imageUploader";
} else if (this.$config.fileUploadTokenService === "vercel") {
// TODO: add vercel function URL
//fetcherService = "https://vercel...";
fetcherService = thisAppUrl + "/api/imageUploader";
}
if (fetcherService) {
Expand Down
4 changes: 2 additions & 2 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export default defineNuxtConfig({
favicon: "/img/favicon.svg",
fileUploadEnabled: true, // enable/disable file uploads (enable only if external file storage is used, e.g. IPFS via Spheron)
fileUploadSizeLimit: 1 * 1024 * 1024, // max file upload size in bytes (1 * 1024 * 1024 = 1 MB)
fileUploadTokenService: "netlify", // "netlify" or "vercel" (or leave empty for no file uploads)
fileUploadTokenService: process.env.FILE_UPLOAD_SERVICE || "netlify", // "netlify" or "vercel" (or leave empty for no file uploads)
getPostsLimit: 30, // number of posts to fetch from Orbis in the getPosts() function
governanceUrl: "https://snapshot.org/#/sgbchat.eth", // governance url (snapshot, Tally, etc.)
iggyPostAddress: "0x63FE8216a66737CFE474DF3949F9081EbD4Bd800",
Expand All @@ -73,7 +73,7 @@ export default defineNuxtConfig({
keysAddress: "0x34E7D66455BE3f6f0cCbF3df3b7c56b482530C8E", // FriendKeys contract address
keysContext: "kjzl6cwe1jw14akr2rh1j3fhup1ewfr2uyyd6l85qllbe2d5fxywt7d8rqnau6j",
keysFeatured: ["tempe", "tekr"],
linkPreviews: "netlify", // "netlify" or "microlink" (or leave empty for no link previews)
linkPreviews: process.env.LINK_PREVIEW_SERVICE || "netlify", // "netlify", "vercel", or "microlink" (or leave empty for no link previews)
lpTokenAddress: "0xF874f79eBfB8FEe898a289C4cAa5dc4383873431", // liquidity pool token (token to stake in the staking contract)
lpTokenSymbol: "LP tokens", // LP token symbol
marketplacePostNftUrl: "https://testnets.opensea.io/assets/mumbai/0x63FE8216a66737CFE474DF3949F9081EbD4Bd800",
Expand Down
6 changes: 6 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"buildCommand": "npm run generate",
"devCommand": "npm run dev",
"installCommand": "npm install",
"outputDirectory": "dist"
}

0 comments on commit 17ec6c3

Please sign in to comment.