diff --git a/404.html b/404.html new file mode 100644 index 00000000..c56830c3 --- /dev/null +++ b/404.html @@ -0,0 +1,33 @@ + + +
+ + + + + +In this section, you will learn everything you need to know before you start building on Web3 with Apillon.
The main topics you can explore are:
Apillon is a Web3 development platform for developers and businesses building on Web3. By gathering unified API endpoints, it delivers the functionalities of Polkadot parachains adapted to the standard development process and user-preferred technology stack.
It gathers a unique set of tools, ample SDKs, and comprehensive documentation to fully support users in building their Web3 products from day one.
With Apillon, developers can create a complex and fully-functional Web3-based product in just days, harnessing the services provided by different parachains but without the need to employ them individually and from scratch or to spend years mastering the technical knowledge.
This way, they can focus more on the functionalities of their Web3 product than the underlying blockchain complexity and drastically shorten its go-to-market timeline.
The dawn of open-source and decentralized technologies has inspired the creation of systems that give individuals more power to exchange assets and open up new business opportunities while reducing their reliance on centralized authorities. However, even though the pace of technological progress has been outstanding, the adoption of decentralized solutions still awaits implementation in the real economy on a large scale.
Polkadot, one of the leading players in the Web3 ecosystem, is set to transform the way businesses, individuals, and organizations manage assets and data. Still, several factors hinder the broader adoption of Web3 solutions:
Apillon's unified points of access deliver the functionalities of Polkadot parachains to developers simply through APIs, so they can create a working Web3-based product from day one while mitigating or avoiding the issues above.
While each parachain is best at solving its own isolated case, Apillon is all about connecting and curating different parachains, protocols, or pallets into the right context that can be easily adopted by developers to build tangible products in Web3.
Simplification further applies to pricing, as the platform takes care of all the underlying payment requirements with a unified payment system. Payment plans in DOT or fiat (EUR, USD) deliver price stability and predictability, ideal for enterprises and frequent users.
Building with Apillon does not require prior knowledge of blockchain technology and surpasses the hassle of lengthy testing and auditing. A streamlined product development substantially reduces the go-to-market timeline and resources spent in the process.
Apillon brings the power of distributed technologies to web developers and opens the floodgate to their widespread adoption. It democratizes the usability of advanced technologies and helps Web3 services reach wider and deeper.
Unpredictable pricing of Web3 services hinders adoption as users cannot foresee the costs generated in the process of using them. The Apillon platform delivers various Web3 services at stable pricing and allows users to devote more time and energy to developing new products.
The Web3 space delivers outstanding possibilities for building advanced decentralized products. However, the projects providing Web3 services have mostly focused on perfecting the technology offering and less on how end-users interact with it and adopt it.
One of the main challenges users need to overcome in Web3 services adoption is token/asset acquisition and management. This could seem like a minor issue when using a single service but could grow into an overwhelming toil when utilizing multiple at once.
"Apillon is a Web3 development platform that gathers and delivers complex blockchain solutions and protocols through a simplified and unified API endpoint, allowing developers to build Web3 projects quickly, effectively and with predictable pricing." Apillon Tokenomics Whitepaper
To deliver as smooth a user experience as possible, the Apillon platform performs automatic payments of underlying services in their native tokens and enables users to pay for all in a single transaction.
Each successful startup goes through typical development phases. First, after the initial idea, they build a prototype and MVP to create traction. Once they perfect their offering in the product-market fit phase, they work towards boosting growth in the scaling phase.
In supporting Web3 builders through their growth process, Apillon delivers a full-stack solution that allows both startups and established companies to develop and scale their products using Web3 building services.
Too often, as they work on perfecting the product-market fit, initial-stage businesses are not focused much on the costs that come with using different services. However, in the following phase, scaling the business model becomes a much more pragmatic issue, as it requires a lot of mid- to long-term planning and continuous cost optimization.
And this can only be achieved by utilizing services with reliable, predictable pricing models.
In the Web3 world, the pricing of most protocols, parachains, and services is typically based around a volatile token. This is directly correlated with project tokenomics, as they aim to boost token value with different token utilities, some more successfully, some less. Moreover, token valuation is heavily subject to market sentiment and community backing.
Charging for Web3 services in volatile tokens leads to unpredictable pricing models, which prevents their users from scaling successfully and reining their spending within rational range.
The unpredictability of service pricing is a huge issue in the current stage of the Web3 space, regardless of (or because of) ever-changing market sentiment. With the implementation of stable service pricing, Apillon provides the platform users with tools to build stellar Web3 products while allowing them to forecast their financial statements and cash flows for stable growth.
Paying for services with a highly volatile asset is both risky and cumbersome. It is mainly because, in Web3, highly volatile assets represent more an investment vehicle than a value transfer instrument.
The Apillon platform is designed to accept payments in either fiat money, stablecoins, or even volatile assets. As it cannot impact the utility of supported parachains' native tokens, the platform sustains a pricing model that resists their volatility and provides users with stable monthly pricing. This way, they can adequately plan the resources spent on Web3 projects.
While Apillon’s pricing model can buffer normal average asset volatility of supported services, it is not designed to withstand cases of dramatic or black swan events on the market.
The Apillon platform and its pricing is built using the following approaches:
The Apillon MVP supports a freemium model to bring the above points into equilibrium. With stably priced services and unified payment, it further helps Apillon's business model to stand the test of the crypto market.
Apillon abstracts the technological complexity behind the Polkadot network and its parachains into a suite of development tools empowering developers to upgrade to Web3 easily.
The platform gathers and delivers Web3 functionalities powered by Polkadot parachains to developers through straightforward API access, and provides support with ample SDKs and complete documentation for each service.
Apillon's adaptability and interoperability allow builders to seamlessly merge use cases into single products offering different distributed services, serving their audiences more comprehensively than they could with specialized products.
Thanks to easy integration into any development framework, the Apillon APIs introduce a new way of Web3 development that significantly simplifies the go-to-market product evolution.
Initially, the Apillon platform will incorporate APIs to the following Polkadot parachains:
In the future, more APIs will be added as new parachains earn their slot on Polkadot, and new Web3 services and features are released on the network.
Easing the integration of the Apillon platform and its APIs, ample SDKs enable faster and more streamlined utilization of Polkadot/Kusama parachains from the first click onwards.
Guiding developers’ way through the individual modules and dapp development process, Apillon documentation helps avoid bugs, mitigate operational issues, and create working products with a lower risk of error and less need for auditing.
With a real-time overview of back-end performance, developers gain valuable insights into the functioning of their Web3 applications and attached services, allowing them to improve on lagging features or tweak the product for better performance.
To help advance the adoption of Web3 products, Apillon's Analytics delivers clear insight into UI and transaction data, allowing developers to understand how their products are used, their best-performing features, and areas that need improvement.
When building on Web3, be it within the Polkadot ecosystem or in general, developers face challenges that still lack proper addressing.
With these obstacles in mind, the process of building a Web3 product from scratch soon becomes a complex, time-consuming, and potentially even risky business.
To overcome them, developers would need to:
Using Apillon, on the other hand, the process of developing a Web3 product is radically different.
Example #1: Building on KILT Protocol*
To build a simple Web3 app utilizing KILT Protocol for user authentication from scratch, a developer needs to do (at least) the following:
Using the Apillon platform, on the other hand, a developer simply calls a function (e. g., createUserWithEmailAndPassword
) from the Apillon SDK and sends the required parameters. The function creates a fully working user DID in the back end.
Example #2: Building on Crust*
To build a simple Web3 app utilizing Crust for file storage from scratch, a developer needs to do (at least) the following:
Using the Apillon platform, on the other hand, a developer simply calls the getStorage()
SDK function and moves the files to a decentralized, pinned service provided by Crust and IPFS.
In both cases, the resources spent on building a functional Web3 application with Apillon are significantly reduced, and the product’s go-to-market trajectory much shorter and streamlined.
*Disclaimer: These examples are technically highly simplified to illustrate the problematic context of building a Web3 product to the general public, whereas in technical reality, the process is much more complex. Examples used do not intend to imply in any way that either KILT or Crust are challenging to use but merely to show that these processes require serious work and introduce friction in cases where developers utilize several parachains to build a single solution.
Polkadot is a “blockchain of blockchains,” allowing many different types of chains to work and interact securely together within the same ecosystem. The network has already contributed great promise and significant progress by encouraging individual sovereignty over personal and business data. And more importantly, the integration of diverse parachains into a scalable and flexible network set a new standard for Web3 builders.
Bitcoin - the very first application of blockchain. Soon, the potential to create other decentralized applications grew big. Through the need for improved tools and technological basis, the next-gen blockchain upgrade sprouted in the form of the Ethereum network. A smart-contract-based technology made it possible to exchange value besides just the currency and gave way for developers to build and deploy dapps on top of Ethereum.
Ethereum - using the one-network-serves-all model resulted in limitations like flexibility, scalability, and sovereignty. While building dapps on Ethereum proved beneficial for many industry verticals and demonstrated innovations increase, the mass-scale adoption still fell behind because of the rigid network system and limited scalability of transactions.
The Polkadot network is becoming the forefront of a scalable Web3 universe-building and mass adoption of blockchain – by connecting different blockchains into one unified network. Unlike layer-1 blockchains, layer 0 of Polkadot allows for multiple layer-1 blockchains to be built on top of it. The Polkadot team even created a framework called Substrate, where developers can build blockchains that work independently from one another.
Polkadot’s layer 0, or the so-called relay chain, executes minimal basic actions in terms of network security and makes the communication between chains possible. The blockchains as parachains design their own governance structures, fine-tune their functionalities, and (usually) serve a specific use case purpose.
It’s a win-win situation:
Parachains have more flexibility in building the architecture and therefore contribute better, more specialized services with improved efficiency. Polkadot as an ecosystem offers higher scalability by processing transactions on different chains in parallel and gives way for more innovation due to more specialized parachains.
Polkadot is currently the leading, highest value, and most secure proof-of-stake platform. Nevertheless, every technology’s success can benefit from a reliable support system that can enhance its adoption and bring it to the masses. Each innovation is only as strong as its community of users.
Web3 developers still face considerable challenges when building on Web3. Polkadot offers an excellent foundation, but there’s still enormous amounts of time that need to be invested in the research and development by the builders.
By making Web3 easier to build on, the Apillon platform will assist in the adoption of use-case-specific Polkadot parachains and bring the utility of Web3 to enterprises and end-users that would benefit from (at least partially) blockchain-based processes.
Web3 is a next-generation, decentralized, and democratic version of the web where the way users control and exchange their data is redefined to empower them to partake in the building of the web, take ownership of their data and identity, as well as co-govern the processes. Web3 is built upon an infrastructure that incorporates blockchain technology and decentralized means of data and asset exchange.
Smart contracts are digital automatic agreements that are stored on a blockchain. Secure and trustless programs that execute functions when pre-determined terms and conditions are met, smart contracts deliver transparency, accuracy, and efficiency. At a basic level, smart contracts follow "if/when… then" statements that are written into code.
In a decentralized network, there is no single central authority that controls all data and governs the processes of data and asset exchange. Instead, a decentralized network is controlled by the pre-determined logic that’s written into code on the blockchain. As the code is stored on a decentralized network of nodes around the globe, this delivers an infrastructure that enables peer-to-peer data and asset exchange, which can allow users to regain control over their data and identity.
Nodes create, receive, and communicate information that they then store or relay to other nodes. The definition of a node is directly tied to the type of network it participates in – in a blockchain network, blockchain nodes are devices, usually computers, that run the blockchain’s software to validate and broadcast transactions as well as secure the network. Blockchain nodes communicate with each other, and the more nodes there are, the more decentralized the blockchain network is.
A decentralized application (dapp) is built upon a decentralized system for executing its operations. Its backend code runs on a decentralized network, usually a blockchain, instead of a centralized server. This means the operations are inherently immutable, irreversible, and sealed on the decentralized network. The app’s data and files, for example, can be hosted and stored on a decentralized network of nodes – once deployed, the files can’t be taken down or tampered with.
The word ‘trustless’ describes the online exchange of data and assets in Web3 that puts trust into the logic of the code in the backend instead of a single central authority. The core infrastructure of Web3 is controlled by the code in the backend, which eliminates the need to trust third-party service providers or big tech to manage the exchange of data and assets between the users.
Contrary to files, websites, or apps that are stored and hosted on central servers with a single point of access and failure, decentralized or Web3-based assets, websites, or apps can be stored and hosted on a global decentralized network of nodes. This defies single censorship, tampering, or single-point attacks, making them unstoppable.
Parity Technologies is a leading blockchain infrastructure company. Founded by Gavin Wood, Parity Technologies has been building the foundation of Web3 by designing Polkadot and the Substrate blockchain development framework.
Polkadot Network is one of the key actors in Web3. As a sharded blockchain, Polkadot Network enables blockchains with different use cases to securely connect into a unified network and operate seamlessly together at scale. This enables apps and services that are built on Polkadot to securely communicate and form the basis for an interoperable decentralized web.
Polkadot is a sharded blockchain. Connecting several blockchains into a unified network, the Polkadot Network allows the separate chains to securely process transactions and exchange data at the same time. Each chain can be optimized for a specific use case while still being able to communicate with the other chains in the network. This unique model is called Polkadot’s heterogeneous sharding model.
The relay chain is Polkadot’s main chain that executes minimal basic actions to ensure network security. It also enables communications between (para)chains.
Parachains are different Polkadot blockchains that connect to the main relay chain. With their own governance structures and different functionalities, parachains serve a specific use case, yet they are able to communicate with each other. The ability of Polkadot’s ecosystem to process transactions on different chains in parallel delivers high scalability.
Founded by Gavin Wood, Web3 Foundation offers support and funds research for technologies and applications in the area of decentralized web software protocols.
Substrate is an open-source and future-proof blockchain framework developed by Parity Technologies. It helps developers build blockchains that can work independently from one another while connecting to the main relay chain. Substrate was designed to power the Polkadot Network and a multi-chain, decentralized web.
Phala Network is a Polkadot parachain that provides decentralized computing power and back-end hosting for complex applications while protecting confidentiality and data privacy.
Crust Network is a multi-purpose Polkadot parachain that delivers decentralized storage for massive amounts of data while prioritizing data privacy and user data ownership.
KILT Protocol is a blockchain protocol and Polkadot parachain that provides decentralized digital authentication with self-sovereign, verifiable, revocable, and anonymous credentials.
Web3 project is a website, program, or app that’s built using decentralized technologies. Even standard Web2 projects can be upgraded to the Web3-level by making small changes and incorporating blockchain technology. The Apillon platform makes building Web3 projects simpler and faster.
Web3 services are features that are powered by blockchain technology instead of a centralized service provider. The Apillon platform delivers essential Web3 services for building websites, applications, and projects through simple API calls.
Web3 Authentication is a Web3 service that enables decentralized verification of unique sets of data, identities, and assets. The Apillon platform offers Web3 authentication services powered by KILT Protocol, which delivers secure identity solutions and credentials for enterprises and consumers.
Web3 Storage is a Web3 service that connects to a decentralized network of computer nodes to store the files of a website or app, increasing accessibility and eliminating a single point of access. As the files get stored on a decentralized network of nodes, they become unstoppable. The Apillon platform delivers Web3 Storage service powered by Crust Network.
Web3 Hosting is a Web3 service that connects to a decentralized network of computer nodes to host a website or app, increasing its accessibility and eliminating a single point of access. As the website or app gets hosted on a decentralized network of nodes, it becomes unstoppable. The Apillon platform delivers Web3 Hosting service powered by Crust Network.
Web3 Computing is a Web3 service that offers decentralized cloud computing power by connecting to a peer-to-peer network of computer nodes. This provides privacy, security, and data confidentiality. The Apillon platform delivers Web3 Computing service, powered by Phala Network.
Unified service pricing is a reliable business model that enables the user to predict the cost of services and pay for multiple services in a single transaction. The Apillon platform delivers various Web3 services at stable monthly pricing with DOT and fiat that allows users to devote more time to developing new products as they don’t have to deal with the typically unstable pricing of Web3 services. Read more >
A freemium business model offers basic services free of charge, while a premium is charged for the more advanced services and features. Currently, all features available on the Apillon platform are free of charge. In the later stages, the basic Web3 services will remain free, while the more advanced features will be available through unified stable pricing.
Certain tokens can be staked by locking them up for a period of time for various reasons, e.g. to support the operation of a Web3 project or network, in exchange for a reward, typically an interest on the staked amount.
Launched on January 26, 2023, the first invitation-only release of the Apillon platform provides Web3 Hosting and Storage services. The main purpose of the Apillon Closed Beta is to test and uncover potential bugs. Read more >
Apillon launched a referral program that will reward existing users for bringing more attention to the Apillon platform among their communities and peers, thus facilitating broad Web3 adoption.
Apillon Lightpaper states the challenges developers face when building Web3 projects and how the Apillon platform can help solve them.
Become part of the Apillon community and stay up to date with the latest news.
On June 19, on the encouragement of the key ecosystem stakeholders, Apillon submitted an OpenGov discussion to back upcoming proposal for Polkadot Treasury funding.
Backed by Polkadot Treasury funding and community support, the Apillon platform would transition to an open-source product with permanent freemium access and community governance. By becoming a common good project, Apillon would help spur Web3 adoption, Polkadot ecosystem growth, and DOT utility.
Here are the most frequent questions and answers to help you navigate and understand the weight of the proposal.
Polkadot’s common good and open-source approach aims to innovate services that benefit projects and users across the whole ecosystem.
With many new protocol-layer projects regularly developed on Polkadot, the ecosystem is in dire need of an application-layer solution that would allow developers to easily onboard the Polkadot ecosystem and bring Web3 to a mainstream level.
With Apillon transforming into a common good solution, the Polkadot ecosystem would get a forever-freemium Web3 development platform. Every new user on the Apillon platform would mean a new developer for Polkadot, boosting the adoption of Web3 technologies. Through DOT-based governance, the Polkadot’s native token would get another utility boost and purpose in driving the network’s adoption.
With decentralized governance, existing and new platform users would get to decide on parachain integrations and the evolution of the Apillon platform, thus collaboratively innovating the future of Web3.
Apillon would make a strong commitment to the community and the ecosystem to achieve the set milestones, spend resources as described in the Proposal, and pursue the vision of the developer community.
Apillon’s Proposal for Polkadot’s Treasury funding seeks community support to transform into an open-source infrastructure on Polkadot.
The funding would have the following direct consequences on Apillon:
With operational costs covered by the Treasury for two years, Apillon would be able to incentivize developers with freemium plans at no additional fees.
After the end of the two-year period, Apillon would introduce a price margin on top of parachain service cost. However, this would be non-profitable and controlled via governance, allowing the Apillon team to survive on fees to keep the project alive and in the best possible shape.
Apillon’s Treasury-backed transition to open-source presents a strong obligation towards the community. Therefore, The Freemium plan will remain permanently or until the project’s governance decides otherwise.
In the current stage, three main pillars of Apillon would require implementation of decentralized control:
With DOT-based governance, the developer community would be able to co-decide the development direction of the Apillon platform, making it more agile in addressing market demands.
Apillon’s product governance would address questions such as:
The Apillon platform would further improve the Polkadot ecosystem and the Web3 space with:
Easier, faster, and cheaper Web3 development would bring developers and other stakeholders:
Apillon's contribution to Web3 adoption and the growth of the Polkadot ecosystem is significant and lies in its provision of an open-source common good development platform. A user-friendly and accessible environment for building Web3 applications would attract more developers, including those transitioning from Web2 to Web3. The influx of talent and ideas would fuel the creation of diverse and innovative decentralized applications built on the Polkadot network, leading to increased usage, adoption, and overall ecosystem growth. Additionally, by providing a streamlined development experience and facilitating the integration of various parachains, Apillon's platform contributes to the scalability and interoperability of the network, making it more appealing to developers and users alike.
The backing of Polkadot Treasury funding would tremendously impact the Apillon platform. It would provide financial support and resources to develop further and enhance the platform's capabilities, enabling Apillon to accelerate its efforts in building a robust Web3 infrastructure. The funding support would help Apillon attract top talent, foster innovation, and execute its roadmap effectively, ultimately contributing to the growth and adoption of Web3 technologies within the Polkadot ecosystem.
The opportunity for Apillon to become an open-source common good infrastructure platform on Polkadot opens up opportunities for early contributors, too.
Polkadot Treasury funding of the Apillon two-and-a-half-year development ensures uninterrupted work on both preset and jointly agreed upon milestones to deliver the most requested and needed Web3 services and features to the developer community.
With every developer using the Apillon platform, the Polkadot and Web3 ecosystems gain a new contributor. Faster growth of Apillon means accelerated expansion and collaboration of both established and up-and-coming Web3 projects.
In addition to the financial aspect, Polkadot Treasury would provide a much-appreciated approval from the wider Web3 community, acknowledging Apillon as the go-to Web3 development platform - that would significantly increase the future value of the project.
Apillon has always greatly appreciated the community support and trust in the project.
At this early point of the referendum process, the benefits for early investors are still undefined. The Apillon team kindly asks for everyone’s patience while the optimal options for the community are being explored.
One of Proposal’s main points is Apillon transitioning to DOT-based governance and operations. Hence, the launch of the NCTR token is postponed until after the end of the period set in the Proposal.
The official discussion on the Apillon Proposal will be taking place on Polkassembly. You can engage with the broader Web3 and Polkadot community on the Polkadot Forum as well.
The public discussion will be open for a month before the voting process begins on July 17, 2023, lasting 28 days. Follow our social media channels and stay updated on the latest developments.
If you are a DOT holder, you will be able to vote with your Polkadot.js wallet, Talisman, or Subwallet on Polkassembly once the proposal moves into the voting period.
If you’re not sure how to navigate the voting process, stay tuned for detailed voting tutorials.
Do you care about boosting Web3 adoption? Providing access to easier, cheaper, and faster Web3 development for all developers? Expanding the possibilities for the growth of Polkadot’s ecosystem?
If you do, you should vote Aye on the Apillon’s Proposal.
If you have second thoughts, please share them with our team on Polkassembly right below the post or on Polkadot Forum. We’ll be happy to answer all your questions.
The Proposal suggests a timeline for Polkadot Treasury funding that spans three milestone periods and ends in Q3 2025.
If the Polkadot community ends up voting Nay on Apillon receiving Treasury funding, the work for the team will not cease.
Aligned with the preset milestones and following the dynamic backlog of integrations, the team will continue working towards developing and delivering state-of-the art features and services to drive Web3 adoption for every developer.
Discover more answers to community questions and join the discussion on Polkassembly.
The NCTR token (pronounced “nectar”) is Apillon’s native utility token and sustains Apillon functionalities when interacting with linked Polkadot parachains and transacting with their protocols.
It represents a uniform means of value exchange in the process of building Web3 projects on the Apillon platform, as it replaces the need to interact with individual tokens of utilized parachains.
For every value-based action on Apillon, the platform manages the utility of parachains’ features in their native tokens in the back end so that developers only deal with NCTR and do not have to worry about acquiring or exchanging other tokens.
The Apillon business model also supports payments in fiat (EUR and USD), further boosting adoption among first-time adopters of Web3. The platform converts it to NCTR to unlock Apillon functionalities.
The tokenomics of the NCTR token and Apillon’s business model rely on decision-making by two main actors:
The NCTR tokenomics are, therefore, built to incentivize both actors and ensure all NCTR holders have a relevant say in the platform’s future and get rewarded for participating in Apillon’s governance.
Developers are the force that drives Web3 and the first group of participants in the Apillon tokenomics. The platform is designed to cater to their ever-evolving needs, respond to their expectations, challenges, and workflows, but also to empower them to voice feedback and impact the course of platform development through governance.
In the vast and ever-evolving field of blockchain technology, it is increasingly challenging for all stakeholders to track all the newly launched projects and evaluate their offerings. To double down on the Web3 research power, Apillon empowers its main users, the developers, to list new service candidates via governance and vote on preferred services to be implemented in the upcoming platform upgrades. Through user-powered governance and a token-curated registry of services, the platform continues to evolve and optimize its offering while preventing any potential censorship.
No Web3 project can stand the test of time and market without community backing. The Apillon community gathers NCTR token holders and Web3 developers. The NCTR token is designed to serve and reward everyone who contributes to the growth of the Apillon platform and boosts Web3 adoption, aligned with Apillon’s primary mission. All NCTR token holders can be Web3 builders, either by developing functional Web3 products or growing the ecosystem, and thus have the right to contribute to the NCTR token pledging and Apillon’s inclusive governance.
The NCTR token is designed to be a multi-purpose and widely used asset, covering a range of utility cases for platform users and community members. NCTR token utilities are spanning across three main pillars:
Each pillar further serves both NCTR Developers and NCTR Holders, offering distinct opportunities for utilizing the NCTR token.
Apillon's product governance does not imply an establishment of Apillon as an end-to-end DAO where participants propose and vote on everything, business decisions included. Instead, the governance aspect is focused on the product, i.e., the Apillon platform, and its narrow scope of user-oriented services and features that participants can help control and upgrade.
The second NCTR token’s utility is aimed at incentivizing both tokenomics actors in various ways while promoting Web3 adoption. Adoption is, therefore, the main measured KPI, and when achieved, NCTR tokens are awarded NCTR to rightful recipients.
Incentivization through NCTR spans several use cases, including proof of adoption (PoA), prebuilt solutions grants, prebuilt solutions marketplace, SDK grands, protocol integration grants, bug bounties, authorship royalties, referral earnings, and many more.
Besides providing few-click-deploy Web3 services and straightforward APIs to integrated parachains, Apillon offers an underlying payments module that simplifies the use of Web3 technologies. The payments module removes the need for developers to acquire and maintain a positive balance of tokens to pay for underlying services. This way, Apillon can charge for its services in a traditional Saas model, where users pay monthly subscriptions with fiat using credit cards and unlock access to a fixed amount of Web3 services and features. The secondary path to pay for Apillon services is through the NCTR token. The NCTR token's governance and incentivization utilities of the NCTR token deliver a fantastic opportunity for synergy between NCTR payments and product governance.
The NCTR token is an ERC-20-compatible token minted on the Astar network.
Total supply: 150,000,000 NCTR
Learn more about the NCTR token, its role in the Apillon business model, and general tokenomics.
The list of endpoints where API is available:
Environment | URL |
---|---|
Production | https://api.apillon.io |
Testing | Coming soon... |
Apillon API is a set of RESTful API endpoints allowing developers to integrate Apillon modules into their Web3 applications.
Unless clearly marked as public, all routes are private and require an API key.
Every request goes through authentication middleware, where the following errors can occur:
Status | Message | Description |
---|---|---|
400 | Missing Authorization header | Request is missing authorization header. |
400 | Malformed Authorization header | Authorization header field has an invalid form. |
401 | Invalid API key or API key secret | Authorization header is valid, but credentials in it are not. |
Each endpoint requires a certain role or permission from the API key.
There are three types of permissions that could be assigned to an API key:
Code | Name | Description |
---|---|---|
50 | KEY_EXECUTE | Permission to execute certain actions |
51 | KEY_WRITE | Permission to create, modify or delete records |
52 | KEY_READ | Permission to read record |
These permissions could be assigned to an API key for every attached service (e.g., Web3 Storage (Crust), Web3 Authentication (KILT), etc.).
If a request is made with an API key that lacks permission for a called endpoint, the following errors can occur:
Status | Message | Description |
---|---|---|
403 | Insufficient permissions - missing permission name permission | API key lacks required permission for called service. |
403 | Insufficient permissions to access this record | API key has required permissions for endpoint, but it does not have the right to access the addressed record (i.e., a record belongs to a different project). |
Endpoints starting with "List" are intended to list different data, where the response contains the below properties.
Name | Description |
---|---|
items | Records on a specified page that match the current query |
total | Number of all records that match the query |
limit | Number of items on a page (default: 20). |
page | Current page |
Listing endpoints by default supports the query parameters below:
Name | Description | Required |
---|---|---|
search | Search the items usually by name or some other property specifying this item. | false |
page | Items are paginated by default. This parameter is used to get items from a specific page. | false |
limit | Number of items on a page (default: 20). | false |
orderBy | One or multiple properties, separated by a comma, used to order data. | false |
desc | Boolean values, mapped to the index of the orderBy parameter. Defaults to false. | false |
status | Integer values, to filter by the entity's status (each entity has corresponding status codes) | false |
Every response has a unique ID, which helps identify potential issues. It also includes a status code that can help identify the cause of a potential problem.
Query requests through the GET
method can return status codes 200
, 400
, 401
, 403
, or 500
. Mutations through POST
, PUT
, and DELETE
can also return codes 201
and 422
. Invalid routes return status code 404
.
A successful request includes a data
key, which holds a valid response object.
List of responses:
A request fails if response code is not 200 or 201. The Apillon API returns two types of errors.
Errors include a unique code number, a property that caused the error, and an error message. The code number helps identify potential issues and points to their exact position in the system.
Fields in code exception:
',7),j={class:"split_content"},C=n('Field | Description |
---|---|
id | Unique ID of request |
code | Apillon API internal error code pointing to the exact position in the system |
message | Message describing the error |
path | Endpoint that threw the error |
timestamp | Date when the error occurred |
Fields in validation exception:
Field | Description |
---|---|
id | Unique ID of request |
model | Apillon API model used to validate request payload |
errors | Array of errors |
path | Endpoint that threw the error |
timestamp | Date when the error occurred |
Through the whole Apillon API, the same errors can occur. The reason behind it can be current subscription package limits or current credit balance.
One of the limits based on the project subscription package is available storage space (on the IPFS node). If a project reaches the storage space limit, the following error will occur.
{
+ ...
+ "code": 40006003,
+ "message": "NOT_ENOUGH_STORAGE_SPACE",
+ ...
+}
+
Some nonrecurrent actions require payment with credits. If a project's credit balance is lower than price of executed action, API will return status 402 and the following response.
{
+ ...
+ "code": 40210000,
+ "message": "CREDIT_BALANCE_TOO_LOW",
+ ...
+}
+
Api key is created inside a project and can be used to get project details through Apillon API.
`,14),U={class:"split_content"},G=n('API to get project credit balance
Name | Type | Description |
---|---|---|
balance | number | Current credit balance - amount of credits in project, that can be used to perform different actions |
This package provides Dart and Flutter developers with tools and libraries to interact with Apillon services, simplifying the use of Apillon's REST API by reducing boilerplate code and streamlining multi-step processes into single operations.
dependencies:
+ apillon_flutter: ^0.0.1
+
To start using the SDK, you need to import it and configure it with your Apillon API key and secret. Here's an example of how to initialize the Storage module:
import 'package:apillon_flutter/apillon_flutter.dart';
+
+void main() {
+ var storage = Storage(ApillonConfig(
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ ));
+}
+
All modules in the Apillon Flutter SDK require the same initial configuration of key
and secret
.
The Apillon Flutter SDK consists of several modules, each corresponding to a specific Apillon service. Below are examples of how to use some of these modules.
The Storage module provides functionalities for interacting with the Storage service.
import 'dart:io';
+import 'package:apillon_flutter/apillon_flutter.dart';
+import 'package:path/path.dart' as path;
+
+void main() async {
+ var storage = Storage(ApillonConfig(
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ ));
+
+ // List all buckets
+ var buckets = await storage.listBuckets(IApillonPagination());
+ print('Buckets:');
+ for (var bucket in buckets) {
+ print('\${bucket.name} - \${bucket.uuid}');
+ }
+
+ var bucketUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616';
+
+ // Get specific bucket details
+ var bucketDetails = await storage.bucket(bucketUuid).get();
+ print('Bucket Details: \${bucketDetails.name}, Size: \${bucketDetails.size}');
+
+ // List files in the bucket
+ var files = await storage.bucket(bucketUuid).listFiles(IBucketFilesRequest());
+ print('Files in bucket:');
+ for (var file in files) {
+ print('\${file.name} - \${file.uuid}');
+ }
+
+ // Upload files from a folder
+ var uploadDir = path.join(Directory.current.path, 'my-folder');
+ print('Uploading files from $uploadDir');
+ await storage.bucket(bucketUuid).uploadFromFolder(uploadDir, IFileUploadRequest());
+
+ // Upload a single file from buffer
+ var filePath = path.join(Directory.current.path, 'file.txt');
+ var fileBytes = File(filePath).readAsBytesSync();
+ await storage.bucket(bucketUuid).uploadFiles([
+ FileMetadata(
+ fileName: 'file.txt',
+ contentType: 'text/plain',
+ content: fileBytes,
+ )
+ ], IFileUploadRequest());
+
+ // Get details of a specific file
+ var fileUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616';
+ var fileDetails = await storage.bucket(bucketUuid).file(fileUuid).get();
+ print('File Details: \${fileDetails.name}, Size: \${fileDetails.size}');
+}
+
The Storage module additionally contains methods for manipulating IPNS records for a specific storage bucket.
import 'package:apillon_flutter/apillon_flutter.dart';
+
+void main() async {
+ var storage = Storage(ApillonConfig(
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ ));
+ var bucketUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616';
+
+ // List all existing IPNS records in a bucket
+ var ipnsRecords = await storage.bucket(bucketUuid).listIpnsNames(IPNSListRequest());
+ print('IPNS Records:');
+ for (var record in ipnsRecords) {
+ print('\${record.name} - \${record.uuid}');
+ }
+
+ // Create a new IPNS record
+ const name = 'Test IPNS';
+ const description = 'This is a test description';
+ const cid = 'QmUxtfFfWFguxSWUUy2FiBsGuH6Px4KYFxJqNYJRiDpemj';
+ var newIpnsRecord = await storage.bucket(bucketUuid).createIpns(ICreateIpns(
+ name: name,
+ description: description,
+ cid: cid,
+ ));
+ print('New IPNS Record: \${newIpnsRecord.uuid}');
+
+ // Publish an IPNS record to point to a new CID
+ const newCid = 'Qmakf2aN7wzt5u9H3RadGjfotu62JsDfBq8hHzGsV2LZFx';
+ await storage.bucket(bucketUuid).ipns(newIpnsRecord.uuid).publish(newCid);
+ print('IPNS record published to new CID: $newCid');
+
+ // Delete an IPNS record
+ await storage.bucket(bucketUuid).ipns(newIpnsRecord.uuid).delete();
+ print('IPNS record deleted: \${newIpnsRecord.uuid}');
+}
+
The NFT module encapsulates functionalities for the NFT service.
import 'package:apillon_flutter/apillon_flutter.dart';
+
+void main() async {
+ var nft = Nft(ApillonConfig(
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ ));
+
+ // Create a new NFT collection
+ var collection = await nft.create(ICreateCollection(
+ chain1: EvmChain.moonbase,
+ collectionType1: CollectionType.generic,
+ name: 'Space Explorers',
+ description: 'A collection of space explorers',
+ symbol: 'SE',
+ royaltiesFees: 3,
+ royaltiesAddress: '0x95B8c6b9225456107649776EF8aAF20C42d58814',
+ baseUri: 'https://test.com/metadata/',
+ baseExtension: '.json',
+ maxSupply: 50,
+ isRevokable: false,
+ isSoulbound: false,
+ drop: false,
+ ));
+ print('Collection created: \${collection.uuid}');
+ // or create a substrate collection
+ var substrateCollection = await nft.createSubstrate({
+ chain1: SubstrateChain.astar,
+ collectionType1: CollectionType.generic,
+ name: 'SpaceExplorers',
+ symbol: 'SE',
+ ...
+ });
+
+ // Mint a new NFT in the collection
+ var mintResult = await nft.collection(collection.uuid).mint(IMintNftData(
+ receivingAddress: '0x5BA8B0c24bA5307b67E619ad500a635204F73bF1',
+ quantity: 1,
+ ));
+ print('Mint transaction hash: \${mintResult.transactionHash}');
+
+ // List NFT collections
+ var collections = await nft.listCollections(ICollectionFilters());
+
+ // Transfer NFT ownership to another address
+ await collection.transferOwnership('0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD');
+}
+
The Identity module provides functionalities for validating wallet signatures and fetching identity data.
import 'package:apillon_flutter/apillon_flutter.dart';
+
+void main() async {
+ var identity = Identity(ApillonConfig(
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ ));
+
+ // Generate a signing message for EVM wallet signature validation
+ const customMessage = 'Identity EVM SDK test';
+ var signingMessage = identity.generateSigningMessage(customMessage)["message"];
+ print('Signing message: $signingMessage');
+
+ var walletAddress = '0xa79bg13g2...';
+ var signature = '0xYourSignature'; // signature obtained from the user's wallet by the client app
+
+ // Validate EVM wallet signature
+ var validationResult = await identity.validateEvmWalletSignature(IValidateEvmWalletSignature(
+ walletAddress: walletAddress,
+ message: signingMessage,
+ signature: signature,
+ ));
+ print('Is valid: \${validationResult.isValid}');
+ print('Address: \${validationResult.address}');
+
+ // Get wallet identity profile for a Polkadot address
+ var polkadotAddress = '5HqHQDGcHqS...',
+ var identityProfile = await identity.getWalletIdentity(polkadotAddress);
+ print('Identity Profile: \${identityProfile.subsocial['content']['name']}');
+}
+
Apillon's Infrastructure Service provides developers with the essential infrastructure required to build modern Web3 applications. Our infrastructure services currently include:
These services are designed to simplify Web3 development while ensuring scalability and reliability for your decentralized applications.
Dwellir is a highly reliable and scalable RPC (Remote Procedure Call) provider that powers the Apillon infrastructure, enabling developers to interact with various blockchain networks. Dwellir ensures secure, low-latency connections and high availability, allowing developers to execute smart contract functions, query blockchain data, and perform transactions seamlessly.
Core Services:
The RPC service is available with two main plants:
Free Plan (default):
Developer Plan:
SQD is a powerful Web3 data infrastructure platform that offers:
Used by major projects like PancakeSwap, Railgun, and Chainsafe, SQD processes hundreds of thousands of terabytes of blockchain data while significantly reducing infrastructure costs.
The indexing process follows a standardized workflow while allowing for flexible implementation approaches. Developers can leverage existing templates as a starting point and customize them according to their specific requirements. Before deployment, indexers can be thoroughly tested in a local environment to ensure proper functionality.
An indexer implementation consists of three core components:
To configure an indexer, developers need to specify:
The indexer processor continuously fetches new blocks from the specified starting point up to the latest block, processing the relevant data according to the configured rules and storing it in the indexer database.
The processed data becomes accessible through a GraphQL API, providing a flexible and efficient way to query the indexed blockchain data. This API supports complex queries, filtering, and data relationships, enabling developers to retrieve exactly the information they need for their applications.
Indexers are billed based on the amount of processed and stored data and the number of queries made to the indexer API. Project need to have sufficient credit balance to deploy an indexer. The deployment itself is free of charge, Apillon charges for the working indexer only. Indexers are billed daily - each day Apillon calculates price for the indexer and uses project's credit balance to pay for it.
If project's credit balance is insufficient, indexer will be hibernated and later deleted after few days if no action is taken.
Apillon's Web3 Infrastructure services provide developers with powerful tools to build and scale decentralized applications. Through SQD integration, developers can efficiently index and query blockchain data across multiple networks, while maintaining cost-effectiveness and high performance. The platform's user-friendly approach, combined with its robust technical capabilities, makes it an ideal choice for projects of any size looking to leverage blockchain data effectively.
',19);function f(b,w){const n=a("ExternalLinkIcon");return s(),l("div",null,[d,r("p",null,[e("The RPC (Remote Procedure Call) service in Apillon's infrastructure provides seamless connectivity to blockchain networks, allowing developers to interact with blockchain data and execute smart contracts. By utilizing "),r("a",h,[e("Dwellir"),t(n)]),e(" as the RPC provider, Apillon ensures reliable and efficient access to blockchain nodes. The service is designed for flexibility, enabling developers to create, manage, and optimize their own RPC endpoints through a user-friendly interface.")]),u,r("p",null,[e("The Indexing Service is a crucial component of Apillon's infrastructure, designed to efficiently index and query blockchain data. It plays a vital role in powering our Web3 services and enhancing the overall user experience. In the background, Apillon uses the "),r("a",p,[e("Subsquid"),t(n)]),e(" indexing framework and Subsquid Cloud to run indexing nodes. Developers can create their own indexers or use one of the available templates, and can query more than 150 blockchain networks.")]),g])}const v=o(c,[["render",f],["__file","10-web3-infrastructure.html.vue"]]);export{v as default}; diff --git a/assets/11-cloud-functions-api.html-5b0f7e00.js b/assets/11-cloud-functions-api.html-5b0f7e00.js new file mode 100644 index 00000000..a0ec32cd --- /dev/null +++ b/assets/11-cloud-functions-api.html-5b0f7e00.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-15e6da9c","path":"/build/11-cloud-functions-api.html","title":"Cloud Functions API","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Create Cloud Function","slug":"create-cloud-function","link":"#create-cloud-function","children":[]},{"level":2,"title":"List Cloud Functions","slug":"list-cloud-functions","link":"#list-cloud-functions","children":[]},{"level":2,"title":"Get Cloud Function","slug":"get-cloud-function","link":"#get-cloud-function","children":[]},{"level":2,"title":"Create Cloud Function Job (Deployment)","slug":"create-cloud-function-job-deployment","link":"#create-cloud-function-job-deployment","children":[]},{"level":2,"title":"Set Cloud Function Environment Variables","slug":"set-cloud-function-environment-variables","link":"#set-cloud-function-environment-variables","children":[]},{"level":2,"title":"Delete Job","slug":"delete-job","link":"#delete-job","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"build/11-cloud-functions-api.md"}');export{e as data}; diff --git a/assets/11-cloud-functions-api.html-6c203f62.js b/assets/11-cloud-functions-api.html-6c203f62.js new file mode 100644 index 00000000..c40267c0 --- /dev/null +++ b/assets/11-cloud-functions-api.html-6c203f62.js @@ -0,0 +1,117 @@ +import{_ as p,r,o as u,c as b,d as n,w as s,e,b as t,a as i}from"./app-e8b865be.js";const h={},k=t("h1",{id:"cloud-functions-api",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#cloud-functions-api","aria-hidden":"true"},"#"),e(" Cloud Functions API")],-1),m=t("p",null,"The Cloud Function API provides an interface for developers to deploy, manage, and execute decentralized cloud functions on the Apillon platform. These endpoints allow you to create cloud functions, manage jobs, and configure runtime environments.",-1),f=t("h2",{id:"create-cloud-function",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#create-cloud-function","aria-hidden":"true"},"#"),e(" Create Cloud Function")],-1),v=t("blockquote",null,[t("p",null,"Create a new cloud function to be executed on decentralized processors.")],-1),_={class:"split_content"},y=i('Field | Type | Description | Required |
---|---|---|---|
name | string | Name of the cloud function | Yes |
description | string | Description of the cloud function | No |
Code | Description |
---|---|
42200212 | Missing required fields |
42200205 | Name not valid |
42200206 | Description not valid |
50000001 | Internal server error |
Field | Type | Description |
---|---|---|
functionUuuid | string | Unique identifier of the cloud function |
projectUuid | string | UUID of the project the cloud function belongs to |
bucketUuid | string | UUID of the bucket which script files are uploaded into |
name | string | Name of the cloud function |
description | string | Description of the cloud function |
activeJobId | number | The ID of the currently active job on the cloud function |
project_uuid | string | Unique identifier of the project |
createTime | DateTime | Creation timestamp |
updateTime | DateTime | Last updated timestamp |
Field | Type | Description | Required |
---|---|---|---|
function_uuid | string | Unique identifier of the cloud function | Yes |
Field | Type | Description |
---|---|---|
functionUuuid | string | Unique identifier of the cloud function |
projectUuid | string | UUID of the project the cloud function belongs to |
bucketUuid | string | UUID of the bucket which script files are uploaded into |
name | string | Name of the cloud function |
description | string | Description of the cloud function |
activeJobId | number | The ID of the currently active job on the cloud function |
project_uuid | string | Unique identifier of the project |
gatewayUrl | string | API gateway endpoint URL of the cloud function |
createTime | DateTime | Creation timestamp |
updateTime | DateTime | Last updated timestamp |
job.scriptCId | string | IPFS CID of the script file the job is running |
job.slots | string | Number of processors running the job |
job.jobStatus | string | The current status of the job. Possible values: 1 (deploying), 2 (deployed), 3 (matched), 4 (inactive), 9 (deleted) |
Code | Description |
---|---|
40300000 | Forbidden |
40418005 | Cloud function not found |
Field | Type | Description | Required |
---|---|---|---|
function_uuid | string | Unique identifier of the cloud function | Yes |
Field | Type | Description | Required |
---|---|---|---|
name | string | Name of the job | Yes |
scriptCid | string | IPFS CID of the script to deploy | Yes |
slots | number | Number of processors to deploy to (default 1) | No |
Code | Description |
---|---|
40300000 | Forbidden |
42200212 | Missing required field |
42200213 | Invalid field data |
40418005 | Cloud function not found |
50018013 | Error creating job |
Field | Type | Description | Required |
---|---|---|---|
function_uuid | string | Unique identifier of the cloud function | Yes |
Field | Type | Description | Required |
---|---|---|---|
variables | array | Array of key-value pairs for environment variables | Yes |
Code | Description |
---|---|
42218016 | Missing or invalid variables field |
40418005 | Cloud function not found |
Field | Type | Description | Required |
---|---|---|---|
job_uuid | string | Unique identifier of the job | Yes |
Code | Description |
---|---|
40418004 | Job not found |
50018014 | Job not yet deployed |
50018016 | Error deleting job |
A Vite plugin is required for running and building Vite apps with Embedded Wallet. This plugin enables Node API in the browser (eg. buffer, crypto).
npm install -D vite-plugin-node-polyfills
+
// vite.config.ts
+import { defineConfig } from "vite";
+import { nodePolyfills } from "vite-plugin-node-polyfills";
+
+export default defineConfig({
+ plugins: [nodePolyfills() /* ... */],
+});
+
npm i -D vite-plugin-node-polyfills
+
// nuxt.config.ts
+import { nodePolyfills } from "vite-plugin-node-polyfills";
+
+export default defineNuxtConfig({
+ vite: {
+ plugins: [nodePolyfills() /* ... */],
+ },
+ build: {
+ transpile: ["@apillon/wallet-vue"],
+ },
+ /* ... */
+});
+
Field | Type | Description |
---|---|---|
name | string | The name of the network |
id | number | The unique Chain ID of the network |
rpcUrl | string | The URL to the network's RPC server |
explorerUrl | string | The URL to the network's block explorer |
To access wallet signer and wallet information we provide core imports (hooks/composables):
',3),cn=n("div",{class:"language-tsx line-numbers-mode","data-ext":"tsx"},[n("pre",{class:"language-tsx"},[n("code",null,[n("span",{class:"token keyword"},"import"),s(),n("span",{class:"token punctuation"},"{"),s(" useAccount"),n("span",{class:"token punctuation"},","),s(" useContract"),n("span",{class:"token punctuation"},","),s(" useWallet "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token keyword"},"from"),s(),n("span",{class:"token string"},'"@apillon/wallet-react"'),n("span",{class:"token punctuation"},";"),s(` + +`),n("span",{class:"token keyword"},"export"),s(),n("span",{class:"token keyword"},"default"),s(),n("span",{class:"token keyword"},"function"),s(),n("span",{class:"token function"},"Component"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" username"),n("span",{class:"token punctuation"},","),s(" address"),n("span",{class:"token punctuation"},","),s(" getBalance "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useAccount"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" wallet"),n("span",{class:"token punctuation"},","),s(" signMessage"),n("span",{class:"token punctuation"},","),s(" sendTransaction "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useWallet"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" read"),n("span",{class:"token punctuation"},","),s(" write "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useContract"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},"{"),s(` + abi`),n("span",{class:"token operator"},":"),s(),n("span",{class:"token punctuation"},"["),s(` + `),n("span",{class:"token string"},'"function claim() public"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token string"},'"function balanceOf(address) view returns (uint256)"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token string"},'"function transfer(address to, uint256 amount) public returns (bool)"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},","),s(` + address`),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"0x67b9DA16d0Adf2dF05F0564c081379479d0448f8"'),n("span",{class:"token punctuation"},","),s(` + chainId`),n("span",{class:"token operator"},":"),s(),n("span",{class:"token number"},"1287"),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token comment"},"// using wallet core SDK"),s(` + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token function-variable function"},"getWalletUserExists"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token punctuation"},"("),s("username"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token builtin"},"string"),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token operator"},"=>"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"return"),s(" wallet"),n("span",{class:"token punctuation"},"."),n("span",{class:"token function"},"userExists"),n("span",{class:"token punctuation"},"("),s("username"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + `),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token comment"},"// sign a message"),s(` + `),n("span",{class:"token keyword"},"const"),s(" onSignMessage "),n("span",{class:"token operator"},"="),s(),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token punctuation"},"("),s("msg"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token builtin"},"string"),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token operator"},"=>"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"signMessage"),n("span",{class:"token punctuation"},"("),s("msg"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + `),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token comment"},"// contract read"),s(` + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token function-variable function"},"logContractBalance"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token punctuation"},"("),s("address"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token builtin"},"string"),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token operator"},"=>"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token builtin"},"console"),n("span",{class:"token punctuation"},"."),n("span",{class:"token function"},"log"),n("span",{class:"token punctuation"},"("),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"read"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"balanceOf"'),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token punctuation"},"["),s("address"),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + `),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token comment"},"// contract write"),s(` + `),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token function-variable function"},"onContractTransfer"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token punctuation"},"("),s("address"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token builtin"},"string"),n("span",{class:"token punctuation"},","),s(" amount"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token builtin"},"string"),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token operator"},"=>"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"write"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"transfer"'),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token punctuation"},"["),s("address"),n("span",{class:"token punctuation"},","),s(" amount"),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token string"},'"Token transfer"'),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + `),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},";"),s(` + + `),n("span",{class:"token keyword"},"return"),s(),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},"<")]),n("span",{class:"token punctuation"},">")]),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},"")]),n("span",{class:"token punctuation"},">")]),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),pn=n("div",{class:"language-vue line-numbers-mode","data-ext":"vue"},[n("pre",{class:"language-vue"},[n("code",null,[n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},"<"),s("script")]),s(),n("span",{class:"token attr-name"},"lang"),n("span",{class:"token attr-value"},[n("span",{class:"token punctuation attr-equals"},"="),n("span",{class:"token punctuation"},'"'),s("ts"),n("span",{class:"token punctuation"},'"')]),s(),n("span",{class:"token attr-name"},"setup"),n("span",{class:"token punctuation"},">")]),n("span",{class:"token script"},[n("span",{class:"token language-javascript"},[s(` +`),n("span",{class:"token keyword"},"import"),s(),n("span",{class:"token punctuation"},"{"),s(" useAccount"),n("span",{class:"token punctuation"},","),s(" useContract"),n("span",{class:"token punctuation"},","),s(" useWallet "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token keyword"},"from"),s(),n("span",{class:"token string"},'"@apillon/wallet-vue"'),n("span",{class:"token punctuation"},";"),s(` + +`),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" info"),n("span",{class:"token punctuation"},","),s(" getBalance "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useAccount"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" wallet"),n("span",{class:"token punctuation"},","),s(" signMessage"),n("span",{class:"token punctuation"},","),s(" sendTransaction "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useWallet"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + +`),n("span",{class:"token keyword"},"const"),s(),n("span",{class:"token punctuation"},"{"),s(" read"),n("span",{class:"token punctuation"},","),s(" write "),n("span",{class:"token punctuation"},"}"),s(),n("span",{class:"token operator"},"="),s(),n("span",{class:"token function"},"useContract"),n("span",{class:"token punctuation"},"("),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token literal-property property"},"abi"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token punctuation"},"["),s(` + `),n("span",{class:"token string"},'"function claim() public"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token string"},'"function balanceOf(address) view returns (uint256)"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token string"},'"function transfer(address to, uint256 amount) public returns (bool)"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token literal-property property"},"address"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"0x67b9DA16d0Adf2dF05F0564c081379479d0448f8"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token literal-property property"},"chainId"),n("span",{class:"token operator"},":"),s(),n("span",{class:"token number"},"1287"),n("span",{class:"token punctuation"},","),s(` +`),n("span",{class:"token punctuation"},"}"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` + +`),n("span",{class:"token comment"},"// using wallet core SDK"),s(` +`),n("span",{class:"token keyword"},"function"),s(),n("span",{class:"token function"},"getWalletUserExists"),n("span",{class:"token punctuation"},"("),n("span",{class:"token parameter"},[n("span",{class:"token literal-property property"},"username"),n("span",{class:"token operator"},":"),s(" string")]),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"return"),s(" wallet"),n("span",{class:"token punctuation"},"."),s("value"),n("span",{class:"token punctuation"},"."),n("span",{class:"token function"},"userExists"),n("span",{class:"token punctuation"},"("),s("username"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` + +`),n("span",{class:"token comment"},"// sign a message"),s(` +`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"function"),s(),n("span",{class:"token function"},"onSignMessage"),n("span",{class:"token punctuation"},"("),n("span",{class:"token parameter"},[n("span",{class:"token literal-property property"},"msg"),n("span",{class:"token operator"},":"),s(" string")]),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"signMessage"),n("span",{class:"token punctuation"},"("),s("msg"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` + +`),n("span",{class:"token comment"},"// contract read"),s(` +`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"function"),s(),n("span",{class:"token function"},"logContractBalance"),n("span",{class:"token punctuation"},"("),n("span",{class:"token parameter"},[n("span",{class:"token literal-property property"},"address"),n("span",{class:"token operator"},":"),s(" string")]),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token punctuation"},"{"),s(` + console`),n("span",{class:"token punctuation"},"."),n("span",{class:"token function"},"log"),n("span",{class:"token punctuation"},"("),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"read"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"balanceOf"'),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token punctuation"},"["),s("address"),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` + +`),n("span",{class:"token comment"},"// contract write"),s(` +`),n("span",{class:"token keyword"},"async"),s(),n("span",{class:"token keyword"},"function"),s(),n("span",{class:"token function"},"onContractTransfer"),n("span",{class:"token punctuation"},"("),n("span",{class:"token parameter"},[n("span",{class:"token literal-property property"},"address"),n("span",{class:"token operator"},":"),s(" string"),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token literal-property property"},"amount"),n("span",{class:"token operator"},":"),s(" string")]),n("span",{class:"token punctuation"},")"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token keyword"},"await"),s(),n("span",{class:"token function"},"write"),n("span",{class:"token punctuation"},"("),n("span",{class:"token string"},'"transfer"'),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token punctuation"},"["),s("address"),n("span",{class:"token punctuation"},","),s(" amount"),n("span",{class:"token punctuation"},"]"),n("span",{class:"token punctuation"},","),s(),n("span",{class:"token string"},'"Token transfer"'),n("span",{class:"token punctuation"},")"),n("span",{class:"token punctuation"},";"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` +`)])]),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},""),s("script")]),n("span",{class:"token punctuation"},">")]),s(` + +`),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},"<"),s("template")]),n("span",{class:"token punctuation"},">")]),s(` + `),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},"<"),s("div")]),n("span",{class:"token punctuation"},">")]),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},""),s("div")]),n("span",{class:"token punctuation"},">")]),s(` +`),n("span",{class:"token tag"},[n("span",{class:"token tag"},[n("span",{class:"token punctuation"},""),s("template")]),n("span",{class:"token punctuation"},">")]),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),un=n("h3",{id:"ethers-5-and-6",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#ethers-5-and-6","aria-hidden":"true"},"#"),s(" Ethers 5 and 6")],-1),rn={href:"https://ethers.org/",target:"_blank",rel:"noopener noreferrer"},dn=l(`import { EmbeddedEthersSigner } from "@apillon/wallet-sdk";
+
You can create a signer like with any other ethers signer as such:
const signer = new EmbeddedEthersSigner();
+
+// eg. sign a message
+await signer.signMessage("test message");
+
import { EmbeddedViemAdapter } from "@apillon/wallet-sdk";
+import { moonbaseAlpha } from "viem/chains";
+
Use can use the adapter to get the user's account and use it with Viem:
const adapter = new EmbeddedViemAdapter();
+const account = adapter.getAccount();
+
+const walletClient = createWalletClient({
+ chain: moonbaseAlpha,
+ transport: http(),
+ account,
+});
+
+// eg. sign a message
+await account.signMessage({ message: "test message" });
+
+// eg. send a plain transaction
+await walletClient.sendRawTransaction({
+ serializedTransaction: await walletClient.signTransaction(
+ await walletClient.prepareTransactionRequest({
+ to: "...",
+ value: parseUnits("0.01", 18),
+ })
+ ),
+});
+
import { getProvider as getEmbeddedProvider } from "@apillon/wallet-sdk";
+
+const wagmiConfig = {
+ /* ... */
+ connectors: [
+ new InjectedConnector({
+ chains,
+ options: {
+ getProvider() {
+ return getEmbeddedProvider() as any;
+ },
+ },
+ }),
+ ],
+};
+
Embedded wallet can be used with plain TypeScript by interacting with the wallet SDK directly.
`,3),gn={class:"custom-container tip"},fn=n("p",{class:"custom-container-title"},"TIP",-1),wn={href:"https://github.com/Apillon/embedded-wallet/tree/main/packages/sdk",target:"_blank",rel:"noopener noreferrer"},_n=l(`<button id="sdk-sign">(SDK) Sign message</button>
+<button id="sdk-native-transfer">(SDK) Transfer native balance</button>
+<button id="sdk-contract-transfer">(SDK) Contract write (transfer)</button>
+
The Infrastructure API provides an interface for managing essential infrastructure services required to build modern Web3 applications.
',6),b={class:"split_content"},m=r('Create a new RPC API key for a project.
Field | Type | Description | Required |
---|---|---|---|
name | string | Name of the API key | Yes |
description | string | Description of the API key | No |
Code | Description |
---|---|
40300000 | Forbidden |
40020001 | Max RPC API keys limit reached |
40405001 | Project owner not found |
50000001 | Internal server error |
422001101 | RPC API key name is missing |
Field | Type | Description |
---|---|---|
id | number | Unique identifier of the RPC API key |
projectUuid | string | UUID of the project the RPC API key belongs to |
name | string | Name of the RPC API key |
uuid | string | Unique identifier of the RPC API key returned by Dwellir |
description | string | Description of the RPC API key |
createTime | DateTime | Creation timestamp |
updateTime | DateTime | Last updated timestamp |
Field | Type | Description | Required |
---|---|---|---|
id | number | Unique identifier of the RPC API key | Yes |
Field | Type | Description |
---|---|---|
id | number | Unique identifier of the RPC API key |
name | string | Name of the RPC API key |
description | string | Description of the RPC API key |
projectUuid | string | Unique identifier of the project |
uuid | string | Unique identifier of the RPC API key |
createTime | DateTime | Creation timestamp |
updateTime | DateTime | Last updated timestamp |
urls | array | Array of favorite URLs for the RPC API key |
Field | Type | Description |
---|---|---|
id | number | Unique identifier of the RPC Endpoint |
apiKeyId | number | Unique identifier of the RPC API key |
chainName | string | Name of the chain the RPC Endpoint belongs to |
network | string | Network of the RPC Endpoint (Usually mainnet, testnet, etc.) |
httpsUrl | string | HTTPS URL of the RPC Endpoint |
wssUrl | string | WSS URL of the RPC Endpoint |
createTime | DateTime | Creation timestamp |
updateTime | DateTime | Last updated timestamp |
Code | Description |
---|---|
40300000 | Forbidden |
40420001 | RPC API key not found |
Field | Type | Description |
---|---|---|
id | number | Unique identifier of the RPC Endpoint |
image_url | string | URL of the RPC Endpoint chain image |
name | string | Name of the RPC Endpoint chain |
networkId | number | Network ID of the RPC Endpoint |
networkName | string | Network of the RPC Endpoint (Usually Mainnet, Testnet, etc.) |
nodes | array | Array of nodes for the RPC Endpoint |
type | string | Type of the Entity (will be 'network') |
version | string | Version of the RPC Endpoint |
Field | Type | Description |
---|---|---|
id | number | Unique identifier of the RPC Endpoint Node |
https | string | HTTPS URL of the RPC Endpoint Node |
wss | string | WSS URL of the RPC Endpoint Node |
type | string | Type of the Entity (will be 'node') |
node_type | string | Type of the RPC Endpoint Node |
version | string | Version of the RPC Endpoint Node |
In all cURL examples, parameters with a colon as a prefix should be replaced with real values.
File upload process through Apillon Web3 Storage API
Name | Description | Required |
---|---|---|
bucketType | Type of bucket: 1 (storage bucket), 2 (website bucket) and 3 (nft bucket). | false |
Each item is an instance of the bucket model with the below properties:
Field | Type | Description |
---|---|---|
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
bucketUuid | string | Bucket unique identifier |
bucketType | integer | Item type with possible values 1 (storage bucket), 2 (website bucket) and 3 (nft bucket) |
name | string | Bucket name |
description | string | Bucket description |
size | integer | Size of bucket in bytes |
Name | Type | Description | Required |
---|---|---|---|
name | string | Bucket name. | true |
description | string | Bucket description. | false |
Code | Description |
---|---|
42200003 | Request body is missing a name field. |
A response is an instance of bucket, described above.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket. Key is displayed on developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
files | array | Array of files metadata. Maximum 200 items. | true |
sessionUuid | string | Session unique key, which must be specified to add more uploads to existing session. | false |
Each metadata object in the files
array contains the properties below.
Code | Description |
---|---|
40406002 | Bucket does not exist. |
40406009 | Bucket is marked for deletion. It is no longer possible to upload files to it. |
40006020 | HTML files cannot be uploaded to storage bucket in freemium subscription plan. |
42200040 | Request body is missing a files field. |
42200150 | files has invalid length. It should be between 1 and 200 |
42200008 | Request body file object is missing a fileName field. |
50006003 | Internal error - Apillon was unable to generate upload URL. |
Name | Type | Description |
---|---|---|
sessionUuid | string | Session unique key, which is later used to end upload and transfer files to bucket |
files | array | Array of files metadata. |
Files in the request body are returned in response data.files
property. Each file is equipped with url
and fileUuid
. All properties are displayed below.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of bucket. Key is displayed in developer dashboard. | true |
sessionUuid | Session uuid, recieved in upload to bucket | true |
Name | Type | Description | Required |
---|---|---|---|
wrapWithDirectory | boolean | Wrap uploaded files to IPFS directory | false |
directoryPath | string | Path to wrapped directory inside bucket | false |
Code | Description |
---|---|
40406004 | Session does not exist |
40006001 | Files in this session were already transferred |
API responds with the status 200 OK
if operation is successfully executed.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of bucket. Key is displayed on developer dashboard. | true |
Name | Description | Required |
---|---|---|
directoryUuid | Gets items inside a specific directory. | false |
markedForDeletion | Include deleted buckets | false |
Code | Description |
---|---|
40406002 | Bucket does not exist. |
Properties of each item:
Field | Type | Description |
---|---|---|
uuid | string | Item UUID property |
type | integer | Item type with possible values 1 (directory) and 2 (file) |
name | string | Item (directory or file) name |
CID | string | File content identifier - label used to point to content in IPFS. |
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
contentType | string | Item content type (MIME type). |
size | integer | Item size in bytes |
directoryUuid | string | Uuid of directory where the file directory is located |
link | string | Link on IPFS gateway. |
fileStatus | number | Current status of file |
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of bucket. Key is displayed on developer dashboard. | true |
Code | Description |
---|---|
40406002 | Bucket does not exist. |
Properties of each item:
Field | Type | Description |
---|---|---|
createTime | DateTime | File create time |
updateTime | DateTime | File last update time |
fileUuid | string | File UUID property |
CID | string | File content identifier - label used to point to content in IPFS. |
name | string | File name |
contentType | string | File content type. Value is taken from file upload request |
path | integer | Full path to file |
size | integer | File size in bytes |
fileStatus | number | File statuses are described in below table |
link | string | Link on IPFS gateway. |
Name | Description | required |
---|---|---|
bucketUuid | Unique key of a bucket. Key is displayed on developer dashboard. | true |
fileUuid | File UUID or CID. | true |
Code | Description |
---|---|
40406005 | File does not exist. |
Field | Type | Description |
---|---|---|
createTime | DateTime | File create time |
updateTime | DateTime | File last update time |
fileUuid | string | File UUID property |
CID | string | File content identifier - label used to point to content in IPFS. |
name | string | File name |
contentType | string | File content type. Value is taken from file upload request |
path | integer | Full path to file |
size | integer | File size in bytes |
fileStatus | number | File statuses are described in below table |
directoryUuid | string | Uuid of directory where the file is located |
link | string | Link on IPFS gateway. |
Number | Description |
---|---|
1 | Request for upload to Apillon storage was generated. |
2 | File is uploaded to Apillon central server. |
3 | File is transferred to the IPFS node. |
4 | File is replicated to different IPFS nodes through Crust Network. |
Name | Description | required |
---|---|---|
bucketUuid | Unique key of bucket. Key is displayed on developer dashboard. | true |
fileUuid | File unique identifier. | true |
Code | Description |
---|---|
40406005 | File does not exist. |
40006009 | File is already marked for deletion. |
The response of the delete function is a boolean value, depends on whether the deletion was successful.
Name | Description | required |
---|---|---|
bucketUuid | Unique key of bucket. Key is displayed on developer dashboard. | true |
directoryUuid | Directory unique identifier. | true |
Code | Description |
---|---|
40406003 | Directory does not exist. |
40006007 | Directory is already marked for deletion. |
The response of the delete function is a boolean value, depends on whether the deletion was successful.
Field | Type | Description |
---|---|---|
secret | string | Secret for this project, which can be used to generate tokens to access content of IPFS gateway |
projectUuid | string | Project unique identifier |
ipfsGateway | string | Gateway that can used to access content via CIDs. |
ipnsGateway | string | Gateway that can be used to access content via IPNS name. |
Name | Description | required |
---|---|---|
cid | Ipfs content identifier. API will automatically detect the type (CIDv0, CIDv1 or IPNS) | true |
Field | Type | Description |
---|---|---|
link | string | Link where requested content can be accessed. |
The JWT sign method expects three (3) parameters:
{
+ "cid": "CID or IPNS address",
+ "project_uuid": "Change with projectUuid value"
+}
+
secret
property from IPFS cluster infoIPFS-token
For each CID, a new token should be generated. Append the generated JWT to URL request as token
query parameter.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket, from which IPNS will be listed | true |
Name | Description | Required |
---|---|---|
ipnsName | List IPNS names with specific name | false |
ipnsValue | List IPNS names that point to this value (CID) | false |
Each item is an instance of the IPNF model, with the following properties:
Field | Type | Description |
---|---|---|
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
ipnsUuid | string | IPNS unique identifier |
name | string | Informational IPNS name, which is set by a user to easily organize the IPNS records |
description | string | IPNS description |
ipnsName | string | IPNS name used to access IPNS content on IPFs gateway |
ipnsValue | string | IPFS value (CID), to which this ipns points |
link | string | IPNS link to Apillon IPFS gateway, allowing to access content to which this IPNS points |
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket where IPNS will be created. Key is displayed on developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
name | string | IPNS name. | true |
description | string | IPNS description. | false |
cid | string | CID to which the IPNS name will point. If this property is specified, API executes IPNS publish, which sets the ipnsName and ipnsValue properties. | false |
Code | Description |
---|---|
42200026 | Request body is missing a name field. |
40406002 | Bucket not found |
Response is an instance of IPNS described above.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket | true |
ipnsUuid | Unique key of IPNS name | true |
Code | Description |
---|---|
40406012 | IPNS not found |
Response is an instance of IPNS described above.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket. | true |
ipnsUuid | Unique key of IPNS record that will be published | true |
Name | Type | Description | Required |
---|---|---|---|
cid | string | CID to which the IPNS name will point. | true |
Code | Description |
---|---|
42200030 | Body is missing CID property |
40406012 | IPNS not found |
The response is an instance of IPNS that was published. Properties are described above.
Name | Description | Required |
---|---|---|
bucketUuid | Unique key of storage bucket | true |
ipnsUuid | Unique key of IPNS record | true |
Code | Description |
---|---|
40406012 | IPNS not found |
The response is deleted IPNS record, an instance of IPNS described above.
To streamline the development experience, Apillon Web3 Storage service further introduces the concept of storage buckets.
A storage bucket is a virtual container that holds directories and files in a hierarchical structure. Each directory can contain multiple subdirectories and multiple files, and so on for each subdirectory.
Before using the Apillon Web3 Storage service, a storage bucket should be created on the Apillon Dashboard. Once ready, it enables file storage from both the Apillon dashboard and the API endpoints.
The process below describes how files are stored with Apillon storage buckets.
Each file hosting that passes through Crust’s pinning and replication service is paid upfront for a minimum period of 6 months. Apillon has no control over amending that period, so keep in mind that all files you deploy to Apillon storage buckets will remain accessible for that period of time.
If you decide to delete a file before the 6-month period expires, the file is marked for deletion. This means that Apillon does not extend the storage lease on Crust once the 6-month period expires, which leads to file deletion on all IPFS instances.
However, to make the storage service more dynamic, Apillon artificially lowers the file deletion period to 3 months. Once this period expires, the load of deleted files in your storage bucket is emptied, and the storage capacity is made available for uploading new files.
Note: These limitations are in the nature of the Apillon Closed Beta release, which is intended for testing purposes only. Once the Beta period is up, the limitations of Apillon Web3 services will be adjusted to more realistic production requirements.
',12),u={href:"https://blog.apillon.io/faq-apillon-web3-storage-c99a9b0e8b12",target:"_blank",rel:"noopener noreferrer"};function b(g,m){const o=a("ExternalLinkIcon");return n(),s("div",null,[c,t("p",null,[e("Apillon Web3 Storage is a Web3-based storage service that implements AWS S3 (as cache to optimize upload of large files), "),t("a",h,[e("IPFS"),i(o)]),e(", and "),t("a",p,[e("Crust Network"),i(o)]),e(" (to pin files on multiple IPFS nodes).")]),f,t("p",null,[e("Learn more: "),t("a",u,[e("Web3 Storage FAQ"),i(o)])])])}const k=r(d,[["render",b],["__file","2-web3-storage.html.vue"]]);export{k as default}; diff --git a/assets/2-web3-storage.html-5be7a21c.js b/assets/2-web3-storage.html-5be7a21c.js new file mode 100644 index 00000000..b62a4e76 --- /dev/null +++ b/assets/2-web3-storage.html-5be7a21c.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-47991eb5","path":"/web3-services/2-web3-storage.html","title":"Web3 Storage","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Storage bucket","slug":"storage-bucket","link":"#storage-bucket","children":[]},{"level":2,"title":"File storage","slug":"file-storage","link":"#file-storage","children":[]},{"level":2,"title":"File deletion","slug":"file-deletion","link":"#file-deletion","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"web3-services/2-web3-storage.md"}');export{e as data}; diff --git a/assets/2-what-is-apillon.html-5098629a.js b/assets/2-what-is-apillon.html-5098629a.js new file mode 100644 index 00000000..cc6f5c7d --- /dev/null +++ b/assets/2-what-is-apillon.html-5098629a.js @@ -0,0 +1 @@ +import{_ as t,o as n,c as o,b as e,e as s}from"./app-e8b865be.js";const i={},a=e("h1",{id:"what-is-apillon",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#what-is-apillon","aria-hidden":"true"},"#"),s(" What is Apillon?")],-1),l=e("div",{class:"divider"},null,-1),d=e("p",null,"Apillon is a Web3 development platform for developers and businesses building on Web3. By gathering unified API endpoints, it delivers the functionalities of Polkadot parachains adapted to the standard development process and user-preferred technology stack.",-1),r=e("p",null,"It gathers a unique set of tools, ample SDKs, and comprehensive documentation to fully support users in building their Web3 products from day one.",-1),c=e("p",null,"With Apillon, developers can create a complex and fully-functional Web3-based product in just days, harnessing the services provided by different parachains but without the need to employ them individually and from scratch or to spend years mastering the technical knowledge.",-1),h=e("p",null,"This way, they can focus more on the functionalities of their Web3 product than the underlying blockchain complexity and drastically shorten its go-to-market timeline.",-1),p=[a,l,d,r,c,h];function u(_,f){return n(),o("div",null,p)}const y=t(i,[["render",u],["__file","2-what-is-apillon.html.vue"]]);export{y as default}; diff --git a/assets/2-what-is-apillon.html-94103eb4.js b/assets/2-what-is-apillon.html-94103eb4.js new file mode 100644 index 00000000..b344ba30 --- /dev/null +++ b/assets/2-what-is-apillon.html-94103eb4.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-d64fcca0","path":"/about/2-what-is-apillon.html","title":"What is Apillon?","lang":"en-US","frontmatter":{},"headers":[],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/2-what-is-apillon.md"}');export{a as data}; diff --git a/assets/3-hosting-api.html-ccb98823.js b/assets/3-hosting-api.html-ccb98823.js new file mode 100644 index 00000000..fa1f6a0f --- /dev/null +++ b/assets/3-hosting-api.html-ccb98823.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-3fe44474","path":"/build/3-hosting-api.html","title":"Hosting API","lang":"en-US","frontmatter":{},"headers":[{"level":3,"title":"List websites","slug":"list-websites","link":"#list-websites","children":[]},{"level":3,"title":"Get website","slug":"get-website","link":"#get-website","children":[]},{"level":3,"title":"Get URLs for files upload","slug":"get-urls-for-files-upload","link":"#get-urls-for-files-upload","children":[]},{"level":3,"title":"End upload session","slug":"end-upload-session","link":"#end-upload-session","children":[]},{"level":3,"title":"Deploy website","slug":"deploy-website","link":"#deploy-website","children":[]},{"level":3,"title":"List website deployments","slug":"list-website-deployments","link":"#list-website-deployments","children":[]},{"level":3,"title":"Get deployment","slug":"get-deployment","link":"#get-deployment","children":[]},{"level":3,"title":"Generate short URL","slug":"generate-short-url","link":"#generate-short-url","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"build/3-hosting-api.md"}');export{e as data}; diff --git a/assets/3-hosting-api.html-d898b05b.js b/assets/3-hosting-api.html-d898b05b.js new file mode 100644 index 00000000..3df9b993 --- /dev/null +++ b/assets/3-hosting-api.html-d898b05b.js @@ -0,0 +1,263 @@ +import{_ as p,r,o as u,c as b,b as e,e as s,d as t,w as n,f as h,a as l}from"./app-e8b865be.js";const m={},k=e("h1",{id:"hosting-api",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#hosting-api","aria-hidden":"true"},"#"),s(" Hosting API")],-1),v={href:"https://en.wikipedia.org/wiki/CI/CD",target:"_blank",rel:"noopener noreferrer"},y=e("ol",null,[e("li",null,"Upload website files to Apillon cloud server.")],-1),f=e("ul",null,[e("li",null,"Request URLs for files upload"),e("li",null,"Upload files to cloud server"),e("li",null,"Trigger transfer into website")],-1),g=e("ol",{start:"2"},[e("li",null,"Execute deployment to staging or production environment.")],-1),_=e("strong",null,"Note:",-1),w={href:"https://app.apillon.io/dashboard/service/hosting",target:"_blank",rel:"noopener noreferrer"},T=e("p",null,"In all cURL examples, parameters with a colon as a prefix should be replaced with real values.",-1),U=e("h3",{id:"list-websites",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#list-websites","aria-hidden":"true"},"#"),s(" List websites")],-1),x={class:"split_content"},A=l('Each item is an instance of website class, with below properties:
Field | Type | Description |
---|---|---|
websiteUuid | string | Website unique identifier |
name | string | Website name |
description | string | Website description |
domain | string | Website domain. This property needs to be specified, so that Apillon is able to create SSL Certificates for IPFS gateway |
bucketUuid | string | Uuid of bucket for file upload |
cidStaging | string | Staging ipfs CID. Set if deployment to staging environment exists |
cidProduction | string | Production ipfs CID. Set if deployment to production environment exists |
ipnsProduction | string | Production IPNS. |
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
Name | Description | Required |
---|---|---|
websiteUuid | Website UUID, visible in developer console website overview | true |
Code | Description |
---|---|
40406010 | Website does not exists |
Response is an instance of website class, described above and additional properties described below. Those properties will receive value after deploy.
Field | Type | Description |
---|---|---|
w3StagingLink | string | Link to staging version of the website |
w3ProductionLink | string | Link to production version of the website |
lastDeploymentUuid | string | Website last deployment (to any environment) unique identifier |
lastDeploymentStatus | string | Status of last deployment |
Name | Description | Required |
---|---|---|
websiteUuid | Unique key of website bucket. Key is displayed on developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
files | array | Array of files metadata. | true |
sessionUuid | string | Session unique key. If not specified, API generates new one. It is possible to use same sessionUuid in multiple requests. | false |
Each file metadata object in files
array, contain below properties.
Code | Description |
---|---|
40406010 | Website does not exists |
42200040 | Request body is missing a files field. |
42200008 | Request body file object is missing a fileName field. |
50006003 | Internal error - Apillon was unable to generate upload URL. |
Name | Type | Description |
---|---|---|
sessionUuid | string | Session unique key, which is later used to end upload and transfer files to website. |
files | array | Array of files metadata. |
Files in request body are returned in response data.files
property. Each file is equipped with url
and fileUuid
. All properties are displayed below.
Name | Description | Required |
---|---|---|
websiteUuid | Unique key of website. | true |
sessionUuid | Session uuid, passed or received in get URL for upload request | true |
Code | Description |
---|---|
40406004 | Session does not exists |
40006001 | Files in this session were already transferred |
Api respond with status 200 OK
, if operation is successfully executed.
Name | Description | Required |
---|---|---|
websiteUuid | Website UUID, visible in developer console website overview | true |
Name | Type | Description | Required |
---|---|---|---|
environment | number | Possible environment values are explained below | true |
Status | Description |
---|---|
1 | Uploaded files are deployed to staging(preview) environment. Website will be available through staging IPNS link |
2 | Files from current staging environment are deployed to production environment. Website is pinned to CRUST, replicated and available through production IPNS link |
3 | Same as 2 , only that the source are uploaded files, not files in staging environment. |
Code | Description |
---|---|
42200039 | Request body is missing an environment field. |
40406010 | Website does not exists |
40006016 | There are no files to deploy. |
40006017 | There are no changes to deploy. |
Endpoint triggers deployment of website to specific environment. As result, deployment record with below field is returned. This deployment is now waiting to be processed.
Note: Deployment is processed in background, which may take several minutes. When deploying to staging
environment, files are added to IPFS and wrapped to directory, which is then accessible in IPFS via IPNS or CID. In production
, this CID is pinned to CRUST and replicated to other nodes.
Field | Type | Description |
---|---|---|
deploymentUuid | string | Deployment unique identifier |
environment | number | Environment to where website will be deployed |
deploymentStatus | number | Current status of deployment. Possible values are listed below. |
cid | string | When deployment is successful, CID points to directory on IPFS, where this page is accessible |
cidv1 | string | CID version 1 |
size | number | Size of website |
number | number | Deployment serial number - for this environment |
createTime | DateTime | Deployment create time |
updateTime | DateTime | Deployment last update time |
Deployment goes through different stages and each stage updates deploymentStatus
. Possible deployment statuses:
Status | Description |
---|---|
0 | Deployment initiated |
1 | In processing |
2 | In review |
3 | Website approved. Deployment will be executed |
10 | Deployment successful |
100 | Deployment failed |
101 | Deployment rejected |
Deployments (to environments 1 and 3) in projects without subscription go to review (deploymentStatus 3
). Review can take some time (up to 1 day) and if the website passes it, then the deployment continues.
Websites with illegal/phishing content goes to status 101
. The project owner is notified via mail and most likely banned from Apillon platform.
To speed up deployment process, make sure that project has one of the subscription packages.
Name | Description | Required |
---|---|---|
deploymentStatus | Current deployment status | false |
environment | Deployment environment | false |
Each item in list is a deployment instance.
Name | Description | Required |
---|---|---|
websiteUuid | Website UUID, visible in developer console website overview | true |
deploymentUuid | Deployment unique identifier, returned from deploy website endpoint | true |
Code | Description |
---|---|
40406011 | Deployment does not exists |
Data
property is a deployment instance.
Name | Description | Required |
---|---|---|
targetUrl | The target URL of the website the short URL will point to | true |
Field | Type | Description |
---|---|---|
id | string | The short URL slug |
url | string | The full short URL |
targetUrl | string | The target URL which the short link points to |
Note: At this point, only hosting of static websites is supported in Apillon Web3 Hosting service, while dynamic websites will be supported in future versions of Apillon.
The process below describes how a static website or app is hosted decentrally with Apillon Web3 Hosting.
To deploy a Web3 website or application, follow the process below:
',6),b={href:"https://app.apillon.io/register",target:"_blank",rel:"noopener noreferrer"},_=e("li",null,"Log in to your Apillon dashboard.",-1),m=e("li",null,'In the menu on the left, under Services, navigate to Hosting, and click "Get started."',-1),y=e("li",null,"Drag and drop your static website to the Hosting view and wait for the upload to finish.",-1),v=e("li",null,'Once the upload is complete and the status turns to "successful," you can deploy the website to Staging.',-1),k=e("li",null,"Click on the Staging tab to monitor the progress.",-1),A=e("li",null,'Deployment of web files will go through several statuses, ending with "successful."',-1),x=e("li",null,'Click "Deploy to production" to get files replicated and unstoppable with decentralized hosting.',-1),S=e("li",null,'Once the deployment to production is finished, click "Add domain" and "Configure domain" to make the domain you own point to the Apillon hosting.',-1),I=e("li",null,"Once DNS is updated, your unstoppable website will become available on the connected domain.",-1),H=e("p",null,"If you want to redeploy the website or app with new changes, repeat the process above simply by uploading the whole website or app via Apillon Hosting view.",-1),C=e("p",null,[e("strong",null,"Note:"),t(" Repeat deployment to Apillon Hosting will continue spending the Hosting storage capacity. However, every 3 months, the capacity will be renewed after older versions are deleted.")],-1),N={href:"https://blog.apillon.io/faq-apillon-web3-hosting-81d5477661e7",target:"_blank",rel:"noopener noreferrer"},W=e("h2",{id:"file-deletion",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#file-deletion","aria-hidden":"true"},"#"),t(" File deletion")],-1),z=e("p",null,"Each file hosting that passes through Crust’s pinning and replication service is paid upfront for a minimum period of 6 months. Apillon has no control over amending that period, so keep in mind that all files you deploy to Apillon storage buckets will remain accessible for that period of time.",-1),D=e("p",null,"If you decide to delete a file before the 6-month period expires, the file is marked for deletion. This means that Apillon does not extend the storage lease on Crust once the 6-month period expires, which leads to file deletion on all IPFS instances.",-1),F=e("p",null,"However, to make the hosting service more dynamic, Apillon artificially lowers the file deletion period to 3 months. Once this period expires, the load of deleted files in your storage bucket is emptied, and the storage capacity is made available for uploading new files and redeployment of website or app.",-1),L=e("strong",null,"Note",-1),T={href:"https://discord.gg/yX3gTw36C4",target:"_blank",rel:"noopener noreferrer"};function O(P,B){const s=n("RouterLink"),i=n("ExternalLinkIcon");return l(),r("div",null,[c,u,e("p",null,[t("Decentralized hosting of a website or an app on Apillon is very similar to the usage of storage buckets in "),o(s,{to:"/web3-services/1-good-to-know.html#web3-storage"},{default:d(()=>[t("decentralized storage")]),_:1}),t(". It implements AWS S3 (as cache to optimize upload of large files), "),e("a",g,[t("IPFS"),o(i)]),t(", and "),e("a",f,[t("Crust Network"),o(i)]),t(" (to pin files on multiple IPFS nodes).")]),w,e("ol",null,[e("li",null,[t("Register an "),e("a",b,[t("account on Apillon"),o(i)]),t(".")]),_,m,y,v,k,A,x,S,I]),H,C,e("p",null,[t("Learn more: "),e("a",N,[t("Web3 Hosting FAQ"),o(i)])]),W,z,D,F,e("p",null,[L,t(": In the Apillon Closed Beta stage, single file changes are not supported. Instead, hosting is treated as batch upload, meaning that with every new version of a website or app, its contents are rewritten, which leads to new files getting pinned and replicated on Crust. This limitation will be improved in future dashboard updates to enhance the developer experience. In case you need a larger storage capacity, feel free to get in touch on "),e("a",T,[t("Apillon Discord"),o(i)]),t(", and we will grant you extra space or more storage buckets.")])])}const R=a(p,[["render",O],["__file","3-web3-hosting.html.vue"]]);export{R as default}; diff --git a/assets/3-why-apillon.html-5e2f11cb.js b/assets/3-why-apillon.html-5e2f11cb.js new file mode 100644 index 00000000..ea20e0a4 --- /dev/null +++ b/assets/3-why-apillon.html-5e2f11cb.js @@ -0,0 +1 @@ +import{_ as e,o as i,c as t,a}from"./app-e8b865be.js";const o={},n=a('The dawn of open-source and decentralized technologies has inspired the creation of systems that give individuals more power to exchange assets and open up new business opportunities while reducing their reliance on centralized authorities. However, even though the pace of technological progress has been outstanding, the adoption of decentralized solutions still awaits implementation in the real economy on a large scale.
Polkadot, one of the leading players in the Web3 ecosystem, is set to transform the way businesses, individuals, and organizations manage assets and data. Still, several factors hinder the broader adoption of Web3 solutions:
Apillon's unified points of access deliver the functionalities of Polkadot parachains to developers simply through APIs, so they can create a working Web3-based product from day one while mitigating or avoiding the issues above.
While each parachain is best at solving its own isolated case, Apillon is all about connecting and curating different parachains, protocols, or pallets into the right context that can be easily adopted by developers to build tangible products in Web3.
Simplification further applies to pricing, as the platform takes care of all the underlying payment requirements with a unified payment system. Payment plans in DOT or fiat (EUR, USD) deliver price stability and predictability, ideal for enterprises and frequent users.
Building with Apillon does not require prior knowledge of blockchain technology and surpasses the hassle of lengthy testing and auditing. A streamlined product development substantially reduces the go-to-market timeline and resources spent in the process.
Apillon brings the power of distributed technologies to web developers and opens the floodgate to their widespread adoption. It democratizes the usability of advanced technologies and helps Web3 services reach wider and deeper.
Unpredictable pricing of Web3 services hinders adoption as users cannot foresee the costs generated in the process of using them. The Apillon platform delivers various Web3 services at stable pricing and allows users to devote more time and energy to developing new products.
The Web3 space delivers outstanding possibilities for building advanced decentralized products. However, the projects providing Web3 services have mostly focused on perfecting the technology offering and less on how end-users interact with it and adopt it.
One of the main challenges users need to overcome in Web3 services adoption is token/asset acquisition and management. This could seem like a minor issue when using a single service but could grow into an overwhelming toil when utilizing multiple at once.
"Apillon is a Web3 development platform that gathers and delivers complex blockchain solutions and protocols through a simplified and unified API endpoint, allowing developers to build Web3 projects quickly, effectively and with predictable pricing." Apillon Tokenomics Whitepaper
To deliver as smooth a user experience as possible, the Apillon platform performs automatic payments of underlying services in their native tokens and enables users to pay for all in a single transaction.
Each successful startup goes through typical development phases. First, after the initial idea, they build a prototype and MVP to create traction. Once they perfect their offering in the product-market fit phase, they work towards boosting growth in the scaling phase.
In supporting Web3 builders through their growth process, Apillon delivers a full-stack solution that allows both startups and established companies to develop and scale their products using Web3 building services.
Too often, as they work on perfecting the product-market fit, initial-stage businesses are not focused much on the costs that come with using different services. However, in the following phase, scaling the business model becomes a much more pragmatic issue, as it requires a lot of mid- to long-term planning and continuous cost optimization.
And this can only be achieved by utilizing services with reliable, predictable pricing models.
In the Web3 world, the pricing of most protocols, parachains, and services is typically based around a volatile token. This is directly correlated with project tokenomics, as they aim to boost token value with different token utilities, some more successfully, some less. Moreover, token valuation is heavily subject to market sentiment and community backing.
Charging for Web3 services in volatile tokens leads to unpredictable pricing models, which prevents their users from scaling successfully and reining their spending within rational range.
The unpredictability of service pricing is a huge issue in the current stage of the Web3 space, regardless of (or because of) ever-changing market sentiment. With the implementation of stable service pricing, Apillon provides the platform users with tools to build stellar Web3 products while allowing them to forecast their financial statements and cash flows for stable growth.
Paying for services with a highly volatile asset is both risky and cumbersome. It is mainly because, in Web3, highly volatile assets represent more an investment vehicle than a value transfer instrument.
The Apillon platform is designed to accept payments in either fiat money, stablecoins, or even volatile assets. As it cannot impact the utility of supported parachains' native tokens, the platform sustains a pricing model that resists their volatility and provides users with stable monthly pricing. This way, they can adequately plan the resources spent on Web3 projects.
While Apillon’s pricing model can buffer normal average asset volatility of supported services, it is not designed to withstand cases of dramatic or black swan events on the market.
The Apillon platform and its pricing is built using the following approaches:
The Apillon MVP supports a freemium model to bring the above points into equilibrium. With stably priced services and unified payment, it further helps Apillon's business model to stand the test of the crypto market.
',33),s=[n];function r(l,c){return i(),t("div",null,s)}const d=e(o,[["render",r],["__file","3-why-apillon.html.vue"]]);export{d as default}; diff --git a/assets/3-why-apillon.html-e3881b0c.js b/assets/3-why-apillon.html-e3881b0c.js new file mode 100644 index 00000000..5aeb93b3 --- /dev/null +++ b/assets/3-why-apillon.html-e3881b0c.js @@ -0,0 +1 @@ +const i=JSON.parse('{"key":"v-0f48940c","path":"/about/3-why-apillon.html","title":"Why Apillon?","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Unified pricing","slug":"unified-pricing","link":"#unified-pricing","children":[{"level":3,"title":"Predictable pricing for greater adoption","slug":"predictable-pricing-for-greater-adoption","link":"#predictable-pricing-for-greater-adoption","children":[]},{"level":3,"title":"Predictable scaling","slug":"predictable-scaling","link":"#predictable-scaling","children":[]},{"level":3,"title":"Token utility, volatility, and predictable pricing paradox","slug":"token-utility-volatility-and-predictable-pricing-paradox","link":"#token-utility-volatility-and-predictable-pricing-paradox","children":[]},{"level":3,"title":"Multiple services at a single price tag","slug":"multiple-services-at-a-single-price-tag","link":"#multiple-services-at-a-single-price-tag","children":[]}]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/3-why-apillon.md"}');export{i as data}; diff --git a/assets/4-how-does-apillon-work.html-d518367e.js b/assets/4-how-does-apillon-work.html-d518367e.js new file mode 100644 index 00000000..e4d9fdd3 --- /dev/null +++ b/assets/4-how-does-apillon-work.html-d518367e.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-6bda2dde","path":"/about/4-how-does-apillon-work.html","title":"How does Apillon work?","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"APIs","slug":"apis","link":"#apis","children":[]},{"level":2,"title":"SDKs","slug":"sdks","link":"#sdks","children":[]},{"level":2,"title":"Documentation","slug":"documentation","link":"#documentation","children":[]},{"level":2,"title":"Monitoring","slug":"monitoring","link":"#monitoring","children":[]},{"level":2,"title":"Analytics","slug":"analytics","link":"#analytics","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/4-how-does-apillon-work.md"}');export{l as data}; diff --git a/assets/4-how-does-apillon-work.html-dcf52b18.js b/assets/4-how-does-apillon-work.html-dcf52b18.js new file mode 100644 index 00000000..39528365 --- /dev/null +++ b/assets/4-how-does-apillon-work.html-dcf52b18.js @@ -0,0 +1 @@ +import{_ as r,r as i,o as s,c as l,b as e,e as o,d as t,a as n}from"./app-e8b865be.js";const d={},h=n('Apillon abstracts the technological complexity behind the Polkadot network and its parachains into a suite of development tools empowering developers to upgrade to Web3 easily.
The platform gathers and delivers Web3 functionalities powered by Polkadot parachains to developers through straightforward API access, and provides support with ample SDKs and complete documentation for each service.
Apillon's adaptability and interoperability allow builders to seamlessly merge use cases into single products offering different distributed services, serving their audiences more comprehensively than they could with specialized products.
Thanks to easy integration into any development framework, the Apillon APIs introduce a new way of Web3 development that significantly simplifies the go-to-market product evolution.
Initially, the Apillon platform will incorporate APIs to the following Polkadot parachains:
',8),p={href:"https://moonbeam.network/",target:"_blank",rel:"noopener noreferrer"},c={href:"https://www.kilt.io/",target:"_blank",rel:"noopener noreferrer"},u={href:"https://crust.network/",target:"_blank",rel:"noopener noreferrer"},f={href:"https://www.phala.network/",target:"_blank",rel:"noopener noreferrer"},m=n('In the future, more APIs will be added as new parachains earn their slot on Polkadot, and new Web3 services and features are released on the network.
Easing the integration of the Apillon platform and its APIs, ample SDKs enable faster and more streamlined utilization of Polkadot/Kusama parachains from the first click onwards.
Guiding developers’ way through the individual modules and dapp development process, Apillon documentation helps avoid bugs, mitigate operational issues, and create working products with a lower risk of error and less need for auditing.
With a real-time overview of back-end performance, developers gain valuable insights into the functioning of their Web3 applications and attached services, allowing them to improve on lagging features or tweak the product for better performance.
To help advance the adoption of Web3 products, Apillon's Analytics delivers clear insight into UI and transaction data, allowing developers to understand how their products are used, their best-performing features, and areas that need improvement.
',9);function w(g,k){const a=i("ExternalLinkIcon");return s(),l("div",null,[h,e("ul",null,[e("li",null,[e("a",p,[o("Moonbeam"),t(a)])]),e("li",null,[e("a",c,[o("KILT"),t(a)])]),e("li",null,[e("a",u,[o("Crust"),t(a)])]),e("li",null,[e("a",f,[o("Phala"),t(a)])])]),m])}const v=r(d,[["render",w],["__file","4-how-does-apillon-work.html.vue"]]);export{v as default}; diff --git a/assets/4-nfts-api.html-b2f21418.js b/assets/4-nfts-api.html-b2f21418.js new file mode 100644 index 00000000..733f107f --- /dev/null +++ b/assets/4-nfts-api.html-b2f21418.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-ae3a6dfc","path":"/build/4-nfts-api.html","title":"NFTs API","lang":"en-US","frontmatter":{},"headers":[{"level":3,"title":"Get NFT Collection","slug":"get-nft-collection","link":"#get-nft-collection","children":[]},{"level":3,"title":"List NFT Collections","slug":"list-nft-collections","link":"#list-nft-collections","children":[]},{"level":3,"title":"List Collection Transactions","slug":"list-collection-transactions","link":"#list-collection-transactions","children":[]},{"level":3,"title":"Create NFT Collection","slug":"create-nft-collection","link":"#create-nft-collection","children":[]},{"level":3,"title":"Transfer Collection","slug":"transfer-collection","link":"#transfer-collection","children":[]},{"level":3,"title":"Mint Collection NFTs","slug":"mint-collection-nfts","link":"#mint-collection-nfts","children":[]},{"level":3,"title":"Nest Mint Collection NFTs","slug":"nest-mint-collection-nfts","link":"#nest-mint-collection-nfts","children":[]},{"level":3,"title":"Burn Collection NFT","slug":"burn-collection-nft","link":"#burn-collection-nft","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"build/4-nfts-api.md"}');export{l as data}; diff --git a/assets/4-nfts-api.html-eaa291cc.js b/assets/4-nfts-api.html-eaa291cc.js new file mode 100644 index 00000000..e364db13 --- /dev/null +++ b/assets/4-nfts-api.html-eaa291cc.js @@ -0,0 +1,330 @@ +import{_ as p,r as d,o as u,c as b,b as t,e,d as s,w as n,a as r}from"./app-e8b865be.js";const h={},k=t("h1",{id:"nfts-api",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#nfts-api","aria-hidden":"true"},"#"),e(" NFTs API")],-1),m={href:"https://docs.opensea.io/docs/metadata-standards",target:"_blank",rel:"noopener noreferrer"},v=t("h3",{id:"get-nft-collection",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#get-nft-collection","aria-hidden":"true"},"#"),e(" Get NFT Collection")],-1),y=t("blockquote",null,[t("p",null,"Get NFT collection by UUID")],-1),f={class:"split_content"},g=r('Name | Description | Required |
---|---|---|
uuid | Unique key of collection. Key is displayed in developer dashboard. | true |
Code | Description |
---|---|
40300000 | Not allowed to access collection. |
50012009 | Collection does not exist. |
Name | Type | Description |
---|---|---|
createTime | DateTime | Collection create time. |
updateTime | DateTime | Collection last update time. |
collectionType | number | Type of smart contract to use for collection. Available types are described here. |
collectionUuid | string | Unique key of a collection. |
symbol | string | NFT collection symbol (usually 3-4 characters long). |
name | string | NFT collection name. |
description | string | NFT collection description. |
maxSupply | number | Maximal number of NFTs ever in existence (0 stands for unlimited). |
bucketUuid | string | UUID of the bucket where metadata is stored. |
baseUri | string | Base URI for collection metadata (token id and file extension is appended to it). |
baseExtension | string | File extension that is auto appended after token id to form a full URL. |
isSoulbound | boolean | Soul bound tokens are NFTs that are bounded to wallet and not transferable. |
isRevokable | boolean | For revocable collection owner can destroy NFTs at any time. |
isAutoIncrement | boolean | If set to false, enables minting NFTs with a custom token ID |
royaltiesFees | number | Percentage (between 0 and 100) of each NFT sale sent to wallet specified under royalties address. |
royaltiesAddress | string | Address where royalties are sent to. |
collectionStatus | number | Apillon internal/database collection status. |
contractAddress | string | Smart address of contract for deployed collection. |
transactionHash | string | Deployment transaction hash/id. |
deployerAddress | string | Wallet address of deployer. |
chain | number | Blockchain id on which you want to release your collection. |
drop | boolean | Determines if collection is mintable by public. |
dropStart | number | UNIX timestamp which determines public mint opening date and time. |
dropPrice | number | Price of NFT at mint stage in token that is used on chain . |
dropReserve | number | Amount of NFTs reserved by owner. |
Number | Description |
---|---|
0 | Generic NFT collection. |
1 | Nestable NFT collection. |
Number | Description |
---|---|
0 | Collection was created. |
1 | Deploying collection was initiated. |
2 | Collection is being deployed. |
3 | Collection was deployed successfully. |
4 | Collection was transferred successfully. |
5 | Failed deploying collection. |
',6),x={class:"split_content"},C={class:"split_side"},R=t("h4",{id:"query-parameters",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#query-parameters","aria-hidden":"true"},"#"),e(" Query parameters")],-1),w=r('List NFT collections. Items are paginated and can be filtered and ordered through query parameters.
Name | Description | Required |
---|---|---|
collectionStatus | Collection status. Find available statuses here. | false |
Response is a list of items described under Response Fields above.
',3),A={class:"split_side"},U=t("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[t("pre",{class:"language-bash"},[t("code",null,[t("span",{class:"token function"},"curl"),e(),t("span",{class:"token parameter variable"},"--location"),e(),t("span",{class:"token string"},"'https://api.apillon.io/nfts/collections'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--header"),e(),t("span",{class:"token string"},"'Authorization: Basic :credentials'"),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),D=t("div",{class:"language-json line-numbers-mode","data-ext":"json"},[t("pre",{class:"language-json"},[t("code",null,[t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"id"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"b5935c73-204d-4365-9f9a-6a1792adab5b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"status"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"200"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"data"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"items"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token punctuation"},"["),e(` + `),t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"createTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"updateTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionType"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"d6355fd3-640d-4803-a4d9-79d875abcb5a"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"symbol"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"name"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"description"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection Description"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"maxSupply"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1000"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"bucketUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"a9425ff7-4802-4a38-b771-84a790112c30"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseUri"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"https://ipfs.apillon.io/metadata/"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseExtension"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'".json"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isSoulbound"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"false"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isRevokable"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesFees"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0.1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x4156edbafc5091507de2dd2a53ded551a346f83b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionStatus"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"contractAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"transactionHash"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"deployerAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x4156edbafc5091507de2dd2a53ded551a346f83b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"chain"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1287"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"drop"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropStart"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1687251003"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropPrice"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0.1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropReserve"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"5"),e(` + `),t("span",{class:"token punctuation"},"}"),e(` + `),t("span",{class:"token punctuation"},"]"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"total"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1"),e(` + `),t("span",{class:"token punctuation"},"}"),e(` +`),t("span",{class:"token punctuation"},"}"),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),S=t("h3",{id:"list-collection-transactions",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#list-collection-transactions","aria-hidden":"true"},"#"),e(" List Collection Transactions")],-1),q=t("blockquote",null,[t("p",null,"List NFT collections. Items are paginated and can be filtered and ordered through query parameters.")],-1),B={class:"split_content"},j={class:"split_side"},P=r('Name | Description | Required |
---|---|---|
uuid | Unique key of collection. Key is displayed in developer dashboard. | true |
Name | Description | Required |
---|---|---|
transactionStatus | Transaction status. | false |
transactionType | Transaction type. | false |
Name | Type | Description |
---|---|---|
chainId | number | Blockchain id on which you want to release your collection. |
transactionType | number | Transaction type. |
transactionStatus | number | Transaction status |
transactionHash | number | Transaction hash/id. |
updateTime | DateTime | Transaction last update time. |
createTime | DateTime | Transaction create time. |
Number | Description |
---|---|
1 | Deploy Contract |
2 | Transfer Contract Ownership |
3 | Mint NFT |
4 | Set Collection Base URI |
5 | Burn NFT |
6 | Nest mint NFT |
Number | Description |
---|---|
1 | Pending |
2 | Confirmed |
3 | Failed |
4 | Error |
API endpoint that creates NFT collection and deploys it on selected network.
An NFT Collection can be created with a few features/functionalities:
2 types of collections are supported:
',9),H={href:"https://evm.rmrk.app/nestable",target:"_blank",rel:"noopener noreferrer"},K={href:"https://docs.unique.network/reference/blockchain/nesting.html",target:"_blank",rel:"noopener noreferrer"},X=t("p",null,"Additionally, 2 chain types/environments are supported: EVM and Substrate.",-1),Z=t("h4",{id:"create-substrate-nft-collection",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#create-substrate-nft-collection","aria-hidden":"true"},"#"),e(" Create Substrate NFT Collection")],-1),z=t("br",null,null,-1),O={class:"split_content"},Y=r('Name | Type | Description | Required |
---|---|---|---|
collectionType | number | Type of smart contract to use when deploying collection (1 for generic, 2 for nestable). | true |
chain | number | Blockchain ID on which you want to release your collection. Options: (8 - Astar) | true |
symbol | string | NFT collection symbol (usually 3-4 characters long). | true |
name | string | NFT collection name. | true |
description | string | NFT collection description. | false |
maxSupply | number | Maximal number of NFTs ever in existence (0 stands for unlimited). | true |
baseUri | string | Base URI for collection metadata (token id and file extension is appended to it). | true |
baseExtension | string | File extension that is auto appended after token id to form a full URL. | true |
royaltiesAddress | string | Address where royalties are sent to. | true |
royaltiesFees | number | Percentage of royalties earned per each NFT trade. | true |
drop | boolean | Determines if collection is mintable by public. | true |
dropStart* | number | UNIX timestamp (in seconds) which determines public mint opening date and time. | true |
dropPrice* | number | Price of NFT at mint stage. | true |
dropReserve* | number | Amount of NFTs reserved by owner. | true |
Notes:
*dropStart
, dropPrice
and dropReserve
are only used if drop
is set to boolean true
.
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40012002 | Collection quota reached |
50012003 | Failed deploying NFT contract on chain. |
50012010 | Failed to create bucket for storing metadata. |
Response payload is described under Response Fields above.
Name | Type | Description | Required |
---|---|---|---|
chain | number | Blockchain ID on which you want to release your collection. Options: (1284 - Moonbeam, 1287 - Moonbase, 592 - Astar) | true |
isRevokable | boolean | For revocable collection owner can destroy NFTs at any time. (default: false) | true |
isSoulbound | boolean | Soul bound tokens are NFTs that are bound to wallet and not transferable. (default: false) | true |
isAutoIncrement | boolean | If set to false, enables minting NFTs with a custom token ID, otherwise defaults to isAutoIncrement = true | false |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40012002 | Collection quota reached |
50012003 | Failed deploying NFT contract on chain. |
50012010 | Failed to create bucket for storing metadata. |
Response payload is described under Response Fields above.
',6),at={class:"split_side"},ot=t("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[t("pre",{class:"language-bash"},[t("code",null,[t("span",{class:"token function"},"curl"),e(),t("span",{class:"token parameter variable"},"--location"),e(),t("span",{class:"token string"},"'https://api.apillon.io/nfts/collections/evm'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--header"),e(),t("span",{class:"token string"},"'Content-Type: application/json'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--header"),e(),t("span",{class:"token string"},"'Authorization: Basic :credentials'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--data"),e(),t("span",{class:"token string"},`'{ + "collectionType": 1, + "chain": 1287, + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection description", + "maxSupply": 1000, + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": "json", + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "royaltiesFees": 10, + "drop": true, + "dropStart": 1687251003, + "dropReserve": 5, + "dropPrice": 0.1, + "isRevokable": true, + "isSoulbound": true +}'`),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),rt=t("div",{class:"language-json line-numbers-mode","data-ext":"json"},[t("pre",{class:"language-json"},[t("code",null,[t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"id"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"b5935c73-204d-4365-9f9a-6a1792adab5b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"status"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"200"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"data"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"createTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"updateTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"chain"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1287"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionType"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"d6355fd3-640d-4803-a4d9-79d875abcb5a"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"symbol"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"name"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"description"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection Description"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"maxSupply"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1000"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"bucketUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"a9425ff7-4802-4a38-b771-84a790112c30"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseUri"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"https://ipfs.apillon.io/metadata/"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseExtension"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'".json"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesFees"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0.1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x4156edbafc5091507de2dd2a53ded551a346f83b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionStatus"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"contractAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"transactionHash"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"deployerAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0x4156edbafc5091507de2dd2a53ded551a346f83b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"drop"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropStart"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1687251003"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropPrice"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0.1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropReserve"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"5"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isRevokable"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isSoulbound"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),e(` + `),t("span",{class:"token punctuation"},"}"),e(` +`),t("span",{class:"token punctuation"},"}"),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),lt=t("h4",{id:"create-unique-nft-collection",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#create-unique-nft-collection","aria-hidden":"true"},"#"),e(" Create Unique NFT Collection")],-1),dt=t("br",null,null,-1),it={class:"split_content"},ct={class:"split_side"},pt=r('Name | Type | Description | Required |
---|---|---|---|
collectionType | number | Type of smart contract to use when deploying collection (1 for generic, 2 for nestable). | true |
symbol | string | NFT collection symbol (usually 3-4 characters long). | true |
name | string | NFT collection name. | true |
description | string | NFT collection description. | false |
maxSupply | number | Maximal number of NFTs ever in existence (0 stands for unlimited). | true |
isRevokable | boolean | For revocable collection owner can destroy NFTs at any time. (default: false) | true |
isSoulbound | boolean | Soul bound tokens are NFTs that are bound to wallet and not transferable. (default: false) | true |
metadata | object | Object containing metadata for different token ids (more details bellow). | true |
Metadata field is an object with token ids as keys and token metadata as values. Here are the fields for each token metadata:
Name | Type | Description | Required |
---|---|---|---|
name | string | NFT name. | true |
description | string | NFT description. | false |
image | string | NFT image URL. | true |
image_details | object | Additional details about the image from the image field (see table bellow). | false |
attributes | array | Array of NFT attributes (see table bellow). | true |
animation_url | string | NFT animation URL. | false |
animation_details | object | Additional details about the animation from the animation_url field (see table bellow). | false |
youtube_url | string | URL to a YouTube video associated with the NFT. | false |
created_by | string | Address of the creator of the NFT. | false |
external_url | string | URL to an external resource providing more information about the NFT. | false |
background_color | string | Background color of the NFT. | false |
locale | string | Locale of the NFT. | false |
Attributes field of metadata field is an array of NFT traits described bellow:
Name | Type | Description | Required |
---|---|---|---|
value | string | Trait value. | true |
trait_type | string | Name of the trait. | true |
display_type | string | Type for displaying trait (number , date ,...). | false |
Name | Type | Description | Required |
---|---|---|---|
name | string | Name of the image (for captions, etc.). | false |
type | enum | Type of content (image ,animation ,video ,audio ,spatial ,pdf ,document ,other ) | false |
bytes | number | Size of the image file in bytes. | false |
format | string | Format of the image file (e.g., PNG, JPEG). | false |
sha256 | string | SHA-256 hash of the image file. | false |
width | number | Width of the image in pixels. | false |
height | number | Height of the image in pixels. | false |
order | number | Order of the image. | false |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40012002 | Collection quota reached |
50012003 | Failed deploying NFT contract on chain. |
Response payload is described under Response Fields above.
',5),ht={class:"split_side"},kt=t("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[t("pre",{class:"language-bash"},[t("code",null,[t("span",{class:"token function"},"curl"),e(),t("span",{class:"token parameter variable"},"--location"),e(),t("span",{class:"token string"},"'https://api.apillon.io/nfts/collections/unique'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--header"),e(),t("span",{class:"token string"},"'Content-Type: application/json'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--header"),e(),t("span",{class:"token string"},"'Authorization: Basic :credentials'"),e(),t("span",{class:"token punctuation"},"\\"),e(` +`),t("span",{class:"token parameter variable"},"--data"),e(),t("span",{class:"token string"},`'{ + "collectionType": 1, + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection description", + "maxSupply": 1000, + "isRevokable": true, + "isSoulbound": true, + "metadata": { + "1": { + "name": "name", + "description": "description", + "image": "image", + "attributes": [ + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + } + ] + }, + "2": { + "name": "name", + "description": "description", + "image": "image", + "attributes": [ + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + }, + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + } + ] + }, + } +}'`),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),mt=t("div",{class:"language-json line-numbers-mode","data-ext":"json"},[t("pre",{class:"language-json"},[t("code",null,[t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"id"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"b5935c73-204d-4365-9f9a-6a1792adab5b"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"status"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"200"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"data"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token punctuation"},"{"),e(` + `),t("span",{class:"token property"},'"createTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"updateTime"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"2023-06-13T10:15:58.000Z"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"chain"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"11"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionType"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"d6355fd3-640d-4803-a4d9-79d875abcb5a"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"symbol"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"name"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"description"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"NFT Collection Description"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"maxSupply"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"1000"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"bucketUuid"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token null keyword"},"null"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseUri"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token null keyword"},"null"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"baseExtension"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'""'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesFees"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"royaltiesAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token null keyword"},"null"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"collectionStatus"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"contractAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"XjuXMnFxcJoAgMCdUQKvvt2Daykq4H9rsCfYEVpF6noFP5u"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"transactionHash"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"0xb59d8497feb121b0ca0b8480df72a456333edddc68ad65f23b6b8b9028e3a6b3"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"deployerAddress"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token string"},'"WmMcyrPY4fivB5FUPN85QPhCMKtnrjmUyAgtXC2oW2XbcnY"'),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"drop"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"false"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropStart"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropPrice"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"dropReserve"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token number"},"0"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isRevokable"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isSoulbound"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),t("span",{class:"token punctuation"},","),e(` + `),t("span",{class:"token property"},'"isAutoIncrement"'),t("span",{class:"token operator"},":"),e(),t("span",{class:"token boolean"},"true"),e(` + `),t("span",{class:"token punctuation"},"}"),e(` +`),t("span",{class:"token punctuation"},"}"),e(` +`)])]),t("div",{class:"line-numbers","aria-hidden":"true"},[t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"}),t("div",{class:"line-number"})])],-1),vt=t("h3",{id:"transfer-collection",tabindex:"-1"},[t("a",{class:"header-anchor",href:"#transfer-collection","aria-hidden":"true"},"#"),e(" Transfer Collection")],-1),yt=t("blockquote",null,[t("p",null,"Transfer collection ownership from a wallet owned by caller to a new wallet address.")],-1),ft={class:"split_content"},gt=r('Name | Description | Required |
---|---|---|
uuid | Unique key of collection. Key is displayed in developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
address | string | Wallet address of a new owner. | true |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40012003 | Contract can't be transferred to wallet address that already owns this collection. |
40012004 | Transfer transaction already exists. |
40300000 | Not allowed to access collection |
50012002 | Collection doesn't exist, wasn't deployed or was already transferred. |
50012004 | Collection transfer failed. |
Response payload is described under Response Fields above.
Name | Description | Required |
---|---|---|
uuid | Unique key of collection. Key is displayed in developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
receivingAddress | string | Wallet address of NFT receiver. | true |
quantity | number | Number of NFTs to mint. | true |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40300000 | Not allowed to access collection. |
50012002 | Collection doesn't exist, wasn't deployed or was already transferred. |
50012005 | Error minting NFT. |
50012007 | Total number of minted NFTs would exceed max supply for this collection. |
50012008 | All of the reserved NFTs were already minted. |
Field | Type | Description |
---|---|---|
success | boolean | Status of action. |
Name | Description | Required |
---|---|---|
uuid | Unique key of (child) collection we are minting. | true |
Name | Type | Description | Required |
---|---|---|---|
parentCollectionUuid | string | Collection UUID of NFT receiving nest-minted NFT. | true |
parentNftId | number | Token id of NFT receiving nest-minted NFT. | true |
quantity | number | Number of NFTs to nest-mint. | true |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40300000 | Not allowed to access collection. |
50012002 | Collection doesn't exist, wasn't deployed or was already transferred. |
50012007 | Total number of minted NFTs would exceed max supply for this collection. |
50012008 | All of the reserved NFTs were already minted. |
50012013 | Parrent collection doesn't support nesting. |
50012014 | Parrent and child collection chain missmatch. |
Field | Type | Description |
---|---|---|
success | boolean | Status of action. |
Name | Description | Required |
---|---|---|
uuid | Unique key of collection. Key is displayed in developer dashboard. | true |
Name | Type | Description | Required |
---|---|---|---|
tokenId | number | Non fungible token id that we are burning. | true |
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code | Description |
---|---|
40300000 | Not allowed to access collection. |
50012002 | Collection doesn't exist, wasn't deployed or was already transferred. |
50012012 | Burning NFT failed. |
Field | Type | Description |
---|---|---|
success | boolean | Status of action. |
npm install @apillon/sdk
+
import { Hosting } from '@apillon/sdk';
+
+const hosting = new Hosting({
+ key: '',
+ secret: '',
+});
+
Apillon SDK consists of different modules depending on which service you want to use. All modules require the same initial config of key
and secret
shown above in Hosting
module example.
Alternatively, you can populate the APILLON_API_KEY
and APILLON_API_SECRET
environment variables.
View each individual module examples in the sections below.
import {
+ DeployToEnvironment,
+ DeploymentStatus,
+ Hosting,
+ LogLevel,
+} from '@apillon/sdk';
+import * as fs from 'fs';
+
+const hosting = new Hosting({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ logLevel: LogLevel.VERBOSE,
+});
+
+// list all websites
+await hosting.listWebsites({ orderBy: 'createTime' });
+
+// create an instance of a website via uuid
+const webpage1 = hosting.website('uuid');
+
+// gets website information
+await webpage1.get();
+
+// Upload files from local folder
+await webpage1.uploadFromFolder('./public');
+// Or alternatively, send file buffers as upload parameters
+const htmlBuffer = fs.readFileSync('./public/index.html');
+await webpage1.uploadFiles(
+ [
+ {
+ fileName: 'index.html',
+ contentType: 'text/html',
+ content: htmlBuffer,
+ },
+ ]
+);
+
+// deploys uploaded files to staging environment
+await webpage1.deploy(DeployToEnvironment.TO_STAGING);
+
+// lists all deployments of a website
+await webpage1.listDeployments();
+
+// gets a specific deployment
+const deployment = await webpage1
+ .deployment('3e0c66ea-317d-4e1f-bcd9-38026c3ea1ee')
+ .get();
+
+// checks if deployment was successful
+if (deployment.deploymentStatus === DeploymentStatus.SUCCESSFUL) {
+ // done
+}
+
Storage module encapsulates functionalities for Storage service available on Apillon dashboard.
`,4),H={href:"https://sdk-docs.apillon.io/classes/Storage.html",target:"_blank",rel:"noopener noreferrer"},q=e(`import { Storage, LogLevel, FileStatus } from '@apillon/sdk';
+import * as fs from 'fs';
+
+const storage = new Storage({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ logLevel: LogLevel.VERBOSE,
+});
+
+// list buckets
+await storage.listBuckets({ limit: 5 });
+
+// create and instance of a bucket directly through uuid
+const bucket = storage.bucket('uuid');
+
+// Upload files from local folder
+await bucket.uploadFromFolder('./my-folder/files/');
+// Or alternatively, send file buffers as upload parameters
+const pdfBuffer = fs.readFileSync('./my-folder/files/document.pdf');
+await bucket.uploadFiles(
+ [
+ {
+ fileName: 'document.pdf',
+ contentType: 'application/pdf',
+ content: pdfBuffer,
+ },
+ ],
+ // Upload the files in a new subdirectory in the bucket instead of in the root of the bucket
+ { wrapWithDirectory: true, directoryPath: 'main/documents' }
+);
+
+// list objects (files, folders) in a bucket
+await bucket.listObjects({
+ directoryUuid: 'eaff2672-3012-46fb-9278-5efacc6cb616',
+ markedForDeletion: false,
+ limit: 5,
+});
+
+// list all files in a bucket no matter if they are in a folder or not
+await bucket.listFiles({ fileStatus: FileStatus.UPLOADED });
+
+// generate an IPFS link for a CID
+const cid = 'bafybeigjhyc2tpvqfqsuvf3byo4e4a4v6spi6jk4qqvvtlpca6rsaf2cqi';
+const link = await storage.generateIpfsLink(cid);
+
+// gets a specific file in a bucket directly through uuid
+const file = await bucket.file('2195521d-15cc-4f6e-abf2-13866f9c6e03').get();
+
+// deletes a file via uuid
+await bucket.file('2195521d-15cc-4f6e-abf2-13866f9c6e03').delete();
+// deletes a directory via uuid
+await bucket.directory('eddc52cf-92d2-436e-b6de-42d7cad621c3').delete();
+
The Storage module additionally contains methods for manipulating IPNS records for a specific storage any.
`,4),M={href:"https://sdk-docs.apillon.io/classes/Ipns.html",target:"_blank",rel:"noopener noreferrer"},V=e(`import { Storage, LogLevel } from '@apillon/sdk';
+
+const storage = new Storage({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ logLevel: LogLevel.VERBOSE,
+});
+
+// create and instance of a bucket directly through uuid
+const bucket = storage.bucket('uuid');
+// list all existing IPNS records
+const ipnsNames = await bucket.listIpnsNames({ ipnsName: 'Images IPNS' });
+// create a new IPNS record
+const newIpns = await bucket.createIpns({
+ name: 'Music IPNS',
+ description: 'IPNS for my music files',
+ cid: 'QmS5NL2Rc6SCjFx7pvZHdTD8WGWjDt25WQskC7DsNKAatW',
+});
+// Get an IPNS record's details by UUID
+const ipns = await bucket.ipns('ipns_uuid').get();
+// Publish an IPNS record to point to a given CID
+await ipns.publish('QmajaeC15ZpcnjBpX4ARRBU127fpcZ2svYEfEBhFRkRZbN');
+// delete an IPNS record from the bucket
+await ipns.delete();
+
NFT module encapsulates functionalities for NFT service available on Apillon dashboard.
`,3),W={href:"https://sdk-docs.apillon.io/classes/Nft.html",target:"_blank",rel:"noopener noreferrer"},j=e(`Warning When you transfer ownership of the collection to another account Apillon will lose the ability to perform actions in your name (mint, burn, etc.). Before you transfer ownership make sure you do not need those functionalities via Apillon anymore.
import {
+ CollectionType,
+ EvmChain,
+ LogLevel,
+ Nft,
+ TransactionStatus,
+} from '@apillon/sdk';
+
+const nft = new Nft({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ logLevel: LogLevel.VERBOSE,
+});
+
+// create a new collection
+let collection = await nft.create({
+ collectionType: CollectionType.GENERIC,
+ chain: EvmChain.MOONBEAM,
+ name: 'SpaceExplorers',
+ symbol: 'SE',
+ description: 'A collection of unique space exploration NFTs.',
+ baseUri: 'https://moonbeamnfts.com/collections/spaceexplorers/',
+ baseExtension: 'json',
+ // If you omit the maxSupply parameter, the max supply will be unlimited
+ maxSupply: 1000,
+ isRevokable: false,
+ isSoulbound: false,
+ royaltiesAddress: '0x1234567890abcdef',
+ royaltiesFees: 5,
+ drop: true,
+ dropStart: 1679875200,
+ dropPrice: 0.05,
+ dropReserve: 100,
+});
+// or create a substrate collection
+const substrateCollection = await nft.createSubstrate({
+ collectionType: CollectionType.GENERIC,
+ chain: SubstrateChain.ASTAR,
+ name: 'SpaceExplorers',
+ symbol: 'SE',
+ ...
+});
+
+// check if collection is deployed - available on chain
+if (collection.collectionStatus == CollectionStatus.DEPLOYED) {
+ console.log('Collection deployed: ', collection.transactionHash);
+}
+
+// search through collections
+await nft.listCollections({ search: 'My NFT' });
+
+// create and instance of collection directly through uuid
+collection = await nft.collection('uuid').get();
+
+// mint a new nft in the collection
+await collection.mint({
+ receivingAddress: '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD',
+ quantity: 1,
+});
+
+// nest mint a new nft if collection type is NESTABLE
+await collection.nestMint(collection.uuid, 1, 1);
+
+// burn/destroy a specific NFT by its ID if collection is set as revokable
+await collection.burn('1');
+
+// list confirmed transactions on a collection
+await collection.listTransactions({
+ transactionStatus: TransactionStatus.CONFIRMED,
+});
+
+// transfer ownership of a collection away from apillon platform to an address
+// NOTE that this will disable the ability to mint/burn etc. from the SDK/API since only the owner
+// has this ability
+await collection.transferOwnership(
+ '0x5BA8B0c24bA5307b67E619ad500a635204F73bF1'
+);
+
Identity module encapsulates functionalities for validating EVM and Polkadot wallet signatures, as well as fetching Polkadot Identity data for any wallet.
`,5),G={href:"https://sdk-docs.apillon.io/classes/Identity.html",target:"_blank",rel:"noopener noreferrer"},Y=e(`import { Identity, LogLevel } from '@apillon/sdk';
+
+// Note: for signature-related methods API config is not required
+const identity = new Identity({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+ logLevel: LogLevel.VERBOSE,
+});
+
+// obtain on-chain identity data for a Polkadot wallet
+const { polkadot, subsocial } = await identity.getWalletIdentity(address);
+
+async function validateEvmWalletSignature() {
+ // generate a custom message to be signed by the user's wallet
+ const { message, timestamp } = await identity.generateSigningMessage(
+ 'Custom display message here',
+ );
+
+ // alternatively, you can generate you own signing message with timestamp like this:
+ // const timestamp = new Date().getTime();
+ // const message = 'Message from my Dapp';
+ // const signingMessage = \`\${message}\\n\${timestamp}\`;
+
+ const walletAddress = '0xa79bg13g2...';
+
+ // validate an EVM wallet's signature for a given message
+ const { isValid, address } = await identity.validateEvmWalletSignature({
+ message,
+ signature, // signature obtained from the user's wallet by the client app
+ walletAddress,
+ /*
+ * optional - check signature time validity by providing a timestamp
+ * which indicates when the signature was generated
+ */
+ timestamp,
+ // additionally, specify for how many minutes the timestamp is valid
+ signatureValidityMinutes: 15,
+ });
+
+ console.log(isValid); // true
+ console.log(address.toLowerCase() === walletAddress.toLowerCase()); // true
+}
+
+async function validatePolkadotWalletSignature() {
+ // If you wish to generate the message yourself and validate the timestamp,
+ // use a signing message as shown below:
+ const timestamp = new Date().getTime();
+ const message = 'Message from my Dapp';
+ const signingMessage = \`\${message}\\n\${timestamp}\`;
+
+ // validate a Polkadot wallet's signature for a given signing message
+ const { isValid } = await identity.validatePolkadotWalletSignature({
+ message: signingMessage,
+ signature, // signature obtained from the user's wallet by the client app
+ walletAddress: '5HqHQDGcHqS...',
+ timestamp,
+ signatureValidityMinutes: 5,
+ });
+}
+
+
The Computing module provides functionalities for managing computing contracts, including creating contracts, listing contracts, and interacting with specific contracts for operations like encryption and ownership transfer.
import { Computing } from '@apillon/sdk';
+
+const computing = new Computing({
+ key: 'yourApiKey',
+ secret: 'yourApiSecret',
+});
+
+// List all computing contracts
+const contracts = await computing.listContracts();
+
+// Create a new computing contract
+const newContract = await computing.createContract({
+ name: 'New Contract',
+ description: 'Description of the new contract',
+ bucket_uuid,
+ contractData: {
+ nftContractAddress: '0xabc...',
+ nftChainRpcUrl: ChainRpcUrl.ASTAR,
+ },
+});
+
+// Interact with a specific computing contract
+const contract = computing.contract(newContract.uuid);
+
+// Get details of the contract
+const contractDetails = await contract.get();
+
+// List transactions of the contract
+const transactions = await contract.listTransactions();
+
+// Encrypt a file and upload it to the associated bucket
+const encryptionResult = await contract.encryptFile({
+ fileName: 'example.txt',
+ content: Buffer.from('Hello, world!'),
+ nftId: 1, // NFT ID used for decryption authentication
+});
+
+// Transfer ownership of the contract
+const newOwnerAddress = '0xNewOwnerAddress';
+const successResult = await contract.transferOwnership(newOwnerAddress);
+console.log(
+ \`Ownership transfer was \${successResult ? 'successful' : 'unsuccessful'}.\`,
+);
+
The Social module provides functionalities for managing social hubs and channels within the Apillon platform. This includes creating, listing, and interacting with hubs and channels. In the background it utilizes Grill.chat, a mobile-friendly, anonymous chat application powered by Subsocial.
import { Social } from '@apillon/sdk';
+
+const social = new Social({ key: 'yourApiKey', secret: 'yourApiSecret' });
+// Create a new hub
+const hub = await social.createHub({
+ name: 'Apillon Hub',
+ about: 'Hub for Apillon channels',
+ tags: 'apillon,web3,build',
+});
+
+// Get a specific hub by UUID
+const hubDetails = await social.hub(hub.uuid).get();
+// List all Hubs
+const hubs = await social.listHubs();
+
+// Create a new channel within a hub
+const channel = await social.createChannel({
+ title: 'Web3 Channel',
+ body: "Let's discuss Web3",
+ tags: 'web3,crypto',
+ hubUuid: hub.uuid,
+});
+
+// Get a specific channel by UUID
+const channelDetails = await social.channel(channel.uuid).get();
+// List all channels within a Hub
+const channels = await social.listChannels({ hubUuid: hub.uuid });
+
When building on Web3, be it within the Polkadot ecosystem or in general, developers face challenges that still lack proper addressing.
With these obstacles in mind, the process of building a Web3 product from scratch soon becomes a complex, time-consuming, and potentially even risky business.
To overcome them, developers would need to:
Using Apillon, on the other hand, the process of developing a Web3 product is radically different.
Example #1: Building on KILT Protocol*
To build a simple Web3 app utilizing KILT Protocol for user authentication from scratch, a developer needs to do (at least) the following:
Using the Apillon platform, on the other hand, a developer simply calls a function (e. g., createUserWithEmailAndPassword
) from the Apillon SDK and sends the required parameters. The function creates a fully working user DID in the back end.
Example #2: Building on Crust*
To build a simple Web3 app utilizing Crust for file storage from scratch, a developer needs to do (at least) the following:
Using the Apillon platform, on the other hand, a developer simply calls the getStorage()
SDK function and moves the files to a decentralized, pinned service provided by Crust and IPFS.
In both cases, the resources spent on building a functional Web3 application with Apillon are significantly reduced, and the product’s go-to-market trajectory much shorter and streamlined.
*Disclaimer: These examples are technically highly simplified to illustrate the problematic context of building a Web3 product to the general public, whereas in technical reality, the process is much more complex. Examples used do not intend to imply in any way that either KILT or Crust are challenging to use but merely to show that these processes require serious work and introduce friction in cases where developers utilize several parachains to build a single solution.
',20),a=[l];function r(s,d){return i(),t("div",null,a)}const h=e(n,[["render",r],["__file","5-developing-web3-with-apillon.html.vue"]]);export{h as default}; diff --git a/assets/5-web3-authentication.html-52c30c94.js b/assets/5-web3-authentication.html-52c30c94.js new file mode 100644 index 00000000..09f5f41d --- /dev/null +++ b/assets/5-web3-authentication.html-52c30c94.js @@ -0,0 +1 @@ +const t=JSON.parse('{"key":"v-662ed367","path":"/web3-services/5-web3-authentication.html","title":"Web3 Authentication","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Authentication workflow","slug":"authentication-workflow","link":"#authentication-workflow","children":[]},{"level":2,"title":"Apillon Open Authentication (OAuth)","slug":"apillon-open-authentication-oauth","link":"#apillon-open-authentication-oauth","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"web3-services/5-web3-authentication.md"}');export{t as data}; diff --git a/assets/5-web3-authentication.html-a9029df0.js b/assets/5-web3-authentication.html-a9029df0.js new file mode 100644 index 00000000..1990f3ee --- /dev/null +++ b/assets/5-web3-authentication.html-a9029df0.js @@ -0,0 +1 @@ +import{_ as r,r as i,o as s,c as h,b as e,e as t,d as n,w as l,a as c}from"./app-e8b865be.js";const d={},p=c('Apillon offers a method for users to integrate an alternative authentication approach using a decentralized identifier (DID) stored on the KILT parachain. KILT-powered decentralized identity includes a credential that comprises a user's email address, which can be attested by Apillon or SocialKYC. Any user can create their own decentralized identity, verify their email address through Apillon's OAuth protocol, and then use this decentralized account and credential to verify their identity on third-party platforms.
Email Verification: This is the initial step in the process of generating a decentralized identity, which also serves as part of the attestation process, as it attests ownership of the provided email address.
Account Generation: A KILT wallet address derived from a BIP39 mnemonic is created. This mnemonic serves as the master key for accessing the account. Users are prompted to store this mnemonic securely.
Identity Generation: This step typically takes one to five minutes. On the front end, the user signs the operation for DID creation with their Sporran wallet, which is then submitted to the blockchain. The result is a DID document. Once the process is complete, the DID document is queried from the blockchain and returned to the user. All querying occurs on the front end, ensuring that Apillon never gains access to the DID document or the generated mnemonic from the previous step. The user has the option to link their newly generated DID with their account, making it possible to retrieve a DID for an account and vice-versa.
Attestation: Attestation consists of two steps. The first is verifying a user's claim, which is the result of the initial email verification step. The second step involves creating a verifiable credential, signed by both Apillon and the claimer (using the authentication key derived from the generated mnemonic in the second step). This credential's root hash is then submitted to the blockchain. The combination of these steps is referred to as the attestation process, and the credential should be stored securely.
DID and Verifiable Credential Storage: The user is prompted to save the generated files. The generated credential can also be imported into the Sporran wallet for convenience and safekeeping.
Identity Revocation: The user has the option to request the revocation of their DID through Apillon's OAuth website.
The first step mirrors the registration process, where an email with a unique token is sent to the user.
A revocation operation for the DID document is issued to the blockchain, rendering the identity invalid. All associated verifiable credentials also become unusable as a result of this process. The wallet account generated in the second step of the registration process remains valid, and all tokens associated with this account address remain accessible and valid.
Credential Restore: The user can restore their previously generated credentials through Apillon's OAuth website in case they lose access to them. The first step is the same as the registration process and involves sending an email with a unique token. Upon following the verification email link, the user is redirected to a secure page, where the saved credential is returned to them.
Credential Verification: The verification process requires two parameters: a verifiable credential (which can be in JSON format or pasted as plain text in the text area) and the mnemonic passphrase used to sign the credential.
From the provided credential and mnemonic, a presentation is created. The presentation should only contain the user's email address, which is the single property requested by Apillon to complete the verification process. The verification process also checks whether the owner of the credential matches the address that signed the request. The presentation is considered valid if the integrity check mentioned above succeeds.
Alternatively, if a user has imported their previously generated credentials into the Sporran wallet, they can log in directly with Sporran without the need to provide the credentials in text or file format, or the mnemonic passphrase. This allows users to select an existing credential from their wallet and sign the request directly.
To install Apillon CLI run
npm install -g @apillon/cli
+
Afterwards you can use CLI with command
apillon <command> [options]
+
Alternately you don't need to install the Apillon CLI to use it. In that case run the desired command using npx
:
npx @apillon/cli <command> [options]
+
Note that when running without installation, you have to use
@apillon/cli
instead ofapillon
execution command.
--key <api key>
: Apillon API key (can be set via the APILLON_API_KEY
environment variable).--secret <api secret>
: Apillon API secret (can be set via the APILLON_API_SECRET
environment variable).--debug
: Output execution logs when running commands.-V
, --version
: Output the version number.You can use environment variables to set an API key, and an API secret:
APILLON_API_KEY
: Apillon API key.APILLON_API_SECRET
: Apillon API secret.If you have these variables set, you do not need to use the global options each time.
To display the help information for the CLI or a specific command, use the -h
or --help
option:
apillon -h
+apillon hosting -h
+npx @apillon/cli hosting deploy-website --help
+
For commands that return a list of results, for example apillon storage list-files
, or apillon hosting list-websites
, there are global list pagination options that are available to use:
--limit <integer>
: Page limit--order-by <string>
: Page order by (can be any property from the response data)--page <integer>
: Page number--search <string>
: Search by name or other object identifierThe Apillon CLI currently supports the following commands:
hosting list-websites
Lists all websites associated with your project.
Example
apillon hosting list-websites --search "My-Website" --limit 1
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-10-25T10:41:06.000Z",
+ "updateTime": "2023-10-26T12:41:41.000Z",
+ "uuid": "5b908779-3687-4592-a073-9bebbf86afe2",
+ "name": "My Website",
+ "description": "My own website",
+ "domain": "https://my-website.com",
+ "bucketUuid": "47251013-37c6-4b30-be2b-8583dea25c4c",
+ "cidStaging": "bafybeidwxptqhokkmwgtzrjgj2pvcapmyce...",
+ "ipnsProduction": "k2k4r8pple7phwm9azqgxshxdzy..."
+ },
+ ...
+ ],
+ "total": 3
+}
+
hosting get-website
Retrieves information about a specific website.
Options
--uuid <string>
: UUID of the website to get details for.Example
apillon hosting get-website --uuid "123e4567-e89b-12d3-a456-426655440000"
+
hosting deploy-website
Deploys a website from a local folder directly to Apillon hosting production environment.
Options
<file-path>
: Path to the folder containing your website files.--uuid <string>
: UUID of the website to upload files to.-p, --preview
: Deploy to staging environment instead.Example
apillon hosting deploy-website ./public_html --uuid "123e4567-e89b-12d3-a456-426655440000" -p
+
hosting upload
Uploads a local folder's contents to a website deployment bucket.
Options
<path>
: Path to the folder containing your website files.--uuid <string>
: UUID of the website to upload files to.Example
apillon hosting upload ./public_html --uuid "123e4567-e89b-12d3-a456-426655440000"
+
hosting start-deployment
Deploys a website to the specified environment, from files already uploaded to the hosting bucket.
Options
--uuid <string>
: UUID of the website to deploy.--env <integer>
: The environment to deploy to.Available choices:
TO_STAGING = 1
+STAGING_TO_PRODUCTION = 2
+DIRECTLY_TO_PRODUCTION = 3
+
Example
apillon hosting start-deployment --uuid "123e4567-e89b-12d3-a456-426655440000" --env 1
+
hosting list-deployments
Lists all deployments for a specific website.
Options
--uuid <string>
: UUID of the website to list deployments for.--status <integer>
: The status of the deployments (DeploymentStatus enum, optional).Available choices:
INITIATED = 0
+IN_PROGRESS = 1
+IN_REVIEW = 2
+APPROVED = 3
+SUCCESSFUL = 10
+FAILED = 100
+REJECTED = 101
+
--env <integer>
: The environment of the deployments (DeploymentStatus enum, optional).Available choices:
STAGING = 2
+PRODUCTION = 3
+
Example
apillon hosting list-deployments --uuid "58a16026-1356-405b-97f9-efcc9dfac1dd" --order-by createTime --desc true
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-14T12:09:20.000Z",
+ "updateTime": "2023-11-14T12:09:42.000Z",
+ "uuid": "9b677fe2-1bb1-44d9-8956-e7749452f02d",
+ "websiteUuid": "58a16026-1356-405b-97f9-efcc9dfac1dd",
+ "cid": "QmPPBMsFccJVaLwvdhSh3zMbfEvonxoNSBLVd1kWK34Nps",
+ "cidv1": "bafybeizpqaa5xb5r46d2voj35qtokhb3c3bekof...",
+ "environment": "DIRECTLY_TO_PRODUCTION",
+ "deploymentStatus": "SUCCESSFUL",
+ "size": 7162,
+ "number": 1
+ },
+ ...
+ ],
+ "total": 7
+}
+
hosting get-deployment
Retrieves information about a specific deployment.
Options
-w, --website-uuid <string>
: UUID of the website.-d, --deployment-uuid <string>
: UUID of the deploymentExample
apillon hosting get-deployment --website-uuid "123e4567-e89b-12d3-a456-426655440000" --deployment-uuid "987e6543-e21c-32f1-b123-426655441111"
+
storage list-buckets
Lists all storage buckets associated with your project.
Example
apillon storage list-buckets
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-15T09:56:53.000Z",
+ "updateTime": "2023-11-23T08:55:46.000Z",
+ "uuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3",
+ "name": "My Storage Bucket",
+ "description": "For storing my images and videos",
+ "size": 23576
+ },
+ ...
+ ],
+ "total": 2
+}
+
storage list-objects
Retrieves objects (files and folders) from a specific bucket or bucket directory.
Options
-b, --bucket-uuid <string>
: UUID of the bucket to retrieve objects from.-d, --directory-uuid <string>
: UUID of the directory to retrieve objects from (optional, default root folder).--deleted
: Include objects deleted from the bucket.Example
apillon storage list-objects --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --directory-uuid "987e6543-e21c-32f1-b123-426655441111"
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-23T08:55:45.000Z",
+ "updateTime": "2023-11-23T08:55:46.000Z",
+ "uuid": "14a7a891-877c-41ac-900c-7382347e1e77",
+ "name": "index.html",
+ "CID": "bafybeidzrd7p5ddj67j2mud32cbnze2c7b2pvbhn...",
+ "status": "AVAILABLE_ON_IPFS_AND_REPLICATED",
+ "directoryUuid": null,
+ "type": "FILE",
+ "link": "https://ipfs.apillon.io/ipfs/bafybeidzrd7p5ddj67j...",
+ "path": null,
+ "bucketUuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3"
+ },
+ ...
+ ],
+ "total": 16
+}
+
storage list-files
Retrieves files from a specific bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket to retrieve files from.-s, --file-status <integer>
: Filter by file status (FileStatus enum, optional).Available choices:
UPLOAD_REQUEST_GENERATED = 1
+UPLOADED = 2
+AVAILABLE_ON_IPFS = 3
+AVAILABLE_ON_IPFS_AND_REPLICATED = 4
+
Example
apillon storage list-files --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" -s 2
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-15T09:58:04.000Z",
+ "updateTime": "2023-11-15T09:58:10.000Z",
+ "name": "style.css",
+ "CID": "bafybeidzrd7p5ddj67j2mud32cbnze2c7b2pvbhn...",
+ "status": "AVAILABLE_ON_IPFS_AND_REPLICATED",
+ "directoryUuid": null,
+ "type": "FILE",
+ "link": "https://ipfs.apillon.io/ipfs/bafybeidzrd7p...",
+ "path": null,
+ "bucketUuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3"
+ },
+ ...
+ ],
+ "total": 10
+}
+
storage upload
Upload contents of a local folder to specified bucket.
Options
<folder-path>
: Path to the folder containing your files.-b, --bucket-uuid <string>
: UUID of the bucket to upload files to.-w, --wrap
: Wrap uploaded files to an IPFS directory-p, --path <string>
: Path to upload files to (e.g. main/subdir). Required when --wrap is supplied.--await
: await file CIDs to be resolvedExample
apillon storage upload ./my_folder --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --wrap --path "main/subdir"
+
storage get-file
Retrieves information about a specific file in a bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-f, --file-uuid <string>
: UUID or CID of the file to retrieve.Example
apillon storage get-file --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --file-uuid "file_uuid_or_cid"
+
storage delete-file
Deletes a specific file from a bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-f, --file-uuid <string>
: UUID or CID of the file to delete.Example
apillon storage delete-file --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --file-uuid "file_uuid_or_cid"
+
storage delete-directory
Delete a directory from a storage bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-d, --directory-uuid <string>
: UUID of the directoru to delete.Example
apillon storage delete-directory --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --directory-uuid "2c84048c-49a1-4ed2-9e1e-8920806ae968"
+
storage ipns list
Lists all IPNS records for a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.Example
apillon storage ipns list --bucket-uuid "123e4567-e89b-12d3-a456-426655440000"
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-12-06T12:29:09.000Z",
+ "updateTime": "2023-12-06T12:29:21.000Z",
+ "uuid": "80383a54-1d86-4761-a5e4-26a2fab474c9",
+ "name": "Images IPNS",
+ "description": "IPNS for images folder",
+ "ipnsName": "k2k4r8jp1jnlbe3qv...",
+ "ipnsValue": "/ipfs/QmUz4...",
+ "link": "https://ipfs.apillon.io/ipns/k2k4r8jp1jnlbe3qv...",
+ "bucketUuid": "a26184d7-acf5-4d6c-9195-465e3a7a5240"
+ },
+ {
+ "createTime": "2023-12-06T12:29:37.000Z",
+ "updateTime": "2023-12-06T12:29:52.000Z",
+ "uuid": "2045db5b-b347-4ea6-a4c0-4445e071180d",
+ "name": "JSON IPNS",
+ "description": "IPNS for metadata folder",
+ "ipnsName": "k2k4r8opkl3i2zq7bin8lis4...",
+ "ipnsValue": "/ipfs/QmUz5Z6RcMynfZWoC...",
+ "link": "https://ipfs.apillon.io/ipns/k2k4r8opkl3i2z...",
+ "bucketUuid": "a26184d7-acf5-4d6c-9195-465e3a7a5240"
+ }
+ ],
+ "total": 2
+}
+
storage ipns create
Creates a new IPNS record for a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-n, --name <name>
: Name of the IPNS record.-d, --description <description>
: Description of the IPNS record (optional).-c, --cid <cid>
: CID to which this IPNS name will point.Example
apillon storage ipns create --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --name "my-ipns-record" --cid "QmWX5CcNvnaVmgGBn4o82XW9uW1uLvsHQDdNrANrQeSdXm"
+
storage ipns get
Retrieves information about a specific IPNS record.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.Example
apillon storage ipns get --ipns-uuid "123e4567-e89b-12d3-a456-426655440000"
+
storage ipns publish
Publishes an IPNS record to IPFS and links it to a CID.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.-c, --cid <string>
: CID to which this IPNS name will point.Example
apillon storage ipns publish --ipns-uuid "123e4567-e89b-12d3-a456-426655440000" --cid "QmWX5CcNvnaVmgGBn4o82XW9uW1uLvsHQDdNrANrQeSdXm"
+
storage ipns delete
Deletes an IPNS record from a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.Example
apillon storage ipns delete --ipns-uuid "123e4567-e89b-12d3-a456-426655440000"
+
nfts list-collections
Lists all NFT collections owned by the project related to the API key.
Options
--status <integer>
: UUID of the collection to retrieve (CollectionStatus enum, optional).Available choices:
CREATED = 0
+DEPLOY_INITIATED = 1
+DEPLOYING = 2
+DEPLOYED = 3
+TRANSFERRED = 4
+FAILED = 5
+
Example
apillon nfts list-collections --status 3
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-20T10:21:12.000Z",
+ "updateTime": "2023-11-20T14:12:33.000Z",
+ "uuid": "2cda3a9b-01b1-4b5e-9709-7087129d55d0",
+ "symbol": "SE",
+ "name": "SpaceExplorers",
+ "description": "A collection of unique space exploration NFTs.",
+ "collectionType": "GENERIC",
+ "maxSupply": 1000,
+ "baseUri": "https://moonbeamnfts.com/collections/spaceexplorers/",
+ "baseExtension": ".json",
+ "isSoulbound": false,
+ "isRevokable": false,
+ "drop": false,
+ "dropPrice": 0.05,
+ "dropStart": 1679875200,
+ "dropReserve": 100,
+ "royaltiesFees": 5,
+ "royaltiesAddress": "0xaz5Bh6E56c5d3B58c944542de2bF18E7F65eED82",
+ "collectionStatus": "TRANSFERRED",
+ "contractAddress": "0x4e22162A6d0c91a088Cb57A72aB976ccA2A96B25",
+ "transactionHash": null,
+ "deployerAddress": "0xba015fgc6d80378a9a95f1687e9960857593983b",
+ "chain": "MOONBASE"
+ }
+ ],
+ "total": 1
+}
+
nfts get-collection
Retrieves information about a specific NFT collection.
Options
--uuid <collection-uuid>
: UUID of the collection to retrieve.Example
apillon nfts get-collection --uuid "123e4567-e89b-12d3-a456-426655440000"
+
nfts create-collection
Options
<file-path>
: Path to the JSON data file for the new collection.Example
apillon nfts create-collection ./nft-data.json
+
nfts mint-nft
Mints NFTs for a collection with a specific UUID.
Options
--uuid <collection-uuid>
: UUID of the collection to mint NFTs to.-a, --address <string>
: Address which will receive minted NFTs.-q --quantity <integer>
: Number of NFTs to mint. (default 1).Example
apillon nfts mint-nft --uuid "123e4567-e89b-12d3-a456-426655440000" --address "0xdAC17F958D2ee523a2206206994597C13D831ec7" --quantity 2
+
nfts nest-mint-nft
Nest mints NFT child collection to a parent collection with a specific UUID and parent NFT with id.
Options
-c, --parent-collection-uuid <collection-uuid>
: Parent collection UUID to which child NFTs will be minted to.-p, --parent-nft-id <string>
: Parent collection NFT id to which child NFTs will be minted to.-q, --quantity <integer>
: Number of child NFTs to mint (default 1).Example
apillon nfts nest-mint-nft --parent-collection-uuid "123e4567-e89b-12d3-a456-426655440000" --parent-nft-id 5 --quantity 2
+
nfts burn-nft
Burns an NFT for a collection with a specific UUID.
Options
--uuid <collection-uuid>
: Collection UUID.-t, --token-id <integer>
: NFT id which will be burned.Example
apillon nfts burn-nft --uuid "123e4567-e89b-12d3-a456-426655440000" --token-id 123
+
nfts transfer-collection
Transfers NFT collection ownership to a new wallet address.
Options
--uuid <collection-uuid>
: Collection UUID.-a, --address <string>
: Address which you want to transfer collection ownership to.Example
apillon nfts transfer-collection --uuid "123e4567-e89b-12d3-a456-426655440000" --address "0xdAC17F958D2ee523a2206206994597C13D831ec7"
+
nfts list-transactions
Lists NFT transactions for a specific collection UUID.
Options
--uuid <collection-uuid>
: Collection UUID.--status <integer>
: Transaction status (TransactionStatus enum, optional).Available choices:
PENDING = 1
+CONFIRMED = 2
+FAILED = 3
+ERROR = 4
+
--type <integer>
: Transaction type (TransactionType enum, optional).Available choices:
DEPLOY_CONTRACT = 1
+TRANSFER_CONTRACT_OWNERSHIP = 2
+MINT_NFT = 3
+SET_COLLECTION_BASE_URI = 4
+BURN_NFT = 5
+NEST_MINT_NFT = 6
+
Example
apillon nfts list-transactions --uuid "123e4567-e89b-12d3-a456-426655440000"
+
Example response
{
+ "items": [
+ {
+ "createTime": "2023-11-20T10:21:22.000Z",
+ "updateTime": "2023-11-20T10:23:31.000Z",
+ "chainId": "MOONBEAM",
+ "transactionType": "DEPLOY_CONTRACT",
+ "transactionStatus": "CONFIRMED",
+ "transactionHash": "0xab99e630f9475df92768b1e5d73f4..."
+ },
+ {
+ "createTime": "2023-11-20T11:55:13.000Z",
+ "updateTime": "2023-11-20T11:57:31.000Z",
+ "chainId": "MOONBEAM",
+ "transactionType": "MINT_NFT",
+ "transactionStatus": "CONFIRMED",
+ "transactionHash": "0x1ecfeeaeddfa0a39fc2ae1ec755d27..."
+ },
+ ...
+ ],
+ "total": 4
+}
+
CLI is particularly useful for CI/CD builds and pipelines.
Here's an example of how you can use the CLI tool in a CI/CD tool like GitHub Actions:
name: Deploy Website
+
+on:
+ push:
+ branches:
+ - master
+
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: 16
+
+ - name: Create dist folder
+ run: mkdir -p dist
+
+ - name: Copy files
+ run: |
+ cp *.html dist/
+ cp -r images dist/
+ cp -r style dist/
+ cp -r js dist/
+
+ ####
+ ## if you are using a framework for building web app, you can replace previous two step with the
+ ## appropriate command for generating static webpage, like the example below.
+ ## Find the correct command in your framework documentation. You may need to change the
+ ## name of the source folder in the last step (CLI call)
+ ####
+ # - name: Build app
+ # run: npm run build
+ - name: Deploy website
+ env:
+ APILLON_API_KEY: ${{ secrets.APILLON_API_KEY }}
+ APILLON_API_SECRET: ${{ secrets.APILLON_API_SECRET }}
+ WEBSITE_UUID: ${{ secrets.WEBSITE_UUID }}
+ run: npx --yes @apillon/cli hosting deploy-website ./dist --uuid $WEBSITE_UUID --key $APILLON_API_KEY --secret $APILLON_API_SECRET
+ # Or alternatively you can use the run configuration below
+ # run: |
+ # npm i -g @apillon/cli
+ # apillon hosting deploy-website ./dist --uuid $WEBSITE_UUID --key $APILLON_API_KEY --secret $APILLON_API_SECRET
+
In this example, the GitHub Actions workflow is triggered when a push event occurs on the master branch. The workflow performs the following steps:
Make sure to setup secret variables with the values from Apillon platform.
That's it! You can now use this example as a starting point to deploy your website using the CLI tool in a CI/CD pipeline with GitHub Actions.
`,50),T={href:"https://github.com/Apillon/website-deploy-example/blob/main/.github/workflows/deploy.yml",target:"_blank",rel:"noopener noreferrer"};function _(w,A){const a=i("ExternalLinkIcon");return p(),l("div",null,[c,s("p",null,[s("a",u,[d,e(a)]),s("a",v,[b,e(a)])]),k,m,s("p",null,[n("To be able to use Apillon CLI, you must register an account at "),s("a",g,[n("Apillon.io"),e(a)]),n(", create a project and generate an API key with appropriate permissions. Also Node.js (version 16 or later) is required.")]),h,s("blockquote",null,[s("p",null,[n("For example responses and for an overview of all properties, refer to "),s("a",q,[n("the Apillon API wiki"),e(a)]),n(". Note: CLI responses may be different from API responses.")])]),f,s("p",null,[n("Creates a new NFT collection. The JSON file needs to have the property structure as type "),s("a",y,[n("ICreateCollection"),e(a)]),n(" for EVM and "),s("a",I,[n("ICreateSubstrateCollection"),e(a)]),n(" for Substrate collections. An example object can be also seen on the "),s("a",x,[n("NFT SDK docs"),e(a)]),n(".")]),E,s("p",null,[n("You can also check a working example on "),s("a",T,[n("Github"),e(a)])])])}const D=o(r,[["render",_],["__file","6-apillon-cli.html.vue"]]);export{D as default}; diff --git a/assets/6-apillon-cli.html-53b63dbe.js b/assets/6-apillon-cli.html-53b63dbe.js new file mode 100644 index 00000000..c2cadf76 --- /dev/null +++ b/assets/6-apillon-cli.html-53b63dbe.js @@ -0,0 +1 @@ +const l=JSON.parse('{"key":"v-6c04f07e","path":"/build/6-apillon-cli.html","title":"Apillon CLI","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Requirements","slug":"requirements","link":"#requirements","children":[]},{"level":2,"title":"Installation","slug":"installation","link":"#installation","children":[{"level":3,"title":"Global Options","slug":"global-options","link":"#global-options","children":[]},{"level":3,"title":"Environment Variables","slug":"environment-variables","link":"#environment-variables","children":[]},{"level":3,"title":"Help","slug":"help","link":"#help","children":[]},{"level":3,"title":"List pagination options","slug":"list-pagination-options","link":"#list-pagination-options","children":[]}]},{"level":2,"title":"Hosting Commands","slug":"hosting-commands","link":"#hosting-commands","children":[]},{"level":2,"title":"Storage Commands","slug":"storage-commands","link":"#storage-commands","children":[{"level":3,"title":"IPNS Commands","slug":"ipns-commands","link":"#ipns-commands","children":[]}]},{"level":2,"title":"NFT Commands","slug":"nft-commands","link":"#nft-commands","children":[]},{"level":2,"title":"Using in CI/CD tools","slug":"using-in-ci-cd-tools","link":"#using-in-ci-cd-tools","children":[{"level":3,"title":"Deploying websites","slug":"deploying-websites","link":"#deploying-websites","children":[]}]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"build/6-apillon-cli.md"}');export{l as data}; diff --git a/assets/6-web3-social.html-a1e42f4b.js b/assets/6-web3-social.html-a1e42f4b.js new file mode 100644 index 00000000..31965015 --- /dev/null +++ b/assets/6-web3-social.html-a1e42f4b.js @@ -0,0 +1 @@ +import{_ as n,r,o as c,c as s,b as a,e,d as o,a as i}from"./app-e8b865be.js";const l={},h=a("h1",{id:"web3-social",tabindex:"-1"},[a("a",{class:"header-anchor",href:"#web3-social","aria-hidden":"true"},"#"),e(" Web3 Social")],-1),d={href:"https://subsocial.network/",target:"_blank",rel:"noopener noreferrer"},p={href:"https://grillapp.net/c/hot-chats",target:"_blank",rel:"noopener noreferrer"},u=i('You can create the chat rooms via Apillon dashboard and integrate the grill chat widget into your page via html
and javascript
. You can also manage your chat rooms via API and SDK for simple on the fly creation.
You can create a single chat room or a hub containing multiple chat rooms.
Hub A hub is a container of multiple chat rooms. When integrating the grill chat widget you can either show a single chat or a whole hub containing multiple chat rooms that the end user selects to chat in.
Channel Channel is the actual chat room the users can talk in. s
',5);function g(_,b){const t=r("ExternalLinkIcon");return c(),s("div",null,[h,a("p",null,[e("Apillon offers web3 alternatives for social networking between end users. This is powered by "),a("a",d,[e("subsocial network"),o(t)]),e(".")]),a("p",null,[e("Currently, Apillon offers a web3 chat alternative called "),a("a",p,[e("grill chat"),o(t)]),e(" that allows anonymous chatting in which content can be displayed anywhere integrating the subsocial grill chat.")]),u])}const f=n(l,[["render",g],["__file","6-web3-social.html.vue"]]);export{f as default}; diff --git a/assets/6-web3-social.html-fc24a382.js b/assets/6-web3-social.html-fc24a382.js new file mode 100644 index 00000000..9e6689de --- /dev/null +++ b/assets/6-web3-social.html-fc24a382.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-592c909e","path":"/web3-services/6-web3-social.html","title":"Web3 Social","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Chat","slug":"chat","link":"#chat","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"web3-services/6-web3-social.md"}');export{e as data}; diff --git a/assets/6-web3-up-close.html-6cf560b5.js b/assets/6-web3-up-close.html-6cf560b5.js new file mode 100644 index 00000000..79b23fa9 --- /dev/null +++ b/assets/6-web3-up-close.html-6cf560b5.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-da41cf52","path":"/about/6-web3-up-close.html","title":"Web3 and Apillon explained","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Polkadot, a complete service stack for Web3 builders","slug":"polkadot-a-complete-service-stack-for-web3-builders","link":"#polkadot-a-complete-service-stack-for-web3-builders","children":[{"level":3,"title":"Evolution of blockchain applications","slug":"evolution-of-blockchain-applications","link":"#evolution-of-blockchain-applications","children":[]},{"level":3,"title":"Polkadot offers flexibility and more","slug":"polkadot-offers-flexibility-and-more","link":"#polkadot-offers-flexibility-and-more","children":[]},{"level":3,"title":"Room for improvement","slug":"room-for-improvement","link":"#room-for-improvement","children":[]}]},{"level":2,"title":"Glossary","slug":"glossary","link":"#glossary","children":[{"level":3,"title":"The world of Web3","slug":"the-world-of-web3","link":"#the-world-of-web3","children":[]},{"level":3,"title":"Polkadot Network","slug":"polkadot-network","link":"#polkadot-network","children":[]},{"level":3,"title":"The Apillon platform","slug":"the-apillon-platform","link":"#the-apillon-platform","children":[]},{"level":3,"title":"Read more","slug":"read-more","link":"#read-more","children":[]}]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/6-web3-up-close.md"}');export{e as data}; diff --git a/assets/6-web3-up-close.html-fa81e3ac.js b/assets/6-web3-up-close.html-fa81e3ac.js new file mode 100644 index 00000000..d8c29f80 --- /dev/null +++ b/assets/6-web3-up-close.html-fa81e3ac.js @@ -0,0 +1 @@ +import{_ as l,r as s,o as d,c as h,b as e,e as a,d as t,w as i,a as r}from"./app-e8b865be.js";const c={},p=r('Polkadot is a “blockchain of blockchains,” allowing many different types of chains to work and interact securely together within the same ecosystem. The network has already contributed great promise and significant progress by encouraging individual sovereignty over personal and business data. And more importantly, the integration of diverse parachains into a scalable and flexible network set a new standard for Web3 builders.
Bitcoin - the very first application of blockchain. Soon, the potential to create other decentralized applications grew big. Through the need for improved tools and technological basis, the next-gen blockchain upgrade sprouted in the form of the Ethereum network. A smart-contract-based technology made it possible to exchange value besides just the currency and gave way for developers to build and deploy dapps on top of Ethereum.
Ethereum - using the one-network-serves-all model resulted in limitations like flexibility, scalability, and sovereignty. While building dapps on Ethereum proved beneficial for many industry verticals and demonstrated innovations increase, the mass-scale adoption still fell behind because of the rigid network system and limited scalability of transactions.
The Polkadot network is becoming the forefront of a scalable Web3 universe-building and mass adoption of blockchain – by connecting different blockchains into one unified network. Unlike layer-1 blockchains, layer 0 of Polkadot allows for multiple layer-1 blockchains to be built on top of it. The Polkadot team even created a framework called Substrate, where developers can build blockchains that work independently from one another.
Polkadot’s layer 0, or the so-called relay chain, executes minimal basic actions in terms of network security and makes the communication between chains possible. The blockchains as parachains design their own governance structures, fine-tune their functionalities, and (usually) serve a specific use case purpose.
It’s a win-win situation:
Parachains have more flexibility in building the architecture and therefore contribute better, more specialized services with improved efficiency. Polkadot as an ecosystem offers higher scalability by processing transactions on different chains in parallel and gives way for more innovation due to more specialized parachains.
Polkadot is currently the leading, highest value, and most secure proof-of-stake platform. Nevertheless, every technology’s success can benefit from a reliable support system that can enhance its adoption and bring it to the masses. Each innovation is only as strong as its community of users.
Web3 developers still face considerable challenges when building on Web3. Polkadot offers an excellent foundation, but there’s still enormous amounts of time that need to be invested in the research and development by the builders.
By making Web3 easier to build on, the Apillon platform will assist in the adoption of use-case-specific Polkadot parachains and bring the utility of Web3 to enterprises and end-users that would benefit from (at least partially) blockchain-based processes.
Web3 is a next-generation, decentralized, and democratic version of the web where the way users control and exchange their data is redefined to empower them to partake in the building of the web, take ownership of their data and identity, as well as co-govern the processes. Web3 is built upon an infrastructure that incorporates blockchain technology and decentralized means of data and asset exchange.
Smart contracts are digital automatic agreements that are stored on a blockchain. Secure and trustless programs that execute functions when pre-determined terms and conditions are met, smart contracts deliver transparency, accuracy, and efficiency. At a basic level, smart contracts follow "if/when… then" statements that are written into code.
In a decentralized network, there is no single central authority that controls all data and governs the processes of data and asset exchange. Instead, a decentralized network is controlled by the pre-determined logic that’s written into code on the blockchain. As the code is stored on a decentralized network of nodes around the globe, this delivers an infrastructure that enables peer-to-peer data and asset exchange, which can allow users to regain control over their data and identity.
Nodes create, receive, and communicate information that they then store or relay to other nodes. The definition of a node is directly tied to the type of network it participates in – in a blockchain network, blockchain nodes are devices, usually computers, that run the blockchain’s software to validate and broadcast transactions as well as secure the network. Blockchain nodes communicate with each other, and the more nodes there are, the more decentralized the blockchain network is.
A decentralized application (dapp) is built upon a decentralized system for executing its operations. Its backend code runs on a decentralized network, usually a blockchain, instead of a centralized server. This means the operations are inherently immutable, irreversible, and sealed on the decentralized network. The app’s data and files, for example, can be hosted and stored on a decentralized network of nodes – once deployed, the files can’t be taken down or tampered with.
The word ‘trustless’ describes the online exchange of data and assets in Web3 that puts trust into the logic of the code in the backend instead of a single central authority. The core infrastructure of Web3 is controlled by the code in the backend, which eliminates the need to trust third-party service providers or big tech to manage the exchange of data and assets between the users.
Contrary to files, websites, or apps that are stored and hosted on central servers with a single point of access and failure, decentralized or Web3-based assets, websites, or apps can be stored and hosted on a global decentralized network of nodes. This defies single censorship, tampering, or single-point attacks, making them unstoppable.
Polkadot is a sharded blockchain. Connecting several blockchains into a unified network, the Polkadot Network allows the separate chains to securely process transactions and exchange data at the same time. Each chain can be optimized for a specific use case while still being able to communicate with the other chains in the network. This unique model is called Polkadot’s heterogeneous sharding model.
The relay chain is Polkadot’s main chain that executes minimal basic actions to ensure network security. It also enables communications between (para)chains.
Parachains are different Polkadot blockchains that connect to the main relay chain. With their own governance structures and different functionalities, parachains serve a specific use case, yet they are able to communicate with each other. The ability of Polkadot’s ecosystem to process transactions on different chains in parallel delivers high scalability.
Web3 project is a website, program, or app that’s built using decentralized technologies. Even standard Web2 projects can be upgraded to the Web3-level by making small changes and incorporating blockchain technology. The Apillon platform makes building Web3 projects simpler and faster.
A freemium business model offers basic services free of charge, while a premium is charged for the more advanced services and features. Currently, all features available on the Apillon platform are free of charge. In the later stages, the basic Web3 services will remain free, while the more advanced features will be available through unified stable pricing.
Certain tokens can be staked by locking them up for a period of time for various reasons, e.g. to support the operation of a Web3 project or network, in exchange for a reward, typically an interest on the staked amount.
To initiate the OAuth flow for the user, use the following code to open Apillon's OAuth website as a pop-up and prompt your users to complete the OAuth flow. The session token passed as a query parameter is obtained from the Apillon API (see Server section below).
Additionally, an event listener is added for the main app/website to handle the successful completion of the OAuth flow by the user, which grants an authentication token to the user. The token is then used to verify the login through Apillon's API, which finally returns the user's email address on Apillon.
async function openOAuthPopup() {
+ const sessionToken = await getAuthToken();
+ oAuthWindow = window.open(
+ \`https://oauth.apillon.io/?embedded=1&token=\${sessionToken}\`,
+ 'Apillon OAuth Form',
+ \`height=\${900} width=\${450} resizable=no\`
+ );
+}
+
+window.addEventListener('message', async event => {
+ if (!event.origin?.includes('apillon.io')) return;
+
+ if (!event.data.verified) {
+ throw new Error('Invalid OAuth verification');
+ }
+ // Close OAuth popup window
+ oAuthWindow?.close();
+
+ verifyUserLogin(event.data.authToken);
+}, false);
+
The server-side part of the OAuth implementation contains the logic to query the Apillon API, obtain a session token to initiate the OAuth flow, and verify the user log-in when the flow is finished.
Obtain a session token from the Apillon API to interact with Apillon's OAuth protocol.
`,8),T={class:"split_content"},P={class:"split_side"},j=n("br",null,null,-1),x=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"curl"),s(),n("span",{class:"token parameter variable"},"--location"),s(),n("span",{class:"token parameter variable"},"--request"),s(" GET "),n("span",{class:"token string"},'"https://api.apillon.io/auth/session-token"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +`),n("span",{class:"token parameter variable"},"--header"),s(),n("span",{class:"token string"},'"Authorization: Basic :credentials"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +`),n("span",{class:"token parameter variable"},"--header"),s(),n("span",{class:"token string"},'"Content-Type: application/json"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),C={class:"split_side"},E=n("br",null,null,-1),G=n("div",{class:"language-json line-numbers-mode","data-ext":"json"},[n("pre",{class:"language-json"},[n("code",null,[n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token property"},'"id"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"0da29b5a-8a8b-473b-9f97-3183819263f4"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token property"},'"status"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token number"},"200"),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token property"},'"data"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token property"},'"sessionToken"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"eyJhbGciOiJIUzI1..."'),s(` + `),n("span",{class:"token punctuation"},"}"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),S=n("h3",{id:"verify-user-login",tabindex:"-1"},[n("a",{class:"header-anchor",href:"#verify-user-login","aria-hidden":"true"},"#"),s(" Verify user login")],-1),U=n("p",null,`After the user has completed the OAuth flow, verify they have successfully logged in with the generated OAuth token from the "message" event handler. As a response, receive the user's Apillon email address.`,-1),L={class:"split_content"},q={class:"split_side"},z=n("br",null,null,-1),B=n("div",{class:"language-bash line-numbers-mode","data-ext":"sh"},[n("pre",{class:"language-bash"},[n("code",null,[n("span",{class:"token function"},"curl"),s(),n("span",{class:"token parameter variable"},"--location"),s(),n("span",{class:"token parameter variable"},"--request"),s(" POST "),n("span",{class:"token string"},'"https://api.apillon.io/auth/verify-login"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +`),n("span",{class:"token parameter variable"},"--header"),s(),n("span",{class:"token string"},'"Authorization: Basic :credentials"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +`),n("span",{class:"token parameter variable"},"--header"),s(),n("span",{class:"token string"},'"Content-Type: application/json"'),s(),n("span",{class:"token punctuation"},"\\"),s(` +--data-raw `),n("span",{class:"token string"},[s(`"{ + `),n("span",{class:"token entity",title:'\\"'},'\\"'),s("token"),n("span",{class:"token entity",title:'\\"'},'\\"'),s(": "),n("span",{class:"token entity",title:'\\"'},'\\"'),s("eyJhbGciOiJIUzI1..."),n("span",{class:"token entity",title:'\\"'},'\\"'),s(` +}"`)]),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1),J={class:"split_side"},N=n("br",null,null,-1),V=n("div",{class:"language-json line-numbers-mode","data-ext":"json"},[n("pre",{class:"language-json"},[n("code",null,[n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token property"},'"id"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"de2cf1e7-0dfe-4378-ab77-98cbc9a00496"'),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token property"},'"status"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token number"},"200"),n("span",{class:"token punctuation"},","),s(` + `),n("span",{class:"token property"},'"data"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token punctuation"},"{"),s(` + `),n("span",{class:"token property"},'"email"'),n("span",{class:"token operator"},":"),s(),n("span",{class:"token string"},'"apillon-user@mail.com"'),s(` + `),n("span",{class:"token punctuation"},"}"),s(` +`),n("span",{class:"token punctuation"},"}"),s(` +`)])]),n("div",{class:"line-numbers","aria-hidden":"true"},[n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"}),n("div",{class:"line-number"})])],-1);function K(R,Y){const t=l("ExternalLinkIcon"),p=l("CodeDiv"),o=l("CodeGroupItem"),i=l("CodeGroup");return r(),u("div",null,[k,n("p",null,[s("You can easily integrate Apillon's OAuth protocol into your own project or website. If you don't have an Apillon account or project already, get started on the "),n("a",v,[s("Apillon dashboard"),a(t)]),s(".")]),n("p",null,[s("Once you have created a project, navigate to the project's "),n("a",m,[s("API keys"),a(t)]),s(" section in your project settings. Generate an API key for the Authentication service with the "),b,s(" permission. This API key will be used to interact with Apillon's API, generate an OAuth session, and verify a user log-in. Make sure you store your API key and your API key secret in a secure manner.")]),_,n("ol",null,[n("li",null,[n("p",null,[g,s(" If you don't have an Apillon account or project yet, create one on the "),n("a",f,[s("Apillon dashboard"),a(t)]),s(".")])]),n("li",null,[n("p",null,[y,s(" Go to your project's settings and navigate to the "),n("a",A,[s("API keys section"),a(t)]),s(". Generate an API key for the Authentication service with the KEY_EXECUTE permission.")])]),w]),n("blockquote",null,[n("p",null,[s("For a complete NodeJS demo of the whole OAuth flow, refer to "),n("a",I,[s("this Github repo"),a(t)])])]),O,a(p,null,{default:e(()=>[s("GET /auth/session-token")]),_:1}),n("div",T,[n("div",P,[j,a(i,null,{default:e(()=>[a(o,{title:"cURL",active:""},{default:e(()=>[x]),_:1})]),_:1})]),n("div",C,[E,a(i,null,{default:e(()=>[a(o,{title:"Response"},{default:e(()=>[G]),_:1})]),_:1})])]),S,U,a(p,null,{default:e(()=>[s("POST /auth/verify-login")]),_:1}),n("div",L,[n("div",q,[z,a(i,null,{default:e(()=>[a(o,{title:"cURL",active:""},{default:e(()=>[B]),_:1})]),_:1})]),n("div",J,[N,a(i,null,{default:e(()=>[a(o,{title:"Response"},{default:e(()=>[V]),_:1})]),_:1})])])])}const D=c(h,[["render",K],["__file","7-apillon-oauth-integration.html.vue"]]);export{D as default}; diff --git a/assets/7-community.html-41b148c0.js b/assets/7-community.html-41b148c0.js new file mode 100644 index 00000000..f2390aa4 --- /dev/null +++ b/assets/7-community.html-41b148c0.js @@ -0,0 +1 @@ +const o=JSON.parse('{"key":"v-929e013e","path":"/about/7-community.html","title":"Community","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Join Apillon Community","slug":"join-apillon-community","link":"#join-apillon-community","children":[]},{"level":2,"title":"Polkadot Treasury Proposal","slug":"polkadot-treasury-proposal","link":"#polkadot-treasury-proposal","children":[{"level":3,"title":"Common good and open source","slug":"common-good-and-open-source","link":"#common-good-and-open-source","children":[]},{"level":3,"title":"Proposal: Apillon, Polkadot, Web3","slug":"proposal-apillon-polkadot-web3","link":"#proposal-apillon-polkadot-web3","children":[]}]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/7-community.md"}');export{o as data}; diff --git a/assets/7-community.html-daedf890.js b/assets/7-community.html-daedf890.js new file mode 100644 index 00000000..0f1c3c74 --- /dev/null +++ b/assets/7-community.html-daedf890.js @@ -0,0 +1,98 @@ +import{_ as i,r,o as s,c as l,b as e,e as o,d as t,f as d,a}from"./app-e8b865be.js";const p={},h=a('Become part of the Apillon community and stay up to date with the latest news.
',4),c={href:"https://twitter.com/apillon",target:"_blank",rel:"noopener noreferrer"},u={href:"https://discord.gg/yX3gTw36C4",target:"_blank",rel:"noopener noreferrer"},m={href:"https://t.me/Apillon",target:"_blank",rel:"noopener noreferrer"},f={href:"https://www.reddit.com/r/apillon/",target:"_blank",rel:"noopener noreferrer"},g={href:"https://blog.apillon.io",target:"_blank",rel:"noopener noreferrer"},b={href:"https://www.linkedin.com/company/apillon",target:"_blank",rel:"noopener noreferrer"},w={href:"https://www.youtube.com/channel/UCH5DxaOQ1cdCgNb_nk-5_ug/about",target:"_blank",rel:"noopener noreferrer"},y={href:"https://github.com/Apillon",target:"_blank",rel:"noopener noreferrer"},v=e("h2",{id:"polkadot-treasury-proposal",tabindex:"-1"},[e("a",{class:"header-anchor",href:"#polkadot-treasury-proposal","aria-hidden":"true"},"#"),o(" Polkadot Treasury Proposal")],-1),A={href:"https://blog.apillon.io/apillon-aims-to-foster-web3-adoption-as-a-common-good-infrastructure-solution-on-polkadot-6566508190c5",target:"_blank",rel:"noopener noreferrer"},k=a('Backed by Polkadot Treasury funding and community support, the Apillon platform would transition to an open-source product with permanent freemium access and community governance. By becoming a common good project, Apillon would help spur Web3 adoption, Polkadot ecosystem growth, and DOT utility.
Here are the most frequent questions and answers to help you navigate and understand the weight of the proposal.
Polkadot’s common good and open-source approach aims to innovate services that benefit projects and users across the whole ecosystem.
With many new protocol-layer projects regularly developed on Polkadot, the ecosystem is in dire need of an application-layer solution that would allow developers to easily onboard the Polkadot ecosystem and bring Web3 to a mainstream level.
With Apillon transforming into a common good solution, the Polkadot ecosystem would get a forever-freemium Web3 development platform. Every new user on the Apillon platform would mean a new developer for Polkadot, boosting the adoption of Web3 technologies. Through DOT-based governance, the Polkadot’s native token would get another utility boost and purpose in driving the network’s adoption.
With decentralized governance, existing and new platform users would get to decide on parachain integrations and the evolution of the Apillon platform, thus collaboratively innovating the future of Web3.
Apillon would make a strong commitment to the community and the ecosystem to achieve the set milestones, spend resources as described in the Proposal, and pursue the vision of the developer community.
Apillon’s Proposal for Polkadot’s Treasury funding seeks community support to transform into an open-source infrastructure on Polkadot.
The funding would have the following direct consequences on Apillon:
With operational costs covered by the Treasury for two years, Apillon would be able to incentivize developers with freemium plans at no additional fees.
After the end of the two-year period, Apillon would introduce a price margin on top of parachain service cost. However, this would be non-profitable and controlled via governance, allowing the Apillon team to survive on fees to keep the project alive and in the best possible shape.
Apillon’s Treasury-backed transition to open-source presents a strong obligation towards the community. Therefore, The Freemium plan will remain permanently or until the project’s governance decides otherwise.
In the current stage, three main pillars of Apillon would require implementation of decentralized control:
With DOT-based governance, the developer community would be able to co-decide the development direction of the Apillon platform, making it more agile in addressing market demands.
Apillon’s product governance would address questions such as:
The Apillon platform would further improve the Polkadot ecosystem and the Web3 space with:
Easier, faster, and cheaper Web3 development would bring developers and other stakeholders:
Apillon's contribution to Web3 adoption and the growth of the Polkadot ecosystem is significant and lies in its provision of an open-source common good development platform. A user-friendly and accessible environment for building Web3 applications would attract more developers, including those transitioning from Web2 to Web3. The influx of talent and ideas would fuel the creation of diverse and innovative decentralized applications built on the Polkadot network, leading to increased usage, adoption, and overall ecosystem growth. Additionally, by providing a streamlined development experience and facilitating the integration of various parachains, Apillon's platform contributes to the scalability and interoperability of the network, making it more appealing to developers and users alike.
The backing of Polkadot Treasury funding would tremendously impact the Apillon platform. It would provide financial support and resources to develop further and enhance the platform's capabilities, enabling Apillon to accelerate its efforts in building a robust Web3 infrastructure. The funding support would help Apillon attract top talent, foster innovation, and execute its roadmap effectively, ultimately contributing to the growth and adoption of Web3 technologies within the Polkadot ecosystem.
The opportunity for Apillon to become an open-source common good infrastructure platform on Polkadot opens up opportunities for early contributors, too.
Polkadot Treasury funding of the Apillon two-and-a-half-year development ensures uninterrupted work on both preset and jointly agreed upon milestones to deliver the most requested and needed Web3 services and features to the developer community.
With every developer using the Apillon platform, the Polkadot and Web3 ecosystems gain a new contributor. Faster growth of Apillon means accelerated expansion and collaboration of both established and up-and-coming Web3 projects.
In addition to the financial aspect, Polkadot Treasury would provide a much-appreciated approval from the wider Web3 community, acknowledging Apillon as the go-to Web3 development platform - that would significantly increase the future value of the project.
Apillon has always greatly appreciated the community support and trust in the project.
At this early point of the referendum process, the benefits for early investors are still undefined. The Apillon team kindly asks for everyone’s patience while the optimal options for the community are being explored.
One of Proposal’s main points is Apillon transitioning to DOT-based governance and operations. Hence, the launch of the NCTR token is postponed until after the end of the period set in the Proposal.
Field | Type | Description | Required |
---|---|---|---|
contractType | number | Type of the computing contract. Available options: 1 = SCHRODINGER | Yes |
name | string | Name of the computing contract | Yes |
description | string | Description of the computing contract | No |
bucket_uuid | string | UUID of the bucket for storing encrypted files from the computing contract. If this is not provided, a new bucket will be created | No |
Data specific for Schrodinger's NFT contract type
Field | Type | Description | Required |
---|---|---|---|
contractData.nftContractAddress | string | Contract address of the NFT collection whose tokens will be used for file decryption | No |
contractData.nftChainRpcUrl | string | RPC URL of the blockchain the NFT contract resides on | Yes |
contractData.restrictToOwner | boolean | If true, only the owner can encrypt files via the contract (Default: true) | Yes |
Code | Description |
---|---|
40412003 | Bucket from given bucket_uuid param not found |
42200202 | Contract type not present |
42200203 | Contract type not valid |
42200204 | Contract name not present |
42200205 | Contract name not valid (length in range 1-255) |
42200206 | Contract description not valid (length in range 1-1000) |
42200210 | Computing field not present |
42200211 | Computing contract data not valid |
50012003 | Error deploying contract |
Field | Type | Description | Required |
---|---|---|---|
contractStatus | number | 0 (created), 1 (deploy initiated), 2 (deploying), 3 (deployed), 4 (transferring), 5 (transferred), 6 (failed) | No |
Field | Type | Description | Required |
---|---|---|---|
uuid | string | The UUID of the computing contract | Yes |
Based on your request to generate a table for the response fields that matches the structure seen in the bucket API documentation, here is how you can format the response fields for the "Get Computing Contract" section:
Field | Type | Description |
---|---|---|
contractUuid | string | The unique identifier of the computing contract. |
bucketUuid | string | The UUID of the bucket associated with this computing contract, where encrypted files are stored. |
name | string | The name of the computing contract. |
description | string | A description of what the computing contract is used for. |
contractType | number | The type of computing contract. For example, 1 could represent SCHRODINGER. |
contractStatus | number | The current status of the computing contract. Possible values: 0 (created), 1 (deploy initiated), 2 (deploying), 3 (deployed), 4 (transferring), 5 (transferred), 6 (failed) |
contractAddress | string | The blockchain address of the computing contract. This can be null if not yet deployed. |
deployerAddress | string | The address of the entity that deployed the computing contract. |
transactionHash | string | The transaction hash of the contract deployment. This can be null if not yet deployed. |
data | object | An object containing additional data related to the computing contract. |
data.nftContractAddress | string | The contract address of the NFT collection used for file decryption. |
data.nftChainRpcUrl | string | The RPC URL of the blockchain where the NFT contract resides. |
data.restrictToOwner | boolean | Indicates if only the owner can encrypt and decrypt files via the contract. |
data.ipfsGatewayUrl | string | The URL of the IPFS gateway used by the computing contract. |
data.clusterId | string | An identifier for the cluster used by the computing contract. |
Field | Type | Description | Required |
---|---|---|---|
uuid | string | The UUID of the computing contract | Yes |
Field | Type | Description | Required |
---|---|---|---|
transactionType | number | The type of transaction. Possible values: 1 (deploy contract), 2 (transfer contract ownership), 3 (deposit to contract cluster), 4 (assign cid to nft) | |
transactionStatus | number | The current status of the transaction. Possible values: 1 (pending), 2 (confirmed), 3 (failed), 4 (error), 5 (worker success), 6 (worker failed) |
Field | Type | Description |
---|---|---|
status | number | The status code of the transaction. |
walletAddress | string | The wallet address which initated the transaction. |
transactionType | number | The type of transaction. Possible values: 1 (deploy contract), 2 (transfer contract ownership), 3 (deposit to contract cluster), 4 (assign cid to nft) |
transactionStatus | number | The current status of the transaction. Possible values: 1 (pending), 2 (confirmed), 3 (failed), 4 (error), 5 (worker success), 6 (worker failed) |
transactionStatusMessage | string | A message providing more details about the transaction status. |
transactionHash | string | The hash of the transaction on the blockchain. |
Field | Type | Description | Required |
---|---|---|---|
uuid | string | The UUID of the computing contract | Yes |
Field | Type | Description | Required |
---|---|---|---|
accountAddress | string | Wallet address of the new owner | Yes |
Code | Description |
---|---|
40012003 | Invalid address to transfer to |
40012004 | Transaction for transfer already exists |
50012004 | Transfer contract server error |
50012009 | Contract not in status 3 (Deployed) |
50012010 | Contract transferring or already transferred |
Success status
Field | Type | Description | Required |
---|---|---|---|
uuid | string | The UUID of the computing contract | Yes |
Field | Type | Description | Required |
---|---|---|---|
content | string | Content to be encrypted. If the content is an image, the format needs to be base64. | Yes |
Code | Description |
---|---|
50012009 | Contract not in status 3 (Deployed) |
50012011 | Encrypt content server error |
The encrypted content, which has been encrypted via the encryption key stored on the schrodinger contract
Field | Type | Description | Required |
---|---|---|---|
uuid | string | The UUID of the computing contract | Yes |
Field | Type | Description | Required |
---|---|---|---|
cid | string | CID of the file where the encrypted content is stored | Yes |
nftId | number | Token ID of the NFT which will be used for decryption | Yes |
Code | Description |
---|---|
50012009 | Contract not in status 3 (Deployed) |
50012012 | Assign CID to NFT server error |
Success status
The NCTR token (pronounced “nectar”) is Apillon’s native utility token and sustains Apillon functionalities when interacting with linked Polkadot parachains and transacting with their protocols.
It represents a uniform means of value exchange in the process of building Web3 projects on the Apillon platform, as it replaces the need to interact with individual tokens of utilized parachains.
For every value-based action on Apillon, the platform manages the utility of parachains’ features in their native tokens in the back end so that developers only deal with NCTR and do not have to worry about acquiring or exchanging other tokens.
The Apillon business model also supports payments in fiat (EUR and USD), further boosting adoption among first-time adopters of Web3. The platform converts it to NCTR to unlock Apillon functionalities.
The tokenomics of the NCTR token and Apillon’s business model rely on decision-making by two main actors:
The NCTR tokenomics are, therefore, built to incentivize both actors and ensure all NCTR holders have a relevant say in the platform’s future and get rewarded for participating in Apillon’s governance.
Developers are the force that drives Web3 and the first group of participants in the Apillon tokenomics. The platform is designed to cater to their ever-evolving needs, respond to their expectations, challenges, and workflows, but also to empower them to voice feedback and impact the course of platform development through governance.
In the vast and ever-evolving field of blockchain technology, it is increasingly challenging for all stakeholders to track all the newly launched projects and evaluate their offerings. To double down on the Web3 research power, Apillon empowers its main users, the developers, to list new service candidates via governance and vote on preferred services to be implemented in the upcoming platform upgrades. Through user-powered governance and a token-curated registry of services, the platform continues to evolve and optimize its offering while preventing any potential censorship.
No Web3 project can stand the test of time and market without community backing. The Apillon community gathers NCTR token holders and Web3 developers. The NCTR token is designed to serve and reward everyone who contributes to the growth of the Apillon platform and boosts Web3 adoption, aligned with Apillon’s primary mission. All NCTR token holders can be Web3 builders, either by developing functional Web3 products or growing the ecosystem, and thus have the right to contribute to the NCTR token pledging and Apillon’s inclusive governance.
The NCTR token is designed to be a multi-purpose and widely used asset, covering a range of utility cases for platform users and community members. NCTR token utilities are spanning across three main pillars:
Each pillar further serves both NCTR Developers and NCTR Holders, offering distinct opportunities for utilizing the NCTR token.
Apillon's product governance does not imply an establishment of Apillon as an end-to-end DAO where participants propose and vote on everything, business decisions included. Instead, the governance aspect is focused on the product, i.e., the Apillon platform, and its narrow scope of user-oriented services and features that participants can help control and upgrade.
The second NCTR token’s utility is aimed at incentivizing both tokenomics actors in various ways while promoting Web3 adoption. Adoption is, therefore, the main measured KPI, and when achieved, NCTR tokens are awarded NCTR to rightful recipients.
Incentivization through NCTR spans several use cases, including proof of adoption (PoA), prebuilt solutions grants, prebuilt solutions marketplace, SDK grands, protocol integration grants, bug bounties, authorship royalties, referral earnings, and many more.
Besides providing few-click-deploy Web3 services and straightforward APIs to integrated parachains, Apillon offers an underlying payments module that simplifies the use of Web3 technologies. The payments module removes the need for developers to acquire and maintain a positive balance of tokens to pay for underlying services. This way, Apillon can charge for its services in a traditional Saas model, where users pay monthly subscriptions with fiat using credit cards and unlock access to a fixed amount of Web3 services and features. The secondary path to pay for Apillon services is through the NCTR token. The NCTR token's governance and incentivization utilities of the NCTR token deliver a fantastic opportunity for synergy between NCTR payments and product governance.
The NCTR token is an ERC-20-compatible token minted on the Astar network.
Total supply: 150,000,000 NCTR
Learn more about the NCTR token, its role in the Apillon business model, and general tokenomics.
',31),h={href:"https://go.web3approved.com/tokenomics",target:"_blank",rel:"noopener noreferrer"},p={href:"https://discord.gg/yX3gTw36C4",target:"_blank",rel:"noopener noreferrer"};function u(m,f){const n=i("ExternalLinkIcon");return r(),s("div",null,[d,e("p",null,[e("a",h,[t("Access Apillon's NCTR Tokenomics Whitepaper here"),o(n)])]),e("p",null,[e("a",p,[t("Become a part of the Apillon Community"),o(n)])])])}const v=a(c,[["render",u],["__file","8-nctr-token.html.vue"]]);export{v as default}; diff --git a/assets/8-nctr-token.html-ae4d0c64.js b/assets/8-nctr-token.html-ae4d0c64.js new file mode 100644 index 00000000..8e019aac --- /dev/null +++ b/assets/8-nctr-token.html-ae4d0c64.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-564790ea","path":"/about/8-nctr-token.html","title":"NCTR token","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Tokenomics Actors","slug":"tokenomics-actors","link":"#tokenomics-actors","children":[{"level":3,"title":"NCTR Developers","slug":"nctr-developers","link":"#nctr-developers","children":[]},{"level":3,"title":"NCTR Holders","slug":"nctr-holders","link":"#nctr-holders","children":[]}]},{"level":2,"title":"Token Utilities","slug":"token-utilities","link":"#token-utilities","children":[{"level":3,"title":"Governance","slug":"governance","link":"#governance","children":[]},{"level":3,"title":"Incentivization","slug":"incentivization","link":"#incentivization","children":[]},{"level":3,"title":"Payments","slug":"payments","link":"#payments","children":[]}]},{"level":2,"title":"Tokenomics","slug":"tokenomics","link":"#tokenomics","children":[{"level":3,"title":"Technical Token Parameters","slug":"technical-token-parameters","link":"#technical-token-parameters","children":[]},{"level":3,"title":"Tokenomics Whitepaper","slug":"tokenomics-whitepaper","link":"#tokenomics-whitepaper","children":[]}]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"about/8-nctr-token.md"}');export{e as data}; diff --git a/assets/8-web3-cloud-functions.html-7f591621.js b/assets/8-web3-cloud-functions.html-7f591621.js new file mode 100644 index 00000000..f0a14926 --- /dev/null +++ b/assets/8-web3-cloud-functions.html-7f591621.js @@ -0,0 +1 @@ +const e=JSON.parse(`{"key":"v-174aec9a","path":"/web3-services/8-web3-cloud-functions.html","title":"Web3 Cloud Functions","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Introduction","slug":"introduction","link":"#introduction","children":[]},{"level":2,"title":"What is Acurast?","slug":"what-is-acurast","link":"#what-is-acurast","children":[]},{"level":2,"title":"Core Features of Apillon's Cloud Function Service","slug":"core-features-of-apillon-s-cloud-function-service","link":"#core-features-of-apillon-s-cloud-function-service","children":[]},{"level":2,"title":"How It Works","slug":"how-it-works","link":"#how-it-works","children":[]},{"level":2,"title":"Conclusion","slug":"conclusion","link":"#conclusion","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"web3-services/8-web3-cloud-functions.md"}`);export{e as data}; diff --git a/assets/8-web3-cloud-functions.html-e694e64a.js b/assets/8-web3-cloud-functions.html-e694e64a.js new file mode 100644 index 00000000..aa287a0d --- /dev/null +++ b/assets/8-web3-cloud-functions.html-e694e64a.js @@ -0,0 +1 @@ +import{_ as t,r as s,o as a,c as r,b as n,e,d as l,a as o}from"./app-e8b865be.js";const c={},u=o('Apillon's Cloud Function service provides developers with the ability to deploy decentralized computing tasks across a distributed network of mobile devices. This ensures that applications and scripts can run in a secure, unstoppable manner, avoiding reliance on centralized infrastructure. By utilizing Acurast's decentralized compute architecture, Apillon offers an alternative to traditional cloud services, ensuring privacy, resilience, and global scalability.
Acurast is a decentralized, serverless cloud framework that separates the layers of cloud infrastructure into distinct components: consensus, execution, and application. By using mobile devices as decentralized processors, Acurast enables verifiable and confidential computations. This design allows developers to deploy applications without needing to rely on centralized systems, ensuring privacy and data verifiability throughout the entire process.
',5),d={href:"https://docs.acurast.com/",target:"_blank",rel:"noopener noreferrer"},p=o('Script Deployment and Execution Apillon Cloud Functions offer developers a familiar environment similar to centralized cloud providers like AWS or Google Cloud. Developers can deploy scripts (e.g., JavaScript or Node.js) as on-demand functions or long-running tasks. These scripts can handle tasks like calling APIs or hosting continuous services such as Discord bots. Apillon also supports scheduled executions through cron expressions, enabling automatic execution without manual intervention.
Decentralized, Verifiable Compute Apillon leverages Acurast’s execution layer, which includes both the Acurast Secure Hardware Runtime (ASHR) and Zero-Knowledge Proof (ZKP)-based runtimes. This setup allows for secure, tamper-proof execution of sensitive computations. Developers can store secrets like API keys or wallet private keys in encrypted environments, which are used as part of their cloud function deployments without the risk of exposure.
Unstoppable Application Execution Apillon ensures that once a cloud function is deployed on the decentralized network, it remains unstoppable by any central authority. By distributing the execution across multiple processors, Apillon guarantees that a single point of failure cannot disrupt the task. This makes Apillon especially suitable for decentralized applications (dApps) that require continuous, reliable execution.
Cross-Chain and Web3 Integration The Cloud Function service integrates smoothly with various blockchain ecosystems, including Ethereum, Tezos, and others. Developers can specify where the results of their computations are delivered, whether to a blockchain or a Web2 system. This cross-chain functionality allows Web3 developers to build highly interoperable, decentralized applications.
Cloud Function Creation: Developers can create cloud functions via Apillon by providing parameters like the function name, description, and project UUID. This is done either through a simple API call or through Apillon’s developer console. Once created, the cloud function is registered on the decentralized network and ready to be executed on available processors.
Job Creation and Matching: After creating a cloud function, developers define specific tasks or jobs. These jobs include parameters like memory usage, storage needs, and scheduling details. Once a job is created, Acurast’s consensus layer matches it with appropriate processors based on their capabilities and reputation. Apillon automates aspects of job creation, such as uploading and pinning the script file to IPFS. Apillon also monitors job status, ensuring it is successfully matched with a processor, simplifying the entire deployment process.
Job Execution: Once matched, processors execute the jobs within Acurast’s secure hardware or ZKP-based runtimes. Apillon provides a dedicated API gateway for developers to trigger job executions, making it easy to initiate compute tasks just like with centralized cloud services. This seamless access eliminates the need for direct interaction with Acurast’s underlying infrastructure.
Environment Management: Developers can set up and manage runtime environments by defining environment variables, which are fully encrypted and securely handled by Apillon. If a new job is deployed under the same cloud function, Apillon automatically transfers the environment variables, ensuring continuity in execution without manual intervention.
Execution Control and Monitoring: Apillon offers real-time monitoring and execution control. Developers can track usage statistics, success rates, and deployment health through a dashboard. In the case of processor failure, Apillon’s health check mechanism automatically redeploys jobs to new processors, ensuring continuous execution without downtime.
Job Versioning: Apillon supports versioning, allowing developers to maintain multiple versions of their cloud functions. They can switch between versions or roll back to previous versions without disrupting the API endpoint. This ensures flexibility in managing application updates.
Load Balancing: Apillon implements a load balancing mechanism that distributes jobs across multiple processors. If a processor becomes overloaded or inaccessible, Apillon automatically switches to an alternative processor, ensuring uninterrupted service and optimal performance.
Apillon’s Cloud Function service provides a groundbreaking solution for developers seeking decentralized computing. By leveraging mobile devices and Acurast’s secure, verifiable compute architecture, Apillon allows developers to deploy unstoppable, cross-chain applications in a simple, seamless manner. Key benefits include easy integration with Web3 platforms, real-time monitoring, environment management, job versioning, and load balancing—all ensuring a reliable, privacy-focused, and scalable solution for decentralized computing.
',6);function h(m,g){const i=s("ExternalLinkIcon");return a(),r("div",null,[u,n("p",null,[e("Through Acurast, developers can run decentralized applications (dApps) that interact seamlessly with both Web3 and Web2 systems. Acurast matches computational jobs to a network of processors using its consensus layer, ensuring secure and efficient task execution. "),n("a",d,[e("Learn more"),l(i)]),e(".")]),p])}const b=t(c,[["render",h],["__file","8-web3-cloud-functions.html.vue"]]);export{b as default}; diff --git a/assets/9-embedded-wallets.html-641d7d93.js b/assets/9-embedded-wallets.html-641d7d93.js new file mode 100644 index 00000000..5957d514 --- /dev/null +++ b/assets/9-embedded-wallets.html-641d7d93.js @@ -0,0 +1 @@ +import{_ as s,r as n,o as r,c as o,b as e,e as t,d,a}from"./app-e8b865be.js";const l={},c=a('Apillon's Embedded Wallet Service redefines crypto asset management by blending the simplicity of Web2 onboarding with the security of hardware wallets and the convenience of hot wallets. It offers a secure, non-custodial, and fully decentralized solution for managing crypto assets seamlessly within applications.
An embedded wallet is an in-app wallet that provides a streamlined experience for generating and signing transactions with your private key, without requiring separate downloads or installations. By integrating directly into applications via an SDK, embedded wallets simplify onboarding, allowing users to log in with just their email and a verification code. This setup eliminates mnemonic phrases, making the experience accessible and secure.
Provider | Wallet Name | Security Method | Authentication Methods | Private Key Exposure | Wallet Scope | Decentralization |
---|---|---|---|---|---|---|
thirdweb | In-App Wallet | Shamir's Secret Sharing with HSM | Email, Social Media | Exposed in browser | Per app | 2/3 keys managed by thirdweb |
Dynamic.xyz | Email, Social Wallet | Outsourced to Turnkey - secure enclaves | Passkey, Email, Social Media | None; allows export | Per app | Stored by Turnkey |
Coinbase | Embedded Wallet | Multi-party Computation | Passkey | None; allows export | Per app | Stored by Coinbase |
Apillon | Embedded Wallet | Oasis Confidential Smart Contract | Passkey, Email, Password | None; allows export | Global | Fully decentralized via Oasis |
Passkeys are secure cryptographic keys stored on a user’s device, enabling wallet access through biometric methods without traditional passwords. This allows for a secure and user-friendly experience that prioritizes privacy.
Upon setting up a passkey, the user’s device generates a cryptographic key pair: a public key (shared with the service) and a private key (stored on the device). When logging in, the user authenticates biometrically, which unlocks the private key to sign the login request. The service verifies this signed request using the public key.
Apillon’s passkeys ensure wallets are protected with advanced biometric-based security, creating a seamless user experience.
Apillon’s Embedded Wallet Service on the Oasis Network combines user-friendly onboarding, top-tier security, and decentralization. It removes the need for wallet downloads and mnemonic phrases, offering a smooth and secure way to manage crypto assets within applications. With Oasis’s confidential smart contracts, Apillon protects users’ private keys, delivering security on par with hardware wallets.
',17);function w(b,f){const i=n("ExternalLinkIcon");return r(),o("div",null,[c,e("ol",null,[h,p,e("li",null,[g,t(": Private keys are securely generated, encrypted, and managed within confidential smart contracts powered by "),e("a",u,[t("Oasis Protocol"),d(i)]),t(".")]),m]),y])}const v=s(l,[["render",w],["__file","9-embedded-wallets.html.vue"]]);export{v as default}; diff --git a/assets/9-embedded-wallets.html-68d9e8bd.js b/assets/9-embedded-wallets.html-68d9e8bd.js new file mode 100644 index 00000000..fe5ff495 --- /dev/null +++ b/assets/9-embedded-wallets.html-68d9e8bd.js @@ -0,0 +1 @@ +const e=JSON.parse('{"key":"v-91d7101c","path":"/web3-services/9-embedded-wallets.html","title":"Embedded Wallets","lang":"en-US","frontmatter":{},"headers":[{"level":2,"title":"Introduction","slug":"introduction","link":"#introduction","children":[]},{"level":2,"title":"What is an Embedded Wallet?","slug":"what-is-an-embedded-wallet","link":"#what-is-an-embedded-wallet","children":[]},{"level":2,"title":"How it Works","slug":"how-it-works","link":"#how-it-works","children":[]},{"level":2,"title":"Security of Embedded Wallets","slug":"security-of-embedded-wallets","link":"#security-of-embedded-wallets","children":[]},{"level":2,"title":"Workflow","slug":"workflow","link":"#workflow","children":[]},{"level":2,"title":"Comparison with Other Providers","slug":"comparison-with-other-providers","link":"#comparison-with-other-providers","children":[]},{"level":2,"title":"Passkeys","slug":"passkeys","link":"#passkeys","children":[{"level":3,"title":"How Passkeys Work","slug":"how-passkeys-work","link":"#how-passkeys-work","children":[]},{"level":3,"title":"Benefits of Passkeys","slug":"benefits-of-passkeys","link":"#benefits-of-passkeys","children":[]}]},{"level":2,"title":"Advantages of Apillon’s Embedded Wallet Service","slug":"advantages-of-apillon-s-embedded-wallet-service","link":"#advantages-of-apillon-s-embedded-wallet-service","children":[]},{"level":2,"title":"Conclusion","slug":"conclusion","link":"#conclusion","children":[]}],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"web3-services/9-embedded-wallets.md"}');export{e as data}; diff --git a/assets/9-social-api.html-48ddfe96.js b/assets/9-social-api.html-48ddfe96.js new file mode 100644 index 00000000..e3173891 --- /dev/null +++ b/assets/9-social-api.html-48ddfe96.js @@ -0,0 +1,132 @@ +import{_ as p,r,o as u,c as h,b as s,e as n,d as e,w as a,a as i}from"./app-e8b865be.js";const b={},k=s("h1",{id:"social-api",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#social-api","aria-hidden":"true"},"#"),n(" Social API")],-1),m={href:"https://github.com/dappforce/grillchat/tree/main/integration",target:"_blank",rel:"noopener noreferrer"},v=s("strong",null,"Hub",-1),_=s("strong",null,"Channel",-1),g=s("strong",null,"Note:",-1),f={href:"https://app.apillon.io/dashboard/service/social",target:"_blank",rel:"noopener noreferrer"},y=s("p",null,"Use the Social API to create hubs and channels from your application. For example: you can create a channel (chatroom) for each NFT collection in your marketplace.",-1),A=s("p",null,"In all cURL examples, parameters with a colon as a prefix should be replaced with real values.",-1),T=s("h2",{id:"channels",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#channels","aria-hidden":"true"},"#"),n(" Channels")],-1),x=s("p",null,"By default, a channel is created inside a hub, therefore a hub can contain multiple channels. The grill widget displays hubs as a list of channels inside it, and a channel is displayed as a chatroom. A channel can be created inside Apillon's default hub or you can create your own hub and create channels within it.",-1),I=s("h3",{id:"list-channels",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#list-channels","aria-hidden":"true"},"#"),n(" List channels")],-1),w={class:"split_content"},P={class:"split_side"},q=s("h4",{id:"query-parameters",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#query-parameters","aria-hidden":"true"},"#"),n(" Query parameters")],-1),R=i('Name | Description | Required |
---|---|---|
hubUuid | Parent hub unique identifier | false |
Each item is an instance of channel class, with below properties:
Field | Type | Description |
---|---|---|
channelUuid | string | Channel unique identifier |
hubUuid | string | Unique identifier of the channel's parent Hub |
channelId | number | Channel id on Subsocial chain. This id is used in widget. |
status | number | Channel status (1: draft - deploying to chain, 5: active, 100: error ) |
title | string | Channel name |
body | string | Channel body - short description |
tags | string | Comma separated tags |
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
Name | Description | Required |
---|---|---|
channelUuid | Channel unique identifier | true |
Code | Description |
---|---|
40419001 | Channel does not exists |
Response is an instance of channel class, described above.
Name | Type | Description | Required |
---|---|---|---|
title | string | Channel name | true |
body | string | Channel content/description | true |
tags | string | Comma separated tags | false |
hubUuid | string | Hub unique identifier - if not specified the channel is created inside a default hub | false |
Code | Description |
---|---|
40419001 | Specified hub does not exist |
42219002 | Body is missing required properties |
50019004 | Parent hub is in invalid state. It is probably not yet transmitted and confirmed on the chain (status = 1) |
50019003 | Internal error - Apillon was unable to create channel. |
Response is an instance of channel class, described above.
Each item is an instance of hub class, with below properties:
Field | Type | Description |
---|---|---|
hubUuid | string | Hub unique identifier |
hubId | number | Hub id on Subsocial chain. This id is used in widget or in grillapp.net. Example: https://grillapp.net/12927 . |
status | number | Hub status (1: draft - deploying to chain, 5: active, 100: error ) |
name | string | Hub name |
about | string | Hub about - short description |
tags | string | Comma separated tags |
numOfChannels | number | Number of channels in hub |
createTime | DateTime | Item create time |
updateTime | DateTime | Item last update time |
Name | Description | Required |
---|---|---|
hubUuid | Hub UUID, visible in developer console | true |
Code | Description |
---|---|
40419001 | Hub does not exists |
Response is an instance of hub class, described above. Only difference is field numOfChannels
, which is not returned by this endpoint.
Name | Type | Description | Required |
---|---|---|---|
name | string | Hub name. | true |
about | string | Hub description | false |
tags | string | Comma separated tags | false |
Code | Description |
---|---|
42219001 | Body is missing required properties |
50019002 | Internal error - Apillon was unable to create hub. |
Response is an instance of hub class, described above.
{const{slotScopeIds:O}=_;O&&($=$?$.concat(O):O);const S=i(v),q=m(r(v),_,S,H,G,$,b);return q&&rl(q)&&q.data==="]"?r(_.anchor=q):(xt=!0,a(_.anchor=c("]"),S,q),q)},k=(v,_,H,G,$,b)=>{if(xt=!0,_.el=null,b){const q=x(v);for(;;){const E=r(v);if(E&&E!==q)s(E);else break}}const O=r(v),S=i(v);return s(v),n(null,_,S,O,H,G,ol(S),$),O},x=(v,_="[",H="]")=>{let G=0;for(;v;)if(v=r(v),v&&rl(v)&&(v.data===_&&G++,v.data===H)){if(G===0)return r(v);G--}return v},T=(v,_,H)=>{const G=_.parentNode;G&&G.replaceChild(v,_);let $=H;for(;$;)$.vnode.el===_&&($.vnode.el=$.subTree.el=v),$=$.parent},A=v=>v.nodeType===1&&v.tagName.toLowerCase()==="template";return[u,d]}const Ve=Wi;function Ac(e){return Pc(e,Tc)}function Pc(e,t){const n=to();n.__VUE__=!0;const{insert:l,remove:o,patchProp:r,createElement:i,createText:s,createComment:a,setText:c,setElementText:u,parentNode:d,nextSibling:h,setScopeId:m=ot,insertStaticContent:y}=e,k=(f,p,g,w=null,L=null,P=null,z=!1,D=null,M=!!p.dynamicChildren)=>{if(f===p)return;f&&!Wt(f,p)&&(w=C(f),He(f,L,P,!0),f=null),p.patchFlag===-2&&(M=!1,p.dynamicChildren=null);const{type:R,ref:Q,shapeFlag:K}=p;switch(R){case fn:x(f,p,g,w);break;case Je:T(f,p,g,w);break;case Pn:f==null&&A(p,g,w,z);break;case ke:E(f,p,g,w,L,P,z,D,M);break;default:K&1?H(f,p,g,w,L,P,z,D,M):K&6?N(f,p,g,w,L,P,z,D,M):(K&64||K&128)&&R.process(f,p,g,w,L,P,z,D,M,F)}Q!=null&&L&&wl(Q,f&&f.ref,P,p||f,!p)},x=(f,p,g,w)=>{if(f==null)l(p.el=s(p.children),g,w);else{const L=p.el=f.el;p.children!==f.children&&c(L,p.children)}},T=(f,p,g,w)=>{f==null?l(p.el=a(p.children||""),g,w):p.el=f.el},A=(f,p,g,w)=>{[f.el,f.anchor]=y(f.children,p,g,w,f.el,f.anchor)},v=({el:f,anchor:p},g,w)=>{let L;for(;f&&f!==p;)L=h(f),l(f,g,w),f=L;l(p,g,w)},_=({el:f,anchor:p})=>{let g;for(;f&&f!==p;)g=h(f),o(f),f=g;o(p)},H=(f,p,g,w,L,P,z,D,M)=>{z=z||p.type==="svg",f==null?G(p,g,w,L,P,z,D,M):O(f,p,L,P,z,D,M)},G=(f,p,g,w,L,P,z,D)=>{let M,R;const{type:Q,props:K,shapeFlag:Z,transition:oe,dirs:se}=f;if(M=f.el=i(f.type,P,K&&K.is,K),Z&8?u(M,f.children):Z&16&&b(f.children,M,null,w,L,P&&Q!=="foreignObject",z,D),se&&at(f,null,w,"created"),$(M,f,f.scopeId,z,w),K){for(const _e in K)_e!=="value"&&!Tn(_e)&&r(M,_e,null,K[_e],P,f.children,w,L,Ne);"value"in K&&r(M,"value",null,K.value),(R=K.onVnodeBeforeMount)&&Ze(R,w,f)}se&&at(f,null,w,"beforeMount");const ye=os(L,oe);ye&&oe.beforeEnter(M),l(M,p,g),((R=K&&K.onVnodeMounted)||ye||se)&&Ve(()=>{R&&Ze(R,w,f),ye&&oe.enter(M),se&&at(f,null,w,"mounted")},L)},$=(f,p,g,w,L)=>{if(g&&m(f,g),w)for(let P=0;P{for(let R=M;R {const D=p.el=f.el;let{patchFlag:M,dynamicChildren:R,dirs:Q}=p;M|=f.patchFlag&16;const K=f.props||Ee,Z=p.props||Ee;let oe;g&&Mt(g,!1),(oe=Z.onVnodeBeforeUpdate)&&Ze(oe,g,p,f),Q&&at(p,f,g,"beforeUpdate"),g&&Mt(g,!0);const se=L&&p.type!=="foreignObject";if(R?S(f.dynamicChildren,R,D,g,w,se,P):z||U(f,p,D,null,g,w,se,P,!1),M>0){if(M&16)q(D,p,K,Z,g,w,L);else if(M&2&&K.class!==Z.class&&r(D,"class",null,Z.class,L),M&4&&r(D,"style",K.style,Z.style,L),M&8){const ye=p.dynamicProps;for(let _e=0;_e {oe&&Ze(oe,g,p,f),Q&&at(p,f,g,"updated")},w)},S=(f,p,g,w,L,P,z)=>{for(let D=0;D {if(g!==w){if(g!==Ee)for(const D in g)!Tn(D)&&!(D in w)&&r(f,D,g[D],null,z,p.children,L,P,Ne);for(const D in w){if(Tn(D))continue;const M=w[D],R=g[D];M!==R&&D!=="value"&&r(f,D,R,M,z,p.children,L,P,Ne)}"value"in w&&r(f,"value",g.value,w.value)}},E=(f,p,g,w,L,P,z,D,M)=>{const R=p.el=f?f.el:s(""),Q=p.anchor=f?f.anchor:s("");let{patchFlag:K,dynamicChildren:Z,slotScopeIds:oe}=p;oe&&(D=D?D.concat(oe):oe),f==null?(l(R,g,w),l(Q,g,w),b(p.children,g,Q,L,P,z,D,M)):K>0&&K&64&&Z&&f.dynamicChildren?(S(f.dynamicChildren,Z,g,L,P,z,D),(p.key!=null||L&&p===L.subTree)&&rs(f,p,!0)):U(f,p,g,Q,L,P,z,D,M)},N=(f,p,g,w,L,P,z,D,M)=>{p.slotScopeIds=D,f==null?p.shapeFlag&512?L.ctx.activate(p,g,w,z,M):ne(p,g,w,L,P,z,M):ie(f,p,M)},ne=(f,p,g,w,L,P,z)=>{const D=f.component=Mc(f,w,L);if(qn(f)&&(D.ctx.renderer=F),Hc(D),D.asyncDep){if(L&&L.registerDep(D,I),!f.el){const M=D.subTree=le(Je);T(null,M,p,g)}return}I(D,f,p,g,L,P,z)},ie=(f,p,g)=>{const w=p.component=f.component;if(Ya(f,p,g))if(w.asyncDep&&!w.asyncResolved){J(w,p,g);return}else w.next=p,Wa(w.update),w.update();else p.el=f.el,w.vnode=p},I=(f,p,g,w,L,P,z)=>{const D=()=>{if(f.isMounted){let{next:Q,bu:K,u:Z,parent:oe,vnode:se}=f,ye=Q,_e;Mt(f,!1),Q?(Q.el=se.el,J(f,Q,z)):Q=se,K&&Bl(K),(_e=Q.props&&Q.props.onVnodeBeforeUpdate)&&Ze(_e,oe,Q,se),Mt(f,!0);const Te=jl(f),et=f.subTree;f.subTree=Te,k(et,Te,d(et.el),C(et),f,L,P),Q.el=Te.el,ye===null&&Ja(f,Te.el),Z&&Ve(Z,L),(_e=Q.props&&Q.props.onVnodeUpdated)&&Ve(()=>Ze(_e,oe,Q,se),L)}else{let Q;const{el:K,props:Z}=p,{bm:oe,m:se,parent:ye}=f,_e=un(p);if(Mt(f,!1),oe&&Bl(oe),!_e&&(Q=Z&&Z.onVnodeBeforeMount)&&Ze(Q,ye,p),Mt(f,!0),K&&ue){const Te=()=>{f.subTree=jl(f),ue(K,f.subTree,f,L,null)};_e?p.type.__asyncLoader().then(()=>!f.isUnmounted&&Te()):Te()}else{const Te=f.subTree=jl(f);k(null,Te,g,w,f,L,P),p.el=Te.el}if(se&&Ve(se,L),!_e&&(Q=Z&&Z.onVnodeMounted)){const Te=p;Ve(()=>Ze(Q,ye,Te),L)}(p.shapeFlag&256||ye&&un(ye.vnode)&&ye.vnode.shapeFlag&256)&&f.a&&Ve(f.a,L),f.isMounted=!0,p=g=w=null}},M=f.effect=new Eo(D,()=>Il(R),f.scope),R=f.update=()=>M.run();R.id=f.uid,Mt(f,!0),R()},J=(f,p,g)=>{p.component=f;const w=f.vnode.props;f.vnode=p,f.next=null,Ec(f,p.props,w,g),Lc(f,p.children,g),bn(),sr(),_n()},U=(f,p,g,w,L,P,z,D,M=!1)=>{const R=f&&f.children,Q=f?f.shapeFlag:0,K=p.children,{patchFlag:Z,shapeFlag:oe}=p;if(Z>0){if(Z&128){$e(R,K,g,w,L,P,z,D,M);return}else if(Z&256){Oe(R,K,g,w,L,P,z,D,M);return}}oe&8?(Q&16&&Ne(R,L,P),K!==R&&u(g,K)):Q&16?oe&16?$e(R,K,g,w,L,P,z,D,M):Ne(R,L,P,!0):(Q&8&&u(g,""),oe&16&&b(K,g,w,L,P,z,D,M))},Oe=(f,p,g,w,L,P,z,D,M)=>{f=f||rn,p=p||rn;const R=f.length,Q=p.length,K=Math.min(R,Q);let Z;for(Z=0;Z Q?Ne(f,L,P,!0,!1,K):b(p,g,w,L,P,z,D,M,K)},$e=(f,p,g,w,L,P,z,D,M)=>{let R=0;const Q=p.length;let K=f.length-1,Z=Q-1;for(;R<=K&&R<=Z;){const oe=f[R],se=p[R]=M?Pt(p[R]):tt(p[R]);if(Wt(oe,se))k(oe,se,g,null,L,P,z,D,M);else break;R++}for(;R<=K&&R<=Z;){const oe=f[K],se=p[Z]=M?Pt(p[Z]):tt(p[Z]);if(Wt(oe,se))k(oe,se,g,null,L,P,z,D,M);else break;K--,Z--}if(R>K){if(R<=Z){const oe=Z+1,se=oe Z)for(;R<=K;)He(f[R],L,P,!0),R++;else{const oe=R,se=R,ye=new Map;for(R=se;R<=Z;R++){const Ge=p[R]=M?Pt(p[R]):tt(p[R]);Ge.key!=null&&ye.set(Ge.key,R)}let _e,Te=0;const et=Z-se+1;let en=!1,Yo=0;const yn=new Array(et);for(R=0;R=et){He(Ge,L,P,!0);continue}let st;if(Ge.key!=null)st=ye.get(Ge.key);else for(_e=se;_e<=Z;_e++)if(yn[_e-se]===0&&Wt(Ge,p[_e])){st=_e;break}st===void 0?He(Ge,L,P,!0):(yn[st-se]=R+1,st>=Yo?Yo=st:en=!0,k(Ge,p[st],g,null,L,P,z,D,M),Te++)}const Jo=en?Sc(yn):rn;for(_e=Jo.length-1,R=et-1;R>=0;R--){const Ge=se+R,st=p[Ge],Qo=Ge+1 {const{el:P,type:z,transition:D,children:M,shapeFlag:R}=f;if(R&6){We(f.component.subTree,p,g,w);return}if(R&128){f.suspense.move(p,g,w);return}if(R&64){z.move(f,p,g,F);return}if(z===ke){l(P,p,g);for(let K=0;KD.enter(P),L);else{const{leave:K,delayLeave:Z,afterLeave:oe}=D,se=()=>l(P,p,g),ye=()=>{K(P,()=>{se(),oe&&oe()})};Z?Z(P,se,ye):ye()}else l(P,p,g)},He=(f,p,g,w=!1,L=!1)=>{const{type:P,props:z,ref:D,children:M,dynamicChildren:R,shapeFlag:Q,patchFlag:K,dirs:Z}=f;if(D!=null&&wl(D,null,g,f,!0),Q&256){p.ctx.deactivate(f);return}const oe=Q&1&&Z,se=!un(f);let ye;if(se&&(ye=z&&z.onVnodeBeforeUnmount)&&Ze(ye,p,f),Q&6)it(f.component,g,w);else{if(Q&128){f.suspense.unmount(g,w);return}oe&&at(f,null,p,"beforeUnmount"),Q&64?f.type.remove(f,p,g,L,F,w):R&&(P!==ke||K>0&&K&64)?Ne(R,p,g,!1,!0):(P===ke&&K&384||!L&&Q&16)&&Ne(M,p,g),w&&kt(f)}(se&&(ye=z&&z.onVnodeUnmounted)||oe)&&Ve(()=>{ye&&Ze(ye,p,f),oe&&at(f,null,p,"unmounted")},g)},kt=f=>{const{type:p,el:g,anchor:w,transition:L}=f;if(p===ke){Et(g,w);return}if(p===Pn){_(f);return}const P=()=>{o(g),L&&!L.persisted&&L.afterLeave&&L.afterLeave()};if(f.shapeFlag&1&&L&&!L.persisted){const{leave:z,delayLeave:D}=L,M=()=>z(g,P);D?D(f.el,P,M):M()}else P()},Et=(f,p)=>{let g;for(;f!==p;)g=h(f),o(f),f=g;o(p)},it=(f,p,g)=>{const{bum:w,scope:L,update:P,subTree:z,um:D}=f;w&&Bl(w),L.stop(),P&&(P.active=!1,He(z,f,p,g)),D&&Ve(D,p),Ve(()=>{f.isUnmounted=!0},p),p&&p.pendingBranch&&!p.isUnmounted&&f.asyncDep&&!f.asyncResolved&&f.suspenseId===p.pendingId&&(p.deps--,p.deps===0&&p.resolve())},Ne=(f,p,g,w=!1,L=!1,P=0)=>{for(let z=P;z f.shapeFlag&6?C(f.component.subTree):f.shapeFlag&128?f.suspense.next():h(f.anchor||f.el),W=(f,p,g)=>{f==null?p._vnode&&He(p._vnode,null,null,!0):k(p._vnode||null,f,p,null,null,null,g),sr(),gl(),p._vnode=f},F={p:k,um:He,m:We,r:kt,mt:ne,mc:b,pc:U,pbc:S,n:C,o:e};let Y,ue;return t&&([Y,ue]=t(F)),{render:W,hydrate:Y,createApp:wc(W,Y)}}function Mt({effect:e,update:t},n){e.allowRecurse=t.allowRecurse=n}function os(e,t){return(!e||e&&!e.pendingBranch)&&t&&!t.persisted}function rs(e,t,n=!1){const l=e.children,o=t.children;if(X(l)&&X(o))for(let r=0;r >1,e[n[s]] 0&&(t[l]=n[r-1]),n[r]=l)}}for(r=n.length,i=n[r-1];r-- >0;)n[r]=i,i=t[i];return n}const Rc=e=>e.__isTeleport,ke=Symbol.for("v-fgt"),fn=Symbol.for("v-txt"),Je=Symbol.for("v-cmt"),Pn=Symbol.for("v-stc"),Sn=[];let lt=null;function B(e=!1){Sn.push(lt=e?null:[])}function Ic(){Sn.pop(),lt=Sn[Sn.length-1]||null}let $n=1;function _r(e){$n+=e}function is(e){return e.dynamicChildren=$n>0?lt||rn:null,Ic(),$n>0&<&<.push(e),e}function ee(e,t,n,l,o,r){return is(pe(e,t,n,l,o,r,!0))}function Ae(e,t,n,l,o){return is(le(e,t,n,l,o,!0))}function kl(e){return e?e.__v_isVNode===!0:!1}function Wt(e,t){return e.type===t.type&&e.key===t.key}const $l="__vInternal",ss=({key:e})=>e??null,dl=({ref:e,ref_key:t,ref_for:n})=>(typeof e=="number"&&(e=""+e),e!=null?ge(e)||De(e)||re(e)?{i:Me,r:e,k:t,f:!!n}:e:null);function pe(e,t=null,n=null,l=0,o=null,r=e===ke?0:1,i=!1,s=!1){const a={__v_isVNode:!0,__v_skip:!0,type:e,props:t,key:t&&ss(t),ref:t&&dl(t),scopeId:Bi,slotScopeIds:null,children:n,component:null,suspense:null,ssContent:null,ssFallback:null,dirs:null,transition:null,el:null,anchor:null,target:null,targetAnchor:null,staticCount:0,shapeFlag:r,patchFlag:l,dynamicProps:o,dynamicChildren:null,appContext:null,ctx:Me};return s?(Oo(a,n),r&128&&e.normalize(a)):n&&(a.shapeFlag|=ge(n)?8:16),$n>0&&!i&<&&(a.patchFlag>0||r&6)&&a.patchFlag!==32&<.push(a),a}const le=Oc;function Oc(e,t=null,n=null,l=0,o=null,r=!1){if((!e||e===Qa)&&(e=Je),kl(e)){const s=$t(e,t,!0);return n&&Oo(s,n),$n>0&&!r&<&&(s.shapeFlag&6?lt[lt.indexOf(e)]=s:lt.push(s)),s.patchFlag|=-2,s}if(Vc(e)&&(e=e.__vccOpts),t){t=Nc(t);let{class:s,style:a}=t;s&&!ge(s)&&(t.class=Ue(s)),Ce(a)&&(Ri(a)&&!X(a)&&(a=Ie({},a)),t.style=Bn(a))}const i=ge(e)?1:Xa(e)?128:Rc(e)?64:Ce(e)?4:re(e)?2:0;return pe(e,t,n,l,o,i,r,!0)}function Nc(e){return e?Ri(e)||$l in e?Ie({},e):e:null}function $t(e,t,n=!1){const{props:l,ref:o,patchFlag:r,children:i}=e,s=t?ho(l||{},t):l;return{__v_isVNode:!0,__v_skip:!0,type:e.type,props:s,key:s&&ss(s),ref:t&&t.ref?n&&o?X(o)?o.concat(dl(t)):[o,dl(t)]:dl(t):o,scopeId:e.scopeId,slotScopeIds:e.slotScopeIds,children:i,target:e.target,targetAnchor:e.targetAnchor,staticCount:e.staticCount,shapeFlag:e.shapeFlag,patchFlag:t&&e.type!==ke?r===-1?16:r|16:r,dynamicProps:e.dynamicProps,dynamicChildren:e.dynamicChildren,appContext:e.appContext,dirs:e.dirs,transition:e.transition,component:e.component,suspense:e.suspense,ssContent:e.ssContent&&$t(e.ssContent),ssFallback:e.ssFallback&&$t(e.ssFallback),el:e.el,anchor:e.anchor,ctx:e.ctx,ce:e.ce}}function Ft(e=" ",t=0){return le(fn,null,e,t)}function Dc(e,t){const n=le(Pn,null,e);return n.staticCount=t,n}function Le(e="",t=!1){return t?(B(),Ae(Je,null,e)):le(Je,null,e)}function tt(e){return e==null||typeof e=="boolean"?le(Je):X(e)?le(ke,null,e.slice()):typeof e=="object"?Pt(e):le(fn,null,String(e))}function Pt(e){return e.el===null&&e.patchFlag!==-1||e.memo?e:$t(e)}function Oo(e,t){let n=0;const{shapeFlag:l}=e;if(t==null)t=null;else if(X(t))n=16;else if(typeof t=="object")if(l&65){const o=t.default;o&&(o._c&&(o._d=!1),Oo(e,o()),o._c&&(o._d=!0));return}else{n=32;const o=t._;!o&&!($l in t)?t._ctx=Me:o===3&&Me&&(Me.slots._===1?t._=1:(t._=2,e.patchFlag|=1024))}else re(t)?(t={default:t,_ctx:Me},n=32):(t=String(t),l&64?(n=16,t=[Ft(t)]):n=8);e.children=t,e.shapeFlag|=n}function ho(...e){const t={};for(let n=0;n Se||Me;let Do,tn,yr="__VUE_INSTANCE_SETTERS__";(tn=to()[yr])||(tn=to()[yr]=[]),tn.push(e=>Se=e),Do=e=>{tn.length>1?tn.forEach(t=>t(e)):tn[0](e)};const hn=e=>{Do(e),e.scope.on()},Gt=()=>{Se&&Se.scope.off(),Do(null)};function as(e){return e.vnode.shapeFlag&4}let pn=!1;function Hc(e,t=!1){pn=t;const{props:n,children:l}=e.vnode,o=as(e);kc(e,n,o,t),xc(e,l);const r=o?zc(e,t):void 0;return pn=!1,r}function zc(e,t){const n=e.type;e.accessCache=Object.create(null),e.proxy=Ii(new Proxy(e.ctx,pc));const{setup:l}=n;if(l){const o=e.setupContext=l.length>1?jc(e):null;hn(e),bn();const r=Ot(l,e,0,[e.props,o]);if(_n(),Gt(),pi(r)){if(r.then(Gt,Gt),t)return r.then(i=>{wr(e,i,t)}).catch(i=>{Vn(i,e,0)});e.asyncDep=r}else wr(e,r,t)}else cs(e,t)}function wr(e,t,n){re(t)?e.type.__ssrInlineRender?e.ssrRender=t:e.render=t:Ce(t)&&(e.setupState=$i(t)),cs(e,n)}let kr;function cs(e,t,n){const l=e.type;if(!e.render){if(!t&&kr&&!l.render){const o=l.template||Ro(e).template;if(o){const{isCustomElement:r,compilerOptions:i}=e.appContext.config,{delimiters:s,compilerOptions:a}=l,c=Ie(Ie({isCustomElement:r,delimiters:s},i),a);l.render=kr(o,c)}}e.render=l.render||ot}{hn(e),bn();try{mc(e)}finally{_n(),Gt()}}}function Bc(e){return e.attrsProxy||(e.attrsProxy=new Proxy(e.attrs,{get(t,n){return qe(e,"get","$attrs"),t[n]}}))}function jc(e){const t=n=>{e.exposed=n||{}};return{get attrs(){return Bc(e)},slots:e.slots,emit:e.emit,expose:t}}function Fl(e){if(e.exposed)return e.exposeProxy||(e.exposeProxy=new Proxy($i(Ii(e.exposed)),{get(t,n){if(n in t)return t[n];if(n in An)return An[n](e)},has(t,n){return n in t||n in An}}))}function Wc(e,t=!0){return re(e)?e.displayName||e.name:e.name||t&&e.__name}function Vc(e){return re(e)&&"__vccOpts"in e}const j=(e,t)=>za(e,t,pn);function ce(e,t,n){const l=arguments.length;return l===2?Ce(t)&&!X(t)?kl(t)?le(e,null,[t]):le(e,t):le(e,null,t):(l>3?n=Array.prototype.slice.call(arguments,2):l===3&&kl(n)&&(n=[n]),le(e,t,n))}const Uc=Symbol.for("v-scx"),qc=()=>Pe(Uc),Kc="3.3.8",Gc="http://www.w3.org/2000/svg",Vt=typeof document<"u"?document:null,Er=Vt&&Vt.createElement("template"),Yc={insert:(e,t,n)=>{t.insertBefore(e,n||null)},remove:e=>{const t=e.parentNode;t&&t.removeChild(e)},createElement:(e,t,n,l)=>{const o=t?Vt.createElementNS(Gc,e):Vt.createElement(e,n?{is:n}:void 0);return e==="select"&&l&&l.multiple!=null&&o.setAttribute("multiple",l.multiple),o},createText:e=>Vt.createTextNode(e),createComment:e=>Vt.createComment(e),setText:(e,t)=>{e.nodeValue=t},setElementText:(e,t)=>{e.textContent=t},parentNode:e=>e.parentNode,nextSibling:e=>e.nextSibling,querySelector:e=>Vt.querySelector(e),setScopeId(e,t){e.setAttribute(t,"")},insertStaticContent(e,t,n,l,o,r){const i=n?n.previousSibling:t.lastChild;if(o&&(o===r||o.nextSibling))for(;t.insertBefore(o.cloneNode(!0),n),!(o===r||!(o=o.nextSibling)););else{Er.innerHTML=l?``:e;const s=Er.content;if(l){const a=s.firstChild;for(;a.firstChild;)s.appendChild(a.firstChild);s.removeChild(a)}t.insertBefore(s,n)}return[i?i.nextSibling:t.firstChild,n?n.previousSibling:t.lastChild]}},Lt="transition",wn="animation",Fn=Symbol("_vtc"),Gn=(e,{slots:t})=>ce(lc,Jc(e),t);Gn.displayName="Transition";const us={name:String,type:String,css:{type:Boolean,default:!0},duration:[String,Number,Object],enterFromClass:String,enterActiveClass:String,enterToClass:String,appearFromClass:String,appearActiveClass:String,appearToClass:String,leaveFromClass:String,leaveActiveClass:String,leaveToClass:String};Gn.props=Ie({},qi,us);const Ht=(e,t=[])=>{X(e)?e.forEach(n=>n(...t)):e&&e(...t)},Cr=e=>e?X(e)?e.some(t=>t.length>1):e.length>1:!1;function Jc(e){const t={};for(const E in e)E in us||(t[E]=e[E]);if(e.css===!1)return t;const{name:n="v",type:l,duration:o,enterFromClass:r=`${n}-enter-from`,enterActiveClass:i=`${n}-enter-active`,enterToClass:s=`${n}-enter-to`,appearFromClass:a=r,appearActiveClass:c=i,appearToClass:u=s,leaveFromClass:d=`${n}-leave-from`,leaveActiveClass:h=`${n}-leave-active`,leaveToClass:m=`${n}-leave-to`}=e,y=Qc(o),k=y&&y[0],x=y&&y[1],{onBeforeEnter:T,onEnter:A,onEnterCancelled:v,onLeave:_,onLeaveCancelled:H,onBeforeAppear:G=T,onAppear:$=A,onAppearCancelled:b=v}=t,O=(E,N,ne)=>{zt(E,N?u:s),zt(E,N?c:i),ne&&ne()},S=(E,N)=>{E._isLeaving=!1,zt(E,d),zt(E,m),zt(E,h),N&&N()},q=E=>(N,ne)=>{const ie=E?$:A,I=()=>O(N,E,ne);Ht(ie,[N,I]),xr(()=>{zt(N,E?a:r),Tt(N,E?u:s),Cr(ie)||Lr(N,l,k,I)})};return Ie(t,{onBeforeEnter(E){Ht(T,[E]),Tt(E,r),Tt(E,i)},onBeforeAppear(E){Ht(G,[E]),Tt(E,a),Tt(E,c)},onEnter:q(!1),onAppear:q(!0),onLeave(E,N){E._isLeaving=!0;const ne=()=>S(E,N);Tt(E,d),eu(),Tt(E,h),xr(()=>{E._isLeaving&&(zt(E,d),Tt(E,m),Cr(_)||Lr(E,l,x,ne))}),Ht(_,[E,ne])},onEnterCancelled(E){O(E,!1),Ht(v,[E])},onAppearCancelled(E){O(E,!0),Ht(b,[E])},onLeaveCancelled(E){S(E),Ht(H,[E])}})}function Qc(e){if(e==null)return null;if(Ce(e))return[ql(e.enter),ql(e.leave)];{const t=ql(e);return[t,t]}}function ql(e){return oa(e)}function Tt(e,t){t.split(/\s+/).forEach(n=>n&&e.classList.add(n)),(e[Fn]||(e[Fn]=new Set)).add(t)}function zt(e,t){t.split(/\s+/).forEach(l=>l&&e.classList.remove(l));const n=e[Fn];n&&(n.delete(t),n.size||(e[Fn]=void 0))}function xr(e){requestAnimationFrame(()=>{requestAnimationFrame(e)})}let Zc=0;function Lr(e,t,n,l){const o=e._endId=++Zc,r=()=>{o===e._endId&&l()};if(n)return setTimeout(r,n);const{type:i,timeout:s,propCount:a}=Xc(e,t);if(!i)return l();const c=i+"end";let u=0;const d=()=>{e.removeEventListener(c,h),r()},h=m=>{m.target===e&&++u>=a&&d()};setTimeout(()=>{u(n[y]||"").split(", "),o=l(`${Lt}Delay`),r=l(`${Lt}Duration`),i=Tr(o,r),s=l(`${wn}Delay`),a=l(`${wn}Duration`),c=Tr(s,a);let u=null,d=0,h=0;t===Lt?i>0&&(u=Lt,d=i,h=r.length):t===wn?c>0&&(u=wn,d=c,h=a.length):(d=Math.max(i,c),u=d>0?i>c?Lt:wn:null,h=u?u===Lt?r.length:a.length:0);const m=u===Lt&&/\b(transform|all)(,|$)/.test(l(`${Lt}Property`).toString());return{type:u,timeout:d,propCount:h,hasTransform:m}}function Tr(e,t){for(;e.length Ar(n)+Ar(e[l])))}function Ar(e){return e==="auto"?0:Number(e.slice(0,-1).replace(",","."))*1e3}function eu(){return document.body.offsetHeight}function tu(e,t,n){const l=e[Fn];l&&(t=(t?[t,...l]:[...l]).join(" ")),t==null?e.removeAttribute("class"):n?e.setAttribute("class",t):e.className=t}const $o=Symbol("_vod"),El={beforeMount(e,{value:t},{transition:n}){e[$o]=e.style.display==="none"?"":e.style.display,n&&t?n.beforeEnter(e):kn(e,t)},mounted(e,{value:t},{transition:n}){n&&t&&n.enter(e)},updated(e,{value:t,oldValue:n},{transition:l}){!t!=!n&&(l?t?(l.beforeEnter(e),kn(e,!0),l.enter(e)):l.leave(e,()=>{kn(e,!1)}):kn(e,t))},beforeUnmount(e,{value:t}){kn(e,t)}};function kn(e,t){e.style.display=t?e[$o]:"none"}function nu(e,t,n){const l=e.style,o=ge(n);if(n&&!o){if(t&&!ge(t))for(const r in t)n[r]==null&&po(l,r,"");for(const r in n)po(l,r,n[r])}else{const r=l.display;o?t!==n&&(l.cssText=n):t&&e.removeAttribute("style"),$o in e&&(l.display=r)}}const Pr=/\s*!important$/;function po(e,t,n){if(X(n))n.forEach(l=>po(e,t,l));else if(n==null&&(n=""),t.startsWith("--"))e.setProperty(t,n);else{const l=lu(e,t);Pr.test(n)?e.setProperty(Qt(l),n.replace(Pr,""),"important"):e[l]=n}}const Sr=["Webkit","Moz","ms"],Kl={};function lu(e,t){const n=Kl[t];if(n)return n;let l=dt(t);if(l!=="filter"&&l in e)return Kl[t]=l;l=Pl(l);for(let o=0;o Gl||(uu.then(()=>Gl=0),Gl=Date.now());function fu(e,t){const n=l=>{if(!l._vts)l._vts=Date.now();else if(l._vts<=n.attached)return;Xe(hu(l,n.value),t,5,[l])};return n.value=e,n.attached=du(),n}function hu(e,t){if(X(t)){const n=e.stopImmediatePropagation;return e.stopImmediatePropagation=()=>{n.call(e),e._stopped=!0},t.map(l=>o=>!o._stopped&&l&&l(o))}else return t}const Nr=/^on[a-z]/,pu=(e,t,n,l,o=!1,r,i,s,a)=>{t==="class"?tu(e,l,o):t==="style"?nu(e,n,l):zn(t)?_o(t)||au(e,t,n,l,i):(t[0]==="."?(t=t.slice(1),!0):t[0]==="^"?(t=t.slice(1),!1):mu(e,t,l,o))?ru(e,t,l,r,i,s,a):(t==="true-value"?e._trueValue=l:t==="false-value"&&(e._falseValue=l),ou(e,t,l,o))};function mu(e,t,n,l){return l?!!(t==="innerHTML"||t==="textContent"||t in e&&Nr.test(t)&&re(n)):t==="spellcheck"||t==="draggable"||t==="translate"||t==="form"||t==="list"&&e.tagName==="INPUT"||t==="type"&&e.tagName==="TEXTAREA"||Nr.test(t)&&ge(n)?!1:t in e}const gu={esc:"escape",space:" ",up:"arrow-up",left:"arrow-left",right:"arrow-right",down:"arrow-down",delete:"backspace"},vu=(e,t)=>n=>{if(!("key"in n))return;const l=Qt(n.key);if(t.some(o=>o===l||gu[o]===l))return e(n)},bu=Ie({patchProp:pu},Yc);let Yl,Dr=!1;function _u(){return Yl=Dr?Yl:Ac(bu),Dr=!0,Yl}const yu=(...e)=>{const t=_u().createApp(...e),{mount:n}=t;return t.mount=l=>{const o=wu(l);if(o)return n(o,!0,o instanceof SVGElement)},t};function wu(e){return ge(e)?document.querySelector(e):e}const ku={"v-8daa1a0e":()=>V(()=>import("./index.html-addec3f2.js"),[]).then(({data:e})=>e),"v-8daa1a0e":()=>V(()=>import("./index.html-addec3f2.js"),[]).then(({data:e})=>e),"v-92c536e4":()=>V(()=>import("./1-navigation.html-1844ebb0.js"),[]).then(({data:e})=>e),"v-d64fcca0":()=>V(()=>import("./2-what-is-apillon.html-94103eb4.js"),[]).then(({data:e})=>e),"v-0f48940c":()=>V(()=>import("./3-why-apillon.html-e3881b0c.js"),[]).then(({data:e})=>e),"v-6bda2dde":()=>V(()=>import("./4-how-does-apillon-work.html-d518367e.js"),[]).then(({data:e})=>e),"v-ac15b5a4":()=>V(()=>import("./5-developing-web3-with-apillon.html-76d0fc89.js"),[]).then(({data:e})=>e),"v-da41cf52":()=>V(()=>import("./6-web3-up-close.html-6cf560b5.js"),[]).then(({data:e})=>e),"v-929e013e":()=>V(()=>import("./7-community.html-41b148c0.js"),[]).then(({data:e})=>e),"v-564790ea":()=>V(()=>import("./8-nctr-token.html-ae4d0c64.js"),[]).then(({data:e})=>e),"v-cdfbcdae":()=>V(()=>import("./1-apillon-api.html-3cd74252.js"),[]).then(({data:e})=>e),"v-4d91ab64":()=>V(()=>import("./10-flutter-sdk.html-0d7688b3.js"),[]).then(({data:e})=>e),"v-15e6da9c":()=>V(()=>import("./11-cloud-functions-api.html-5b0f7e00.js"),[]).then(({data:e})=>e),"v-3453e56e":()=>V(()=>import("./12-embedded-wallets-integration.html-764e9a78.js"),[]).then(({data:e})=>e),"v-7a601078":()=>V(()=>import("./13-infrastructure-api.html-ecddf386.js"),[]).then(({data:e})=>e),"v-1da918f4":()=>V(()=>import("./2-storage-api.html-503dd3a7.js"),[]).then(({data:e})=>e),"v-3fe44474":()=>V(()=>import("./3-hosting-api.html-ccb98823.js"),[]).then(({data:e})=>e),"v-ae3a6dfc":()=>V(()=>import("./4-nfts-api.html-b2f21418.js"),[]).then(({data:e})=>e),"v-fc8498f6":()=>V(()=>import("./5-apillon-sdk.html-ca58359b.js"),[]).then(({data:e})=>e),"v-6c04f07e":()=>V(()=>import("./6-apillon-cli.html-53b63dbe.js"),[]).then(({data:e})=>e),"v-15f6e7df":()=>V(()=>import("./7-apillon-oauth-integration.html-359dd462.js"),[]).then(({data:e})=>e),"v-6b6a7fe7":()=>V(()=>import("./8-computing-api.html-2e3a9060.js"),[]).then(({data:e})=>e),"v-6ef47b51":()=>V(()=>import("./9-social-api.html-bb19f920.js"),[]).then(({data:e})=>e),"v-2d5fd574":()=>V(()=>import("./1-good-to-know.html-ac614477.js"),[]).then(({data:e})=>e),"v-0c17de3a":()=>V(()=>import("./10-web3-infrastructure.html-11bd2130.js"),[]).then(({data:e})=>e),"v-47991eb5":()=>V(()=>import("./2-web3-storage.html-5be7a21c.js"),[]).then(({data:e})=>e),"v-f2d17dd2":()=>V(()=>import("./3-web3-hosting.html-211cf8f9.js"),[]).then(({data:e})=>e),"v-713d4f4d":()=>V(()=>import("./4-nfts.html-1caeb901.js"),[]).then(({data:e})=>e),"v-662ed367":()=>V(()=>import("./5-web3-authentication.html-52c30c94.js"),[]).then(({data:e})=>e),"v-592c909e":()=>V(()=>import("./6-web3-social.html-fc24a382.js"),[]).then(({data:e})=>e),"v-b6f01184":()=>V(()=>import("./7-web3-compute.html-2f436aa7.js"),[]).then(({data:e})=>e),"v-174aec9a":()=>V(()=>import("./8-web3-cloud-functions.html-7f591621.js"),[]).then(({data:e})=>e),"v-91d7101c":()=>V(()=>import("./9-embedded-wallets.html-68d9e8bd.js"),[]).then(({data:e})=>e),"v-3706649a":()=>V(()=>import("./404.html-60b35caa.js"),[]).then(({data:e})=>e)},Eu=JSON.parse('{"base":"/","lang":"en-US","title":"Apillon Wiki","description":"Apillon Wiki","head":[["link",{"rel":"icon","href":"/assets/logo-favicon.png","sizes":"32x32"}],["link",{"rel":"icon","href":"/assets/logo-favicon.png","sizes":"192x192"}],["link",{"rel":"apple-touch-icon","href":"/assets/logo-favicon.png"}],["meta",{"name":"msapplication-TileImage","content":"/assets/logo-favicon.png"}]],"locales":{}}');var Cu=([e,t,n])=>e==="meta"&&t.name?`${e}.${t.name}`:["title","base"].includes(e)?e:e==="template"&&t.id?`${e}.${t.id}`:JSON.stringify([e,t,n]),xu=e=>{const t=new Set,n=[];return e.forEach(l=>{const o=Cu(l);t.has(o)||(t.add(o),n.push(l))}),n},Yn=e=>/^(https?:)?\/\//.test(e),Lu=e=>/^mailto:/.test(e),Tu=e=>/^tel:/.test(e),Fo=e=>Object.prototype.toString.call(e)==="[object Object]",ds=e=>e[e.length-1]==="/"?e.slice(0,-1):e,fs=e=>e[0]==="/"?e.slice(1):e,hs=(e,t)=>{const n=Object.keys(e).sort((l,o)=>{const r=o.split("/").length-l.split("/").length;return r!==0?r:o.length-l.length});for(const l of n)if(t.startsWith(l))return l;return"/"};const ps={"v-8daa1a0e":ae(()=>V(()=>import("./index.html-4e0e9fe3.js"),[])),"v-8daa1a0e":ae(()=>V(()=>import("./index.html-4e0e9fe3.js"),[])),"v-92c536e4":ae(()=>V(()=>import("./1-navigation.html-cc4d8e50.js"),[])),"v-d64fcca0":ae(()=>V(()=>import("./2-what-is-apillon.html-5098629a.js"),[])),"v-0f48940c":ae(()=>V(()=>import("./3-why-apillon.html-5e2f11cb.js"),[])),"v-6bda2dde":ae(()=>V(()=>import("./4-how-does-apillon-work.html-dcf52b18.js"),[])),"v-ac15b5a4":ae(()=>V(()=>import("./5-developing-web3-with-apillon.html-9ef9fc9f.js"),[])),"v-da41cf52":ae(()=>V(()=>import("./6-web3-up-close.html-fa81e3ac.js"),[])),"v-929e013e":ae(()=>V(()=>import("./7-community.html-daedf890.js"),[])),"v-564790ea":ae(()=>V(()=>import("./8-nctr-token.html-0243cb28.js"),[])),"v-cdfbcdae":ae(()=>V(()=>import("./1-apillon-api.html-22e8226e.js"),[])),"v-4d91ab64":ae(()=>V(()=>import("./10-flutter-sdk.html-390dcbc7.js"),[])),"v-15e6da9c":ae(()=>V(()=>import("./11-cloud-functions-api.html-6c203f62.js"),[])),"v-3453e56e":ae(()=>V(()=>import("./12-embedded-wallets-integration.html-19ee857f.js"),[])),"v-7a601078":ae(()=>V(()=>import("./13-infrastructure-api.html-f384aa98.js"),[])),"v-1da918f4":ae(()=>V(()=>import("./2-storage-api.html-8c8a347a.js"),[])),"v-3fe44474":ae(()=>V(()=>import("./3-hosting-api.html-d898b05b.js"),[])),"v-ae3a6dfc":ae(()=>V(()=>import("./4-nfts-api.html-eaa291cc.js"),[])),"v-fc8498f6":ae(()=>V(()=>import("./5-apillon-sdk.html-a6baace8.js"),[])),"v-6c04f07e":ae(()=>V(()=>import("./6-apillon-cli.html-21eb873e.js"),[])),"v-15f6e7df":ae(()=>V(()=>import("./7-apillon-oauth-integration.html-4b6bb4e8.js"),[])),"v-6b6a7fe7":ae(()=>V(()=>import("./8-computing-api.html-3a569377.js"),[])),"v-6ef47b51":ae(()=>V(()=>import("./9-social-api.html-48ddfe96.js"),[])),"v-2d5fd574":ae(()=>V(()=>import("./1-good-to-know.html-ec261250.js"),[])),"v-0c17de3a":ae(()=>V(()=>import("./10-web3-infrastructure.html-a6a54873.js"),[])),"v-47991eb5":ae(()=>V(()=>import("./2-web3-storage.html-0a54578d.js"),[])),"v-f2d17dd2":ae(()=>V(()=>import("./3-web3-hosting.html-5c7ceb75.js"),[])),"v-713d4f4d":ae(()=>V(()=>import("./4-nfts.html-4ada86fc.js"),[])),"v-662ed367":ae(()=>V(()=>import("./5-web3-authentication.html-a9029df0.js"),[])),"v-592c909e":ae(()=>V(()=>import("./6-web3-social.html-a1e42f4b.js"),[])),"v-b6f01184":ae(()=>V(()=>import("./7-web3-compute.html-6e31905a.js"),[])),"v-174aec9a":ae(()=>V(()=>import("./8-web3-cloud-functions.html-e694e64a.js"),[])),"v-91d7101c":ae(()=>V(()=>import("./9-embedded-wallets.html-641d7d93.js"),[])),"v-3706649a":ae(()=>V(()=>import("./404.html-d269ab15.js"),[]))};var Au=Symbol(""),Pu=be(ku),ms=Wn({key:"",path:"",title:"",lang:"",frontmatter:{},headers:[]}),St=be(ms),Yt=()=>St,gs=Symbol(""),vt=()=>{const e=Pe(gs);if(!e)throw new Error("usePageFrontmatter() is called without provider.");return e},vs=Symbol(""),Su=()=>{const e=Pe(vs);if(!e)throw new Error("usePageHead() is called without provider.");return e},Ru=Symbol(""),bs=Symbol(""),Iu=()=>{const e=Pe(bs);if(!e)throw new Error("usePageLang() is called without provider.");return e},_s=Symbol(""),Ou=()=>{const e=Pe(_s);if(!e)throw new Error("usePageLayout() is called without provider.");return e},Mo=Symbol(""),Jn=()=>{const e=Pe(Mo);if(!e)throw new Error("useRouteLocale() is called without provider.");return e},on=be(Eu),ys=()=>on,ws=Symbol(""),Ho=()=>{const e=Pe(ws);if(!e)throw new Error("useSiteLocaleData() is called without provider.");return e},Nu=Symbol(""),Du="Layout",$u="NotFound",ht=jn({resolveLayouts:e=>e.reduce((t,n)=>({...t,...n.layouts}),{}),resolvePageData:async e=>{const t=Pu.value[e];return await(t==null?void 0:t())??ms},resolvePageFrontmatter:e=>e.frontmatter,resolvePageHead:(e,t,n)=>{const l=ge(t.description)?t.description:n.description,o=[...X(t.head)?t.head:[],...n.head,["title",{},e],["meta",{name:"description",content:l}]];return xu(o)},resolvePageHeadTitle:(e,t)=>[e.title,t.title].filter(n=>!!n).join(" | "),resolvePageLang:(e,t)=>e.lang||t.lang||"en-US",resolvePageLayout:(e,t)=>{let n;if(e.path){const l=e.frontmatter.layout;ge(l)?n=l:n=Du}else n=$u;return t[n]},resolveRouteLocale:(e,t)=>hs(e,t),resolveSiteLocaleData:(e,t)=>({...e,...e.locales[t]})}),zo=de({name:"ClientOnly",setup(e,t){const n=be(!1);return Ke(()=>{n.value=!0}),()=>{var l,o;return n.value?(o=(l=t.slots).default)==null?void 0:o.call(l):null}}}),Fu=de({name:"Content",props:{pageKey:{type:String,required:!1,default:""}},setup(e){const t=Yt(),n=j(()=>ps[e.pageKey||t.value.key]);return()=>n.value?ce(n.value):ce("div","404 Not Found")}}),wt=(e={})=>e,Bo=e=>Yn(e)?e:`/${fs(e)}`;function ks(e,t,n){var l,o,r;t===void 0&&(t=50),n===void 0&&(n={});var i=(l=n.isImmediate)!=null&&l,s=(o=n.callback)!=null&&o,a=n.maxWait,c=Date.now(),u=[];function d(){if(a!==void 0){var m=Date.now()-c;if(m+t>=a)return a-m}return t}var h=function(){var m=[].slice.call(arguments),y=this;return new Promise(function(k,x){var T=i&&r===void 0;if(r!==void 0&&clearTimeout(r),r=setTimeout(function(){if(r=void 0,c=Date.now(),!i){var v=e.apply(y,m);s&&s(v),u.forEach(function(_){return(0,_.resolve)(v)}),u=[]}},d()),T){var A=e.apply(y,m);return s&&s(A),k(A)}u.push({resolve:k,reject:x})})};return h.cancel=function(m){r!==void 0&&clearTimeout(r),u.forEach(function(y){return(0,y.reject)(m)}),u=[]},h}/*! + * vue-router v4.2.5 + * (c) 2023 Eduardo San Martin Morote + * @license MIT + */const ln=typeof window<"u";function Mu(e){return e.__esModule||e[Symbol.toStringTag]==="Module"}const ve=Object.assign;function Jl(e,t){const n={};for(const l in t){const o=t[l];n[l]=rt(o)?o.map(e):e(o)}return n}const Rn=()=>{},rt=Array.isArray,Hu=/\/$/,zu=e=>e.replace(Hu,"");function Ql(e,t,n="/"){let l,o={},r="",i="";const s=t.indexOf("#");let a=t.indexOf("?");return s=0&&(a=-1),a>-1&&(l=t.slice(0,a),r=t.slice(a+1,s>-1?s:t.length),o=e(r)),s>-1&&(l=l||t.slice(0,s),i=t.slice(s,t.length)),l=Vu(l??t,n),{fullPath:l+(r&&"?")+r+i,path:l,query:o,hash:i}}function Bu(e,t){const n=t.query?e(t.query):"";return t.path+(n&&"?")+n+(t.hash||"")}function $r(e,t){return!t||!e.toLowerCase().startsWith(t.toLowerCase())?e:e.slice(t.length)||"/"}function ju(e,t,n){const l=t.matched.length-1,o=n.matched.length-1;return l>-1&&l===o&&mn(t.matched[l],n.matched[o])&&Es(t.params,n.params)&&e(t.query)===e(n.query)&&t.hash===n.hash}function mn(e,t){return(e.aliasOf||e)===(t.aliasOf||t)}function Es(e,t){if(Object.keys(e).length!==Object.keys(t).length)return!1;for(const n in e)if(!Wu(e[n],t[n]))return!1;return!0}function Wu(e,t){return rt(e)?Fr(e,t):rt(t)?Fr(t,e):e===t}function Fr(e,t){return rt(t)?e.length===t.length&&e.every((n,l)=>n===t[l]):e.length===1&&e[0]===t}function Vu(e,t){if(e.startsWith("/"))return e;if(!e)return t;const n=t.split("/"),l=e.split("/"),o=l[l.length-1];(o===".."||o===".")&&l.push("");let r=n.length-1,i,s;for(i=0;i 1&&r--;else break;return n.slice(0,r).join("/")+"/"+l.slice(i-(i===l.length?1:0)).join("/")}var Mn;(function(e){e.pop="pop",e.push="push"})(Mn||(Mn={}));var In;(function(e){e.back="back",e.forward="forward",e.unknown=""})(In||(In={}));function Uu(e){if(!e)if(ln){const t=document.querySelector("base");e=t&&t.getAttribute("href")||"/",e=e.replace(/^\w+:\/\/[^\/]+/,"")}else e="/";return e[0]!=="/"&&e[0]!=="#"&&(e="/"+e),zu(e)}const qu=/^[^#]+#/;function Ku(e,t){return e.replace(qu,"#")+t}function Gu(e,t){const n=document.documentElement.getBoundingClientRect(),l=e.getBoundingClientRect();return{behavior:t.behavior,left:l.left-n.left-(t.left||0),top:l.top-n.top-(t.top||0)}}const Ml=()=>({left:window.pageXOffset,top:window.pageYOffset});function Yu(e){let t;if("el"in e){const n=e.el,l=typeof n=="string"&&n.startsWith("#"),o=typeof n=="string"?l?document.getElementById(n.slice(1)):document.querySelector(n):n;if(!o)return;t=Gu(o,e)}else t=e;"scrollBehavior"in document.documentElement.style?window.scrollTo(t):window.scrollTo(t.left!=null?t.left:window.pageXOffset,t.top!=null?t.top:window.pageYOffset)}function Mr(e,t){return(history.state?history.state.position-t:-1)+e}const mo=new Map;function Ju(e,t){mo.set(e,t)}function Qu(e){const t=mo.get(e);return mo.delete(e),t}let Zu=()=>location.protocol+"//"+location.host;function Cs(e,t){const{pathname:n,search:l,hash:o}=t,r=e.indexOf("#");if(r>-1){let s=o.includes(e.slice(r))?e.slice(r).length:1,a=o.slice(s);return a[0]!=="/"&&(a="/"+a),$r(a,"")}return $r(n,e)+l+o}function Xu(e,t,n,l){let o=[],r=[],i=null;const s=({state:h})=>{const m=Cs(e,location),y=n.value,k=t.value;let x=0;if(h){if(n.value=m,t.value=h,i&&i===y){i=null;return}x=k?h.position-k.position:0}else l(m);o.forEach(T=>{T(n.value,y,{delta:x,type:Mn.pop,direction:x?x>0?In.forward:In.back:In.unknown})})};function a(){i=n.value}function c(h){o.push(h);const m=()=>{const y=o.indexOf(h);y>-1&&o.splice(y,1)};return r.push(m),m}function u(){const{history:h}=window;h.state&&h.replaceState(ve({},h.state,{scroll:Ml()}),"")}function d(){for(const h of r)h();r=[],window.removeEventListener("popstate",s),window.removeEventListener("beforeunload",u)}return window.addEventListener("popstate",s),window.addEventListener("beforeunload",u,{passive:!0}),{pauseListeners:a,listen:c,destroy:d}}function Hr(e,t,n,l=!1,o=!1){return{back:e,current:t,forward:n,replaced:l,position:window.history.length,scroll:o?Ml():null}}function ed(e){const{history:t,location:n}=window,l={value:Cs(e,n)},o={value:t.state};o.value||r(l.value,{back:null,current:l.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function r(a,c,u){const d=e.indexOf("#"),h=d>-1?(n.host&&document.querySelector("base")?e:e.slice(d))+a:Zu()+e+a;try{t[u?"replaceState":"pushState"](c,"",h),o.value=c}catch(m){console.error(m),n[u?"replace":"assign"](h)}}function i(a,c){const u=ve({},t.state,Hr(o.value.back,a,o.value.forward,!0),c,{position:o.value.position});r(a,u,!0),l.value=a}function s(a,c){const u=ve({},o.value,t.state,{forward:a,scroll:Ml()});r(u.current,u,!0);const d=ve({},Hr(l.value,a,null),{position:u.position+1},c);r(a,d,!1),l.value=a}return{location:l,state:o,push:s,replace:i}}function td(e){e=Uu(e);const t=ed(e),n=Xu(e,t.state,t.location,t.replace);function l(r,i=!0){i||n.pauseListeners(),history.go(r)}const o=ve({location:"",base:e,go:l,createHref:Ku.bind(null,e)},t,n);return Object.defineProperty(o,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(o,"state",{enumerable:!0,get:()=>t.state.value}),o}function nd(e){return typeof e=="string"||e&&typeof e=="object"}function xs(e){return typeof e=="string"||typeof e=="symbol"}const pt={path:"/",name:void 0,params:{},query:{},hash:"",fullPath:"/",matched:[],meta:{},redirectedFrom:void 0},Ls=Symbol("");var zr;(function(e){e[e.aborted=4]="aborted",e[e.cancelled=8]="cancelled",e[e.duplicated=16]="duplicated"})(zr||(zr={}));function gn(e,t){return ve(new Error,{type:e,[Ls]:!0},t)}function ft(e,t){return e instanceof Error&&Ls in e&&(t==null||!!(e.type&t))}const Br="[^/]+?",ld={sensitive:!1,strict:!1,start:!0,end:!0},od=/[.+*?^${}()[\]/\\]/g;function rd(e,t){const n=ve({},ld,t),l=[];let o=n.start?"^":"";const r=[];for(const c of e){const u=c.length?[]:[90];n.strict&&!c.length&&(o+="/");for(let d=0;d t.length?t.length===1&&t[0]===40+40?1:-1:0}function sd(e,t){let n=0;const l=e.score,o=t.score;for(;n 0&&t[t.length-1]<0}const ad={type:0,value:""},cd=/[a-zA-Z0-9_]/;function ud(e){if(!e)return[[]];if(e==="/")return[[ad]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(m){throw new Error(`ERR (${n})/"${c}": ${m}`)}let n=0,l=n;const o=[];let r;function i(){r&&o.push(r),r=[]}let s=0,a,c="",u="";function d(){c&&(n===0?r.push({type:0,value:c}):n===1||n===2||n===3?(r.length>1&&(a==="*"||a==="+")&&t(`A repeatable param (${c}) must be alone in its segment. eg: '/:ids+.`),r.push({type:1,value:c,regexp:u,repeatable:a==="*"||a==="+",optional:a==="*"||a==="?"})):t("Invalid state to consume buffer"),c="")}function h(){c+=a}for(;s {i(A)}:Rn}function i(u){if(xs(u)){const d=l.get(u);d&&(l.delete(u),n.splice(n.indexOf(d),1),d.children.forEach(i),d.alias.forEach(i))}else{const d=n.indexOf(u);d>-1&&(n.splice(d,1),u.record.name&&l.delete(u.record.name),u.children.forEach(i),u.alias.forEach(i))}}function s(){return n}function a(u){let d=0;for(;d =0&&(u.record.path!==n[d].record.path||!Ts(u,n[d]));)d++;n.splice(d,0,u),u.record.name&&!Vr(u)&&l.set(u.record.name,u)}function c(u,d){let h,m={},y,k;if("name"in u&&u.name){if(h=l.get(u.name),!h)throw gn(1,{location:u});k=h.record.name,m=ve(Wr(d.params,h.keys.filter(A=>!A.optional).map(A=>A.name)),u.params&&Wr(u.params,h.keys.map(A=>A.name))),y=h.stringify(m)}else if("path"in u)y=u.path,h=n.find(A=>A.re.test(y)),h&&(m=h.parse(y),k=h.record.name);else{if(h=d.name?l.get(d.name):n.find(A=>A.re.test(d.path)),!h)throw gn(1,{location:u,currentLocation:d});k=h.record.name,m=ve({},d.params,u.params),y=h.stringify(m)}const x=[];let T=h;for(;T;)x.unshift(T.record),T=T.parent;return{name:k,path:y,params:m,matched:x,meta:md(x)}}return e.forEach(u=>r(u)),{addRoute:r,resolve:c,removeRoute:i,getRoutes:s,getRecordMatcher:o}}function Wr(e,t){const n={};for(const l of t)l in e&&(n[l]=e[l]);return n}function hd(e){return{path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:void 0,beforeEnter:e.beforeEnter,props:pd(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}}}function pd(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const l in e.components)t[l]=typeof n=="object"?n[l]:n;return t}function Vr(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function md(e){return e.reduce((t,n)=>ve(t,n.meta),{})}function Ur(e,t){const n={};for(const l in e)n[l]=l in t?t[l]:e[l];return n}function Ts(e,t){return t.children.some(n=>n===e||Ts(e,n))}const As=/#/g,gd=/&/g,vd=/\//g,bd=/=/g,_d=/\?/g,Ps=/\+/g,yd=/%5B/g,wd=/%5D/g,Ss=/%5E/g,kd=/%60/g,Rs=/%7B/g,Ed=/%7C/g,Is=/%7D/g,Cd=/%20/g;function jo(e){return encodeURI(""+e).replace(Ed,"|").replace(yd,"[").replace(wd,"]")}function xd(e){return jo(e).replace(Rs,"{").replace(Is,"}").replace(Ss,"^")}function go(e){return jo(e).replace(Ps,"%2B").replace(Cd,"+").replace(As,"%23").replace(gd,"%26").replace(kd,"`").replace(Rs,"{").replace(Is,"}").replace(Ss,"^")}function Ld(e){return go(e).replace(bd,"%3D")}function Td(e){return jo(e).replace(As,"%23").replace(_d,"%3F")}function Ad(e){return e==null?"":Td(e).replace(vd,"%2F")}function Cl(e){try{return decodeURIComponent(""+e)}catch{}return""+e}function Pd(e){const t={};if(e===""||e==="?")return t;const l=(e[0]==="?"?e.slice(1):e).split("&");for(let o=0;o r&&go(r)):[l&&go(l)]).forEach(r=>{r!==void 0&&(t+=(t.length?"&":"")+n,r!=null&&(t+="="+r))})}return t}function Sd(e){const t={};for(const n in e){const l=e[n];l!==void 0&&(t[n]=rt(l)?l.map(o=>o==null?null:""+o):l==null?l:""+l)}return t}const Rd=Symbol(""),Kr=Symbol(""),Hl=Symbol(""),Wo=Symbol(""),vo=Symbol("");function En(){let e=[];function t(l){return e.push(l),()=>{const o=e.indexOf(l);o>-1&&e.splice(o,1)}}function n(){e=[]}return{add:t,list:()=>e.slice(),reset:n}}function Rt(e,t,n,l,o){const r=l&&(l.enterCallbacks[o]=l.enterCallbacks[o]||[]);return()=>new Promise((i,s)=>{const a=d=>{d===!1?s(gn(4,{from:n,to:t})):d instanceof Error?s(d):nd(d)?s(gn(2,{from:t,to:d})):(r&&l.enterCallbacks[o]===r&&typeof d=="function"&&r.push(d),i())},c=e.call(l&&l.instances[o],t,n,a);let u=Promise.resolve(c);e.length<3&&(u=u.then(a)),u.catch(d=>s(d))})}function Zl(e,t,n,l){const o=[];for(const r of e)for(const i in r.components){let s=r.components[i];if(!(t!=="beforeRouteEnter"&&!r.instances[i]))if(Id(s)){const c=(s.__vccOpts||s)[t];c&&o.push(Rt(c,n,l,r,i))}else{let a=s();o.push(()=>a.then(c=>{if(!c)return Promise.reject(new Error(`Couldn't resolve component "${i}" at "${r.path}"`));const u=Mu(c)?c.default:c;r.components[i]=u;const h=(u.__vccOpts||u)[t];return h&&Rt(h,n,l,r,i)()}))}}return o}function Id(e){return typeof e=="object"||"displayName"in e||"props"in e||"__vccOpts"in e}function Gr(e){const t=Pe(Hl),n=Pe(Wo),l=j(()=>t.resolve(te(e.to))),o=j(()=>{const{matched:a}=l.value,{length:c}=a,u=a[c-1],d=n.matched;if(!u||!d.length)return-1;const h=d.findIndex(mn.bind(null,u));if(h>-1)return h;const m=Yr(a[c-2]);return c>1&&Yr(u)===m&&d[d.length-1].path!==m?d.findIndex(mn.bind(null,a[c-2])):h}),r=j(()=>o.value>-1&&$d(n.params,l.value.params)),i=j(()=>o.value>-1&&o.value===n.matched.length-1&&Es(n.params,l.value.params));function s(a={}){return Dd(a)?t[te(e.replace)?"replace":"push"](te(e.to)).catch(Rn):Promise.resolve()}return{route:l,href:j(()=>l.value.href),isActive:r,isExactActive:i,navigate:s}}const Od=de({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"}},useLink:Gr,setup(e,{slots:t}){const n=jn(Gr(e)),{options:l}=Pe(Hl),o=j(()=>({[Jr(e.activeClass,l.linkActiveClass,"router-link-active")]:n.isActive,[Jr(e.exactActiveClass,l.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const r=t.default&&t.default(n);return e.custom?r:ce("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:o.value},r)}}}),Nd=Od;function Dd(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function $d(e,t){for(const n in t){const l=t[n],o=e[n];if(typeof l=="string"){if(l!==o)return!1}else if(!rt(o)||o.length!==l.length||l.some((r,i)=>r!==o[i]))return!1}return!0}function Yr(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const Jr=(e,t,n)=>e??t??n,Fd=de({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const l=Pe(vo),o=j(()=>e.route||l.value),r=Pe(Kr,0),i=j(()=>{let c=te(r);const{matched:u}=o.value;let d;for(;(d=u[c])&&!d.components;)c++;return c}),s=j(()=>o.value.matched[i.value]);Kt(Kr,j(()=>i.value+1)),Kt(Rd,s),Kt(vo,o);const a=be();return ut(()=>[a.value,s.value,e.name],([c,u,d],[h,m,y])=>{u&&(u.instances[d]=c,m&&m!==u&&c&&c===h&&(u.leaveGuards.size||(u.leaveGuards=m.leaveGuards),u.updateGuards.size||(u.updateGuards=m.updateGuards))),c&&u&&(!m||!mn(u,m)||!h)&&(u.enterCallbacks[d]||[]).forEach(k=>k(c))},{flush:"post"}),()=>{const c=o.value,u=e.name,d=s.value,h=d&&d.components[u];if(!h)return Qr(n.default,{Component:h,route:c});const m=d.props[u],y=m?m===!0?c.params:typeof m=="function"?m(c):m:null,x=ce(h,ve({},y,t,{onVnodeUnmounted:T=>{T.component.isUnmounted&&(d.instances[u]=null)},ref:a}));return Qr(n.default,{Component:x,route:c})||x}}});function Qr(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const Os=Fd;function Md(e){const t=fd(e.routes,e),n=e.parseQuery||Pd,l=e.stringifyQuery||qr,o=e.history,r=En(),i=En(),s=En(),a=Ao(pt);let c=pt;ln&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=Jl.bind(null,C=>""+C),d=Jl.bind(null,Ad),h=Jl.bind(null,Cl);function m(C,W){let F,Y;return xs(C)?(F=t.getRecordMatcher(C),Y=W):Y=C,t.addRoute(Y,F)}function y(C){const W=t.getRecordMatcher(C);W&&t.removeRoute(W)}function k(){return t.getRoutes().map(C=>C.record)}function x(C){return!!t.getRecordMatcher(C)}function T(C,W){if(W=ve({},W||a.value),typeof C=="string"){const g=Ql(n,C,W.path),w=t.resolve({path:g.path},W),L=o.createHref(g.fullPath);return ve(g,w,{params:h(w.params),hash:Cl(g.hash),redirectedFrom:void 0,href:L})}let F;if("path"in C)F=ve({},C,{path:Ql(n,C.path,W.path).path});else{const g=ve({},C.params);for(const w in g)g[w]==null&&delete g[w];F=ve({},C,{params:d(g)}),W.params=d(W.params)}const Y=t.resolve(F,W),ue=C.hash||"";Y.params=u(h(Y.params));const f=Bu(l,ve({},C,{hash:xd(ue),path:Y.path})),p=o.createHref(f);return ve({fullPath:f,hash:ue,query:l===qr?Sd(C.query):C.query||{}},Y,{redirectedFrom:void 0,href:p})}function A(C){return typeof C=="string"?Ql(n,C,a.value.path):ve({},C)}function v(C,W){if(c!==C)return gn(8,{from:W,to:C})}function _(C){return $(C)}function H(C){return _(ve(A(C),{replace:!0}))}function G(C){const W=C.matched[C.matched.length-1];if(W&&W.redirect){const{redirect:F}=W;let Y=typeof F=="function"?F(C):F;return typeof Y=="string"&&(Y=Y.includes("?")||Y.includes("#")?Y=A(Y):{path:Y},Y.params={}),ve({query:C.query,hash:C.hash,params:"path"in Y?{}:C.params},Y)}}function $(C,W){const F=c=T(C),Y=a.value,ue=C.state,f=C.force,p=C.replace===!0,g=G(F);if(g)return $(ve(A(g),{state:typeof g=="object"?ve({},ue,g.state):ue,force:f,replace:p}),W||F);const w=F;w.redirectedFrom=W;let L;return!f&&ju(l,Y,F)&&(L=gn(16,{to:w,from:Y}),We(Y,Y,!0,!1)),(L?Promise.resolve(L):S(w,Y)).catch(P=>ft(P)?ft(P,2)?P:$e(P):U(P,w,Y)).then(P=>{if(P){if(ft(P,2))return $(ve({replace:p},A(P.to),{state:typeof P.to=="object"?ve({},ue,P.to.state):ue,force:f}),W||w)}else P=E(w,Y,!0,p,ue);return q(w,Y,P),P})}function b(C,W){const F=v(C,W);return F?Promise.reject(F):Promise.resolve()}function O(C){const W=Et.values().next().value;return W&&typeof W.runWithContext=="function"?W.runWithContext(C):C()}function S(C,W){let F;const[Y,ue,f]=Hd(C,W);F=Zl(Y.reverse(),"beforeRouteLeave",C,W);for(const g of Y)g.leaveGuards.forEach(w=>{F.push(Rt(w,C,W))});const p=b.bind(null,C,W);return F.push(p),Ne(F).then(()=>{F=[];for(const g of r.list())F.push(Rt(g,C,W));return F.push(p),Ne(F)}).then(()=>{F=Zl(ue,"beforeRouteUpdate",C,W);for(const g of ue)g.updateGuards.forEach(w=>{F.push(Rt(w,C,W))});return F.push(p),Ne(F)}).then(()=>{F=[];for(const g of f)if(g.beforeEnter)if(rt(g.beforeEnter))for(const w of g.beforeEnter)F.push(Rt(w,C,W));else F.push(Rt(g.beforeEnter,C,W));return F.push(p),Ne(F)}).then(()=>(C.matched.forEach(g=>g.enterCallbacks={}),F=Zl(f,"beforeRouteEnter",C,W),F.push(p),Ne(F))).then(()=>{F=[];for(const g of i.list())F.push(Rt(g,C,W));return F.push(p),Ne(F)}).catch(g=>ft(g,8)?g:Promise.reject(g))}function q(C,W,F){s.list().forEach(Y=>O(()=>Y(C,W,F)))}function E(C,W,F,Y,ue){const f=v(C,W);if(f)return f;const p=W===pt,g=ln?history.state:{};F&&(Y||p?o.replace(C.fullPath,ve({scroll:p&&g&&g.scroll},ue)):o.push(C.fullPath,ue)),a.value=C,We(C,W,F,p),$e()}let N;function ne(){N||(N=o.listen((C,W,F)=>{if(!it.listening)return;const Y=T(C),ue=G(Y);if(ue){$(ve(ue,{replace:!0}),Y).catch(Rn);return}c=Y;const f=a.value;ln&&Ju(Mr(f.fullPath,F.delta),Ml()),S(Y,f).catch(p=>ft(p,12)?p:ft(p,2)?($(p.to,Y).then(g=>{ft(g,20)&&!F.delta&&F.type===Mn.pop&&o.go(-1,!1)}).catch(Rn),Promise.reject()):(F.delta&&o.go(-F.delta,!1),U(p,Y,f))).then(p=>{p=p||E(Y,f,!1),p&&(F.delta&&!ft(p,8)?o.go(-F.delta,!1):F.type===Mn.pop&&ft(p,20)&&o.go(-1,!1)),q(Y,f,p)}).catch(Rn)}))}let ie=En(),I=En(),J;function U(C,W,F){$e(C);const Y=I.list();return Y.length?Y.forEach(ue=>ue(C,W,F)):console.error(C),Promise.reject(C)}function Oe(){return J&&a.value!==pt?Promise.resolve():new Promise((C,W)=>{ie.add([C,W])})}function $e(C){return J||(J=!C,ne(),ie.list().forEach(([W,F])=>C?F(C):W()),ie.reset()),C}function We(C,W,F,Y){const{scrollBehavior:ue}=e;if(!ln||!ue)return Promise.resolve();const f=!F&&Qu(Mr(C.fullPath,0))||(Y||!F)&&history.state&&history.state.scroll||null;return Un().then(()=>ue(C,W,f)).then(p=>p&&Yu(p)).catch(p=>U(p,C,W))}const He=C=>o.go(C);let kt;const Et=new Set,it={currentRoute:a,listening:!0,addRoute:m,removeRoute:y,hasRoute:x,getRoutes:k,resolve:T,options:e,push:_,replace:H,go:He,back:()=>He(-1),forward:()=>He(1),beforeEach:r.add,beforeResolve:i.add,afterEach:s.add,onError:I.add,isReady:Oe,install(C){const W=this;C.component("RouterLink",Nd),C.component("RouterView",Os),C.config.globalProperties.$router=W,Object.defineProperty(C.config.globalProperties,"$route",{enumerable:!0,get:()=>te(a)}),ln&&!kt&&a.value===pt&&(kt=!0,_(o.location).catch(ue=>{}));const F={};for(const ue in pt)Object.defineProperty(F,ue,{get:()=>a.value[ue],enumerable:!0});C.provide(Hl,W),C.provide(Wo,Si(F)),C.provide(vo,a);const Y=C.unmount;Et.add(C),C.unmount=function(){Et.delete(C),Et.size<1&&(c=pt,N&&N(),N=null,a.value=pt,kt=!1,J=!1),Y()}}};function Ne(C){return C.reduce((W,F)=>W.then(()=>O(F)),Promise.resolve())}return it}function Hd(e,t){const n=[],l=[],o=[],r=Math.max(t.matched.length,e.matched.length);for(let i=0;i mn(c,s))?l.push(s):n.push(s));const a=e.matched[i];a&&(t.matched.find(c=>mn(c,a))||o.push(a))}return[n,l,o]}function Zt(){return Pe(Hl)}function Xt(){return Pe(Wo)}const zd=({headerLinkSelector:e,headerAnchorSelector:t,delay:n,offset:l=5})=>{const o=Zt(),i=ks(()=>{var k,x;const s=Math.max(window.scrollY,document.documentElement.scrollTop,document.body.scrollTop);if(Math.abs(s-0) h.some(A=>A.hash===T.hash));for(let T=0;T =(((k=A.parentElement)==null?void 0:k.offsetTop)??0)-l,H=!v||s<(((x=v.parentElement)==null?void 0:x.offsetTop)??0)-l;if(!(_&&H))continue;const $=decodeURIComponent(o.currentRoute.value.hash),b=decodeURIComponent(A.hash);if($===b)return;if(d){for(let O=T+1;O {window.addEventListener("scroll",i)}),Kn(()=>{window.removeEventListener("scroll",i)})},Zr=async(e,t)=>{const{scrollBehavior:n}=e.options;e.options.scrollBehavior=void 0,await e.replace({query:e.currentRoute.value.query,hash:t}).finally(()=>e.options.scrollBehavior=n)},Bd="a.sidebar-item",jd=".header-anchor",Wd=300,Vd=5,Ud=wt({setup(){zd({headerLinkSelector:Bd,headerAnchorSelector:jd,delay:Wd,offset:Vd})}}),Xr=()=>window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,qd=()=>window.scrollTo({top:0,behavior:"smooth"});const Kd=de({name:"BackToTop",setup(){const e=be(0),t=j(()=>e.value>300),n=ks(()=>{e.value=Xr()},100);Ke(()=>{e.value=Xr(),window.addEventListener("scroll",()=>n())});const l=ce("div",{class:"back-to-top",onClick:qd});return()=>ce(Gn,{name:"back-to-top"},()=>t.value?l:null)}}),Gd=wt({rootComponents:[Kd]});const Yd=ce("svg",{class:"external-link-icon",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",focusable:"false",x:"0px",y:"0px",viewBox:"0 0 100 100",width:"15",height:"15"},[ce("path",{fill:"currentColor",d:"M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"}),ce("polygon",{fill:"currentColor",points:"45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"})]),Jd=de({name:"ExternalLinkIcon",props:{locales:{type:Object,required:!1,default:()=>({})}},setup(e){const t=Jn(),n=j(()=>e.locales[t.value]??{openInNewWindow:"open in new window"});return()=>ce("span",[Yd,ce("span",{class:"external-link-icon-sr-only"},n.value.openInNewWindow)])}}),Qd={"/":{openInNewWindow:"open in new window"}},Zd=wt({enhance({app:e}){e.component("ExternalLinkIcon",ce(Jd,{locales:Qd}))}});/*! medium-zoom 1.0.8 | MIT License | https://github.com/francoischalifour/medium-zoom */var Bt=Object.assign||function(e){for(var t=1;t 1&&arguments[1]!==void 0?arguments[1]:{},l=window.Promise||function(E){function N(){}E(N,N)},o=function(E){var N=E.target;if(N===O){y();return}v.indexOf(N)!==-1&&k({target:N})},r=function(){if(!(H||!b.original)){var E=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0;Math.abs(G-E)>$.scrollOffset&&setTimeout(y,150)}},i=function(E){var N=E.key||E.keyCode;(N==="Escape"||N==="Esc"||N===27)&&y()},s=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},N=E;if(E.background&&(O.style.background=E.background),E.container&&E.container instanceof Object&&(N.container=Bt({},$.container,E.container)),E.template){var ne=fl(E.template)?E.template:document.querySelector(E.template);N.template=ne}return $=Bt({},$,N),v.forEach(function(ie){ie.dispatchEvent(nn("medium-zoom:update",{detail:{zoom:S}}))}),S},a=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};return e(Bt({},$,E))},c=function(){for(var E=arguments.length,N=Array(E),ne=0;ne 0?N.reduce(function(I,J){return[].concat(I,ti(J))},[]):v;return ie.forEach(function(I){I.classList.remove("medium-zoom-image"),I.dispatchEvent(nn("medium-zoom:detach",{detail:{zoom:S}}))}),v=v.filter(function(I){return ie.indexOf(I)===-1}),S},d=function(E,N){var ne=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return v.forEach(function(ie){ie.addEventListener("medium-zoom:"+E,N,ne)}),_.push({type:"medium-zoom:"+E,listener:N,options:ne}),S},h=function(E,N){var ne=arguments.length>2&&arguments[2]!==void 0?arguments[2]:{};return v.forEach(function(ie){ie.removeEventListener("medium-zoom:"+E,N,ne)}),_=_.filter(function(ie){return!(ie.type==="medium-zoom:"+E&&ie.listener.toString()===N.toString())}),S},m=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},N=E.target,ne=function(){var I={width:document.documentElement.clientWidth,height:document.documentElement.clientHeight,left:0,top:0,right:0,bottom:0},J=void 0,U=void 0;if($.container)if($.container instanceof Object)I=Bt({},I,$.container),J=I.width-I.left-I.right-$.margin*2,U=I.height-I.top-I.bottom-$.margin*2;else{var Oe=fl($.container)?$.container:document.querySelector($.container),$e=Oe.getBoundingClientRect(),We=$e.width,He=$e.height,kt=$e.left,Et=$e.top;I=Bt({},I,{width:We,height:He,left:kt,top:Et})}J=J||I.width-$.margin*2,U=U||I.height-$.margin*2;var it=b.zoomedHd||b.original,Ne=ei(it)?J:it.naturalWidth||J,C=ei(it)?U:it.naturalHeight||U,W=it.getBoundingClientRect(),F=W.top,Y=W.left,ue=W.width,f=W.height,p=Math.min(Math.max(ue,Ne),J)/ue,g=Math.min(Math.max(f,C),U)/f,w=Math.min(p,g),L=(-Y+(J-ue)/2+$.margin+I.left)/w,P=(-F+(U-f)/2+$.margin+I.top)/w,z="scale("+w+") translate3d("+L+"px, "+P+"px, 0)";b.zoomed.style.transform=z,b.zoomedHd&&(b.zoomedHd.style.transform=z)};return new l(function(ie){if(N&&v.indexOf(N)===-1){ie(S);return}var I=function We(){H=!1,b.zoomed.removeEventListener("transitionend",We),b.original.dispatchEvent(nn("medium-zoom:opened",{detail:{zoom:S}})),ie(S)};if(b.zoomed){ie(S);return}if(N)b.original=N;else if(v.length>0){var J=v;b.original=J[0]}else{ie(S);return}if(b.original.dispatchEvent(nn("medium-zoom:open",{detail:{zoom:S}})),G=window.pageYOffset||document.documentElement.scrollTop||document.body.scrollTop||0,H=!0,b.zoomed=tf(b.original),document.body.appendChild(O),$.template){var U=fl($.template)?$.template:document.querySelector($.template);b.template=document.createElement("div"),b.template.appendChild(U.content.cloneNode(!0)),document.body.appendChild(b.template)}if(b.original.parentElement&&b.original.parentElement.tagName==="PICTURE"&&b.original.currentSrc&&(b.zoomed.src=b.original.currentSrc),document.body.appendChild(b.zoomed),window.requestAnimationFrame(function(){document.body.classList.add("medium-zoom--opened")}),b.original.classList.add("medium-zoom-image--hidden"),b.zoomed.classList.add("medium-zoom-image--opened"),b.zoomed.addEventListener("click",y),b.zoomed.addEventListener("transitionend",I),b.original.getAttribute("data-zoom-src")){b.zoomedHd=b.zoomed.cloneNode(),b.zoomedHd.removeAttribute("srcset"),b.zoomedHd.removeAttribute("sizes"),b.zoomedHd.removeAttribute("loading"),b.zoomedHd.src=b.zoomed.getAttribute("data-zoom-src"),b.zoomedHd.onerror=function(){clearInterval(Oe),console.warn("Unable to reach the zoom image target "+b.zoomedHd.src),b.zoomedHd=null,ne()};var Oe=setInterval(function(){b.zoomedHd.complete&&(clearInterval(Oe),b.zoomedHd.classList.add("medium-zoom-image--opened"),b.zoomedHd.addEventListener("click",y),document.body.appendChild(b.zoomedHd),ne())},10)}else if(b.original.hasAttribute("srcset")){b.zoomedHd=b.zoomed.cloneNode(),b.zoomedHd.removeAttribute("sizes"),b.zoomedHd.removeAttribute("loading");var $e=b.zoomedHd.addEventListener("load",function(){b.zoomedHd.removeEventListener("load",$e),b.zoomedHd.classList.add("medium-zoom-image--opened"),b.zoomedHd.addEventListener("click",y),document.body.appendChild(b.zoomedHd),ne()})}else ne()})},y=function(){return new l(function(E){if(H||!b.original){E(S);return}var N=function ne(){b.original.classList.remove("medium-zoom-image--hidden"),document.body.removeChild(b.zoomed),b.zoomedHd&&document.body.removeChild(b.zoomedHd),document.body.removeChild(O),b.zoomed.classList.remove("medium-zoom-image--opened"),b.template&&document.body.removeChild(b.template),H=!1,b.zoomed.removeEventListener("transitionend",ne),b.original.dispatchEvent(nn("medium-zoom:closed",{detail:{zoom:S}})),b.original=null,b.zoomed=null,b.zoomedHd=null,b.template=null,E(S)};H=!0,document.body.classList.remove("medium-zoom--opened"),b.zoomed.style.transform="",b.zoomedHd&&(b.zoomedHd.style.transform=""),b.template&&(b.template.style.transition="opacity 150ms",b.template.style.opacity=0),b.original.dispatchEvent(nn("medium-zoom:close",{detail:{zoom:S}})),b.zoomed.addEventListener("transitionend",N)})},k=function(){var E=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},N=E.target;return b.original?y():m({target:N})},x=function(){return $},T=function(){return v},A=function(){return b.original},v=[],_=[],H=!1,G=0,$=n,b={original:null,zoomed:null,zoomedHd:null,template:null};Object.prototype.toString.call(t)==="[object Object]"?$=t:(t||typeof t=="string")&&c(t),$=Bt({margin:0,background:"#fff",scrollOffset:40,container:null,template:null},$);var O=ef($.background);document.addEventListener("click",o),document.addEventListener("keyup",i),document.addEventListener("scroll",r),window.addEventListener("resize",y);var S={open:m,close:y,toggle:k,update:s,clone:a,attach:c,detach:u,on:d,off:h,getOptions:x,getImages:T,getZoomedImage:A};return S};function lf(e,t){t===void 0&&(t={});var n=t.insertAt;if(!(!e||typeof document>"u")){var l=document.head||document.getElementsByTagName("head")[0],o=document.createElement("style");o.type="text/css",n==="top"&&l.firstChild?l.insertBefore(o,l.firstChild):l.appendChild(o),o.styleSheet?o.styleSheet.cssText=e:o.appendChild(document.createTextNode(e))}}var of=".medium-zoom-overlay{position:fixed;top:0;right:0;bottom:0;left:0;opacity:0;transition:opacity .3s;will-change:opacity}.medium-zoom--opened .medium-zoom-overlay{cursor:pointer;cursor:zoom-out;opacity:1}.medium-zoom-image{cursor:pointer;cursor:zoom-in;transition:transform .3s cubic-bezier(.2,0,.2,1)!important}.medium-zoom-image--hidden{visibility:hidden}.medium-zoom-image--opened{position:relative;cursor:pointer;cursor:zoom-out;will-change:transform}";lf(of);const rf=nf,sf=Symbol("mediumZoom");const af=".theme-default-content > img, .theme-default-content :not(a) > img",cf={},uf=300,df=wt({enhance({app:e,router:t}){const n=rf(cf);n.refresh=(l=af)=>{n.detach(),n.attach(l)},e.provide(sf,n),t.afterEach(()=>{setTimeout(()=>n.refresh(),uf)})}});/** + * NProgress, (c) 2013, 2014 Rico Sta. Cruz - http://ricostacruz.com/nprogress + * @license MIT + */const fe={settings:{minimum:.08,easing:"ease",speed:200,trickle:!0,trickleRate:.02,trickleSpeed:800,barSelector:'[role="bar"]',parent:"body",template:''},status:null,set:e=>{const t=fe.isStarted();e=Xl(e,fe.settings.minimum,1),fe.status=e===1?null:e;const n=fe.render(!t),l=n.querySelector(fe.settings.barSelector),o=fe.settings.speed,r=fe.settings.easing;return n.offsetWidth,ff(i=>{sl(l,{transform:"translate3d("+ni(e)+"%,0,0)",transition:"all "+o+"ms "+r}),e===1?(sl(n,{transition:"none",opacity:"1"}),n.offsetWidth,setTimeout(function(){sl(n,{transition:"all "+o+"ms linear",opacity:"0"}),setTimeout(function(){fe.remove(),i()},o)},o)):setTimeout(()=>i(),o)}),fe},isStarted:()=>typeof fe.status=="number",start:()=>{fe.status||fe.set(0);const e=()=>{setTimeout(()=>{fe.status&&(fe.trickle(),e())},fe.settings.trickleSpeed)};return fe.settings.trickle&&e(),fe},done:e=>!e&&!fe.status?fe:fe.inc(.3+.5*Math.random()).set(1),inc:e=>{let t=fe.status;return t?(typeof e!="number"&&(e=(1-t)*Xl(Math.random()*t,.1,.95)),t=Xl(t+e,0,.994),fe.set(t)):fe.start()},trickle:()=>fe.inc(Math.random()*fe.settings.trickleRate),render:e=>{if(fe.isRendered())return document.getElementById("nprogress");li(document.documentElement,"nprogress-busy");const t=document.createElement("div");t.id="nprogress",t.innerHTML=fe.settings.template;const n=t.querySelector(fe.settings.barSelector),l=e?"-100":ni(fe.status||0),o=document.querySelector(fe.settings.parent);return sl(n,{transition:"all 0 linear",transform:"translate3d("+l+"%,0,0)"}),o!==document.body&&li(o,"nprogress-custom-parent"),o==null||o.appendChild(t),t},remove:()=>{oi(document.documentElement,"nprogress-busy"),oi(document.querySelector(fe.settings.parent),"nprogress-custom-parent");const e=document.getElementById("nprogress");e&&hf(e)},isRendered:()=>!!document.getElementById("nprogress")},Xl=(e,t,n)=>e n?n:e,ni=e=>(-1+e)*100,ff=function(){const e=[];function t(){const n=e.shift();n&&n(t)}return function(n){e.push(n),e.length===1&&t()}}(),sl=function(){const e=["Webkit","O","Moz","ms"],t={};function n(i){return i.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(s,a){return a.toUpperCase()})}function l(i){const s=document.body.style;if(i in s)return i;let a=e.length;const c=i.charAt(0).toUpperCase()+i.slice(1);let u;for(;a--;)if(u=e[a]+c,u in s)return u;return i}function o(i){return i=n(i),t[i]??(t[i]=l(i))}function r(i,s,a){s=o(s),i.style[s]=a}return function(i,s){for(const a in s){const c=s[a];c!==void 0&&Object.prototype.hasOwnProperty.call(s,a)&&r(i,a,c)}}}(),Ns=(e,t)=>(typeof e=="string"?e:Vo(e)).indexOf(" "+t+" ")>=0,li=(e,t)=>{const n=Vo(e),l=n+t;Ns(n,t)||(e.className=l.substring(1))},oi=(e,t)=>{const n=Vo(e);if(!Ns(e,t))return;const l=n.replace(" "+t+" "," ");e.className=l.substring(1,l.length-1)},Vo=e=>(" "+(e.className||"")+" ").replace(/\s+/gi," "),hf=e=>{e&&e.parentNode&&e.parentNode.removeChild(e)};const pf=()=>{Ke(()=>{const e=Zt(),t=new Set;t.add(e.currentRoute.value.path),e.beforeEach(n=>{t.has(n.path)||fe.start()}),e.afterEach(n=>{t.add(n.path),fe.done()})})},mf=wt({setup(){pf()}}),gf=JSON.parse(`{"repo":"Apillon/wiki","docsDir":"","colorModeSwitch":false,"colorMode":"dark","locales":{"/":{"sidebar":{"/":[],"/about":[{"text":"About","collapsible":true,"children":["/about/1-navigation.md","/about/2-what-is-apillon.md","/about/3-why-apillon.md","/about/4-how-does-apillon-work.md","/about/5-developing-web3-with-apillon.md","/about/6-web3-up-close.md","/about/7-community.md","/about/8-nctr-token.md"]},{"text":"Web3-services","collapsible":true,"children":["/web3-services/1-good-to-know.md","/web3-services/2-web3-storage.md","/web3-services/3-web3-hosting.md","/web3-services/4-nfts.md","/web3-services/5-web3-authentication.md","/web3-services/6-web3-social.md","/web3-services/7-web3-compute.md","/web3-services/8-web3-cloud-functions.md","/web3-services/9-embedded-wallets.md","/web3-services/10-web3-infrastructure.md"]},{"text":"Build","collapsible":true,"children":["/build/1-apillon-api.md","/build/2-storage-api.md","/build/3-hosting-api.md","/build/4-nfts-api.md","/build/5-apillon-sdk.md","/build/6-apillon-cli.md","/build/7-apillon-oauth-integration.md","/build/8-computing-api.md","/build/9-social-api.md","/build/10-flutter-sdk.md","/build/11-cloud-functions-api.md","/build/12-embedded-wallets-integration.md","/build/13-infrastructure-api.md"]}],"/web3-services":[{"text":"About","collapsible":true,"children":["/about/1-navigation.md","/about/2-what-is-apillon.md","/about/3-why-apillon.md","/about/4-how-does-apillon-work.md","/about/5-developing-web3-with-apillon.md","/about/6-web3-up-close.md","/about/7-community.md","/about/8-nctr-token.md"]},{"text":"Web3-services","collapsible":true,"children":["/web3-services/1-good-to-know.md","/web3-services/2-web3-storage.md","/web3-services/3-web3-hosting.md","/web3-services/4-nfts.md","/web3-services/5-web3-authentication.md","/web3-services/6-web3-social.md","/web3-services/7-web3-compute.md","/web3-services/8-web3-cloud-functions.md","/web3-services/9-embedded-wallets.md","/web3-services/10-web3-infrastructure.md"]},{"text":"Build","collapsible":true,"children":["/build/1-apillon-api.md","/build/2-storage-api.md","/build/3-hosting-api.md","/build/4-nfts-api.md","/build/5-apillon-sdk.md","/build/6-apillon-cli.md","/build/7-apillon-oauth-integration.md","/build/8-computing-api.md","/build/9-social-api.md","/build/10-flutter-sdk.md","/build/11-cloud-functions-api.md","/build/12-embedded-wallets-integration.md","/build/13-infrastructure-api.md"]}],"/build":[{"text":"About","collapsible":true,"children":["/about/1-navigation.md","/about/2-what-is-apillon.md","/about/3-why-apillon.md","/about/4-how-does-apillon-work.md","/about/5-developing-web3-with-apillon.md","/about/6-web3-up-close.md","/about/7-community.md","/about/8-nctr-token.md"]},{"text":"Web3-services","collapsible":true,"children":["/web3-services/1-good-to-know.md","/web3-services/2-web3-storage.md","/web3-services/3-web3-hosting.md","/web3-services/4-nfts.md","/web3-services/5-web3-authentication.md","/web3-services/6-web3-social.md","/web3-services/7-web3-compute.md","/web3-services/8-web3-cloud-functions.md","/web3-services/9-embedded-wallets.md","/web3-services/10-web3-infrastructure.md"]},{"text":"Build","collapsible":true,"children":["/build/1-apillon-api.md","/build/2-storage-api.md","/build/3-hosting-api.md","/build/4-nfts-api.md","/build/5-apillon-sdk.md","/build/6-apillon-cli.md","/build/7-apillon-oauth-integration.md","/build/8-computing-api.md","/build/9-social-api.md","/build/10-flutter-sdk.md","/build/11-cloud-functions-api.md","/build/12-embedded-wallets-integration.md","/build/13-infrastructure-api.md"]}]},"contributors":false,"selectLanguageName":"English"}},"logo":"assets/logo.svg","logoDark":"assets/logo-dark.svg","navbar":[{"text":"About","link":"/about/","children":["/about/1-navigation.md","/about/2-what-is-apillon.md","/about/3-why-apillon.md","/about/4-how-does-apillon-work.md","/about/5-developing-web3-with-apillon.md","/about/6-web3-up-close.md","/about/7-community.md","/about/8-nctr-token.md"]},{"text":"Web3-services","link":"/web3-services/","children":["/web3-services/1-good-to-know.md","/web3-services/2-web3-storage.md","/web3-services/3-web3-hosting.md","/web3-services/4-nfts.md","/web3-services/5-web3-authentication.md","/web3-services/6-web3-social.md","/web3-services/7-web3-compute.md","/web3-services/8-web3-cloud-functions.md","/web3-services/9-embedded-wallets.md","/web3-services/10-web3-infrastructure.md"]},{"text":"Build","link":"/build/","children":["/build/1-apillon-api.md","/build/2-storage-api.md","/build/3-hosting-api.md","/build/4-nfts-api.md","/build/5-apillon-sdk.md","/build/6-apillon-cli.md","/build/7-apillon-oauth-integration.md","/build/8-computing-api.md","/build/9-social-api.md","/build/10-flutter-sdk.md","/build/11-cloud-functions-api.md","/build/12-embedded-wallets-integration.md","/build/13-infrastructure-api.md"]}],"selectLanguageText":"Languages","selectLanguageAriaLabel":"Select language","sidebar":"auto","sidebarDepth":2,"editLink":true,"editLinkText":"Edit this page","lastUpdated":true,"lastUpdatedText":"Last Updated","contributors":true,"contributorsText":"Contributors","notFound":["There's nothing here.","How did we get here?","That's a Four-Oh-Four.","Looks like we've got some broken links."],"backToHome":"Take me home","openInNewWindow":"open in new window","toggleColorMode":"toggle color mode","toggleSidebar":"toggle sidebar"}`),vf=be(gf),Ds=()=>vf,$s=Symbol(""),bf=()=>{const e=Pe($s);if(!e)throw new Error("useThemeLocaleData() is called without provider.");return e},_f=(e,t)=>{const{locales:n,...l}=e;return{...l,...n==null?void 0:n[t]}},yf=wt({enhance({app:e}){const t=Ds(),n=e._context.provides[Mo],l=j(()=>_f(t.value,n.value));e.provide($s,l),Object.defineProperties(e.config.globalProperties,{$theme:{get(){return t.value}},$themeLocale:{get(){return l.value}}})}}),wf=de({__name:"Badge",props:{type:{type:String,required:!1,default:"tip"},text:{type:String,required:!1,default:""},vertical:{type:String,required:!1,default:void 0}},setup(e){return(t,n)=>(B(),ee("span",{class:Ue(["badge",e.type]),style:Bn({verticalAlign:e.vertical})},[we(t.$slots,"default",{},()=>[Ft(Re(e.text),1)])],6))}}),xe=(e,t)=>{const n=e.__vccOpts||e;for(const[l,o]of t)n[l]=o;return n},kf=xe(wf,[["__file","Badge.vue"]]),Ef=de({name:"CodeGroup",slots:Object,setup(e,{slots:t}){const n=be(-1),l=be([]),o=(s=n.value)=>{s {s>0?n.value=s-1:n.value=l.value.length-1,l.value[n.value].focus()},i=(s,a)=>{s.key===" "||s.key==="Enter"?(s.preventDefault(),n.value=a):s.key==="ArrowRight"?(s.preventDefault(),o(a)):s.key==="ArrowLeft"&&(s.preventDefault(),r(a))};return()=>{var a;const s=(((a=t.default)==null?void 0:a.call(t))||[]).filter(c=>c.type.name==="CodeGroupItem").map(c=>(c.props===null&&(c.props={}),c));return s.length===0?null:(n.value<0||n.value>s.length-1?(n.value=s.findIndex(c=>c.props.active===""||c.props.active===!0),n.value===-1&&(n.value=0)):s.forEach((c,u)=>{c.props.active=u===n.value}),ce("div",{class:"code-group"},[ce("div",{class:"code-group__nav"},ce("ul",{class:"code-group__ul"},s.map((c,u)=>{const d=u===n.value;return ce("li",{class:"code-group__li"},ce("button",{ref:h=>{h&&(l.value[u]=h)},class:{"code-group__nav-tab":!0,"code-group__nav-tab-active":d},ariaPressed:d,ariaExpanded:d,onClick:()=>n.value=u,onKeydown:h=>i(h,u)},c.props.title))}))),s]))}}}),Cf=["aria-selected"],xf=de({name:"CodeGroupItem"}),Lf=de({...xf,props:{title:{type:String,required:!0},active:{type:Boolean,required:!1,default:!1}},setup(e){return(t,n)=>(B(),ee("div",{class:Ue(["code-group-item",{"code-group-item__active":e.active}]),"aria-selected":e.active},[we(t.$slots,"default")],10,Cf))}}),Tf=xe(Lf,[["__file","CodeGroupItem.vue"]]);function ri(e,t){var n;const l=Ao();return Vi(()=>{l.value=e()},{...t,flush:(n=t==null?void 0:t.flush)!=null?n:"sync"}),Wn(l)}function Fs(e){return _i()?(ha(e),!0):!1}function vn(e){return typeof e=="function"?e():te(e)}const Af=typeof window<"u"&&typeof document<"u";typeof WorkerGlobalScope<"u"&&globalThis instanceof WorkerGlobalScope;const Pf=Object.prototype.toString,Sf=e=>Pf.call(e)==="[object Object]",Rf=()=>{};function If(e,t){function n(...l){return new Promise((o,r)=>{Promise.resolve(e(()=>t.apply(this,l),{fn:t,thisArg:this,args:l})).then(o).catch(r)})}return n}const Ms=e=>e();function Of(e=Ms){const t=be(!0);function n(){t.value=!1}function l(){t.value=!0}const o=(...r)=>{t.value&&e(...r)};return{isActive:Wn(t),pause:n,resume:l,eventFilter:o}}function Nf(e,t,n={}){const{eventFilter:l=Ms,...o}=n;return ut(e,If(l,t),o)}function Df(e,t,n={}){const{eventFilter:l,...o}=n,{eventFilter:r,pause:i,resume:s,isActive:a}=Of(l);return{stop:Nf(e,t,{...o,eventFilter:r}),pause:i,resume:s,isActive:a}}function $f(e,t=!0){No()?Ke(e):t?e():Un(e)}function Ff(e=!1,t={}){const{truthyValue:n=!0,falsyValue:l=!1}=t,o=De(e),r=be(e);function i(s){if(arguments.length)return r.value=s,r.value;{const a=vn(n);return r.value=r.value===a?vn(l):a,r.value}}return o?i:[r,i]}function Mf(e){var t;const n=vn(e);return(t=n==null?void 0:n.$el)!=null?t:n}const xl=Af?window:void 0;function ii(...e){let t,n,l,o;if(typeof e[0]=="string"||Array.isArray(e[0])?([n,l,o]=e,t=xl):[t,n,l,o]=e,!t)return Rf;Array.isArray(n)||(n=[n]),Array.isArray(l)||(l=[l]);const r=[],i=()=>{r.forEach(u=>u()),r.length=0},s=(u,d,h,m)=>(u.addEventListener(d,h,m),()=>u.removeEventListener(d,h,m)),a=ut(()=>[Mf(t),vn(o)],([u,d])=>{if(i(),!u)return;const h=Sf(d)?{...d}:d;r.push(...n.flatMap(m=>l.map(y=>s(u,m,y,h))))},{immediate:!0,flush:"post"}),c=()=>{a(),i()};return Fs(c),c}function Hf(){const e=be(!1);return No()&&Ke(()=>{e.value=!0}),e}function zf(e){const t=Hf();return j(()=>(t.value,!!e()))}function Bf(e,t={}){const{window:n=xl}=t,l=zf(()=>n&&"matchMedia"in n&&typeof n.matchMedia=="function");let o;const r=be(!1),i=c=>{r.value=c.matches},s=()=>{o&&("removeEventListener"in o?o.removeEventListener("change",i):o.removeListener(i))},a=Vi(()=>{l.value&&(s(),o=n.matchMedia(vn(e)),"addEventListener"in o?o.addEventListener("change",i):o.addListener(i),r.value=o.matches)});return Fs(()=>{a(),s(),o=void 0}),r}const al=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},cl="__vueuse_ssr_handlers__",jf=Wf();function Wf(){return cl in al||(al[cl]=al[cl]||{}),al[cl]}function Vf(e,t){return jf[e]||t}function Uf(e){return e==null?"any":e instanceof Set?"set":e instanceof Map?"map":e instanceof Date?"date":typeof e=="boolean"?"boolean":typeof e=="string"?"string":typeof e=="object"?"object":Number.isNaN(e)?"any":"number"}const qf={boolean:{read:e=>e==="true",write:e=>String(e)},object:{read:e=>JSON.parse(e),write:e=>JSON.stringify(e)},number:{read:e=>Number.parseFloat(e),write:e=>String(e)},any:{read:e=>e,write:e=>String(e)},string:{read:e=>e,write:e=>String(e)},map:{read:e=>new Map(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e.entries()))},set:{read:e=>new Set(JSON.parse(e)),write:e=>JSON.stringify(Array.from(e))},date:{read:e=>new Date(e),write:e=>e.toISOString()}},si="vueuse-storage";function Kf(e,t,n,l={}){var o;const{flush:r="pre",deep:i=!0,listenToStorageChanges:s=!0,writeDefaults:a=!0,mergeDefaults:c=!1,shallow:u,window:d=xl,eventFilter:h,onError:m=O=>{console.error(O)},initOnMounted:y}=l,k=(u?Ao:be)(typeof t=="function"?t():t);if(!n)try{n=Vf("getDefaultStorage",()=>{var O;return(O=xl)==null?void 0:O.localStorage})()}catch(O){m(O)}if(!n)return k;const x=vn(t),T=Uf(x),A=(o=l.serializer)!=null?o:qf[T],{pause:v,resume:_}=Df(k,()=>H(k.value),{flush:r,deep:i,eventFilter:h});return d&&s&&$f(()=>{ii(d,"storage",b),ii(d,si,$),y&&b()}),y||b(),k;function H(O){try{if(O==null)n.removeItem(e);else{const S=A.write(O),q=n.getItem(e);q!==S&&(n.setItem(e,S),d&&d.dispatchEvent(new CustomEvent(si,{detail:{key:e,oldValue:q,newValue:S,storageArea:n}})))}}catch(S){m(S)}}function G(O){const S=O?O.newValue:n.getItem(e);if(S==null)return a&&x!==null&&n.setItem(e,A.write(x)),x;if(!O&&c){const q=A.read(S);return typeof c=="function"?c(q,x):T==="object"&&!Array.isArray(q)?{...x,...q}:q}else return typeof S!="string"?S:A.read(S)}function $(O){b(O.detail)}function b(O){if(!(O&&O.storageArea!==n)){if(O&&O.key==null){k.value=x;return}if(!(O&&O.key!==e)){v();try{(O==null?void 0:O.newValue)!==A.write(k.value)&&(k.value=G(O))}catch(S){m(S)}finally{O?Un(_):_()}}}}}function Gf(e){return Bf("(prefers-color-scheme: dark)",e)}const Yf=()=>Ds(),je=()=>bf(),Hs=Symbol(""),Uo=()=>{const e=Pe(Hs);if(!e)throw new Error("useDarkMode() is called without provider.");return e},Jf=()=>{const e=je(),t=Gf(),n=Kf("vuepress-color-scheme",e.value.colorMode),l=j({get(){return e.value.colorModeSwitch?n.value==="auto"?t.value:n.value==="dark":e.value.colorMode==="dark"},set(o){o===t.value?n.value="auto":n.value=o?"dark":"light"}});Kt(Hs,l),Qf(l)},Qf=e=>{const t=(n=e.value)=>{const l=window==null?void 0:window.document.querySelector("html");l==null||l.classList.toggle("dark",n)};Ke(()=>{ut(e,t,{immediate:!0})}),Dl(()=>t())},zs=(...e)=>{const n=Zt().resolve(...e),l=n.matched[n.matched.length-1];if(!(l!=null&&l.redirect))return n;const{redirect:o}=l,r=re(o)?o(n):o,i=ge(r)?{path:r}:r;return zs({hash:n.hash,query:n.query,params:n.params,...i})},qo=e=>{const t=zs(encodeURI(e));return{text:t.meta.title||e,link:t.name==="404"?e:t.fullPath}};let eo=null,Cn=null;const Zf={wait:()=>eo,pending:()=>{eo=new Promise(e=>Cn=e)},resolve:()=>{Cn==null||Cn(),eo=null,Cn=null}},Bs=()=>Zf,js=Symbol("sidebarItems"),Ko=()=>{const e=Pe(js);if(!e)throw new Error("useSidebarItems() is called without provider.");return e},Xf=()=>{const e=je(),t=vt(),n=j(()=>eh(t.value,e.value));Kt(js,n)},eh=(e,t)=>{const n=e.sidebar??t.sidebar??"auto",l=e.sidebarDepth??t.sidebarDepth??2;return e.home||n===!1?[]:n==="auto"?nh(l):X(n)?Ws(n,l):Fo(n)?lh(n,l):[]},th=(e,t)=>({text:e.title,link:e.link,children:Go(e.children,t)}),Go=(e,t)=>t>0?e.map(n=>th(n,t-1)):[],nh=e=>{const t=Yt();return[{text:t.value.title,children:Go(t.value.headers,e)}]},Ws=(e,t)=>{const n=Xt(),l=Yt(),o=r=>{var s;let i;if(ge(r)?i=qo(r):i=r,i.children)return{...i,children:i.children.map(a=>o(a))};if(i.link===n.path){const a=((s=l.value.headers[0])==null?void 0:s.level)===1?l.value.headers[0].children:l.value.headers;return{...i,children:Go(a,t)}}return i};return e.map(r=>o(r))},lh=(e,t)=>{const n=Xt(),l=hs(e,n.path),o=e[l]??[];return Ws(o,t)},oh="719px",rh={mobile:oh};var Hn;(function(e){e.MOBILE="mobile"})(Hn||(Hn={}));var fi;const ih={[Hn.MOBILE]:Number.parseInt((fi=rh.mobile)==null?void 0:fi.replace("px",""),10)},Vs=(e,t)=>{const n=ih[e];Number.isInteger(n)&&Ke(()=>{t(n),window.addEventListener("resize",()=>t(n),!1),window.addEventListener("orientationchange",()=>t(n),!1)})},sh={},ah={class:"theme-default-content"};function ch(e,t){const n=_t("Content");return B(),ee("div",ah,[le(n)])}const uh=xe(sh,[["render",ch],["__file","HomeContent.vue"]]),dh={key:0,class:"features"},fh=de({__name:"HomeFeatures",setup(e){const t=vt(),n=j(()=>X(t.value.features)?t.value.features:[]);return(l,o)=>n.value.length?(B(),ee("div",dh,[(B(!0),ee(ke,null,Dt(n.value,r=>(B(),ee("div",{key:r.title,class:"feature"},[pe("h2",null,Re(r.title),1),pe("p",null,Re(r.details),1)]))),128))])):Le("v-if",!0)}}),hh=xe(fh,[["__file","HomeFeatures.vue"]]),ph=["innerHTML"],mh=["textContent"],gh=de({__name:"HomeFooter",setup(e){const t=vt(),n=j(()=>t.value.footer),l=j(()=>t.value.footerHtml);return(o,r)=>n.value?(B(),ee(ke,{key:0},[Le(" eslint-disable-next-line vue/no-v-html "),l.value?(B(),ee("div",{key:0,class:"footer",innerHTML:n.value},null,8,ph)):(B(),ee("div",{key:1,class:"footer",textContent:Re(n.value)},null,8,mh))],64)):Le("v-if",!0)}}),vh=xe(gh,[["__file","HomeFooter.vue"]]),bh=["href","rel","target","aria-label"],_h=de({inheritAttrs:!1}),yh=de({..._h,__name:"AutoLink",props:{item:{type:Object,required:!0}},setup(e){const t=e,n=Xt(),l=ys(),{item:o}=Rl(t),r=j(()=>Yn(o.value.link)),i=j(()=>Lu(o.value.link)||Tu(o.value.link)),s=j(()=>{if(!i.value){if(o.value.target)return o.value.target;if(r.value)return"_blank"}}),a=j(()=>s.value==="_blank"),c=j(()=>!r.value&&!i.value&&!a.value),u=j(()=>{if(!i.value){if(o.value.rel)return o.value.rel;if(a.value)return"noopener noreferrer"}}),d=j(()=>o.value.ariaLabel||o.value.text),h=j(()=>{const k=Object.keys(l.value.locales);return k.length?!k.some(x=>x===o.value.link):o.value.link!=="/"}),m=j(()=>h.value?n.path.startsWith(o.value.link):!1),y=j(()=>c.value?o.value.activeMatch?new RegExp(o.value.activeMatch).test(n.path):m.value:!1);return(k,x)=>{const T=_t("RouterLink"),A=_t("AutoLinkExternalIcon");return c.value?(B(),Ae(T,ho({key:0,class:{"router-link-active":y.value},to:te(o).link,"aria-label":d.value},k.$attrs),{default:Fe(()=>[we(k.$slots,"before"),Ft(" "+Re(te(o).text)+" ",1),we(k.$slots,"after")]),_:3},16,["class","to","aria-label"])):(B(),ee("a",ho({key:1,class:"external-link",href:te(o).link,rel:u.value,target:s.value,"aria-label":d.value},k.$attrs),[we(k.$slots,"before"),Ft(" "+Re(te(o).text)+" ",1),a.value?(B(),Ae(A,{key:0})):Le("v-if",!0),we(k.$slots,"after")],16,bh))}}}),bt=xe(yh,[["__file","AutoLink.vue"]]),wh={class:"hero"},kh={key:0,id:"main-title"},Eh={key:1,class:"description"},Ch={key:2,class:"actions"},xh=de({__name:"HomeHero",setup(e){const t=vt(),n=Ho(),l=Uo(),o=j(()=>l.value&&t.value.heroImageDark!==void 0?t.value.heroImageDark:t.value.heroImage),r=j(()=>t.value.heroAlt||s.value||"hero"),i=j(()=>t.value.heroHeight||280),s=j(()=>t.value.heroText===null?null:t.value.heroText||n.value.title||"Hello"),a=j(()=>t.value.tagline===null?null:t.value.tagline||n.value.description||"Welcome to your VuePress site"),c=j(()=>X(t.value.actions)?t.value.actions.map(({text:d,link:h,type:m="primary"})=>({text:d,link:h,type:m})):[]),u=()=>{if(!o.value)return null;const d=ce("img",{src:Bo(o.value),alt:r.value,height:i.value});return t.value.heroImageDark===void 0?d:ce(zo,()=>d)};return(d,h)=>(B(),ee("header",wh,[le(u),s.value?(B(),ee("h1",kh,Re(s.value),1)):Le("v-if",!0),a.value?(B(),ee("p",Eh,Re(a.value),1)):Le("v-if",!0),c.value.length?(B(),ee("p",Ch,[(B(!0),ee(ke,null,Dt(c.value,m=>(B(),Ae(bt,{key:m.text,class:Ue(["action-button",[m.type]]),item:m},null,8,["class","item"]))),128))])):Le("v-if",!0)]))}}),Lh=xe(xh,[["__file","HomeHero.vue"]]),Th={class:"home"},Ah=de({__name:"Home",setup(e){return(t,n)=>(B(),ee("main",Th,[le(Lh),le(hh),le(uh),le(vh)]))}}),Ph=xe(Ah,[["__file","Home.vue"]]),Sh=de({__name:"NavbarBrand",setup(e){const t=Jn(),n=Ho(),l=je(),o=Uo(),r=j(()=>l.value.home||t.value),i=j(()=>n.value.title),s=j(()=>o.value&&l.value.logoDark!==void 0?l.value.logoDark:l.value.logo),a=()=>{if(!s.value)return null;const c=ce("img",{class:"logo",src:Bo(s.value),alt:i.value});return l.value.logoDark===void 0?c:ce(zo,()=>c)};return(c,u)=>{const d=_t("RouterLink");return B(),Ae(d,{to:r.value},{default:Fe(()=>[le(a),i.value?(B(),ee("span",{key:0,class:Ue(["site-name",{"can-hide":s.value}])},Re(i.value),3)):Le("v-if",!0)]),_:1},8,["to"])}}}),Rh=xe(Sh,[["__file","NavbarBrand.vue"]]),Ih=de({__name:"DropdownTransition",setup(e){const t=l=>{l.style.height=l.scrollHeight+"px"},n=l=>{l.style.height=""};return(l,o)=>(B(),Ae(Gn,{name:"dropdown",onEnter:t,onAfterEnter:n,onBeforeLeave:t},{default:Fe(()=>[we(l.$slots,"default")]),_:3}))}}),Us=xe(Ih,[["__file","DropdownTransition.vue"]]),Oh=["aria-label"],Nh={class:"title"},Dh=pe("span",{class:"arrow down"},null,-1),$h=["aria-label"],Fh={class:"title"},Mh={class:"navbar-dropdown"},Hh={class:"navbar-dropdown-subtitle"},zh={key:1},Bh={class:"navbar-dropdown-subitem-wrapper"},jh=de({__name:"NavbarDropdown",props:{item:{type:Object,required:!0}},setup(e){const t=e,{item:n}=Rl(t),l=j(()=>n.value.ariaLabel||n.value.text),o=be(!1),r=Xt();ut(()=>r.path,()=>{o.value=!1});const i=a=>{a.detail===0?o.value=!o.value:o.value=!1},s=(a,c)=>c[c.length-1]===a;return(a,c)=>(B(),ee("div",{class:Ue(["navbar-dropdown-wrapper",{open:o.value}])},[pe("button",{class:"navbar-dropdown-title",type:"button","aria-label":l.value,onClick:i},[pe("span",Nh,Re(te(n).text),1),Dh],8,Oh),pe("button",{class:"navbar-dropdown-title-mobile",type:"button","aria-label":l.value,onClick:c[0]||(c[0]=u=>o.value=!o.value)},[pe("span",Fh,Re(te(n).text),1),pe("span",{class:Ue(["arrow",o.value?"down":"right"])},null,2)],8,$h),le(Us,null,{default:Fe(()=>[bl(pe("ul",Mh,[(B(!0),ee(ke,null,Dt(te(n).children,u=>(B(),ee("li",{key:u.text,class:"navbar-dropdown-item"},[u.children?(B(),ee(ke,{key:0},[pe("h4",Hh,[u.link?(B(),Ae(bt,{key:0,item:u,onFocusout:d=>s(u,te(n).children)&&u.children.length===0&&(o.value=!1)},null,8,["item","onFocusout"])):(B(),ee("span",zh,Re(u.text),1))]),pe("ul",Bh,[(B(!0),ee(ke,null,Dt(u.children,d=>(B(),ee("li",{key:d.link,class:"navbar-dropdown-subitem"},[le(bt,{item:d,onFocusout:h=>s(d,u.children)&&s(u,te(n).children)&&(o.value=!1)},null,8,["item","onFocusout"])]))),128))])],64)):(B(),Ae(bt,{key:1,item:u,onFocusout:d=>s(u,te(n).children)&&(o.value=!1)},null,8,["item","onFocusout"]))]))),128))],512),[[El,o.value]])]),_:1})],2))}}),Wh=xe(jh,[["__file","NavbarDropdown.vue"]]),ai=e=>decodeURI(e).replace(/#.*$/,"").replace(/(index)?\.(md|html)$/,""),Vh=(e,t)=>{if(t.hash===e)return!0;const n=ai(t.path),l=ai(e);return n===l},qs=(e,t)=>e.link&&Vh(e.link,t)?!0:e.children?e.children.some(n=>qs(n,t)):!1,Ks=e=>!Yn(e)||/github\.com/.test(e)?"GitHub":/bitbucket\.org/.test(e)?"Bitbucket":/gitlab\.com/.test(e)?"GitLab":/gitee\.com/.test(e)?"Gitee":null,Uh={GitHub:":repo/edit/:branch/:path",GitLab:":repo/-/edit/:branch/:path",Gitee:":repo/edit/:branch/:path",Bitbucket:":repo/src/:branch/:path?mode=edit&spa=0&at=:branch&fileviewer=file-view-default"},qh=({docsRepo:e,editLinkPattern:t})=>{if(t)return t;const n=Ks(e);return n!==null?Uh[n]:null},Kh=({docsRepo:e,docsBranch:t,docsDir:n,filePathRelative:l,editLinkPattern:o})=>{if(!l)return null;const r=qh({docsRepo:e,editLinkPattern:o});return r?r.replace(/:repo/,Yn(e)?e:`https://github.com/${e}`).replace(/:branch/,t).replace(/:path/,fs(`${ds(n)}/${l}`)):null},Gh={key:0,class:"navbar-items"},Yh=de({__name:"NavbarItems",setup(e){const t=()=>{const u=Zt(),d=Jn(),h=ys(),m=Ho(),y=Yf(),k=je();return j(()=>{const x=Object.keys(h.value.locales);if(x.length<2)return[];const T=u.currentRoute.value.path,A=u.currentRoute.value.fullPath;return[{text:`${k.value.selectLanguageText}`,ariaLabel:`${k.value.selectLanguageAriaLabel??k.value.selectLanguageText}`,children:x.map(_=>{var S,q;const H=((S=h.value.locales)==null?void 0:S[_])??{},G=((q=y.value.locales)==null?void 0:q[_])??{},$=`${H.lang}`,b=G.selectLanguageName??$;let O;if($===m.value.lang)O=A;else{const E=T.replace(d.value,_);u.getRoutes().some(N=>N.path===E)?O=A.replace(T,E):O=G.home??_}return{text:b,link:O}})}]})},n=()=>{const u=je(),d=j(()=>u.value.repo),h=j(()=>d.value?Ks(d.value):null),m=j(()=>d.value&&!Yn(d.value)?`https://github.com/${d.value}`:d.value),y=j(()=>m.value?u.value.repoLabel?u.value.repoLabel:h.value===null?"Source":h.value:null);return j(()=>!m.value||!y.value?[]:[{text:y.value,link:m.value}])},l=u=>ge(u)?qo(u):u.children?{...u,children:u.children.map(l)}:u,o=()=>{const u=je();return j(()=>(u.value.navbar||[]).map(l))},r=be(!1),i=o(),s=t(),a=n(),c=j(()=>[...i.value,...s.value,...a.value]);return Vs(Hn.MOBILE,u=>{window.innerWidthc.value.length?(B(),ee("nav",Gh,[(B(!0),ee(ke,null,Dt(c.value,h=>(B(),ee("div",{key:h.text,class:"navbar-item"},[h.children?(B(),Ae(Wh,{key:0,item:h,class:Ue(r.value?"mobile":"")},null,8,["item","class"])):(B(),Ae(bt,{key:1,item:h},null,8,["item"]))]))),128))])):Le("v-if",!0)}}),Gs=xe(Yh,[["__file","NavbarItems.vue"]]),Jh=["title"],Qh={class:"icon",focusable:"false",viewBox:"0 0 32 32"},Zh=Dc(' ',9),Xh=[Zh],ep={class:"icon",focusable:"false",viewBox:"0 0 32 32"},tp=pe("path",{d:"M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z",fill:"currentColor"},null,-1),np=[tp],lp=de({__name:"ToggleColorModeButton",setup(e){const t=je(),n=Uo(),l=()=>{n.value=!n.value};return(o,r)=>(B(),ee("button",{class:"toggle-color-mode-button",title:te(t).toggleColorMode,onClick:l},[bl((B(),ee("svg",Qh,Xh,512)),[[El,!te(n)]]),bl((B(),ee("svg",ep,np,512)),[[El,te(n)]])],8,Jh))}}),op=xe(lp,[["__file","ToggleColorModeButton.vue"]]),rp=["title"],ip=pe("div",{class:"icon","aria-hidden":"true"},[pe("span"),pe("span"),pe("span")],-1),sp=[ip],ap=de({__name:"ToggleSidebarButton",emits:["toggle"],setup(e){const t=je();return(n,l)=>(B(),ee("div",{class:"toggle-sidebar-button",title:te(t).toggleSidebar,"aria-expanded":"false",role:"button",tabindex:"0",onClick:l[0]||(l[0]=o=>n.$emit("toggle"))},sp,8,rp))}}),cp=xe(ap,[["__file","ToggleSidebarButton.vue"]]),up=de({__name:"Navbar",emits:["toggle-sidebar"],setup(e){const t=je(),n=be(null),l=be(null),o=be(0),r=j(()=>o.value?{maxWidth:o.value+"px"}:{});Vs(Hn.MOBILE,s=>{var c;const a=i(n.value,"paddingLeft")+i(n.value,"paddingRight");window.innerWidth {const c=_t("NavbarSearch");return B(),ee("header",{ref_key:"navbar",ref:n,class:"navbar"},[le(cp,{onToggle:a[0]||(a[0]=u=>s.$emit("toggle-sidebar"))}),pe("span",{ref_key:"navbarBrand",ref:l},[le(Rh)],512),pe("div",{class:"navbar-items-wrapper",style:Bn(r.value)},[we(s.$slots,"before"),le(Gs,{class:"can-hide"}),we(s.$slots,"after"),te(t).colorModeSwitch?(B(),Ae(op,{key:0})):Le("v-if",!0),le(c)],4)],512)}}}),dp=xe(up,[["__file","Navbar.vue"]]),fp={class:"page-meta"},hp={key:0,class:"meta-item edit-link"},pp={key:1,class:"meta-item last-updated"},mp={class:"meta-item-label"},gp={class:"meta-item-info"},vp={key:2,class:"meta-item contributors"},bp={class:"meta-item-label"},_p={class:"meta-item-info"},yp=["title"],wp=de({__name:"PageMeta",setup(e){const t=()=>{const a=je(),c=Yt(),u=vt();return j(()=>{if(!(u.value.editLink??a.value.editLink??!0))return null;const{repo:h,docsRepo:m=h,docsBranch:y="main",docsDir:k="",editLinkText:x}=a.value;if(!m)return null;const T=Kh({docsRepo:m,docsBranch:y,docsDir:k,filePathRelative:c.value.filePathRelative,editLinkPattern:u.value.editLinkPattern??a.value.editLinkPattern});return T?{text:x??"Edit this page",link:T}:null})},n=()=>{const a=je(),c=Yt(),u=vt();return j(()=>{var m,y;return!(u.value.lastUpdated??a.value.lastUpdated??!0)||!((m=c.value.git)!=null&&m.updatedTime)?null:new Date((y=c.value.git)==null?void 0:y.updatedTime).toLocaleString()})},l=()=>{const a=je(),c=Yt(),u=vt();return j(()=>{var h;return u.value.contributors??a.value.contributors??!0?((h=c.value.git)==null?void 0:h.contributors)??null:null})},o=je(),r=t(),i=n(),s=l();return(a,c)=>{const u=_t("ClientOnly");return B(),ee("footer",fp,[te(r)?(B(),ee("div",hp,[le(bt,{class:"meta-item-label",item:te(r)},null,8,["item"])])):Le("v-if",!0),te(i)?(B(),ee("div",pp,[pe("span",mp,Re(te(o).lastUpdatedText)+": ",1),le(u,null,{default:Fe(()=>[pe("span",gp,Re(te(i)),1)]),_:1})])):Le("v-if",!0),te(s)&&te(s).length?(B(),ee("div",vp,[pe("span",bp,Re(te(o).contributorsText)+": ",1),pe("span",_p,[(B(!0),ee(ke,null,Dt(te(s),(d,h)=>(B(),ee(ke,{key:h},[pe("span",{class:"contributor",title:`email: ${d.email}`},Re(d.name),9,yp),h!==te(s).length-1?(B(),ee(ke,{key:0},[Ft(", ")],64)):Le("v-if",!0)],64))),128))])])):Le("v-if",!0)])}}}),kp=xe(wp,[["__file","PageMeta.vue"]]),Ep={key:0,class:"page-nav"},Cp={class:"inner"},xp={key:0,class:"prev"},Lp={key:1,class:"next"},Tp=de({__name:"PageNav",setup(e){const t=a=>a===!1?null:ge(a)?qo(a):Fo(a)?a:!1,n=(a,c,u)=>{const d=a.findIndex(h=>h.link===c);if(d!==-1){const h=a[d+u];return h!=null&&h.link?h:null}for(const h of a)if(h.children){const m=n(h.children,c,u);if(m)return m}return null},l=vt(),o=Ko(),r=Xt(),i=j(()=>{const a=t(l.value.prev);return a!==!1?a:n(o.value,r.path,-1)}),s=j(()=>{const a=t(l.value.next);return a!==!1?a:n(o.value,r.path,1)});return(a,c)=>i.value||s.value?(B(),ee("nav",Ep,[pe("p",Cp,[i.value?(B(),ee("span",xp,[le(bt,{item:i.value},null,8,["item"])])):Le("v-if",!0),s.value?(B(),ee("span",Lp,[le(bt,{item:s.value},null,8,["item"])])):Le("v-if",!0)])])):Le("v-if",!0)}}),Ap=xe(Tp,[["__file","PageNav.vue"]]),Pp={class:"page"},Sp={class:"theme-default-content"},Rp=de({__name:"Page",setup(e){return(t,n)=>{const l=_t("Content");return B(),ee("main",Pp,[we(t.$slots,"top"),pe("div",Sp,[we(t.$slots,"content-top"),le(l),we(t.$slots,"content-bottom")]),le(kp),le(Ap),we(t.$slots,"bottom")])}}}),Ip=xe(Rp,[["__file","Page.vue"]]),Op=["onKeydown"],Np={class:"sidebar-item-children"},Dp=de({__name:"SidebarItem",props:{item:{type:Object,required:!0},depth:{type:Number,required:!1,default:0}},setup(e){const t=e,{item:n,depth:l}=Rl(t),o=Xt(),r=Zt(),i=j(()=>qs(n.value,o)),s=j(()=>({"sidebar-item":!0,"sidebar-heading":l.value===0,active:i.value,collapsible:n.value.collapsible})),a=j(()=>n.value.collapsible?i.value:!0),[c,u]=Ff(a.value),d=m=>{n.value.collapsible&&(m.preventDefault(),u())},h=r.afterEach(m=>{Un(()=>{c.value=a.value})});return Kn(()=>{h()}),(m,y)=>{var x;const k=_t("SidebarItem",!0);return B(),ee("li",null,[te(n).link?(B(),Ae(bt,{key:0,class:Ue(s.value),item:te(n)},null,8,["class","item"])):(B(),ee("p",{key:1,tabindex:"0",class:Ue(s.value),onClick:d,onKeydown:vu(d,["enter"])},[Ft(Re(te(n).text)+" ",1),te(n).collapsible?(B(),ee("span",{key:0,class:Ue(["arrow",te(c)?"down":"right"])},null,2)):Le("v-if",!0)],42,Op)),(x=te(n).children)!=null&&x.length?(B(),Ae(Us,{key:2},{default:Fe(()=>[bl(pe("ul",Np,[(B(!0),ee(ke,null,Dt(te(n).children,T=>(B(),Ae(k,{key:`${te(l)}${T.text}${T.link}`,item:T,depth:te(l)+1},null,8,["item","depth"]))),128))],512),[[El,te(c)]])]),_:1})):Le("v-if",!0)])}}}),$p=xe(Dp,[["__file","SidebarItem.vue"]]),Fp={key:0,class:"sidebar-items"},Mp=de({__name:"SidebarItems",setup(e){const t=Xt(),n=Ko();return Ke(()=>{ut(()=>t.hash,l=>{const o=document.querySelector(".sidebar");if(!o)return;const r=document.querySelector(`.sidebar a.sidebar-item[href="${t.path}${l}"]`);if(!r)return;const{top:i,height:s}=o.getBoundingClientRect(),{top:a,height:c}=r.getBoundingClientRect();ai+s&&r.scrollIntoView(!1)})}),(l,o)=>te(n).length?(B(),ee("ul",Fp,[(B(!0),ee(ke,null,Dt(te(n),r=>(B(),Ae($p,{key:`${r.text}${r.link}`,item:r},null,8,["item"]))),128))])):Le("v-if",!0)}}),Hp=xe(Mp,[["__file","SidebarItems.vue"]]),zp={class:"sidebar"},Bp=de({__name:"Sidebar",setup(e){return(t,n)=>(B(),ee("aside",zp,[le(Gs),we(t.$slots,"top"),le(Hp),we(t.$slots,"bottom")]))}}),jp=xe(Bp,[["__file","Sidebar.vue"]]),Wp=de({__name:"Layout",setup(e){const t=Yt(),n=vt(),l=je(),o=j(()=>n.value.navbar!==!1&&l.value.navbar!==!1),r=Ko(),i=be(!1),s=x=>{i.value=typeof x=="boolean"?x:!i.value},a={x:0,y:0},c=x=>{a.x=x.changedTouches[0].clientX,a.y=x.changedTouches[0].clientY},u=x=>{const T=x.changedTouches[0].clientX-a.x,A=x.changedTouches[0].clientY-a.y;Math.abs(T)>Math.abs(A)&&Math.abs(T)>40&&(T>0&&a.x<=80?s(!0):s(!1))},d=j(()=>[{"no-navbar":!o.value,"no-sidebar":!r.value.length,"sidebar-open":i.value},n.value.pageClass]);let h;Ke(()=>{h=Zt().afterEach(()=>{s(!1)})}),Dl(()=>{h()});const m=Bs(),y=m.resolve,k=m.pending;return(x,T)=>(B(),ee("div",{class:Ue(["theme-container",d.value]),onTouchstart:c,onTouchend:u},[we(x.$slots,"navbar",{},()=>[o.value?(B(),Ae(dp,{key:0,onToggleSidebar:s},{before:Fe(()=>[we(x.$slots,"navbar-before")]),after:Fe(()=>[we(x.$slots,"navbar-after")]),_:3})):Le("v-if",!0)]),pe("div",{class:"sidebar-mask",onClick:T[0]||(T[0]=A=>s(!1))}),we(x.$slots,"sidebar",{},()=>[le(jp,null,{top:Fe(()=>[we(x.$slots,"sidebar-top")]),bottom:Fe(()=>[we(x.$slots,"sidebar-bottom")]),_:3})]),we(x.$slots,"page",{},()=>[te(n).home?(B(),Ae(Ph,{key:0})):(B(),Ae(Gn,{key:1,name:"fade-slide-y",mode:"out-in",onBeforeEnter:te(y),onBeforeLeave:te(k)},{default:Fe(()=>[(B(),Ae(Ip,{key:te(t).path},{top:Fe(()=>[we(x.$slots,"page-top")]),"content-top":Fe(()=>[we(x.$slots,"page-content-top")]),"content-bottom":Fe(()=>[we(x.$slots,"page-content-bottom")]),bottom:Fe(()=>[we(x.$slots,"page-bottom")]),_:3}))]),_:3},8,["onBeforeEnter","onBeforeLeave"]))])],34))}}),Vp=xe(Wp,[["__file","Layout.vue"]]),Up={class:"theme-container"},qp={class:"page"},Kp={class:"theme-default-content"},Gp=pe("h1",null,"404",-1),Yp=de({__name:"NotFound",setup(e){const t=Jn(),n=je(),l=n.value.notFound??["Not Found"],o=()=>l[Math.floor(Math.random()*l.length)],r=n.value.home??t.value,i=n.value.backToHome??"Back to home";return(s,a)=>{const c=_t("RouterLink");return B(),ee("div",Up,[pe("main",qp,[pe("div",Kp,[Gp,pe("blockquote",null,Re(o()),1),le(c,{to:te(r)},{default:Fe(()=>[Ft(Re(te(i)),1)]),_:1},8,["to"])])])])}}}),Jp=xe(Yp,[["__file","NotFound.vue"]]);const Qp=wt({enhance({app:e,router:t}){e.component("Badge",kf),e.component("CodeGroup",Ef),e.component("CodeGroupItem",Tf),e.component("AutoLinkExternalIcon",()=>{const l=e.component("ExternalLinkIcon");return l?ce(l):null}),e.component("NavbarSearch",()=>{const l=e.component("Docsearch")||e.component("SearchBox");return l?ce(l):null});const n=t.options.scrollBehavior;t.options.scrollBehavior=async(...l)=>(await Bs().wait(),n(...l))},setup(){Jf(),Xf()},layouts:{Layout:Vp,NotFound:Jp}}),Zp=e=>e instanceof Element?document.activeElement===e&&(["TEXTAREA","SELECT","INPUT"].includes(e.tagName)||e.hasAttribute("contenteditable")):!1,Xp=(e,t)=>t.some(n=>{if(ge(n))return n===e.key;const{key:l,ctrl:o=!1,shift:r=!1,alt:i=!1}=n;return l===e.key&&o===e.ctrlKey&&r===e.shiftKey&&i===e.altKey}),em=/[^\x00-\x7F]/,tm=e=>e.split(/\s+/g).map(t=>t.trim()).filter(t=>!!t),ci=e=>e.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),ui=(e,t)=>{const n=t.join(" "),l=tm(e);if(em.test(e))return l.some(i=>n.toLowerCase().indexOf(i)>-1);const o=e.endsWith(" ");return new RegExp(l.map((i,s)=>l.length===s+1&&!o?`(?=.*\\b${ci(i)})`:`(?=.*\\b${ci(i)}\\b)`).join("")+".+","gi").test(n)},nm=({input:e,hotKeys:t})=>{if(t.value.length===0)return;const n=l=>{e.value&&Xp(l,t.value)&&!Zp(l.target)&&(l.preventDefault(),e.value.focus())};Ke(()=>{document.addEventListener("keydown",n)}),Kn(()=>{document.removeEventListener("keydown",n)})},lm=[{title:"Apillon Wiki",headers:[{level:2,title:"Setup",slug:"setup",link:"#setup",children:[]},{level:2,title:"Development Server",slug:"development-server",link:"#development-server",children:[]}],path:"/",pathLocale:"/",extraFields:[]},{title:"",headers:[],path:"/",pathLocale:"/",extraFields:[]},{title:"Navigation",headers:[],path:"/about/1-navigation.html",pathLocale:"/",extraFields:[]},{title:"What is Apillon?",headers:[],path:"/about/2-what-is-apillon.html",pathLocale:"/",extraFields:[]},{title:"Why Apillon?",headers:[{level:2,title:"Unified pricing",slug:"unified-pricing",link:"#unified-pricing",children:[{level:3,title:"Predictable pricing for greater adoption",slug:"predictable-pricing-for-greater-adoption",link:"#predictable-pricing-for-greater-adoption",children:[]},{level:3,title:"Predictable scaling",slug:"predictable-scaling",link:"#predictable-scaling",children:[]},{level:3,title:"Token utility, volatility, and predictable pricing paradox",slug:"token-utility-volatility-and-predictable-pricing-paradox",link:"#token-utility-volatility-and-predictable-pricing-paradox",children:[]},{level:3,title:"Multiple services at a single price tag",slug:"multiple-services-at-a-single-price-tag",link:"#multiple-services-at-a-single-price-tag",children:[]}]}],path:"/about/3-why-apillon.html",pathLocale:"/",extraFields:[]},{title:"How does Apillon work?",headers:[{level:2,title:"APIs",slug:"apis",link:"#apis",children:[]},{level:2,title:"SDKs",slug:"sdks",link:"#sdks",children:[]},{level:2,title:"Documentation",slug:"documentation",link:"#documentation",children:[]},{level:2,title:"Monitoring",slug:"monitoring",link:"#monitoring",children:[]},{level:2,title:"Analytics",slug:"analytics",link:"#analytics",children:[]}],path:"/about/4-how-does-apillon-work.html",pathLocale:"/",extraFields:[]},{title:"Developing Web3 with Apillon",headers:[{level:2,title:"Challenges of blockchain complexity",slug:"challenges-of-blockchain-complexity",link:"#challenges-of-blockchain-complexity",children:[]},{level:2,title:"Web3 Development with and without Apillon",slug:"web3-development-with-and-without-apillon",link:"#web3-development-with-and-without-apillon",children:[]}],path:"/about/5-developing-web3-with-apillon.html",pathLocale:"/",extraFields:[]},{title:"Web3 and Apillon explained",headers:[{level:2,title:"Polkadot, a complete service stack for Web3 builders",slug:"polkadot-a-complete-service-stack-for-web3-builders",link:"#polkadot-a-complete-service-stack-for-web3-builders",children:[{level:3,title:"Evolution of blockchain applications",slug:"evolution-of-blockchain-applications",link:"#evolution-of-blockchain-applications",children:[]},{level:3,title:"Polkadot offers flexibility and more",slug:"polkadot-offers-flexibility-and-more",link:"#polkadot-offers-flexibility-and-more",children:[]},{level:3,title:"Room for improvement",slug:"room-for-improvement",link:"#room-for-improvement",children:[]}]},{level:2,title:"Glossary",slug:"glossary",link:"#glossary",children:[{level:3,title:"The world of Web3",slug:"the-world-of-web3",link:"#the-world-of-web3",children:[]},{level:3,title:"Polkadot Network",slug:"polkadot-network",link:"#polkadot-network",children:[]},{level:3,title:"The Apillon platform",slug:"the-apillon-platform",link:"#the-apillon-platform",children:[]},{level:3,title:"Read more",slug:"read-more",link:"#read-more",children:[]}]}],path:"/about/6-web3-up-close.html",pathLocale:"/",extraFields:[]},{title:"Community",headers:[{level:2,title:"Join Apillon Community",slug:"join-apillon-community",link:"#join-apillon-community",children:[]},{level:2,title:"Polkadot Treasury Proposal",slug:"polkadot-treasury-proposal",link:"#polkadot-treasury-proposal",children:[{level:3,title:"Common good and open source",slug:"common-good-and-open-source",link:"#common-good-and-open-source",children:[]},{level:3,title:"Proposal: Apillon, Polkadot, Web3",slug:"proposal-apillon-polkadot-web3",link:"#proposal-apillon-polkadot-web3",children:[]}]}],path:"/about/7-community.html",pathLocale:"/",extraFields:[]},{title:"NCTR token",headers:[{level:2,title:"Tokenomics Actors",slug:"tokenomics-actors",link:"#tokenomics-actors",children:[{level:3,title:"NCTR Developers",slug:"nctr-developers",link:"#nctr-developers",children:[]},{level:3,title:"NCTR Holders",slug:"nctr-holders",link:"#nctr-holders",children:[]}]},{level:2,title:"Token Utilities",slug:"token-utilities",link:"#token-utilities",children:[{level:3,title:"Governance",slug:"governance",link:"#governance",children:[]},{level:3,title:"Incentivization",slug:"incentivization",link:"#incentivization",children:[]},{level:3,title:"Payments",slug:"payments",link:"#payments",children:[]}]},{level:2,title:"Tokenomics",slug:"tokenomics",link:"#tokenomics",children:[{level:3,title:"Technical Token Parameters",slug:"technical-token-parameters",link:"#technical-token-parameters",children:[]},{level:3,title:"Tokenomics Whitepaper",slug:"tokenomics-whitepaper",link:"#tokenomics-whitepaper",children:[]}]}],path:"/about/8-nctr-token.html",pathLocale:"/",extraFields:[]},{title:"Apillon API",headers:[{level:2,title:"Endpoints",slug:"endpoints",link:"#endpoints",children:[]},{level:2,title:"API to Web3",slug:"api-to-web3",link:"#api-to-web3",children:[{level:3,title:"Requests",slug:"requests",link:"#requests",children:[]},{level:3,title:"Authentication and authorization",slug:"authentication-and-authorization",link:"#authentication-and-authorization",children:[]},{level:3,title:"Listing requests",slug:"listing-requests",link:"#listing-requests",children:[]},{level:3,title:"Responses",slug:"responses",link:"#responses",children:[]},{level:3,title:"Error handling",slug:"error-handling",link:"#error-handling",children:[]},{level:3,title:"Common errors",slug:"common-errors",link:"#common-errors",children:[]}]},{level:2,title:"Project",slug:"project",link:"#project",children:[{level:3,title:"Credit balance",slug:"credit-balance",link:"#credit-balance",children:[]}]},{level:2,title:"API Code Examples",slug:"api-code-examples",link:"#api-code-examples",children:[]}],path:"/build/1-apillon-api.html",pathLocale:"/",extraFields:[]},{title:"Apillon Flutter SDK",headers:[{level:2,title:"Requirements",slug:"requirements",link:"#requirements",children:[]},{level:2,title:"Getting started",slug:"getting-started",link:"#getting-started",children:[{level:3,title:"Initialization",slug:"initialization",link:"#initialization",children:[]}]},{level:2,title:"Modules",slug:"modules",link:"#modules",children:[{level:3,title:"Storage",slug:"storage",link:"#storage",children:[]},{level:3,title:"NFTs",slug:"nfts",link:"#nfts",children:[]},{level:3,title:"Identity",slug:"identity",link:"#identity",children:[]}]}],path:"/build/10-flutter-sdk.html",pathLocale:"/",extraFields:[]},{title:"Cloud Functions API",headers:[{level:2,title:"Create Cloud Function",slug:"create-cloud-function",link:"#create-cloud-function",children:[]},{level:2,title:"List Cloud Functions",slug:"list-cloud-functions",link:"#list-cloud-functions",children:[]},{level:2,title:"Get Cloud Function",slug:"get-cloud-function",link:"#get-cloud-function",children:[]},{level:2,title:"Create Cloud Function Job (Deployment)",slug:"create-cloud-function-job-deployment",link:"#create-cloud-function-job-deployment",children:[]},{level:2,title:"Set Cloud Function Environment Variables",slug:"set-cloud-function-environment-variables",link:"#set-cloud-function-environment-variables",children:[]},{level:2,title:"Delete Job",slug:"delete-job",link:"#delete-job",children:[]}],path:"/build/11-cloud-functions-api.html",pathLocale:"/",extraFields:[]},{title:"Embedded Wallet Integration",headers:[{level:2,title:"Prerequisites",slug:"prerequisites",link:"#prerequisites",children:[{level:3,title:"React, Vue",slug:"react-vue",link:"#react-vue",children:[]},{level:3,title:"Next.js",slug:"next-js",link:"#next-js",children:[]},{level:3,title:"Nuxt",slug:"nuxt",link:"#nuxt",children:[]}]},{level:2,title:"Installation",slug:"installation",link:"#installation",children:[]},{level:2,title:"Add wallet widget",slug:"add-wallet-widget",link:"#add-wallet-widget",children:[{level:3,title:"Parameters",slug:"parameters",link:"#parameters",children:[]}]},{level:2,title:"Use wallet",slug:"use-wallet",link:"#use-wallet",children:[{level:3,title:"Ethers 5 and 6",slug:"ethers-5-and-6",link:"#ethers-5-and-6",children:[]},{level:3,title:"Viem",slug:"viem",link:"#viem",children:[]},{level:3,title:"Wagmi",slug:"wagmi",link:"#wagmi",children:[]},{level:3,title:"TypeScript",slug:"typescript",link:"#typescript",children:[]}]},{level:2,title:"Create custom UI",slug:"create-custom-ui",link:"#create-custom-ui",children:[]},{level:2,title:"NPM Packages",slug:"npm-packages",link:"#npm-packages",children:[]},{level:2,title:"Examples",slug:"examples",link:"#examples",children:[{level:3,title:"React",slug:"react",link:"#react",children:[]},{level:3,title:"Next.js",slug:"next-js-1",link:"#next-js-1",children:[]},{level:3,title:"Vue.js",slug:"vue-js",link:"#vue-js",children:[]},{level:3,title:"Nuxt",slug:"nuxt-1",link:"#nuxt-1",children:[]},{level:3,title:"TypeScript",slug:"typescript-1",link:"#typescript-1",children:[]}]}],path:"/build/12-embedded-wallets-integration.html",pathLocale:"/",extraFields:[]},{title:"Infrastructure API",headers:[{level:2,title:"RPC Service",slug:"rpc-service",link:"#rpc-service",children:[{level:3,title:"Create a RPC API Key",slug:"create-a-rpc-api-key",link:"#create-a-rpc-api-key",children:[]},{level:3,title:"List RPC API Keys",slug:"list-rpc-api-keys",link:"#list-rpc-api-keys",children:[]},{level:3,title:"Get a RPC API Key",slug:"get-a-rpc-api-key",link:"#get-a-rpc-api-key",children:[]},{level:3,title:"List RPC Endpoints",slug:"list-rpc-endpoints",link:"#list-rpc-endpoints",children:[]}]}],path:"/build/13-infrastructure-api.html",pathLocale:"/",extraFields:[]},{title:"Storage API",headers:[{level:3,title:"List buckets",slug:"list-buckets",link:"#list-buckets",children:[]},{level:3,title:"Create new bucket",slug:"create-new-bucket",link:"#create-new-bucket",children:[]},{level:3,title:"Upload to bucket",slug:"upload-to-bucket",link:"#upload-to-bucket",children:[]},{level:3,title:"End upload session",slug:"end-upload-session",link:"#end-upload-session",children:[]},{level:3,title:"List bucket content",slug:"list-bucket-content",link:"#list-bucket-content",children:[]},{level:3,title:"List files",slug:"list-files",link:"#list-files",children:[]},{level:3,title:"Get file details",slug:"get-file-details",link:"#get-file-details",children:[]},{level:3,title:"Delete file",slug:"delete-file",link:"#delete-file",children:[]},{level:3,title:"Delete directory",slug:"delete-directory",link:"#delete-directory",children:[]},{level:3,title:"Get storage info",slug:"get-storage-info",link:"#get-storage-info",children:[]},{level:3,title:"Get IPFS cluster info",slug:"get-ipfs-cluster-info",link:"#get-ipfs-cluster-info",children:[]},{level:3,title:"Get or generate link for IPFS",slug:"get-or-generate-link-for-ipfs",link:"#get-or-generate-link-for-ipfs",children:[]},{level:2,title:"IPNS",slug:"ipns",link:"#ipns",children:[{level:3,title:"List IPNS names",slug:"list-ipns-names",link:"#list-ipns-names",children:[]},{level:3,title:"Create new IPNS",slug:"create-new-ipns",link:"#create-new-ipns",children:[]},{level:3,title:"Get IPNS",slug:"get-ipns",link:"#get-ipns",children:[]},{level:3,title:"Publish IPNS",slug:"publish-ipns",link:"#publish-ipns",children:[]},{level:3,title:"Delete IPNS",slug:"delete-ipns",link:"#delete-ipns",children:[]}]}],path:"/build/2-storage-api.html",pathLocale:"/",extraFields:[]},{title:"Hosting API",headers:[{level:3,title:"List websites",slug:"list-websites",link:"#list-websites",children:[]},{level:3,title:"Get website",slug:"get-website",link:"#get-website",children:[]},{level:3,title:"Get URLs for files upload",slug:"get-urls-for-files-upload",link:"#get-urls-for-files-upload",children:[]},{level:3,title:"End upload session",slug:"end-upload-session",link:"#end-upload-session",children:[]},{level:3,title:"Deploy website",slug:"deploy-website",link:"#deploy-website",children:[]},{level:3,title:"List website deployments",slug:"list-website-deployments",link:"#list-website-deployments",children:[]},{level:3,title:"Get deployment",slug:"get-deployment",link:"#get-deployment",children:[]},{level:3,title:"Generate short URL",slug:"generate-short-url",link:"#generate-short-url",children:[]}],path:"/build/3-hosting-api.html",pathLocale:"/",extraFields:[]},{title:"NFTs API",headers:[{level:3,title:"Get NFT Collection",slug:"get-nft-collection",link:"#get-nft-collection",children:[]},{level:3,title:"List NFT Collections",slug:"list-nft-collections",link:"#list-nft-collections",children:[]},{level:3,title:"List Collection Transactions",slug:"list-collection-transactions",link:"#list-collection-transactions",children:[]},{level:3,title:"Create NFT Collection",slug:"create-nft-collection",link:"#create-nft-collection",children:[]},{level:3,title:"Transfer Collection",slug:"transfer-collection",link:"#transfer-collection",children:[]},{level:3,title:"Mint Collection NFTs",slug:"mint-collection-nfts",link:"#mint-collection-nfts",children:[]},{level:3,title:"Nest Mint Collection NFTs",slug:"nest-mint-collection-nfts",link:"#nest-mint-collection-nfts",children:[]},{level:3,title:"Burn Collection NFT",slug:"burn-collection-nft",link:"#burn-collection-nft",children:[]}],path:"/build/4-nfts-api.html",pathLocale:"/",extraFields:[]},{title:"Apillon SDK",headers:[{level:2,title:"Requirements",slug:"requirements",link:"#requirements",children:[]},{level:2,title:"Getting started",slug:"getting-started",link:"#getting-started",children:[{level:3,title:"Installation",slug:"installation",link:"#installation",children:[]},{level:3,title:"Initialization",slug:"initialization",link:"#initialization",children:[]},{level:3,title:"Detailed docs",slug:"detailed-docs",link:"#detailed-docs",children:[]},{level:3,title:"Examples",slug:"examples",link:"#examples",children:[]}]},{level:2,title:"Hosting",slug:"hosting",link:"#hosting",children:[{level:3,title:"Usage example",slug:"usage-example",link:"#usage-example",children:[]}]},{level:2,title:"Storage",slug:"storage",link:"#storage",children:[{level:3,title:"Usage example",slug:"usage-example-1",link:"#usage-example-1",children:[]},{level:3,title:"IPNS methods",slug:"ipns-methods",link:"#ipns-methods",children:[]}]},{level:2,title:"NFTs",slug:"nfts",link:"#nfts",children:[{level:3,title:"Usage example",slug:"usage-example-2",link:"#usage-example-2",children:[]}]},{level:2,title:"Identity",slug:"identity",link:"#identity",children:[{level:3,title:"Usage example",slug:"usage-example-3",link:"#usage-example-3",children:[]}]},{level:2,title:"Computing",slug:"computing",link:"#computing",children:[{level:3,title:"Usage example",slug:"usage-example-4",link:"#usage-example-4",children:[]}]},{level:2,title:"Social",slug:"social",link:"#social",children:[{level:3,title:"Usage example",slug:"usage-example-5",link:"#usage-example-5",children:[]}]}],path:"/build/5-apillon-sdk.html",pathLocale:"/",extraFields:[]},{title:"Apillon CLI",headers:[{level:2,title:"Requirements",slug:"requirements",link:"#requirements",children:[]},{level:2,title:"Installation",slug:"installation",link:"#installation",children:[{level:3,title:"Global Options",slug:"global-options",link:"#global-options",children:[]},{level:3,title:"Environment Variables",slug:"environment-variables",link:"#environment-variables",children:[]},{level:3,title:"Help",slug:"help",link:"#help",children:[]},{level:3,title:"List pagination options",slug:"list-pagination-options",link:"#list-pagination-options",children:[]}]},{level:2,title:"Hosting Commands",slug:"hosting-commands",link:"#hosting-commands",children:[]},{level:2,title:"Storage Commands",slug:"storage-commands",link:"#storage-commands",children:[{level:3,title:"IPNS Commands",slug:"ipns-commands",link:"#ipns-commands",children:[]}]},{level:2,title:"NFT Commands",slug:"nft-commands",link:"#nft-commands",children:[]},{level:2,title:"Using in CI/CD tools",slug:"using-in-ci-cd-tools",link:"#using-in-ci-cd-tools",children:[{level:3,title:"Deploying websites",slug:"deploying-websites",link:"#deploying-websites",children:[]}]}],path:"/build/6-apillon-cli.html",pathLocale:"/",extraFields:[]},{title:"Apillon OAuth Integration",headers:[{level:2,title:"Client - OAuth popup & events",slug:"client-oauth-popup-events",link:"#client-oauth-popup-events",children:[]},{level:2,title:"Server - Auth API endpoints",slug:"server-auth-api-endpoints",link:"#server-auth-api-endpoints",children:[{level:3,title:"Obtain a session token",slug:"obtain-a-session-token",link:"#obtain-a-session-token",children:[]},{level:3,title:"Verify user login",slug:"verify-user-login",link:"#verify-user-login",children:[]}]}],path:"/build/7-apillon-oauth-integration.html",pathLocale:"/",extraFields:[]},{title:"Computing API",headers:[{level:2,title:"Create Computing Contract",slug:"create-computing-contract",link:"#create-computing-contract",children:[]},{level:2,title:"List Computing Contracts",slug:"list-computing-contracts",link:"#list-computing-contracts",children:[]},{level:2,title:"Get Computing Contract",slug:"get-computing-contract",link:"#get-computing-contract",children:[]},{level:2,title:"List Contract Transactions",slug:"list-contract-transactions",link:"#list-contract-transactions",children:[]},{level:2,title:"Transfer Ownership",slug:"transfer-ownership",link:"#transfer-ownership",children:[]},{level:2,title:"Encrypt Content",slug:"encrypt-content",link:"#encrypt-content",children:[]},{level:2,title:"Assign CID to NFT",slug:"assign-cid-to-nft",link:"#assign-cid-to-nft",children:[]}],path:"/build/8-computing-api.html",pathLocale:"/",extraFields:[]},{title:"Social API",headers:[{level:2,title:"Channels",slug:"channels",link:"#channels",children:[{level:3,title:"List channels",slug:"list-channels",link:"#list-channels",children:[]},{level:3,title:"Get channel",slug:"get-channel",link:"#get-channel",children:[]},{level:3,title:"Create channel",slug:"create-channel",link:"#create-channel",children:[]}]},{level:2,title:"Hubs",slug:"hubs",link:"#hubs",children:[{level:3,title:"List hubs",slug:"list-hubs",link:"#list-hubs",children:[]},{level:3,title:"Get hub",slug:"get-hub",link:"#get-hub",children:[]},{level:3,title:"Create hub",slug:"create-hub",link:"#create-hub",children:[]}]}],path:"/build/9-social-api.html",pathLocale:"/",extraFields:[]},{title:"Good to know",headers:[{level:2,title:"Concepts",slug:"concepts",link:"#concepts",children:[{level:3,title:"Centralized vs. decentralized",slug:"centralized-vs-decentralized",link:"#centralized-vs-decentralized",children:[]},{level:3,title:"Production vs. Beta",slug:"production-vs-beta",link:"#production-vs-beta",children:[]}]},{level:2,title:"Terminology and underlying technology",slug:"terminology-and-underlying-technology",link:"#terminology-and-underlying-technology",children:[{level:3,title:"IPFS",slug:"ipfs",link:"#ipfs",children:[]},{level:3,title:"Crust Network",slug:"crust-network",link:"#crust-network",children:[]},{level:3,title:"Storage buckets",slug:"storage-buckets",link:"#storage-buckets",children:[]}]}],path:"/web3-services/1-good-to-know.html",pathLocale:"/",extraFields:[]},{title:"Web3 infrastructure",headers:[{level:2,title:"Introduction",slug:"introduction",link:"#introduction",children:[]},{level:2,title:"RPC Service",slug:"rpc-service",link:"#rpc-service",children:[{level:3,title:"Dwellir",slug:"dwellir",link:"#dwellir",children:[]},{level:3,title:"How it works",slug:"how-it-works",link:"#how-it-works",children:[]},{level:3,title:"Pricing",slug:"pricing",link:"#pricing",children:[]}]},{level:2,title:"Indexing service",slug:"indexing-service",link:"#indexing-service",children:[{level:3,title:"SQD (Subsquid) Web3 Data Infrastructure",slug:"sqd-subsquid-web3-data-infrastructure",link:"#sqd-subsquid-web3-data-infrastructure",children:[]},{level:3,title:"Workflow",slug:"workflow",link:"#workflow",children:[]},{level:3,title:"How it works",slug:"how-it-works-1",link:"#how-it-works-1",children:[]},{level:3,title:"Pricing",slug:"pricing-1",link:"#pricing-1",children:[]}]},{level:2,title:"Conclusion",slug:"conclusion",link:"#conclusion",children:[]}],path:"/web3-services/10-web3-infrastructure.html",pathLocale:"/",extraFields:[]},{title:"Web3 Storage",headers:[{level:2,title:"Storage bucket",slug:"storage-bucket",link:"#storage-bucket",children:[]},{level:2,title:"File storage",slug:"file-storage",link:"#file-storage",children:[]},{level:2,title:"File deletion",slug:"file-deletion",link:"#file-deletion",children:[]}],path:"/web3-services/2-web3-storage.html",pathLocale:"/",extraFields:[]},{title:"Web3 Hosting",headers:[{level:2,title:"Website/app hosting",slug:"website-app-hosting",link:"#website-app-hosting",children:[]},{level:2,title:"Deployment",slug:"deployment",link:"#deployment",children:[]},{level:2,title:"File deletion",slug:"file-deletion",link:"#file-deletion",children:[]}],path:"/web3-services/3-web3-hosting.html",pathLocale:"/",extraFields:[]},{title:"NFTs",headers:[{level:2,title:"NFT media",slug:"nft-media",link:"#nft-media",children:[]},{level:2,title:"NFT metadata",slug:"nft-metadata",link:"#nft-metadata",children:[]},{level:2,title:"NFT deployment",slug:"nft-deployment",link:"#nft-deployment",children:[]}],path:"/web3-services/4-nfts.html",pathLocale:"/",extraFields:[]},{title:"Web3 Authentication",headers:[{level:2,title:"Authentication workflow",slug:"authentication-workflow",link:"#authentication-workflow",children:[]},{level:2,title:"Apillon Open Authentication (OAuth)",slug:"apillon-open-authentication-oauth",link:"#apillon-open-authentication-oauth",children:[]}],path:"/web3-services/5-web3-authentication.html",pathLocale:"/",extraFields:[]},{title:"Web3 Social",headers:[{level:2,title:"Chat",slug:"chat",link:"#chat",children:[]}],path:"/web3-services/6-web3-social.html",pathLocale:"/",extraFields:[]},{title:"Web3 Compute power",headers:[{level:2,title:"NFT gated file access",slug:"nft-gated-file-access",link:"#nft-gated-file-access",children:[]}],path:"/web3-services/7-web3-compute.html",pathLocale:"/",extraFields:[]},{title:"Web3 Cloud Functions",headers:[{level:2,title:"Introduction",slug:"introduction",link:"#introduction",children:[]},{level:2,title:"What is Acurast?",slug:"what-is-acurast",link:"#what-is-acurast",children:[]},{level:2,title:"Core Features of Apillon's Cloud Function Service",slug:"core-features-of-apillon-s-cloud-function-service",link:"#core-features-of-apillon-s-cloud-function-service",children:[]},{level:2,title:"How It Works",slug:"how-it-works",link:"#how-it-works",children:[]},{level:2,title:"Conclusion",slug:"conclusion",link:"#conclusion",children:[]}],path:"/web3-services/8-web3-cloud-functions.html",pathLocale:"/",extraFields:[]},{title:"Embedded Wallets",headers:[{level:2,title:"Introduction",slug:"introduction",link:"#introduction",children:[]},{level:2,title:"What is an Embedded Wallet?",slug:"what-is-an-embedded-wallet",link:"#what-is-an-embedded-wallet",children:[]},{level:2,title:"How it Works",slug:"how-it-works",link:"#how-it-works",children:[]},{level:2,title:"Security of Embedded Wallets",slug:"security-of-embedded-wallets",link:"#security-of-embedded-wallets",children:[]},{level:2,title:"Workflow",slug:"workflow",link:"#workflow",children:[]},{level:2,title:"Comparison with Other Providers",slug:"comparison-with-other-providers",link:"#comparison-with-other-providers",children:[]},{level:2,title:"Passkeys",slug:"passkeys",link:"#passkeys",children:[{level:3,title:"How Passkeys Work",slug:"how-passkeys-work",link:"#how-passkeys-work",children:[]},{level:3,title:"Benefits of Passkeys",slug:"benefits-of-passkeys",link:"#benefits-of-passkeys",children:[]}]},{level:2,title:"Advantages of Apillon’s Embedded Wallet Service",slug:"advantages-of-apillon-s-embedded-wallet-service",link:"#advantages-of-apillon-s-embedded-wallet-service",children:[]},{level:2,title:"Conclusion",slug:"conclusion",link:"#conclusion",children:[]}],path:"/web3-services/9-embedded-wallets.html",pathLocale:"/",extraFields:[]},{title:"",headers:[],path:"/404.html",pathLocale:"/",extraFields:[]}],om=be(lm),rm=()=>om,im=({searchIndex:e,routeLocale:t,query:n,maxSuggestions:l})=>{const o=j(()=>e.value.filter(r=>r.pathLocale===t.value));return j(()=>{const r=n.value.trim().toLowerCase();if(!r)return[];const i=[],s=(a,c)=>{ui(r,[c.title])&&i.push({link:`${a.path}#${c.slug}`,title:a.title,header:c.title});for(const u of c.children){if(i.length>=l.value)return;s(a,u)}};for(const a of o.value){if(i.length>=l.value)break;if(ui(r,[a.title,...a.extraFields])){i.push({link:a.path,title:a.title});continue}for(const c of a.headers){if(i.length>=l.value)break;s(a,c)}}return i})},sm=e=>{const t=be(0);return{focusIndex:t,focusNext:()=>{t.value{t.value>0?t.value-=1:t.value=e.value.length-1}}},am=de({name:"SearchBox",props:{locales:{type:Object,required:!1,default:()=>({})},hotKeys:{type:Array,required:!1,default:()=>[]},maxSuggestions:{type:Number,required:!1,default:5}},setup(e){const{locales:t,hotKeys:n,maxSuggestions:l}=Rl(e),o=Zt(),r=Jn(),i=rm(),s=be(null),a=be(!1),c=be(""),u=j(()=>t.value[r.value]??{}),d=im({searchIndex:i,routeLocale:r,query:c,maxSuggestions:l}),{focusIndex:h,focusNext:m,focusPrev:y}=sm(d);nm({input:s,hotKeys:n});const k=j(()=>a.value&&!!d.value.length),x=()=>{k.value&&y()},T=()=>{k.value&&m()},A=v=>{if(!k.value)return;const _=d.value[v];_&&o.push(_.link).then(()=>{c.value="",h.value=0})};return()=>ce("form",{class:"search-box",role:"search"},[ce("input",{ref:s,type:"search",placeholder:u.value.placeholder,autocomplete:"off",spellcheck:!1,value:c.value,onFocus:()=>a.value=!0,onBlur:()=>a.value=!1,onInput:v=>c.value=v.target.value,onKeydown:v=>{switch(v.key){case"ArrowUp":{x();break}case"ArrowDown":{T();break}case"Enter":{v.preventDefault(),A(h.value);break}}}}),k.value&&ce("ul",{class:"suggestions",onMouseleave:()=>h.value=-1},d.value.map(({link:v,title:_,header:H},G)=>ce("li",{class:["suggestion",{focus:h.value===G}],onMouseenter:()=>h.value=G,onMousedown:()=>A(G)},ce("a",{href:v,onClick:$=>$.preventDefault()},[ce("span",{class:"page-title"},_),H&&ce("span",{class:"page-header"},`> ${H}`)]))))])}});const cm={"/":{placeholder:"Search"}},um=["s","/"],dm=5,fm=wt({enhance({app:e}){e.component("SearchBox",t=>ce(am,{locales:cm,hotKeys:um,maxSuggestions:dm,...t}))}}),hm={enhance:({app:e})=>{e.component("CodeDiv",ae(()=>V(()=>import("./CodeDiv-9fb5b766.js"),[])))}},pm=wt({enhance({app:e,router:t,siteData:n}){t.beforeEach((l,o,r)=>{const s={"/build/2-web3-services.html#storage-bucket":"/web3-services/2-web3-storage.html#storage-bucket","/build/2-web3-services.html#web3-hosting":"/web3-services/3-web3-hosting.html","/build/3-apillon-api.html#web3-hosting-api":"/build/3-hosting-api.html","/build/3-apillon-api.html#web3-storage-api":"/build/2-storage-api.html","/build/3-apillon-api.html":"/build/1-apillon-api.html","/build/3-apillon-api.html#api-to-web3":"/build/1-apillon-api.html","/build/#concepts":"/web3-services/1-good-to-know.html#concepts","/build/2-web3-services.html#web3-storage":"/web3-services/2-web3-storage.html","/build/2-web3-services.html#nfts":"/web3-services/4-nfts.html","/build/#ipfs":"/web3-services/1-good-to-know.html#ipfs"}[l.fullPath];s?r({path:s}):r()})}}),ul=[Ud,Gd,Zd,df,mf,yf,Qp,fm,hm,pm],mm=[["v-8daa1a0e","/",{title:"Apillon Wiki"},["/README.md"]],["v-8daa1a0e","/",{title:""},["/index.md"]],["v-92c536e4","/about/1-navigation.html",{title:"Navigation"},[":md"]],["v-d64fcca0","/about/2-what-is-apillon.html",{title:"What is Apillon?"},[":md"]],["v-0f48940c","/about/3-why-apillon.html",{title:"Why Apillon?"},[":md"]],["v-6bda2dde","/about/4-how-does-apillon-work.html",{title:"How does Apillon work?"},[":md"]],["v-ac15b5a4","/about/5-developing-web3-with-apillon.html",{title:"Developing Web3 with Apillon"},[":md"]],["v-da41cf52","/about/6-web3-up-close.html",{title:"Web3 and Apillon explained"},[":md"]],["v-929e013e","/about/7-community.html",{title:"Community"},[":md"]],["v-564790ea","/about/8-nctr-token.html",{title:"NCTR token"},[":md"]],["v-cdfbcdae","/build/1-apillon-api.html",{title:"Apillon API"},[":md"]],["v-4d91ab64","/build/10-flutter-sdk.html",{title:"Apillon Flutter SDK"},[":md"]],["v-15e6da9c","/build/11-cloud-functions-api.html",{title:"Cloud Functions API"},[":md"]],["v-3453e56e","/build/12-embedded-wallets-integration.html",{title:"Embedded Wallet Integration"},[":md"]],["v-7a601078","/build/13-infrastructure-api.html",{title:"Infrastructure API"},[":md"]],["v-1da918f4","/build/2-storage-api.html",{title:"Storage API"},[":md"]],["v-3fe44474","/build/3-hosting-api.html",{title:"Hosting API"},[":md"]],["v-ae3a6dfc","/build/4-nfts-api.html",{title:"NFTs API"},[":md"]],["v-fc8498f6","/build/5-apillon-sdk.html",{title:"Apillon SDK"},[":md"]],["v-6c04f07e","/build/6-apillon-cli.html",{title:"Apillon CLI"},[":md"]],["v-15f6e7df","/build/7-apillon-oauth-integration.html",{title:"Apillon OAuth Integration"},[":md"]],["v-6b6a7fe7","/build/8-computing-api.html",{title:"Computing API"},[":md"]],["v-6ef47b51","/build/9-social-api.html",{title:"Social API"},[":md"]],["v-2d5fd574","/web3-services/1-good-to-know.html",{title:"Good to know"},[":md"]],["v-0c17de3a","/web3-services/10-web3-infrastructure.html",{title:"Web3 infrastructure"},[":md"]],["v-47991eb5","/web3-services/2-web3-storage.html",{title:"Web3 Storage"},[":md"]],["v-f2d17dd2","/web3-services/3-web3-hosting.html",{title:"Web3 Hosting"},[":md"]],["v-713d4f4d","/web3-services/4-nfts.html",{title:"NFTs"},[":md"]],["v-662ed367","/web3-services/5-web3-authentication.html",{title:"Web3 Authentication"},[":md"]],["v-592c909e","/web3-services/6-web3-social.html",{title:"Web3 Social"},[":md"]],["v-b6f01184","/web3-services/7-web3-compute.html",{title:"Web3 Compute power"},[":md"]],["v-174aec9a","/web3-services/8-web3-cloud-functions.html",{title:"Web3 Cloud Functions"},[":md"]],["v-91d7101c","/web3-services/9-embedded-wallets.html",{title:"Embedded Wallets"},[":md"]],["v-3706649a","/404.html",{title:""},[]]];var di=de({name:"Vuepress",setup(){const e=Ou();return()=>ce(e.value)}}),gm=()=>mm.reduce((e,[t,n,l,o])=>(e.push({name:t,path:n,component:di,meta:l},{path:n.endsWith("/")?n+"index.html":n.substring(0,n.length-5),redirect:n},...o.map(r=>({path:r===":md"?n.substring(0,n.length-5)+".md":r,redirect:n}))),e),[{name:"404",path:"/:catchAll(.*)",component:di}]),vm=td,bm=()=>{const e=Md({history:vm(ds("/")),routes:gm(),scrollBehavior:(t,n,l)=>l||(t.hash?{el:t.hash}:{top:0})});return e.beforeResolve(async(t,n)=>{var l;(t.path!==n.path||n===pt)&&([St.value]=await Promise.all([ht.resolvePageData(t.name),(l=ps[t.name])==null?void 0:l.__asyncLoader()]))}),e},_m=e=>{e.component("ClientOnly",zo),e.component("Content",Fu)},ym=(e,t,n)=>{const l=j(()=>ht.resolveLayouts(n)),o=ri(()=>t.currentRoute.value.path),r=ri(()=>ht.resolveRouteLocale(on.value.locales,o.value)),i=j(()=>ht.resolveSiteLocaleData(on.value,r.value)),s=j(()=>ht.resolvePageFrontmatter(St.value)),a=j(()=>ht.resolvePageHeadTitle(St.value,i.value)),c=j(()=>ht.resolvePageHead(a.value,s.value,i.value)),u=j(()=>ht.resolvePageLang(St.value,i.value)),d=j(()=>ht.resolvePageLayout(St.value,l.value));return e.provide(Au,l),e.provide(gs,s),e.provide(Ru,a),e.provide(vs,c),e.provide(bs,u),e.provide(_s,d),e.provide(Mo,r),e.provide(ws,i),Object.defineProperties(e.config.globalProperties,{$frontmatter:{get:()=>s.value},$head:{get:()=>c.value},$headTitle:{get:()=>a.value},$lang:{get:()=>u.value},$page:{get:()=>St.value},$routeLocale:{get:()=>r.value},$site:{get:()=>on.value},$siteLocale:{get:()=>i.value},$withBase:{get:()=>Bo}}),{layouts:l,pageData:St,pageFrontmatter:s,pageHead:c,pageHeadTitle:a,pageLang:u,pageLayout:d,routeLocale:r,siteData:on,siteLocaleData:i}},wm=()=>{const e=Su(),t=Iu(),n=be([]),l=()=>{e.value.forEach(r=>{const i=km(r);i&&n.value.push(i)})},o=()=>{document.documentElement.lang=t.value,n.value.forEach(r=>{r.parentNode===document.head&&document.head.removeChild(r)}),n.value.splice(0,n.value.length),e.value.forEach(r=>{const i=Em(r);i!==null&&(document.head.appendChild(i),n.value.push(i))})};Kt(Nu,o),Ke(()=>{l(),o(),ut(()=>e.value,o)})},km=([e,t,n=""])=>{const l=Object.entries(t).map(([s,a])=>ge(a)?`[${s}=${JSON.stringify(a)}]`:a===!0?`[${s}]`:"").join(""),o=`head > ${e}${l}`;return Array.from(document.querySelectorAll(o)).find(s=>s.innerText===n)||null},Em=([e,t,n])=>{if(!ge(e))return null;const l=document.createElement(e);return Fo(t)&&Object.entries(t).forEach(([o,r])=>{ge(r)?l.setAttribute(o,r):r===!0&&l.setAttribute(o,"")}),ge(n)&&l.appendChild(document.createTextNode(n)),l},Cm=yu,xm=async()=>{var n;const e=Cm({name:"VuepressApp",setup(){var l;wm();for(const o of ul)(l=o.setup)==null||l.call(o);return()=>[ce(Os),...ul.flatMap(({rootComponents:o=[]})=>o.map(r=>ce(r)))]}}),t=bm();_m(e),ym(e,t,ul);for(const l of ul)await((n=l.enhance)==null?void 0:n.call(l,{app:e,router:t,siteData:on}));return e.use(t),{app:e,router:t}};xm().then(({app:e,router:t})=>{t.isReady().then(()=>{e.mount("#app")})});export{xe as _,Dc as a,pe as b,ee as c,xm as createVueApp,le as d,Ft as e,Le as f,we as g,B as o,_t as r,Fe as w}; diff --git a/assets/arrow-right.svg b/assets/arrow-right.svg new file mode 100644 index 00000000..6e5eb4ae --- /dev/null +++ b/assets/arrow-right.svg @@ -0,0 +1,3 @@ + diff --git a/assets/authtrail-nino-kutnjak-new-chief-product-owner.png b/assets/authtrail-nino-kutnjak-new-chief-product-owner.png new file mode 100644 index 00000000..edae8ed7 Binary files /dev/null and b/assets/authtrail-nino-kutnjak-new-chief-product-owner.png differ diff --git a/assets/back-to-top-8efcbe56.svg b/assets/back-to-top-8efcbe56.svg new file mode 100644 index 00000000..83236781 --- /dev/null +++ b/assets/back-to-top-8efcbe56.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/homepage.svg b/assets/homepage.svg new file mode 100644 index 00000000..31e3d056 --- /dev/null +++ b/assets/homepage.svg @@ -0,0 +1,2219 @@ + + + diff --git a/assets/index.html-4e0e9fe3.js b/assets/index.html-4e0e9fe3.js new file mode 100644 index 00000000..b98bd2a0 --- /dev/null +++ b/assets/index.html-4e0e9fe3.js @@ -0,0 +1 @@ +import{_ as t,o as a,c as i,a as s}from"./app-e8b865be.js";const e="/assets/arrow-right.svg",o={},c=s(' ',1),l=[c];function n(r,h){return a(),i("div",null,l)}const p=t(o,[["render",n],["__file","index.html.vue"]]);export{p as default}; diff --git a/assets/index.html-addec3f2.js b/assets/index.html-addec3f2.js new file mode 100644 index 00000000..f78436d1 --- /dev/null +++ b/assets/index.html-addec3f2.js @@ -0,0 +1 @@ +const a=JSON.parse('{"key":"v-8daa1a0e","path":"/","title":"","lang":"en-US","frontmatter":{"pageClass":"homepage","lastUpdated":false,"editLink":false},"headers":[],"git":{"updatedTime":1730191807000,"contributors":[{"name":"Damjan Dimitrov","email":"damjandimitrov1@gmail.com","commits":1}]},"filePathRelative":"index.md"}');export{a as data}; diff --git a/assets/logo-dark.svg b/assets/logo-dark.svg new file mode 100644 index 00000000..5056f46b --- /dev/null +++ b/assets/logo-dark.svg @@ -0,0 +1,10 @@ + diff --git a/assets/logo-favicon-light.png b/assets/logo-favicon-light.png new file mode 100644 index 00000000..e782bc39 Binary files /dev/null and b/assets/logo-favicon-light.png differ diff --git a/assets/logo-favicon.png b/assets/logo-favicon.png new file mode 100644 index 00000000..3d409a1e Binary files /dev/null and b/assets/logo-favicon.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 00000000..3d409a1e Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 00000000..61f8c2a7 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,10 @@ + diff --git a/assets/search-0782d0d1.svg b/assets/search-0782d0d1.svg new file mode 100644 index 00000000..03d83913 --- /dev/null +++ b/assets/search-0782d0d1.svg @@ -0,0 +1 @@ + diff --git a/assets/sidebar-minus.svg b/assets/sidebar-minus.svg new file mode 100644 index 00000000..c5da15fb --- /dev/null +++ b/assets/sidebar-minus.svg @@ -0,0 +1,3 @@ + diff --git a/assets/sidebar-plus.svg b/assets/sidebar-plus.svg new file mode 100644 index 00000000..45a845cb --- /dev/null +++ b/assets/sidebar-plus.svg @@ -0,0 +1,3 @@ + diff --git a/assets/style-f42405cd.css b/assets/style-f42405cd.css new file mode 100644 index 00000000..1b27d1b5 --- /dev/null +++ b/assets/style-f42405cd.css @@ -0,0 +1 @@ +@import"https://fonts.googleapis.com/css2?family=Inter:wght@300;900&display=swap";@import"https://fonts.googleapis.com/css2?family=Inter:wght@200;300;900&display=swap";:root{--back-to-top-z-index: 5;--back-to-top-color: #3eaf7c;--back-to-top-color-hover: #71cda3}.back-to-top{cursor:pointer;position:fixed;bottom:2rem;right:2.5rem;width:2rem;height:1.2rem;background-color:var(--back-to-top-color);-webkit-mask:url(/assets/back-to-top-8efcbe56.svg) no-repeat;mask:url(/assets/back-to-top-8efcbe56.svg) no-repeat;z-index:var(--back-to-top-z-index)}.back-to-top:hover{background-color:var(--back-to-top-color-hover)}@media (max-width: 959px){.back-to-top{display:none}}@media print{.back-to-top{display:none}}.back-to-top-enter-active,.back-to-top-leave-active{transition:opacity .3s}.back-to-top-enter-from,.back-to-top-leave-to{opacity:0}:root{--external-link-icon-color: #aaa}.external-link-icon{position:relative;display:inline-block;color:var(--external-link-icon-color);vertical-align:middle;top:-1px}@media print{.external-link-icon{display:none}}.external-link-icon-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}:root{--medium-zoom-z-index: 100;--medium-zoom-bg-color: #ffffff;--medium-zoom-opacity: 1}.medium-zoom-overlay{background-color:var(--medium-zoom-bg-color)!important;z-index:var(--medium-zoom-z-index)}.medium-zoom-overlay~img{z-index:calc(var(--medium-zoom-z-index) + 1)}.medium-zoom--opened .medium-zoom-overlay{opacity:var(--medium-zoom-opacity)}:root{--nprogress-color: #29d;--nprogress-z-index: 1031}#nprogress{pointer-events:none}#nprogress .bar{background:var(--nprogress-color);position:fixed;z-index:var(--nprogress-z-index);top:0;left:0;width:100%;height:2px}:root{--c-brand: #3eaf7c;--c-brand-light: #4abf8a;--c-bg: #ffffff;--c-bg-light: #f3f4f5;--c-bg-lighter: #eeeeee;--c-bg-dark: #ebebec;--c-bg-darker: #e6e6e6;--c-bg-navbar: var(--c-bg);--c-bg-sidebar: var(--c-bg);--c-bg-arrow: #cccccc;--c-text: #2c3e50;--c-text-accent: var(--c-brand);--c-text-light: #3a5169;--c-text-lighter: #4e6e8e;--c-text-lightest: #6a8bad;--c-text-quote: #999999;--c-border: #eaecef;--c-border-dark: #dfe2e5;--c-tip: #42b983;--c-tip-bg: var(--c-bg-light);--c-tip-title: var(--c-text);--c-tip-text: var(--c-text);--c-tip-text-accent: var(--c-text-accent);--c-warning: #ffc310;--c-warning-bg: #fffae3;--c-warning-bg-light: #fff3ba;--c-warning-bg-lighter: #fff0b0;--c-warning-border-dark: #f7dc91;--c-warning-details-bg: #fff5ca;--c-warning-title: #f1b300;--c-warning-text: #746000;--c-warning-text-accent: #edb100;--c-warning-text-light: #c1971c;--c-warning-text-quote: #ccab49;--c-danger: #f11e37;--c-danger-bg: #ffe0e0;--c-danger-bg-light: #ffcfde;--c-danger-bg-lighter: #ffc9c9;--c-danger-border-dark: #f1abab;--c-danger-details-bg: #ffd4d4;--c-danger-title: #ed1e2c;--c-danger-text: #660000;--c-danger-text-accent: #bd1a1a;--c-danger-text-light: #b5474d;--c-danger-text-quote: #c15b5b;--c-details-bg: #eeeeee;--c-badge-tip: var(--c-tip);--c-badge-warning: #ecc808;--c-badge-warning-text: var(--c-bg);--c-badge-danger: #dc2626;--c-badge-danger-text: var(--c-bg);--t-color: .3s ease;--t-transform: .3s ease;--code-bg-color: #282c34;--code-hl-bg-color: rgba(0, 0, 0, .66);--code-ln-color: #9e9e9e;--code-ln-wrapper-width: 3.5rem;--font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;--font-family-code: Consolas, Monaco, "Andale Mono", "Ubuntu Mono", monospace;--navbar-height: 3.6rem;--navbar-padding-v: .7rem;--navbar-padding-h: 1.5rem;--sidebar-width: 20rem;--sidebar-width-mobile: calc(var(--sidebar-width) * .82);--content-width: 740px;--homepage-width: 960px}.back-to-top{--back-to-top-color: var(--c-brand);--back-to-top-color-hover: var(--c-brand-light)}.DocSearch{--docsearch-primary-color: var(--c-brand);--docsearch-text-color: var(--c-text);--docsearch-highlight-color: var(--c-brand);--docsearch-muted-color: var(--c-text-quote);--docsearch-container-background: rgba(9, 10, 17, .8);--docsearch-modal-background: var(--c-bg-light);--docsearch-searchbox-background: var(--c-bg-lighter);--docsearch-searchbox-focus-background: var(--c-bg);--docsearch-searchbox-shadow: inset 0 0 0 2px var(--c-brand);--docsearch-hit-color: var(--c-text-light);--docsearch-hit-active-color: var(--c-bg);--docsearch-hit-background: var(--c-bg);--docsearch-hit-shadow: 0 1px 3px 0 var(--c-border-dark);--docsearch-footer-background: var(--c-bg)}.external-link-icon{--external-link-icon-color: var(--c-text-quote)}.medium-zoom-overlay{--medium-zoom-bg-color: var(--c-bg)}#nprogress{--nprogress-color: var(--c-brand)}.pwa-popup{--pwa-popup-text-color: var(--c-text);--pwa-popup-bg-color: var(--c-bg);--pwa-popup-border-color: var(--c-brand);--pwa-popup-shadow: 0 4px 16px var(--c-brand);--pwa-popup-btn-text-color: var(--c-bg);--pwa-popup-btn-bg-color: var(--c-brand);--pwa-popup-btn-hover-bg-color: var(--c-brand-light)}.search-box{--search-bg-color: var(--c-bg);--search-accent-color: var(--c-brand);--search-text-color: var(--c-text);--search-border-color: var(--c-border);--search-item-text-color: var(--c-text-lighter);--search-item-focus-bg-color: var(--c-bg-light)}html.dark{--c-brand: #3aa675;--c-brand-light: #349469;--c-bg: #22272e;--c-bg-light: #2b313a;--c-bg-lighter: #262c34;--c-bg-dark: #343b44;--c-bg-darker: #37404c;--c-text: #adbac7;--c-text-light: #96a7b7;--c-text-lighter: #8b9eb0;--c-text-lightest: #8094a8;--c-border: #3e4c5a;--c-border-dark: #34404c;--c-tip: #318a62;--c-warning: #e0ad15;--c-warning-bg: #2d2f2d;--c-warning-bg-light: #423e2a;--c-warning-bg-lighter: #44442f;--c-warning-border-dark: #957c35;--c-warning-details-bg: #39392d;--c-warning-title: #fdca31;--c-warning-text: #d8d96d;--c-warning-text-accent: #ffbf00;--c-warning-text-light: #ddb84b;--c-warning-text-quote: #ccab49;--c-danger: #fc1e38;--c-danger-bg: #39232c;--c-danger-bg-light: #4b2b35;--c-danger-bg-lighter: #553040;--c-danger-border-dark: #a25151;--c-danger-details-bg: #482936;--c-danger-title: #fc2d3b;--c-danger-text: #ea9ca0;--c-danger-text-accent: #fd3636;--c-danger-text-light: #d9777c;--c-danger-text-quote: #d56b6b;--c-details-bg: #323843;--c-badge-warning: var(--c-warning);--c-badge-warning-text: #3c2e05;--c-badge-danger: var(--c-danger);--c-badge-danger-text: #401416;--code-hl-bg-color: #363b46}html.dark .DocSearch{--docsearch-logo-color: var(--c-text);--docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309;--docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, 0 2px 2px 0 rgba(3, 4, 9, .3);--docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21);--docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, .5), 0 -4px 8px 0 rgba(0, 0, 0, .2)}html,body{padding:0;margin:0;background-color:var(--c-bg);transition:background-color var(--t-color)}html.dark{color-scheme:dark}html{font-size:16px}body{font-family:var(--font-family);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-size:1rem;color:var(--c-text)}a{font-weight:500;color:var(--c-text-accent);text-decoration:none;overflow-wrap:break-word}p a code{font-weight:400;color:var(--c-text-accent)}kbd{font-family:var(--font-family-code);color:var(--c-text);background:var(--c-bg-lighter);border:solid .15rem var(--c-border-dark);border-bottom:solid .25rem var(--c-border-dark);border-radius:.15rem;padding:0 .15em}code{font-family:var(--font-family-code);color:var(--c-text-lighter);padding:.25rem .5rem;margin:0;font-size:.85em;background-color:var(--c-bg-light);border-radius:3px;overflow-wrap:break-word;transition:background-color var(--t-color)}blockquote{font-size:1rem;color:var(--c-text-quote);border-left:.2rem solid var(--c-border-dark);margin:1rem 0;padding:.25rem 0 .25rem 1rem;overflow-wrap:break-word}blockquote>p{margin:0}ul,ol{padding-left:1.2em}strong{font-weight:600}h1,h2,h3,h4,h5,h6{font-weight:600;line-height:1.25;overflow-wrap:break-word}h1:focus-visible,h2:focus-visible,h3:focus-visible,h4:focus-visible,h5:focus-visible,h6:focus-visible{outline:none}h1:hover .header-anchor,h2:hover .header-anchor,h3:hover .header-anchor,h4:hover .header-anchor,h5:hover .header-anchor,h6:hover .header-anchor{opacity:1}h1{font-size:2.2rem}h2{font-size:1.65rem;padding-bottom:.3rem;border-bottom:1px solid var(--c-border);transition:border-color var(--t-color)}h3{font-size:1.35rem}h4{font-size:1.15rem}h5{font-size:1.05rem}h6{font-size:1rem}a.header-anchor{font-size:.85em;float:left;margin-left:-.87em;padding-right:.23em;margin-top:.125em;opacity:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}@media print{a.header-anchor{display:none}}a.header-anchor:hover{text-decoration:none}a.header-anchor:focus-visible{opacity:1}@media print{a[href^="http://"]:after,a[href^="https://"]:after{content:" (" attr(href) ") "}}p,ul,ol{line-height:1.7;overflow-wrap:break-word}hr{border:0;border-top:1px solid var(--c-border)}table{border-collapse:collapse;margin:1rem 0;display:block;overflow-x:auto;transition:border-color var(--t-color)}tr{border-top:1px solid var(--c-border-dark);transition:border-color var(--t-color)}tr:nth-child(2n){background-color:var(--c-bg-light);transition:background-color var(--t-color)}tr:nth-child(2n) code{background-color:var(--c-bg-dark)}th,td{padding:.6em 1em;border:1px solid var(--c-border-dark);transition:border-color var(--t-color)}.arrow{display:inline-block;width:0;height:0}.arrow.up{border-left:4px solid transparent;border-right:4px solid transparent;border-bottom:6px solid var(--c-bg-arrow)}.arrow.down{border-left:4px solid transparent;border-right:4px solid transparent;border-top:6px solid var(--c-bg-arrow)}.arrow.right{border-top:4px solid transparent;border-bottom:4px solid transparent;border-left:6px solid var(--c-bg-arrow)}.arrow.left{border-top:4px solid transparent;border-bottom:4px solid transparent;border-right:6px solid var(--c-bg-arrow)}.badge{display:inline-block;font-size:14px;font-weight:600;height:18px;line-height:18px;border-radius:3px;padding:0 6px;color:var(--c-bg);vertical-align:top;transition:color var(--t-color),background-color var(--t-color)}.badge.tip{background-color:var(--c-badge-tip)}.badge.warning{background-color:var(--c-badge-warning);color:var(--c-badge-warning-text)}.badge.danger{background-color:var(--c-badge-danger);color:var(--c-badge-danger-text)}.badge+.badge{margin-left:5px}code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:var(--font-family-code);font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#999}.token.punctuation{color:#ccc}.token.tag,.token.attr-name,.token.namespace,.token.deleted{color:#ec5975}.token.function-name{color:#6196cc}.token.boolean,.token.number,.token.function{color:#f08d49}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699}.token.operator,.token.entity,.token.url{color:#67cdcc}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:#3eaf7c}.theme-default-content pre,.theme-default-content pre[class*=language-]{line-height:1.375;padding:1.3rem 1.5rem;margin:.85rem 0;border-radius:6px;overflow:auto}.theme-default-content pre code,.theme-default-content pre[class*=language-] code{color:#fff;padding:0;background-color:transparent!important;border-radius:0;overflow-wrap:unset;-webkit-font-smoothing:auto;-moz-osx-font-smoothing:auto}.theme-default-content .line-number{font-family:var(--font-family-code)}div[class*=language-]{position:relative;background-color:var(--code-bg-color);border-radius:6px}div[class*=language-]:before{content:attr(data-ext);position:absolute;z-index:3;top:.8em;right:1em;font-size:.75rem;color:var(--code-ln-color)}div[class*=language-] pre,div[class*=language-] pre[class*=language-]{background:transparent!important;position:relative;z-index:1}div[class*=language-] .highlight-lines{-webkit-user-select:none;-moz-user-select:none;user-select:none;padding-top:1.3rem;position:absolute;top:0;left:0;width:100%;line-height:1.375}div[class*=language-] .highlight-lines .highlight-line{background-color:var(--code-hl-bg-color)}div[class*=language-]:not(.line-numbers-mode) .line-numbers{display:none}div[class*=language-].line-numbers-mode .highlight-lines .highlight-line{position:relative}div[class*=language-].line-numbers-mode .highlight-lines .highlight-line:before{content:" ";position:absolute;z-index:2;left:0;top:0;display:block;width:var(--code-ln-wrapper-width);height:100%}div[class*=language-].line-numbers-mode pre{margin-left:var(--code-ln-wrapper-width);padding-left:1rem;vertical-align:middle}div[class*=language-].line-numbers-mode .line-numbers{position:absolute;top:0;width:var(--code-ln-wrapper-width);text-align:center;color:var(--code-ln-color);padding-top:1.25rem;line-height:1.375;counter-reset:line-number}div[class*=language-].line-numbers-mode .line-numbers .line-number{position:relative;z-index:3;-webkit-user-select:none;-moz-user-select:none;user-select:none;height:1.375em}div[class*=language-].line-numbers-mode .line-numbers .line-number:before{counter-increment:line-number;content:counter(line-number);font-size:.85em}div[class*=language-].line-numbers-mode:after{content:"";position:absolute;top:0;left:0;width:var(--code-ln-wrapper-width);height:100%;border-radius:6px 0 0 6px;border-right:1px solid var(--code-hl-bg-color)}@media (max-width: 419px){.theme-default-content div[class*=language-]{margin:.85rem -1.5rem;border-radius:0}}.code-group__nav{margin-top:.85rem;margin-bottom:calc(-1.7rem - 6px);padding-bottom:calc(1.7rem - 6px);padding-left:10px;padding-top:10px;border-top-left-radius:6px;border-top-right-radius:6px;background-color:var(--code-bg-color)}.code-group__ul{margin:auto 0;padding-left:0;display:inline-flex;list-style:none}.code-group__nav-tab{border:0;padding:5px;cursor:pointer;background-color:transparent;font-size:.85em;line-height:1.4;color:#ffffffe6;font-weight:600}.code-group__nav-tab:focus{outline:none}.code-group__nav-tab:focus-visible{outline:1px solid rgba(255,255,255,.9)}.code-group__nav-tab-active{border-bottom:var(--c-brand) 1px solid}@media (max-width: 419px){.code-group__nav{margin-left:-1.5rem;margin-right:-1.5rem;border-radius:0}}.code-group-item{display:none}.code-group-item__active{display:block}.code-group-item>pre{background-color:orange}.custom-container{transition:color var(--t-color),border-color var(--t-color),background-color var(--t-color)}.custom-container .custom-container-title{font-weight:600}.custom-container .custom-container-title:not(:only-child){margin-bottom:-.4rem}.custom-container.tip,.custom-container.warning,.custom-container.danger{padding:.1rem 1.5rem;border-left-width:.5rem;border-left-style:solid;margin:1rem 0}.custom-container.tip{border-color:var(--c-tip);background-color:var(--c-tip-bg);color:var(--c-tip-text)}.custom-container.tip .custom-container-title{color:var(--c-tip-title)}.custom-container.tip a{color:var(--c-tip-text-accent)}.custom-container.tip code{background-color:var(--c-bg-dark)}.custom-container.warning{border-color:var(--c-warning);background-color:var(--c-warning-bg);color:var(--c-warning-text)}.custom-container.warning .custom-container-title{color:var(--c-warning-title)}.custom-container.warning a{color:var(--c-warning-text-accent)}.custom-container.warning blockquote{border-left-color:var(--c-warning-border-dark);color:var(--c-warning-text-quote)}.custom-container.warning code{color:var(--c-warning-text-light);background-color:var(--c-warning-bg-light)}.custom-container.warning details{background-color:var(--c-warning-details-bg)}.custom-container.warning details code{background-color:var(--c-warning-bg-lighter)}.custom-container.warning .external-link-icon{--external-link-icon-color: var(--c-warning-text-quote)}.custom-container.danger{border-color:var(--c-danger);background-color:var(--c-danger-bg);color:var(--c-danger-text)}.custom-container.danger .custom-container-title{color:var(--c-danger-title)}.custom-container.danger a{color:var(--c-danger-text-accent)}.custom-container.danger blockquote{border-left-color:var(--c-danger-border-dark);color:var(--c-danger-text-quote)}.custom-container.danger code{color:var(--c-danger-text-light);background-color:var(--c-danger-bg-light)}.custom-container.danger details{background-color:var(--c-danger-details-bg)}.custom-container.danger details code{background-color:var(--c-danger-bg-lighter)}.custom-container.danger .external-link-icon{--external-link-icon-color: var(--c-danger-text-quote)}.custom-container.details{display:block;position:relative;border-radius:2px;margin:1.6em 0;padding:1.6em;background-color:var(--c-details-bg)}.custom-container.details code{background-color:var(--c-bg-darker)}.custom-container.details h4{margin-top:0}.custom-container.details figure:last-child,.custom-container.details p:last-child{margin-bottom:0;padding-bottom:0}.custom-container.details summary{outline:none;cursor:pointer}.home{padding:var(--navbar-height) 2rem 0;max-width:var(--homepage-width);margin:0 auto;display:block}.home .hero{text-align:center}.home .hero img{max-width:100%;max-height:280px;display:block;margin:3rem auto 1.5rem}.home .hero h1{font-size:3rem}.home .hero h1,.home .hero .description,.home .hero .actions{margin:1.8rem auto}.home .hero .actions{display:flex;flex-wrap:wrap;gap:1rem;justify-content:center}.home .hero .description{max-width:35rem;font-size:1.6rem;line-height:1.3;color:var(--c-text-lightest)}.home .hero .action-button{display:inline-block;font-size:1.2rem;padding:.8rem 1.6rem;border-width:2px;border-style:solid;border-radius:4px;transition:background-color var(--t-color);box-sizing:border-box}.home .hero .action-button.primary{color:var(--c-bg);background-color:var(--c-brand);border-color:var(--c-brand)}.home .hero .action-button.primary:hover{background-color:var(--c-brand-light)}.home .hero .action-button.secondary{color:var(--c-brand);background-color:var(--c-bg);border-color:var(--c-brand)}.home .hero .action-button.secondary:hover{color:var(--c-bg);background-color:var(--c-brand-light)}.home .features{border-top:1px solid var(--c-border);transition:border-color var(--t-color);padding:1.2rem 0;margin-top:2.5rem;display:flex;flex-wrap:wrap;align-items:flex-start;align-content:stretch;justify-content:space-between}.home .feature{flex-grow:1;flex-basis:30%;max-width:30%}.home .feature h2{font-size:1.4rem;font-weight:500;border-bottom:none;padding-bottom:0;color:var(--c-text-light)}.home .feature p{color:var(--c-text-lighter)}.home .theme-default-content{padding:0;margin:0}.home .footer{padding:2.5rem;border-top:1px solid var(--c-border);text-align:center;color:var(--c-text-lighter);transition:border-color var(--t-color)}@media (max-width: 719px){.home .features{flex-direction:column}.home .feature{max-width:100%;padding:0 2.5rem}}@media (max-width: 419px){.home{padding-left:1.5rem;padding-right:1.5rem}.home .hero img{max-height:210px;margin:2rem auto 1.2rem}.home .hero h1{font-size:2rem}.home .hero h1,.home .hero .description,.home .hero .actions{margin:1.2rem auto}.home .hero .description{font-size:1.2rem}.home .hero .action-button{font-size:1rem;padding:.6rem 1.2rem}.home .feature h2{font-size:1.25rem}}.page{padding-top:var(--navbar-height);padding-left:var(--sidebar-width)}.navbar{position:fixed;z-index:20;top:0;left:0;right:0;height:var(--navbar-height);box-sizing:border-box;border-bottom:1px solid var(--c-border);background-color:var(--c-bg-navbar);transition:background-color var(--t-color),border-color var(--t-color)}.sidebar{font-size:16px;width:var(--sidebar-width);position:fixed;z-index:10;margin:0;top:var(--navbar-height);left:0;bottom:0;box-sizing:border-box;border-right:1px solid var(--c-border);overflow-y:auto;scrollbar-width:thin;scrollbar-color:var(--c-brand) var(--c-border);background-color:var(--c-bg-sidebar);transition:transform var(--t-transform),background-color var(--t-color),border-color var(--t-color)}.sidebar::-webkit-scrollbar{width:7px}.sidebar::-webkit-scrollbar-track{background-color:var(--c-border)}.sidebar::-webkit-scrollbar-thumb{background-color:var(--c-brand)}.sidebar-mask{position:fixed;z-index:9;top:0;left:0;width:100vw;height:100vh;display:none}.theme-container.sidebar-open .sidebar-mask{display:block}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(1){transform:rotate(45deg) translate3d(5.5px,5.5px,0)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(2){transform:scale3d(0,1,1)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(3){transform:rotate(-45deg) translate3d(6px,-6px,0)}.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(1),.theme-container.sidebar-open .navbar>.toggle-sidebar-button .icon span:nth-child(3){transform-origin:center}.theme-container.no-navbar .theme-default-content h1,.theme-container.no-navbar .theme-default-content h2,.theme-container.no-navbar .theme-default-content h3,.theme-container.no-navbar .theme-default-content h4,.theme-container.no-navbar .theme-default-content h5,.theme-container.no-navbar .theme-default-content h6{margin-top:1.5rem;padding-top:0}.theme-container.no-navbar .page{padding-top:0}.theme-container.no-navbar .sidebar{top:0}.theme-container.no-sidebar .sidebar{display:none}@media (max-width: 719px){.theme-container.no-sidebar .sidebar{display:block}}.theme-container.no-sidebar .page{padding-left:0}.theme-default-content a:hover{text-decoration:underline}.theme-default-content img{max-width:100%}.theme-default-content h1,.theme-default-content h2,.theme-default-content h3,.theme-default-content h4,.theme-default-content h5,.theme-default-content h6{margin-top:calc(.5rem - var(--navbar-height));padding-top:calc(1rem + var(--navbar-height));margin-bottom:0}.theme-default-content h1:first-child,.theme-default-content h2:first-child,.theme-default-content h3:first-child,.theme-default-content h4:first-child,.theme-default-content h5:first-child,.theme-default-content h6:first-child{margin-bottom:1rem}.theme-default-content h1:first-child+p,.theme-default-content h1:first-child+pre,.theme-default-content h1:first-child+.custom-container,.theme-default-content h2:first-child+p,.theme-default-content h2:first-child+pre,.theme-default-content h2:first-child+.custom-container,.theme-default-content h3:first-child+p,.theme-default-content h3:first-child+pre,.theme-default-content h3:first-child+.custom-container,.theme-default-content h4:first-child+p,.theme-default-content h4:first-child+pre,.theme-default-content h4:first-child+.custom-container,.theme-default-content h5:first-child+p,.theme-default-content h5:first-child+pre,.theme-default-content h5:first-child+.custom-container,.theme-default-content h6:first-child+p,.theme-default-content h6:first-child+pre,.theme-default-content h6:first-child+.custom-container{margin-top:2rem}@media (max-width: 959px){.sidebar{font-size:15px;width:var(--sidebar-width-mobile)}.page{padding-left:var(--sidebar-width-mobile)}}@media (max-width: 719px){.sidebar{top:0;padding-top:var(--navbar-height);transform:translate(-100%)}.page{padding-left:0}.theme-container.sidebar-open .sidebar{transform:translate(0)}.theme-container.no-navbar .sidebar{padding-top:0}}@media (max-width: 419px){h1{font-size:1.9rem}}.navbar{--navbar-line-height: calc( var(--navbar-height) - 2 * var(--navbar-padding-v) );padding:var(--navbar-padding-v) var(--navbar-padding-h);line-height:var(--navbar-line-height)}.navbar .logo{height:var(--navbar-line-height);margin-right:var(--navbar-padding-v);vertical-align:top}.navbar .site-name{font-size:1.3rem;font-weight:600;color:var(--c-text);position:relative}.navbar .navbar-items-wrapper{display:flex;position:absolute;box-sizing:border-box;top:var(--navbar-padding-v);right:var(--navbar-padding-h);height:var(--navbar-line-height);padding-left:var(--navbar-padding-h);white-space:nowrap;font-size:.9rem}.navbar .navbar-items-wrapper .search-box{flex:0 0 auto;vertical-align:top}@media screen and (max-width: 719px){.navbar{padding-left:4rem}.navbar .site-name{display:block;width:calc(100vw - 11rem);overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.navbar .can-hide{display:none}}.navbar-items{display:inline-block}@media print{.navbar-items{display:none}}.navbar-items a{display:inline-block;line-height:1.4rem;color:inherit}.navbar-items a:hover,.navbar-items a.router-link-active{color:var(--c-text)}.navbar-items .navbar-item{position:relative;display:inline-block;margin-left:1.5rem;line-height:var(--navbar-line-height)}.navbar-items .navbar-item:first-child{margin-left:0}.navbar-items .navbar-item>a:hover,.navbar-items .navbar-item>a.router-link-active{margin-bottom:-2px;border-bottom:2px solid var(--c-text-accent)}@media (max-width: 719px){.navbar-items .navbar-item{margin-left:0}.navbar-items .navbar-item>a:hover,.navbar-items .navbar-item>a.router-link-active{margin-bottom:0;border-bottom:none}.navbar-items a:hover,.navbar-items a.router-link-active{color:var(--c-text-accent)}}.toggle-sidebar-button{position:absolute;top:.6rem;left:1rem;display:none;padding:.6rem;cursor:pointer}.toggle-sidebar-button .icon{display:flex;flex-direction:column;justify-content:center;align-items:center;width:1.25rem;height:1.25rem;cursor:inherit}.toggle-sidebar-button .icon span{display:inline-block;width:100%;height:2px;border-radius:2px;background-color:var(--c-text);transition:transform var(--t-transform)}.toggle-sidebar-button .icon span:nth-child(2){margin:6px 0}@media screen and (max-width: 719px){.toggle-sidebar-button{display:block}}.toggle-color-mode-button{display:flex;margin:auto;margin-left:1rem;border:0;background:none;color:var(--c-text);opacity:.8;cursor:pointer}@media print{.toggle-color-mode-button{display:none}}.toggle-color-mode-button:hover{opacity:1}.toggle-color-mode-button .icon{width:1.25rem;height:1.25rem}.DocSearch{transition:background-color var(--t-color)}.navbar-dropdown-wrapper{cursor:pointer}.navbar-dropdown-wrapper .navbar-dropdown-title,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile{display:block;font-size:.9rem;font-family:inherit;cursor:inherit;padding:inherit;line-height:1.4rem;background:transparent;border:none;font-weight:500;color:var(--c-text)}.navbar-dropdown-wrapper .navbar-dropdown-title:hover,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile:hover{border-color:transparent}.navbar-dropdown-wrapper .navbar-dropdown-title .arrow,.navbar-dropdown-wrapper .navbar-dropdown-title-mobile .arrow{vertical-align:middle;margin-top:-1px;margin-left:.4rem}.navbar-dropdown-wrapper .navbar-dropdown-title-mobile{display:none;font-weight:600;font-size:inherit}.navbar-dropdown-wrapper .navbar-dropdown-title-mobile:hover{color:var(--c-text-accent)}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item{color:inherit;line-height:1.7rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle{margin:.45rem 0 0;border-top:1px solid var(--c-border);padding:1rem 0 .45rem;font-size:.9rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>span{padding:0 1.5rem 0 1.25rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>a{font-weight:inherit}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle>a.router-link-active:after{display:none}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem-wrapper{padding:0;list-style:none}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem-wrapper .navbar-dropdown-subitem{font-size:.9em}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a{display:block;line-height:1.7rem;position:relative;border-bottom:none;font-weight:400;margin-bottom:0;padding:0 1.5rem 0 1.25rem}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a:hover,.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active{color:var(--c-text-accent)}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active:after{content:"";width:0;height:0;border-left:5px solid var(--c-text-accent);border-top:3px solid transparent;border-bottom:3px solid transparent;position:absolute;top:calc(50% - 2px);left:9px}.navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item:first-child .navbar-dropdown-subtitle{margin-top:0;padding-top:0;border-top:0}.navbar-dropdown-wrapper.mobile.open .navbar-dropdown-title,.navbar-dropdown-wrapper.mobile.open .navbar-dropdown-title-mobile{margin-bottom:.5rem}.navbar-dropdown-wrapper.mobile .navbar-dropdown-title,.navbar-dropdown-wrapper.mobile .navbar-dropdown-title-mobile{display:none}.navbar-dropdown-wrapper.mobile .navbar-dropdown-title-mobile{display:block}.navbar-dropdown-wrapper.mobile .navbar-dropdown{transition:height .1s ease-out;overflow:hidden}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle{border-top:0;margin-top:0;padding-top:0;padding-bottom:0}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subtitle,.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item>a{font-size:15px;line-height:2rem}.navbar-dropdown-wrapper.mobile .navbar-dropdown .navbar-dropdown-item .navbar-dropdown-subitem{font-size:14px;padding-left:1rem}.navbar-dropdown-wrapper:not(.mobile){height:1.8rem}.navbar-dropdown-wrapper:not(.mobile):hover .navbar-dropdown,.navbar-dropdown-wrapper:not(.mobile).open .navbar-dropdown{display:block!important}.navbar-dropdown-wrapper:not(.mobile).open:blur{display:none}.navbar-dropdown-wrapper:not(.mobile) .navbar-dropdown{display:none;height:auto!important;box-sizing:border-box;max-height:calc(100vh - 2.7rem);overflow-y:auto;position:absolute;top:100%;right:0;background-color:var(--c-bg-navbar);padding:.6rem 0;border:1px solid var(--c-border);border-bottom-color:var(--c-border-dark);text-align:left;border-radius:.25rem;white-space:nowrap;margin:0}.page{padding-bottom:2rem;display:block}.page .theme-default-content{max-width:var(--content-width);margin:0 auto;padding:2rem 2.5rem;padding-top:0}@media (max-width: 959px){.page .theme-default-content{padding:2rem}}@media (max-width: 419px){.page .theme-default-content{padding:1.5rem}}.page-meta{max-width:var(--content-width);margin:0 auto;padding:1rem 2.5rem;overflow:auto}@media (max-width: 959px){.page-meta{padding:2rem}}@media (max-width: 419px){.page-meta{padding:1.5rem}}.page-meta .meta-item{cursor:default;margin-top:.8rem}.page-meta .meta-item .meta-item-label{font-weight:500;color:var(--c-text-lighter)}.page-meta .meta-item .meta-item-info{font-weight:400;color:var(--c-text-quote)}.page-meta .edit-link{display:inline-block;margin-right:.25rem}@media print{.page-meta .edit-link{display:none}}.page-meta .last-updated{float:right}@media (max-width: 719px){.page-meta .last-updated{font-size:.8em;float:none}.page-meta .contributors{font-size:.8em}}.page-nav{max-width:var(--content-width);margin:0 auto;padding:1rem 2.5rem 2rem;padding-bottom:0}@media (max-width: 959px){.page-nav{padding:2rem}}@media (max-width: 419px){.page-nav{padding:1.5rem}}.page-nav .inner{min-height:2rem;margin-top:0;border-top:1px solid var(--c-border);transition:border-color var(--t-color);padding-top:1rem;overflow:auto}.page-nav .prev a:before{content:"←"}.page-nav .next{float:right}.page-nav .next a:after{content:"→"}.sidebar ul{padding:0;margin:0;list-style-type:none}.sidebar a{display:inline-block}.sidebar .navbar-items{display:none;border-bottom:1px solid var(--c-border);transition:border-color var(--t-color);padding:.5rem 0 .75rem}.sidebar .navbar-items a{font-weight:600}.sidebar .navbar-items .navbar-item{display:block;line-height:1.25rem;font-size:1.1em;padding:.5rem 0 .5rem 1.5rem}.sidebar .sidebar-items{padding:1.5rem 0}@media (max-width: 719px){.sidebar .navbar-items{display:block}.sidebar .navbar-items .navbar-dropdown-wrapper .navbar-dropdown .navbar-dropdown-item a.router-link-active:after{top:calc(1rem - 2px)}.sidebar .sidebar-items{padding:1rem 0}}.sidebar-item{cursor:default;border-left:.25rem solid transparent;color:var(--c-text)}.sidebar-item:focus-visible{outline-width:1px;outline-offset:-1px}.sidebar-item.active:not(p.sidebar-heading){font-weight:600;color:var(--c-text-accent);border-left-color:var(--c-text-accent)}.sidebar-item.sidebar-heading{transition:color .15s ease;font-size:1.1em;font-weight:700;padding:.35rem 1.5rem .35rem 1.25rem;width:100%;box-sizing:border-box;margin:0}.sidebar-item.sidebar-heading+.sidebar-item-children{transition:height .1s ease-out;overflow:hidden;margin-bottom:.75rem}.sidebar-item.collapsible{cursor:pointer}.sidebar-item.collapsible .arrow{position:relative;top:-.12em;left:.5em}.sidebar-item:not(.sidebar-heading){font-size:1em;font-weight:400;display:inline-block;margin:0;padding:.35rem 1rem .35rem 2rem;line-height:1.4;width:100%;box-sizing:border-box}.sidebar-item:not(.sidebar-heading)+.sidebar-item-children{padding-left:1rem;font-size:.95em}.sidebar-item-children .sidebar-item-children .sidebar-item:not(.sidebar-heading){padding:.25rem 1rem .25rem 1.75rem}.sidebar-item-children .sidebar-item-children .sidebar-item:not(.sidebar-heading).active{font-weight:500;border-left-color:transparent}a.sidebar-heading+.sidebar-item-children .sidebar-item:not(.sidebar-heading).active{border-left-color:transparent}a.sidebar-item{cursor:pointer}a.sidebar-item:hover{color:var(--c-text-accent)}.table-of-contents .badge{vertical-align:middle}.dropdown-enter-from,.dropdown-leave-to{height:0!important}.fade-slide-y-enter-active{transition:all .2s ease}.fade-slide-y-leave-active{transition:all .2s cubic-bezier(1,.5,.8,1)}.fade-slide-y-enter-from,.fade-slide-y-leave-to{transform:translateY(10px);opacity:0}@font-face{font-family:CabinetGrotesk-Variable;src:url(/fonts/CabinetGrotesk-Variable.ttf);font-weight:900}@font-face{font-family:ui-sans-serif;src:url(/fonts/IBMPlexSans-Regular.ttf);font-weight:400}@font-face{font-family:ui-sans-serif;src:url(/fonts/IBMPlexSans-Bold.ttf);font-weight:700}@font-face{font-family:NewSpirit;src:url(/fonts/NewSpirit.otf);font-weight:900}.sidebar-item{background-color:var(--primary-dark);color:var(--secondary-dark);width:90%!important;position:relative}.sidebar-item span.arrow{top:.4em!important;float:right!important;border:none!important;height:20px;width:20px;background-repeat:no-repeat!important;background-size:contain!important}.sidebar-item span.arrow.right{background-image:url(../assets/sidebar-plus.svg)!important}.sidebar-item span.arrow.down{background-image:url(../assets/sidebar-minus.svg)!important}.sidebar-item:hover{background-color:var(--primary-light)!important;color:var(--secondary-dark)!important;border-radius:8px}.sidebar-item.active{background-color:var(--primary-dark)!important;color:var(--secondary-light)!important;font-weight:bolder!important;border:none!important}.sidebar-item.active:hover,.sidebar-item.active:nth-last-child(1){border-radius:8px;background-color:var(--primary-light)!important}ul.sidebar-items>li{margin-top:1rem}ul.sidebar-items>li:nth-child(2)>.sidebar-item:before,ul.sidebar-items>li:nth-child(3)>.sidebar-item:before{content:"";position:absolute;top:-8px;left:5%;width:90%;height:1px;background-color:var(--primary-bright)}.homepage{background-color:var(--c-bg-dark)}.homepage:before{content:"";position:fixed;top:0%;left:-20%;width:140%;height:100vh;z-index:0;background:url(/assets/homepage.svg) center/300px 150px repeat}.homepage>.navbar{background-color:var(--c-bg-dark)}.homepage>.page{position:relative;padding:0!important;height:initial;min-height:100vh}.homepage>.page>.theme-default-content{max-width:100%;padding:0 1rem}.homepage_content{display:flex;align-items:center;width:100%;min-height:100vh;padding:calc(var(--navbar-height) + 2rem) 0 2rem;box-sizing:border-box}.homepage_container{display:flex;flex-wrap:wrap;justify-content:center;margin:0 auto;gap:4rem}.homepage_item{display:flex;flex-direction:column;justify-content:space-between;text-align:left;width:calc(33.3333333333% - 8rem);background-color:var(--c-bg-light);border:none;padding:40px 25px;min-height:280px;box-shadow:0 2px 4px 0 var(--c-glow);transition:box-shadow .3s ease-in-out,background-color .3s ease-in-out;text-decoration:none!important}.homepage_item:hover{background-color:var(--c-bg-darker);box-shadow:0 2px 30px 0 var(--c-glow)}.homepage_item h2{padding:0;margin:0!important;color:var(--c-text);font-family:var(--font-family-title);font-size:1.75rem;line-height:3rem;font-weight:900;border:none}.homepage_item p{padding:0;margin:20px 0 0!important;color:var(--c-text-lighter);font-size:1.125rem;line-height:1.5;font-weight:500;border:none}.homepage_title{display:flex;align-items:center;justify-content:space-between;width:100%}.homepage footer{display:none!important}:root{--c-brand: #f9ff73;--c-brand-light: #faff81;--c-bg: #faf8f5;--c-bg-dark: #faf8f5;--c-bg-light: #ffffff;--c-bg-lighter: #fafafa;--c-bg-navbar: var(--c-bg);--c-bg-sidebar: var(--c-bg);--c-bg-arrow: #f9ff73;--c-glow: rgba(0, 0, 0, .2);--c-text: #010101;--c-text-accent: var(--c-brand);--c-text-light: #6a7380;--c-text-lighter: #6a7380;--c-text-lightest: rgb(120 220 232);--c-text-quote: #f9ff73;--c-border: #edebe9;--c-border-dark: #e1dfdd;--c-tip: rgb(120, 220, 232);--c-tip-bg: rgba(120, 220, 232, .3);--c-tip-title: var(--c-tip);--c-tip-text: var(--c-text);--c-tip-text-accent: var(--c-text-accent);--c-warning: rgb(249, 255, 115);--c-warning-bg: rgba(249, 255, 115, .3);--c-warning-title: var(--c-warning);--c-warning-text: var(--c-text);--c-warning-text-accent: var(--c-text-accent);--c-danger: #e46b71;--c-danger-bg: rgba(228, 107, 113, .3);--c-danger-title: var(--c-danger);--c-danger-text: var(--c-text);--c-details-bg: var(--c-bg-light);--c-danger-text-accent: var(--c-text);--c-badge-tip: var(--c-tip);--c-badge-warning: var(--c-warning);--c-badge-danger: var(--c-danger);--t-color: .3s ease;--t-transform: .3s ease;--code-bg-color: #282c34;--code-hl-bg-color: rgba(0, 0, 0, .66);--code-ln-color: #9e9e9e;--code-ln-wrapper-width: 3.5rem;--navbar-height: 3.6rem;--navbar-padding-v: .8rem;--navbar-line-height: calc( var(--navbar-height) - 2 * var(--navbar-padding-v) );--homepage-width: 1275px;--content-width: 1275px;--search-input-width: 10rem !important;--search-result-width: 20rem !important;--font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--font-family-title: NewSpirit, Inter, CabinetGrotesk-Variable, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;--primary-dark: #06080f;--primary-light: #1e212b;--primary-bright: #313442;--secondary-dark: #9d9e91;--secondary-light: #f0f2da}html.dark{--c-brand: #f9ff73;--c-brand-light: #faff81;--c-bg-arrow: #f9ff73;--c-text: #f0f2da;--c-text-light: #9d9e91;--c-text-lighter: #9d9e91;--c-text-lightest: rgb(120 220 232);--c-bg: var(--primary-dark);--c-bg-dark: #141721;--c-bg-darker: #06080f;--c-bg-light: #1f212b;--c-bg-lighter: #2b2e30;--c-border: #2b2e30;--c-glow: rgba(20, 23, 33, .8);--c-tip: rgb(120, 220, 232);--c-tip-bg: rgba(120, 220, 232, .3);--c-tip-title: var(--c-tip);--c-tip-text: var(--c-text);--c-tip-text-accent: var(--c-text-accent);--c-warning: rgb(249, 255, 115);--c-warning-bg: rgba(249, 255, 115, .3);--c-warning-title: var(--c-warning);--c-warning-text: var(--c-text);--c-warning-text-accent: var(--c-text-accent);--c-danger: #e46b71;--c-danger-bg: rgba(228, 107, 113, .3);--c-danger-title: var(--c-danger);--c-danger-text: var(--c-text);--c-details-bg: var(--c-bg-light);--c-danger-text-accent: var(--c-text);--c-badge-tip: var(--c-tip);--c-badge-warning: var(--c-warning);--c-badge-danger: var(--c-danger)}.navbar-items .navbar-item{margin-left:1rem}h2,h3{padding-top:2.5rem!important}.search-box{order:-1;margin:0!important;margin-right:1rem!important;--search-item-focus-bg-color: var(--c-bg-light)}.search-box input{--search-border-color: var(--c-text)}.site-name{display:none!important}.navbar .logo{height:24px;vertical-align:middle}.split_content{display:flex;flex-wrap:wrap;width:100%;gap:3rem}.split_side{width:calc(50% - 1.5rem)}@media (max-width: 1140px){.homepage_item{width:calc(50% - 8rem)}.split_side{width:100%}nav{display:none!important}}@media (max-width: 720px){.homepage_container{width:100%;margin:0 auto}.homepage_item{width:100%;min-height:200px}.search-box{margin-right:0rem!important}}h1,h2,h3{font-family:var(--font-family-title)!important;font-weight:900!important;padding-bottom:16px}h2,h3{margin-top:1rem!important}div.divider{margin:3rem auto;border-bottom:1px solid var(--primary-bright)}div.request-url{color:var(--c-text);font-size:1.15rem;font-weight:300;line-height:1.25;overflow-wrap:break-word;background:#121415;padding:15px;border:1px solid rgb(87,85,85);border-radius:10px}:root{--search-bg-color: #ffffff;--search-accent-color: #3eaf7c;--search-text-color: #2c3e50;--search-border-color: #eaecef;--search-item-text-color: #5d81a5;--search-item-focus-bg-color: #f3f4f5;--search-input-width: 8rem;--search-result-width: 20rem}.search-box{display:inline-block;position:relative;margin-left:1rem}@media print{.search-box{display:none}}.search-box input{-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:text;width:var(--search-input-width);height:2rem;color:var(--search-text-color);display:inline-block;border:1px solid var(--search-border-color);border-radius:2rem;font-size:.9rem;line-height:2rem;padding:0 .5rem 0 2rem;outline:none;transition:all ease .3s;background:var(--search-bg-color) url(/assets/search-0782d0d1.svg) .6rem .5rem no-repeat;background-size:1rem}.search-box input:focus{cursor:auto;border-color:var(--search-accent-color)}.search-box .suggestions{background:var(--search-bg-color);width:var(--search-result-width);position:absolute;top:2rem;right:0;border:1px solid var(--search-border-color);border-radius:6px;padding:.4rem;list-style-type:none}.search-box .suggestion{line-height:1.4;padding:.4rem .6rem;border-radius:4px;cursor:pointer}.search-box .suggestion.focus{background-color:var(--search-item-focus-bg-color)}.search-box .suggestion.focus a{color:var(--search-accent-color)}.search-box .suggestion a{white-space:normal;color:var(--search-item-text-color)}.search-box .suggestion .page-title{font-weight:600}.search-box .suggestion .page-header{font-size:.9em;margin-left:.25em}@media (max-width: 719px){.search-box input{cursor:pointer;width:0;border-color:transparent;position:relative}.search-box input:focus{cursor:text;left:0;width:10rem}}@media (max-width: 419px){.search-box input:focus{width:8rem}.search-box .suggestions{width:calc(100vw - 4rem);right:-.5rem}}.code-div[data-v-c21333f5]{font-size:1.15rem;font-weight:300;line-height:1.25;overflow-wrap:break-word;background:#121415;padding:15px;border:1px solid rgb(87,85,85);border-radius:10px;display:flex;justify-content:space-between;align-items:center}.copyButton[data-v-c21333f5]{background-color:var(--c-brand);border:none;color:#000;text-align:center;text-decoration:none;display:inline-block;font-size:16px;margin:4px 2px;cursor:pointer;border-radius:15px;padding:8px 15px} diff --git a/build/1-apillon-api.html b/build/1-apillon-api.html new file mode 100644 index 00000000..06f6d584 --- /dev/null +++ b/build/1-apillon-api.html @@ -0,0 +1,76 @@ + + + + + + + + +Apillon API | Apillon Wiki + + + + ++ + + diff --git a/build/10-flutter-sdk.html b/build/10-flutter-sdk.html new file mode 100644 index 00000000..0763d06c --- /dev/null +++ b/build/10-flutter-sdk.html @@ -0,0 +1,207 @@ + + + + + + + + +Apillon Wiki Apillon API
Endpoints
The list of endpoints where API is available:
Environment URL Production https://api.apillon.io Testing Coming soon... API to Web3
Apillon API is a set of RESTful API endpoints allowing developers to integrate Apillon modules into their Web3 applications.
Unless clearly marked as public, all routes are private and require an API key.
Requests
The server speaks JSON. It is recommended that every call to the server includes a
Content-Type
header set toapplication/json;
.Authentication and authorization
API routes restrict public access and require authentication.
Requests must include a basic auth HTTP header field in the form of
Authorization: Basic <credentials>
, where credentials represent the Base64 encoding of API key and API key secret joined by a single colon:
.API keys could be generated on the developer dashboard under Project settings.
Authentication errors
Every request goes through authentication middleware, where the following errors can occur:
Status Message Description 400 Missing Authorization header Request is missing authorization header. 400 Malformed Authorization header Authorization header field has an invalid form. 401 Invalid API key or API key secret Authorization header is valid, but credentials in it are not. Authorization errors
Each endpoint requires a certain role or permission from the API key.
There are three types of permissions that could be assigned to an API key:
Code Name Description 50 KEY_EXECUTE Permission to execute certain actions 51 KEY_WRITE Permission to create, modify or delete records 52 KEY_READ Permission to read record These permissions could be assigned to an API key for every attached service (e.g., Web3 Storage (Crust), Web3 Authentication (KILT), etc.).
If a request is made with an API key that lacks permission for a called endpoint, the following errors can occur:
Status Message Description 403 Insufficient permissions - missing permission name
permissionAPI key lacks required permission for called service. 403 Insufficient permissions to access this record API key has required permissions for endpoint, but it does not have the right to access the addressed record (i.e., a record belongs to a different project). Listing requests
Endpoints starting with "List" are intended to list different data, where the response contains the below properties.
Name Description items Records on a specified page that match the current query total Number of all records that match the query limit Number of items on a page (default: 20). page Current page Listing endpoints by default supports the query parameters below:
Name Description Required search Search the items usually by name or some other property specifying this item. false page Items are paginated by default. This parameter is used to get items from a specific page. false limit Number of items on a page (default: 20). false orderBy One or multiple properties, separated by a comma, used to order data. false desc Boolean
values, mapped to the index of theorderBy
parameter. Defaults to false.false status Integer values, to filter by the entity's status (each entity has corresponding status codes) false Responses
Every response has a unique ID, which helps identify potential issues. It also includes a status code that can help identify the cause of a potential problem.
Query requests through the
GET
method can return status codes200
,400
,401
,403
, or500
. Mutations throughPOST
,PUT
, andDELETE
can also return codes201
and422
. Invalid routes return status code404
.A successful request includes a
data
key, which holds a valid response object.{ + "id": ..., + "status": ..., + "data": { ... }, +} +
List of responses:
- 200: Success
- 201: Creation successful
- 400: Bad request
- 401: Unauthenticated access
- 402: Payment required
- 403: Unauthorized access
- 404: Path not found
- 422: Data validation failed
- 500: System error
Error handling
A request fails if response code is not 200 or 201. The Apillon API returns two types of errors.
Code exception
Errors include a unique code number, a property that caused the error, and an error message. The code number helps identify potential issues and points to their exact position in the system.
Fields in code exception:
Field Description id Unique ID of request code Apillon API internal error code pointing to the exact position in the system message Message describing the error path Endpoint that threw the error timestamp Date when the error occurred { + "id": "c46821e7-a6c3-4377-bc32-0001e348ceb4", + "code": 40406005, + "message": "FILE_DOES_NOT_EXIST", + "path": "/storage/cee9f151-a371-495b-acd2-4362fbb87780/file/xxx/detail", + "timestamp": "2022-12-29T11:54:47.555Z" +} +
Validation exception
Unprocessable entity
422 Error status
includes anerrors
key containing a list of error objects.This error typically occurs when the request body is not valid (i.e., it is invalid or missing keys).
Errors include a unique code number, a property that caused the error, and an error message. The code number helps identify potential issues and points to their exact position in the system.
{ + ... + "errors": [ + { + "code": 42200008, + "property": "fileName", + "message": "FILE_NAME_NOT_PRESENT" + }, + ] +} +
Fields in validation exception:
Field Description id Unique ID of request model Apillon API model used to validate request payload errors Array of errors path Endpoint that threw the error timestamp Date when the error occurred Common errors
Through the whole Apillon API, the same errors can occur. The reason behind it can be current subscription package limits or current credit balance.
Not enough storage space
One of the limits based on the project subscription package is available storage space (on the IPFS node). If a project reaches the storage space limit, the following error will occur.
{ + ... + "code": 40006003, + "message": "NOT_ENOUGH_STORAGE_SPACE", + ... +} +
Credit balance too low
Some nonrecurrent actions require payment with credits. If a project's credit balance is lower than price of executed action, API will return status 402 and the following response.
{ + ... + "code": 40210000, + "message": "CREDIT_BALANCE_TOO_LOW", + ... +} +
Project
Api key is created inside a project and can be used to get project details through Apillon API.
Credit balance
API to get project credit balance
GET /project/creditResponse fields
Name Type Description balance number
Current credit balance - amount of credits in project, that can be used to perform different actions curl --location --request GET "https://api.apillon.io/project/credit" \ +--header "Authorization: Basic :credentials" +
{ + "id": "ec700ddd-4a0d-4d6d-b3ba-64b7ab031c4b", + "status": 200, + "data": { + "balance": 120 + } +} +
API Code Examples
Examples for using the Apillon API in PHP, .NET (C#) and Python can be found on our code examples github repo
Apillon Flutter SDK | Apillon Wiki + + + + ++ + + diff --git a/build/11-cloud-functions-api.html b/build/11-cloud-functions-api.html new file mode 100644 index 00000000..8251977e --- /dev/null +++ b/build/11-cloud-functions-api.html @@ -0,0 +1,149 @@ + + + + + + + + +Apillon Wiki Apillon Flutter SDK
This package provides Dart and Flutter developers with tools and libraries to interact with Apillon services, simplifying the use of Apillon's REST API by reducing boilerplate code and streamlining multi-step processes into single operations.
Requirements
- Dart SDK: '>=3.2.2 <4.0.0'
- An Apillon API key and secret
- http package version 1.1.0
Getting started
To use the Apillon Flutter SDK, you must first register an account at Apillon.io, create a project, and generate an API key with the appropriate permissions.
The Flutter SDK package is available as a Dart package on pub.dev and you can also check it out directly on GitHub. To include it in your project, add the following to your
pubspec.yaml
file:dependencies: + apillon_flutter: ^0.0.1 +
Initialization
To start using the SDK, you need to import it and configure it with your Apillon API key and secret. Here's an example of how to initialize the Storage module:
import 'package:apillon_flutter/apillon_flutter.dart'; + +void main() { + var storage = Storage(ApillonConfig( + key: 'yourApiKey', + secret: 'yourApiSecret', + )); +} +
All modules in the Apillon Flutter SDK require the same initial configuration of
key
andsecret
.Modules
The Apillon Flutter SDK consists of several modules, each corresponding to a specific Apillon service. Below are examples of how to use some of these modules.
Storage
The Storage module provides functionalities for interacting with the Storage service.
Usage example
import 'dart:io'; +import 'package:apillon_flutter/apillon_flutter.dart'; +import 'package:path/path.dart' as path; + +void main() async { + var storage = Storage(ApillonConfig( + key: 'yourApiKey', + secret: 'yourApiSecret', + )); + + // List all buckets + var buckets = await storage.listBuckets(IApillonPagination()); + print('Buckets:'); + for (var bucket in buckets) { + print('${bucket.name} - ${bucket.uuid}'); + } + + var bucketUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616'; + + // Get specific bucket details + var bucketDetails = await storage.bucket(bucketUuid).get(); + print('Bucket Details: ${bucketDetails.name}, Size: ${bucketDetails.size}'); + + // List files in the bucket + var files = await storage.bucket(bucketUuid).listFiles(IBucketFilesRequest()); + print('Files in bucket:'); + for (var file in files) { + print('${file.name} - ${file.uuid}'); + } + + // Upload files from a folder + var uploadDir = path.join(Directory.current.path, 'my-folder'); + print('Uploading files from $uploadDir'); + await storage.bucket(bucketUuid).uploadFromFolder(uploadDir, IFileUploadRequest()); + + // Upload a single file from buffer + var filePath = path.join(Directory.current.path, 'file.txt'); + var fileBytes = File(filePath).readAsBytesSync(); + await storage.bucket(bucketUuid).uploadFiles([ + FileMetadata( + fileName: 'file.txt', + contentType: 'text/plain', + content: fileBytes, + ) + ], IFileUploadRequest()); + + // Get details of a specific file + var fileUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616'; + var fileDetails = await storage.bucket(bucketUuid).file(fileUuid).get(); + print('File Details: ${fileDetails.name}, Size: ${fileDetails.size}'); +} +
IPNS methods
The Storage module additionally contains methods for manipulating IPNS records for a specific storage bucket.
import 'package:apillon_flutter/apillon_flutter.dart'; + +void main() async { + var storage = Storage(ApillonConfig( + key: 'yourApiKey', + secret: 'yourApiSecret', + )); + var bucketUuid = 'eaff2672-3012-46fb-9278-5efacc6cb616'; + + // List all existing IPNS records in a bucket + var ipnsRecords = await storage.bucket(bucketUuid).listIpnsNames(IPNSListRequest()); + print('IPNS Records:'); + for (var record in ipnsRecords) { + print('${record.name} - ${record.uuid}'); + } + + // Create a new IPNS record + const name = 'Test IPNS'; + const description = 'This is a test description'; + const cid = 'QmUxtfFfWFguxSWUUy2FiBsGuH6Px4KYFxJqNYJRiDpemj'; + var newIpnsRecord = await storage.bucket(bucketUuid).createIpns(ICreateIpns( + name: name, + description: description, + cid: cid, + )); + print('New IPNS Record: ${newIpnsRecord.uuid}'); + + // Publish an IPNS record to point to a new CID + const newCid = 'Qmakf2aN7wzt5u9H3RadGjfotu62JsDfBq8hHzGsV2LZFx'; + await storage.bucket(bucketUuid).ipns(newIpnsRecord.uuid).publish(newCid); + print('IPNS record published to new CID: $newCid'); + + // Delete an IPNS record + await storage.bucket(bucketUuid).ipns(newIpnsRecord.uuid).delete(); + print('IPNS record deleted: ${newIpnsRecord.uuid}'); +} +
NFTs
The NFT module encapsulates functionalities for the NFT service.
Usage example
import 'package:apillon_flutter/apillon_flutter.dart'; + +void main() async { + var nft = Nft(ApillonConfig( + key: 'yourApiKey', + secret: 'yourApiSecret', + )); + + // Create a new NFT collection + var collection = await nft.create(ICreateCollection( + chain1: EvmChain.moonbase, + collectionType1: CollectionType.generic, + name: 'Space Explorers', + description: 'A collection of space explorers', + symbol: 'SE', + royaltiesFees: 3, + royaltiesAddress: '0x95B8c6b9225456107649776EF8aAF20C42d58814', + baseUri: 'https://test.com/metadata/', + baseExtension: '.json', + maxSupply: 50, + isRevokable: false, + isSoulbound: false, + drop: false, + )); + print('Collection created: ${collection.uuid}'); + // or create a substrate collection + var substrateCollection = await nft.createSubstrate({ + chain1: SubstrateChain.astar, + collectionType1: CollectionType.generic, + name: 'SpaceExplorers', + symbol: 'SE', + ... + }); + + // Mint a new NFT in the collection + var mintResult = await nft.collection(collection.uuid).mint(IMintNftData( + receivingAddress: '0x5BA8B0c24bA5307b67E619ad500a635204F73bF1', + quantity: 1, + )); + print('Mint transaction hash: ${mintResult.transactionHash}'); + + // List NFT collections + var collections = await nft.listCollections(ICollectionFilters()); + + // Transfer NFT ownership to another address + await collection.transferOwnership('0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD'); +} +
Identity
The Identity module provides functionalities for validating wallet signatures and fetching identity data.
Usage example
import 'package:apillon_flutter/apillon_flutter.dart'; + +void main() async { + var identity = Identity(ApillonConfig( + key: 'yourApiKey', + secret: 'yourApiSecret', + )); + + // Generate a signing message for EVM wallet signature validation + const customMessage = 'Identity EVM SDK test'; + var signingMessage = identity.generateSigningMessage(customMessage)["message"]; + print('Signing message: $signingMessage'); + + var walletAddress = '0xa79bg13g2...'; + var signature = '0xYourSignature'; // signature obtained from the user's wallet by the client app + + // Validate EVM wallet signature + var validationResult = await identity.validateEvmWalletSignature(IValidateEvmWalletSignature( + walletAddress: walletAddress, + message: signingMessage, + signature: signature, + )); + print('Is valid: ${validationResult.isValid}'); + print('Address: ${validationResult.address}'); + + // Get wallet identity profile for a Polkadot address + var polkadotAddress = '5HqHQDGcHqS...', + var identityProfile = await identity.getWalletIdentity(polkadotAddress); + print('Identity Profile: ${identityProfile.subsocial['content']['name']}'); +} +
Cloud Functions API | Apillon Wiki + + + + ++ + + diff --git a/build/12-embedded-wallets-integration.html b/build/12-embedded-wallets-integration.html new file mode 100644 index 00000000..6a220fbb --- /dev/null +++ b/build/12-embedded-wallets-integration.html @@ -0,0 +1,297 @@ + + + + + + + + +Apillon Wiki Cloud Functions API
The Cloud Function API provides an interface for developers to deploy, manage, and execute decentralized cloud functions on the Apillon platform. These endpoints allow you to create cloud functions, manage jobs, and configure runtime environments.
Create Cloud Function
Create a new cloud function to be executed on decentralized processors.
POST /acurast/cloud-functionsBody Fields
Field Type Description Required name string
Name of the cloud function Yes description string
Description of the cloud function No Possible Errors
Code Description 42200212 Missing required fields 42200205 Name not valid 42200206 Description not valid 50000001 Internal server error curl --location --request POST "https://api.apillon.io/acurast/cloud-functions" \ +--header "Authorization: Bearer :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"My Cloud Function\", + \"description\": \"Handles automated tasks\" +}" +
{ + "status": 201, + "data": { + "createTime": "2024-09-12T13:32:26.706Z", + "updateTime": null, + "functionUuid": "90c37572-571e-4d8c-a906-7275e8e3cd8e", + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "bucketUuid": "1a100c47-56cc-4550-a969-6631bfb1c37b", + "name": "My Cloud Function", + "description": "Handles automated tasks", + "activeJobId": null + } +} +
List Cloud Functions
Retrieve a list of cloud functions associated with a project.
GET /acurast/cloud-functionsQuery Parameters
All query parameters from listing request
Response Fields
Field Type Description functionUuuid string
Unique identifier of the cloud function projectUuid string
UUID of the project the cloud function belongs to bucketUuid string
UUID of the bucket which script files are uploaded into name string
Name of the cloud function description string
Description of the cloud function activeJobId number
The ID of the currently active job on the cloud function project_uuid string
Unique identifier of the project createTime DateTime
Creation timestamp updateTime DateTime
Last updated timestamp curl --location --request GET "https://api.apillon.io/acurast/cloud-functions?project_uuid=abc123-project" \ +--header "Authorization: Bearer :credentials" +
{ + "status": 200, + "data": { + "items": [ + { + "createTime": "2024-09-09T11:15:26.000Z", + "updateTime": "2024-09-10T13:18:31.000Z", + "functionUuid": "cfd85992-8f79-4486-97cf-2406bd722d90", + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "bucketUuid": "e85fa5ce-8c37-42fc-bf54-a578b0fd2d1f", + "name": "My Cloud Function", + "description": "Handles automated tasks", + "activeJobId": 77 + } + ], + "total": 1, + "page": 1, + "limit": 20 + } +} +
Get Cloud Function
Get the details of a specific cloud function by its UUID.
GET /acurast/cloud-functions/:function_uuidURL Parameters
Field Type Description Required function_uuid string
Unique identifier of the cloud function Yes Response Fields
Field Type Description functionUuuid string
Unique identifier of the cloud function projectUuid string
UUID of the project the cloud function belongs to bucketUuid string
UUID of the bucket which script files are uploaded into name string
Name of the cloud function description string
Description of the cloud function activeJobId number
The ID of the currently active job on the cloud function project_uuid string
Unique identifier of the project gatewayUrl string
API gateway endpoint URL of the cloud function createTime DateTime
Creation timestamp updateTime DateTime
Last updated timestamp job.scriptCId string
IPFS CID of the script file the job is running job.slots string
Number of processors running the job job.jobStatus string
The current status of the job. Possible values: 1
(deploying),2
(deployed),3
(matched),4
(inactive),9
(deleted)Possible Errors
Code Description 40300000 Forbidden 40418005 Cloud function not found curl --location --request GET "https://api.apillon.io/acurast/cloud-functions/d1e8b9f2-4d18-4ef7-9f59-87348590d5a6" \ +--header "Authorization: Bearer :credentials" +
{ + "id": "60020364-7edc-495a-a0a2-df695bb1cc3f", + "status": 200, + "data": { + "createTime": "2024-09-09T11:15:26.000Z", + "updateTime": "2024-09-10T13:18:31.000Z", + "functionUuid": "cfd85992-8f79-4486-97cf-2406bd722d90", + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "bucketUuid": "e85fa5ce-8c37-42fc-bf54-a578b0fd2d1f", + "name": "Env CF", + "description": null, + "activeJobId": 77, + "gatewayUrl": "https://cfd85992-8f79-4486-97cf-2406bd722d90.gw.web3approved.com", + "jobs": [ + { + "id": 77, + "createTime": "2024-09-10T12:55:44.000Z", + "updateTime": "2024-09-12T13:57:26.000Z", + "jobUuid": "2ead7ed9-125f-436d-9a09-5e8e95206791", + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "functionUuid": "cfd85992-8f79-4486-97cf-2406bd722d90", + "scriptCid": "QmUq4iFLKZUpEsHCAqfsBermXHRnPuE5CNcyPv1xaNkyGp", + "slots": 1, + "jobStatus": 3 + } + ] + } +} +
Create Cloud Function Job (Deployment)
Create a job/deployment for a specific cloud function.
POST /acurast/cloud-functions/:function_uuid/jobsWARNING
The deployed code should be made on top of this Node.js template: https://github.com/Apillon/cloud-function-template If it does not contain the boilerplate code, the deployment will not be accessible via the provided API gateway URL.
URL Parameters
Field Type Description Required function_uuid string
Unique identifier of the cloud function Yes Body Fields
Field Type Description Required name string
Name of the job Yes scriptCid string
IPFS CID of the script to deploy Yes slots number
Number of processors to deploy to (default 1) No Possible Errors
Code Description 40300000 Forbidden 42200212 Missing required field 42200213 Invalid field data 40418005 Cloud function not found 50018013 Error creating job curl --location --request POST "https://api.apillon.io/acurast/cloud-functions/d1e8b9f2-4d18-4ef7-9f59-87348590d5a6/jobs" \ +--header "Authorization: Bearer :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"Price fetcher\", + \"scriptCid\": \"QmYwAPJzv5CZsnAzt8JCRdjD7...", + \"slots\": 3 +}" +
{ + "id": "c7059955-688a-406d-8a61-9be3e931250c", + "status": 201, + "data": { + "id": 79, + "createTime": "2024-09-13T08:58:24.740Z", + "updateTime": null, + "jobUuid": "21a54e84-4daf-4c0e-98ed-fdcc859d1a1a", + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "functionUuid": "cfd85992-8f79-4486-97cf-2406bd722d90", + "scriptCid": "QmYwAPJzv5CZsnAzt8JCRdjD7...", + "slots": 3, + "jobStatus": 1 + } +} +
Set Cloud Function Environment Variables
Set the environment variables for a specific cloud function.
POST /acurast/cloud-functions/:function_uuid/environmentURL Parameters
Field Type Description Required function_uuid string
Unique identifier of the cloud function Yes Body Fields
Field Type Description Required variables array
Array of key-value pairs for environment variables Yes Possible Errors
Code Description 42218016 Missing or invalid variables field 40418005 Cloud function not found curl --location --request POST "https://api.apillon.io/acurast/cloud-functions/d1e8b9f2-4d18-4ef7-9f59-87348590d5a6/environment" \ +--header "Authorization: Bearer :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"variables\": [{ \"key\": \"API_KEY\", \"value\": \"12345\" }] +}" +
{ + "status": 200, + "data": { + "function_uuid": "d1e8b9f2-4d18-4ef7-9f59-87348590d5a6", + "variables": [ + { "key": "API_KEY", "value": "12345" } + ] + } +} +
Delete Job
Delete a specific job using its unique identifier.
DELETE /acurast/jobs/:job_uuidURL Parameters
Field Type Description Required job_uuid string
Unique identifier of the job Yes Possible Errors
Code Description 40418004 Job not found 50018014 Job not yet deployed 50018016 Error deleting job curl --location --request DELETE "https://api.apillon.io/acurast/jobs/e3c86bb2-4190-4bda-9c8a-3852b6d04971" \ +--header "Authorization: Bearer :credentials" +
{ + "status": 200, + "message": "Job successfully deleted" +} +
Embedded Wallet Integration | Apillon Wiki + + + + ++ + + diff --git a/build/13-infrastructure-api.html b/build/13-infrastructure-api.html new file mode 100644 index 00000000..831d3e44 --- /dev/null +++ b/build/13-infrastructure-api.html @@ -0,0 +1,118 @@ + + + + + + + + +Apillon Wiki Embedded Wallet Integration
To get started with integrating embedded wallets into your dapp, follow these steps:
Create an Apillon account: If you don't have an Apillon account or project yet, create one on the Apillon dashboard.
Open the Embedded Wallet page and create a new embedded wallet integration: Go to the Embedded Wallet page on the Apillon developer console and create a new embedded wallet integration.
Integration UUID
is needed for using the SDK.Setup whitelist: Input the domains on which you allow the integration to work on. Leave empty if you allow all website (this is not recommended).
TIP
If you want to learn more about Apillon's Embedded Wallet Service, visit the embedded wallet service wiki page.
Prerequisites
React, Vue
A Vite plugin is required for running and building Vite apps with Embedded Wallet. This plugin enables Node API in the browser (eg. buffer, crypto).
npm install -D vite-plugin-node-polyfills +
// vite.config.ts +import { defineConfig } from "vite"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; + +export default defineConfig({ + plugins: [nodePolyfills() /* ... */], +}); +
Next.js
To use the Embedded wallet UI, your Next app has to be in
app router
mode. When inpages routing
mode, global CSS file imports throw an error. Github Discussion.Nuxt
When using Vite as the build tool, a Vite plugin is required for running and building Nuxt apps with Embedded Wallet. This plugin enables Node API in the browser (eg. buffer, crypto).
WARNING
The Embedded wallet integration includes a style (CSS) file imported through JavaScript. Nuxt fails to resolve this import by default. To avoid errors, the Embedded wallet dependency needs to be added to the build.transpile setting.
npm i -D vite-plugin-node-polyfills +
// nuxt.config.ts +import { nodePolyfills } from "vite-plugin-node-polyfills"; + +export default defineNuxtConfig({ + vite: { + plugins: [nodePolyfills() /* ... */], + }, + build: { + transpile: ["@apillon/wallet-vue"], + }, + /* ... */ +}); +
Installation
npm install @apillon/wallet-react +
npm install @apillon/wallet-vue +
npm install @apillon/wallet-ui +
Installing the wallet UI also installs the core wallet package
@apillon/wallet-sdk
as a dependency.In the usage examples below you will see some imports from this package.
Add wallet widget
Replace the parameters with however you wish to setup your wallet.
import { WalletWidget } from "@apillon/wallet-react"; + +<WalletWidget + clientId={"YOUR INTEGRATION UUID HERE"} + defaultNetworkId={1287} + networks={[ + { + name: "Moonbase Testnet", + id: 1287, + rpcUrl: "https://rpc.testnet.moonbeam.network", + explorerUrl: "https://moonbase.moonscan.io", + }, + /* ... */ + ]} +/> +
import { WalletWidget } from "@apillon/wallet-vue"; + +<WalletWidget + clientId="YOUR INTEGRATION UUID HERE" + :defaultNetworkId="1287" + :networks="[ + { + name: 'Moonbase Testnet', + id: 1287, + rpcUrl: 'https://rpc.testnet.moonbeam.network', + explorerUrl: 'https://moonbase.moonscan.io', + }, + /* ... */ + ]" +/> +
import { EmbeddedWalletUI } from "@apillon/wallet-ui"; + +EmbeddedWalletUI("#wallet", { + clientId: "YOUR INTEGRATION UUID HERE", + defaultNetworkId: 1287, + networks: [ + { + name: "Moonbase Testnet", + id: 1287, + rpcUrl: "https://rpc.testnet.moonbeam.network", + explorerUrl: "https://moonbase.moonscan.io", + }, + /* ... */ + ] +}); +
Parameters
Field Type Required Description clientId string
Yes UUID of the integration that you obtain when creating it on the Apillon embedded wallet dashboard. defaultNetworkId number
No Chain ID set as default when opening wallet. networks Network[]
No Array of network specifications broadcastAfterSign boolean
No Automatically broadcast with SDK after confirming a transaction. disableDefaultActivatorStyle boolean
No Remove styles from "open wallet" button authFormPlaceholder string
No Placeholder displayed in input for username/email Network Object
The Network Object defines the properties required to connect to a blockchain network.
TIP
To find the information for your desired network, visit chainlist.org.
Field Type Description name string
The name of the network id number
The unique Chain ID of the network rpcUrl string
The URL to the network's RPC server explorerUrl string
The URL to the network's block explorer Use wallet
To access wallet signer and wallet information we provide core imports (hooks/composables):
import { useAccount, useContract, useWallet } from "@apillon/wallet-react"; + +export default function Component() { + const { username, address, getBalance } = useAccount(); + const { wallet, signMessage, sendTransaction } = useWallet(); + + const { read, write } = useContract({ + abi: [ + "function claim() public", + "function balanceOf(address) view returns (uint256)", + "function transfer(address to, uint256 amount) public returns (bool)", + ], + address: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8", + chainId: 1287, + }); + + // using wallet core SDK + const getWalletUserExists = (username: string) => { + return wallet.userExists(username); + }; + + // sign a message + const onSignMessage = await (msg: string) => { + await signMessage(msg); + }; + + // contract read + const logContractBalance = async (address: string) => { + console.log(await read("balanceOf", [address])); + }; + + // contract write + const onContractTransfer = async (address: string, amount: string) => { + await write("transfer", [address, amount], "Token transfer"); + }; + + return <></>; +} +
<script lang="ts" setup> +import { useAccount, useContract, useWallet } from "@apillon/wallet-vue"; + +const { info, getBalance } = useAccount(); +const { wallet, signMessage, sendTransaction } = useWallet(); + +const { read, write } = useContract({ + abi: [ + "function claim() public", + "function balanceOf(address) view returns (uint256)", + "function transfer(address to, uint256 amount) public returns (bool)", + ], + address: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8", + chainId: 1287, +}); + +// using wallet core SDK +function getWalletUserExists(username: string) { + return wallet.value.userExists(username); +} + +// sign a message +async function onSignMessage(msg: string) { + await signMessage(msg); +} + +// contract read +async function logContractBalance(address: string) { + console.log(await read("balanceOf", [address])); +} + +// contract write +async function onContractTransfer(address: string, amount: string) { + await write("transfer", [address, amount], "Token transfer"); +} +</script> + +<template> + <div></div> +</template> +
Ethers 5 and 6
To use with ethers library we provide a specialized ethers signer.
import { EmbeddedEthersSigner } from "@apillon/wallet-sdk"; +
You can create a signer like with any other ethers signer as such:
const signer = new EmbeddedEthersSigner(); + +// eg. sign a message +await signer.signMessage("test message"); +
Viem
To use viem we provide a specialized Viem adapter.
import { EmbeddedViemAdapter } from "@apillon/wallet-sdk"; +import { moonbaseAlpha } from "viem/chains"; +
Use can use the adapter to get the user's account and use it with Viem:
const adapter = new EmbeddedViemAdapter(); +const account = adapter.getAccount(); + +const walletClient = createWalletClient({ + chain: moonbaseAlpha, + transport: http(), + account, +}); + +// eg. sign a message +await account.signMessage({ message: "test message" }); + +// eg. send a plain transaction +await walletClient.sendRawTransaction({ + serializedTransaction: await walletClient.signTransaction( + await walletClient.prepareTransactionRequest({ + to: "...", + value: parseUnits("0.01", 18), + }) + ), +}); +
Wagmi
We provide an EIP-1193 provider that can be used with Wagmi or any other integration that supports it.
import { getProvider as getEmbeddedProvider } from "@apillon/wallet-sdk"; + +const wagmiConfig = { + /* ... */ + connectors: [ + new InjectedConnector({ + chains, + options: { + getProvider() { + return getEmbeddedProvider() as any; + }, + }, + }), + ], +}; +
TypeScript
Embedded wallet can be used with plain TypeScript by interacting with the wallet SDK directly.
TIP
Find out more about the SDK in the github repository
<button id="sdk-sign">(SDK) Sign message</button> +<button id="sdk-native-transfer">(SDK) Transfer native balance</button> +<button id="sdk-contract-transfer">(SDK) Contract write (transfer)</button> +
import { getEmbeddedWallet } from "@apillon/wallet-sdk"; + +document.getElementById("sdk-sign")?.addEventListener("click", async () => { + const w = getEmbeddedWallet(); + + if (w) { + await w.signMessage({ + message: "test message", + mustConfirm: true, + }); + } +}); +
import { getEmbeddedWallet } from "@apillon/wallet-sdk"; + +document + .getElementById("sdk-native-transfer") + ?.addEventListener("click", async () => { + const w = getEmbeddedWallet(); + + if (w) { + const result = await w.signPlainTransaction({ + tx: { + to: "...", + value: "10000000", + }, + mustConfirm: true, + }); + + console.log(result); + + if (result) { + console.log( + await w.broadcastTransaction(result.signedTxData, result.chainId) + ); + } + } + }); +
import { getEmbeddedWallet } from "@apillon/wallet-sdk"; + +document + .getElementById("sdk-contract-transfer") + ?.addEventListener("click", async () => { + const w = getEmbeddedWallet(); + + if (w) { + const result = await w.signContractWrite({ + contractAbi: [ + "function claim() public", + "function balanceOf(address) view returns (uint256)", + "function transfer(address to, uint256 amount) public returns (bool)", + ], + contractAddress: "0x67b9DA16d0Adf2dF05F0564c081379479d0448f8", + contractFunctionName: "transfer", + contractFunctionValues: ["...", "10000000"], + chainId: 1287, + mustConfirm: true, + }); + + console.log(result); + + if (result) { + console.log( + await w.broadcastTransaction( + result.signedTxData, + result.chainId, + "JS transfer" + ) + ); + } + } + }); +
Create custom UI
All the functionalities of embedded wallets are contained in base package
@apillon/wallet-sdk
. The SDK exposes all the core methods of the wallet and you can create completely custom UI of the wallet on top of it.TIP
For detailed technical documentation about the embedded wallet SDK, visit the github repository
NPM Packages
- Embedded Wallet SDK (@apillon/wallet-sdk)
- Embedded Wallet UI (@apillon/wallet-ui)
- Embedded Wallet React UI (@apillon/wallet-react)
- Embedded Wallet Vue UI (@apillon/wallet-vue)
Examples
React
Next.js
Vue.js
Nuxt
TypeScript
Infrastructure API | Apillon Wiki + + + + ++ + + diff --git a/build/2-storage-api.html b/build/2-storage-api.html new file mode 100644 index 00000000..783d1688 --- /dev/null +++ b/build/2-storage-api.html @@ -0,0 +1,376 @@ + + + + + + + + +Apillon Wiki Infrastructure API
The Infrastructure API provides an interface for managing essential infrastructure services required to build modern Web3 applications.
RPC Service
Create a RPC API Key
Create a new RPC API key for a project.
POST /rpc/api-keyBody Fields
Field Type Description Required name string
Name of the API key Yes description string
Description of the API key No Possible Errors
Code Description 40300000 Forbidden 40020001 Max RPC API keys limit reached 40405001 Project owner not found 50000001 Internal server error 422001101 RPC API key name is missing curl --location --request POST "https://api.apillon.io/rpc/api-key" \ +--header "Authorization: Bearer :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"RPC API Key\", + \"description\": \"Description of the API key\" +}" +
{ + "status": 201, + "data": { + "id": 4, + "projectUuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "name": "RPC API Key", + "description": "Description of the API key", + "uuid": "60020364-7edc-495a-a0a2-df695bb1cc3f" + } +} +
List RPC API Keys
Retrieve a list of RPC API keys associated with a project.
GET /rpc/api-keyQuery Parameters
All query parameters from listing request
Response Fields
Field Type Description id number
Unique identifier of the RPC API key projectUuid string
UUID of the project the RPC API key belongs to name string
Name of the RPC API key uuid string
Unique identifier of the RPC API key returned by Dwellir description string
Description of the RPC API key createTime DateTime
Creation timestamp updateTime DateTime
Last updated timestamp curl --location --request GET "https://api.apillon.io/rpc/api-key" \ +--header "Authorization: Bearer :credentials" +
{ + "status": 200, + "data": { + "items": [ + { + "id": 4, + "createTime": "2024-09-09T11:15:26.000Z", + "updateTime": "2024-09-10T13:18:31.000Z", + "projectUuid": "cfd85992-8f79-4486-97cf-2406bd722d90", + "name": "RPC API Key", + "description": "Description of the API key", + "uuid": "60020364-7edc-495a-a0a2-df695bb1cc3f" + } + ], + "total": 1, + "page": 1, + "limit": 20 + } +} +
Get a RPC API Key
Retrieve the details of a specific RPC API key by its ID along with the list of RPC endpoints marked as favorite for this API key.
GET /rpc/api-key/:idURL Parameters
Field Type Description Required id number
Unique identifier of the RPC API key Yes Response Fields
Field Type Description id number
Unique identifier of the RPC API key name string
Name of the RPC API key description string
Description of the RPC API key projectUuid string
Unique identifier of the project uuid string
Unique identifier of the RPC API key createTime DateTime
Creation timestamp updateTime DateTime
Last updated timestamp urls array
Array of favorite URLs for the RPC API key URL Fields
Field Type Description id number
Unique identifier of the RPC Endpoint apiKeyId number
Unique identifier of the RPC API key chainName string
Name of the chain the RPC Endpoint belongs to network string
Network of the RPC Endpoint (Usually mainnet, testnet, etc.) httpsUrl string
HTTPS URL of the RPC Endpoint wssUrl string
WSS URL of the RPC Endpoint createTime DateTime
Creation timestamp updateTime DateTime
Last updated timestamp Possible Errors
Code Description 40300000 Forbidden 40420001 RPC API key not found curl --location --request GET "https://api.apillon.io/rpc/api-key/:id" \ +--header "Authorization: Bearer :credentials" +
{ + "id": "60020364-7edc-495a-a0a2-df695bb1cc3f", + "status": 200, + "data": { + "createTime": "2024-09-09T11:15:26.000Z", + "updateTime": "2024-09-10T13:18:31.000Z", + "name": "RPC API Key", + "description": null, + "project_uuid": "d0c34b5e-1fd6-473e-81f8-e89ee479f7aa", + "uuid": "60020364-7edc-495a-a0a2-df695bb1cc3f", + "urls": [ + { + "id": 77, + "chainName": "Ethereum", + "network": "mainnet", + "httpsUrl": "https://mainnet.apillon.io/60020364-7edc-495a-a0a2-df695bb1cc3f", + "wssUrl": "wss://mainnet.apillon.io/60020364-7edc-495a-a0a2-df695bb1cc3f", + "createTime": "2024-09-10T12:55:44.000Z", + "updateTime": "2024-09-12T13:57:26.000Z", + } + ] + } +} +
List RPC Endpoints
Retrieve a list of available RPC endpoints by Dwellir.
GET /rpc/endpointsResponse Fields
Field Type Description id number
Unique identifier of the RPC Endpoint image_url string
URL of the RPC Endpoint chain image name string
Name of the RPC Endpoint chain networkId number
Network ID of the RPC Endpoint networkName string
Network of the RPC Endpoint (Usually Mainnet, Testnet, etc.) nodes array
Array of nodes for the RPC Endpoint type string
Type of the Entity (will be 'network') version string
Version of the RPC Endpoint Node Fields
Field Type Description id number
Unique identifier of the RPC Endpoint Node https string
HTTPS URL of the RPC Endpoint Node wss string
WSS URL of the RPC Endpoint Node type string
Type of the Entity (will be 'node') node_type string
Type of the RPC Endpoint Node version string
Version of the RPC Endpoint Node curl --location --request GET "https://api.apillon.io/rpc/endpoints" \ +--header "Authorization: Bearer :credentials" +
{ + "status": 200, + "data": [{ + "id": 1, + "image_url": "https://apillon.io/images/chains/ethereum.svg", + "name": "Ethereum", + "networkId": 31, + "networkName": "Mainnet", + "nodes": [{ + "id": 1, + "https": "https://mainnet.apillon.io/<key>", + "wss": "wss://mainnet.apillon.io/<key>", + "type": "node", + "node_type": "Archive", + "version": "1.0" + }], + "type": "network", + "version": "1.0" + }] +} +
Storage API | Apillon Wiki + + + + ++ + + diff --git a/build/3-hosting-api.html b/build/3-hosting-api.html new file mode 100644 index 00000000..8ed161d7 --- /dev/null +++ b/build/3-hosting-api.html @@ -0,0 +1,295 @@ + + + + + + + + +Apillon Wiki Storage API
In all cURL examples, parameters with a colon as a prefix should be replaced with real values.
File upload process through Apillon Web3 Storage API
- Request signed URL(s) for upload.
- File is uploaded to Apillon central server.
- File is transferred to IPFS and available through the Apillon gateway.
- File is replicated to different IPFS nodes globally via Crust Network.
List buckets
API to list all buckets in project. Items are paginated and can be filtered and ordered through query parameters. This is a listing request.
GET /storage/bucketsQuery parameters
All query parameters from listing request plus:
Name Description Required bucketType Type of bucket: 1
(storage bucket),2
(website bucket) and3
(nft bucket).false Response fields (bucket)
Each item is an instance of the bucket model with the below properties:
Field Type Description createTime DateTime
Item create time updateTime DateTime
Item last update time bucketUuid string
Bucket unique identifier bucketType integer
Item type with possible values 1
(storage bucket),2
(website bucket) and3
(nft bucket)name string
Bucket name description string
Bucket description size integer
Size of bucket in bytes curl --location --request GET "https://api.apillon.io/storage/buckets" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets?search=My bucket" \ +--header "Authorization: Basic :credentials" +
{ + "id": "75095bf9-e976-45c8-8a9d-e013ca3b203a", + "status": 200, + "data": { + "items": [ + ... + { + "createTime": "2022-12-06T12:03:32.000Z", + "updateTime": "2023-10-09T11:42:23.000Z", + "bucketUuid": "cee9f151-a371-495b-acd2-4362fbb87780", + "bucketType": 1, + "name": "Storage bucket", + "description": "", + "size": 3215839730 + } + ... + ], + "total": 10 + } +} +
Create new bucket
API for creating a new storage bucket. NFT and website buckets are automatically generated when a new website or NFT collection is initialized.
POST /storage/bucketsBody fields
Name Type Description Required name string
Bucket name. true description string
Bucket description. false Possible errors
Code Description 42200003 Request body is missing a name
field.Response
A response is an instance of bucket, described above.
curl --location --request POST "https://api.apillon.io/storage/buckets" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ \"name\": \"My bucket\" }" +
{ + "id": "e50c8276-fd8d-47c4-b42a-bf19645a204b", + "status": 201, + "data": { + "createTime": "2023-10-12T11:49:49.551Z", + "updateTime": "2023-10-12T11:49:49.551Z", + "bucketUuid": "8218080f-1321-4687-9a89-200b06afb930", + "bucketType": 1, + "name": "My bucket", + "description": null, + "size": 0 + } +} +
Upload to bucket
API that creates file upload requests and returns URLs for file upload along with
sessionUuid
.POST /storage/buckets/:bucketUuid/uploadURL parameters
Name Description Required bucketUuid Unique key of storage bucket. Key is displayed on developer dashboard. true Body fields
Name Type Description Required files array
Array of files metadata. Maximum 200 items. true sessionUuid string
Session unique key, which must be specified to add more uploads to existing session. false Each metadata object in the
files
array contains the properties below.
Name Type Description Required fileName string
Full name (name and extension) of file to be uploaded true contentType string
File MIME type false path string
Virtual file path. Empty for root. It must not contain fileName
.
Thepath
field can be used to place file in virtual directories inside a bucket. If directories do not yet exist, they will be automatically generated.
For example, animages/icons
path creates animages
directory in a bucket and anicons
directory inside it. A file will then be created in theicons
directory.false Possible errors
Code Description 40406002 Bucket does not exist. 40406009 Bucket is marked for deletion. It is no longer possible to upload files to it. 40006020 HTML files cannot be uploaded to storage bucket in freemium subscription plan. 42200040 Request body is missing a files
field.42200150 files
has invalid length. It should be between 1 and 20042200008 Request body file object is missing a fileName
field.50006003 Internal error - Apillon was unable to generate upload URL. Response
Name Type Description sessionUuid string
Session unique key, which is later used to end upload and transfer files to bucket files array
Array of files metadata. Files in the request body are returned in response
data.files
property. Each file is equipped withurl
andfileUuid
. All properties are displayed below.
Field Type Description url string
URL for file upload. Signed URL is unique for each file and is valid only for a limited time (1 min), so you should start with file upload as soon as possible.
Request should usePUT
method andbinary
body.
Binary data should be sent in body as-is, but with the appropriate Content-Type header (e.g., text/plain).fileUuid string
File unique identifier used to query file status, etc. fileName string
Full name (name and extension) of file to be uploaded contentType string
File MIME type path string
File path on the storage bucket. curl --location --request POST "https://api.apillon.io/storage/buckets/:bucketUuid/upload" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"files\": [ + { + \"fileName\": \"My test file\", + \"contentType\": \"text/html\" + } + ] + +}" +
{ + "id": "cbdc4930-2bbd-4b20-84fa-15daa4429952", + "status": 201, + "data": { + "sessionUuid": "3b6113bc-f265-4662-8cc5-ea86f06cc74b", + "files": [ + { + "path": null, + "fileName": "My test file", + "contentType": "text/html", + "url": "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/STORAGE_sessions/73/3b6113bc-f265-4662-8cc5-ea86f06cc74b/My%20test%20file?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T114524Z&X-Amz-Expires=900&X-Amz-Signature=499367f6c6bff5be50686724475ac2fa6307b77b94fd1a25584c092fe74b0a58&X-Amz-SignedHeaders=host&x-id=PutObject", + "fileUuid": "4ef1177b-f7c9-4434-be56-a559cec0cc18" + } + ] + } +} +
Example for uploading to signed URL:
curl --location --request PUT "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/STORAGE_sessions/73/3b6113bc-f265-4662-8cc5-ea86f06cc74b/My%20test%20file?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T114524Z&X-Amz-Expires=900&X-Amz-Signature=499367f6c6bff5be50686724475ac2fa6307b77b94fd1a25584c092fe74b0a58&X-Amz-SignedHeaders=host&x-id=PutObject" \ +--data-binary "My test content" +
curl --location --request PUT "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/STORAGE_sessions/73/3b6113bc-f265-4662-8cc5-ea86f06cc74b/My%20test%20file?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T114524Z&X-Amz-Expires=900&X-Amz-Signature=499367f6c6bff5be50686724475ac2fa6307b77b94fd1a25584c092fe74b0a58&X-Amz-SignedHeaders=host&x-id=PutObject" \ +--header "Content-Type: text/plain" \ +--data-binary ":full path to file" +
End upload session
Once files are uploaded to the cloud server via the received URL, trigger file sync to IPFS and CRUST.
Note: Files in session can be wrapped to CID on IPFS via the
wrapWithDirectory
body field. This means that the directory gets its own CID and its content cannot be modified afterwards. The directory path is mandatory when thewrapWithDirectory
option is set totrue
. Read more about this option in the IPFS docsPOST /storage/buckets/:bucketUuid/upload/:sessionUuid/endURL parameters
Name Description Required bucketUuid Unique key of bucket. Key is displayed in developer dashboard. true sessionUuid Session uuid, recieved in upload to bucket true Body fields
Name Type Description Required wrapWithDirectory boolean
Wrap uploaded files to IPFS directory false directoryPath string
Path to wrapped directory inside bucket false Possible errors
Code Description 40406004 Session does not exist 40006001 Files in this session were already transferred Response
API responds with the status
200 OK
if operation is successfully executed.curl --location --request POST "https://api.apillon.io/storage/buckets/:bucketUuid/upload/:sessionUuid/end" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +
{ + "id": "b64b1c07-1a8a-4b05-9e3b-3c6a519d6ff7", + "status": 200, + "data": true +} +
List bucket content
Lists bucket directories and files in a folder structure. Endpoint lists files and directories in a single directory; if
directoryUuid
is not present, endpoint lists items in the bucket root directory. More about listing requests can be found hereNote: This endpoint returns files from ended sessions. I.e. files with fileStatus 2, 3 or 4.
GET /storage/buckets/:bucketUuid/contentURL parameters
Name Description Required bucketUuid Unique key of bucket. Key is displayed on developer dashboard. true Query parameters
All query parameters from listing request plus:
Name Description Required directoryUuid Gets items inside a specific directory. false markedForDeletion Include deleted buckets false Possible errors
Code Description 40406002 Bucket does not exist. Response fields
Properties of each item:
Field Type Description uuid string
Item UUID property type integer
Item type with possible values 1
(directory) and2
(file)name string
Item (directory or file) name CID string
File content identifier - label used to point to content in IPFS. createTime DateTime
Item create time updateTime DateTime
Item last update time contentType string
Item content type (MIME type). size integer
Item size in bytes directoryUuid string
Uuid of directory where the file directory is located link string
Link on IPFS gateway. fileStatus number
Current status of file curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/content" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/content?orderBy=name&desc=false&limit=5&page=1" \ +--header "Authorization: Basic :credentials" +
{ + "id": "c8c50b3b-91ff-42c7-b0af-f866ce23f18a", + "status": 200, + "data": { + "items": [ + ... + { + "uuid": "d61753fd-26ba-45cb-9277-89e96d6cfd11", + "type": 1, + "name": "Folder 1", + "CID": null, + "createTime": "2023-10-12T12:20:54.000Z", + "updateTime": "2023-10-12T12:20:54.000Z", + "contentType": null, + "size": null, + "directoryUuid": null, + "link": null, + "fileStatus": null + }, + { + "uuid": "63ace39b-ec7c-4889-8d94-83a2ad7fb154", + "type": 2, + "name": "My file.txt", + "CID": "QmaufbAR2dX62TSiYYJUS5sV9KNFZLnxgP4ZMkKFoJhSAM", + "createTime": "2023-10-12T12:17:19.000Z", + "updateTime": "2023-10-12T12:17:42.000Z", + "contentType": "", + "size": 6, + "directoryUuid": null, + "link": "https://ipfs-dev.apillon.io/ipfs/QmaufbAR2dX62TSiYYJUS5sV9KNFZLnxgP4ZMkKFoJhSAM", + "fileStatus": 3 + } + ... + ], + "total": 10 + } +} +
List files
Lists files inside a bucket. This endpoint returns all files in a flat structure and each file has a
path
property. More about listing requests can be found hereNote: This endpoint returns files from ended sessions. I.e. files with fileStatus 2, 3 or 4.
GET /storage/buckets/:bucketUuid/filesURL parameters
Name Description Required bucketUuid Unique key of bucket. Key is displayed on developer dashboard. true Possible errors
Code Description 40406002 Bucket does not exist. Response fields
Properties of each item:
Field Type Description createTime DateTime
File create time updateTime DateTime
File last update time fileUuid string
File UUID property CID string
File content identifier - label used to point to content in IPFS. name string
File name contentType string
File content type. Value is taken from file upload request path integer
Full path to file size integer
File size in bytes fileStatus number
File statuses are described in below table link string
Link on IPFS gateway. curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/files" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/files?search=Hello.txt" \ +--header "Authorization: Basic :credentials" +
{ + "id": "c8c50b3b-91ff-42c7-b0af-f866ce23f18a", + "status": 200, + "data": { + "items": [ + ... + { + "createTime": "2023-10-12T12:20:54.000Z", + "updateTime": "2023-10-13T06:08:00.000Z", + "fileUuid": "120afe0e-b146-45a5-82e0-52d2125df294", + "CID": "QmXKvPVY6jJ7e4oL3QcYjKFw6Bg7EKzzJAXCgXYjuCSyq5", + "name": "Hello.txt", + "contentType": "", + "path": "Folder 1/", + "size": 11, + "fileStatus": 3, + "link": "https://ipfs-dev.apillon.io/ipfs/QmXKvPVY6jJ7e4oL3QcYjKFw6Bg7EKzzJAXCgXYjuCSyq5" + }, + { + "createTime": "2023-10-12T12:17:19.000Z", + "updateTime": "2023-10-12T12:17:42.000Z", + "fileUuid": "63ace39b-ec7c-4889-8d94-83a2ad7fb154", + "CID": "QmaufbAR2dX62TSiYYJUS5sV9KNFZLnxgP4ZMkKFoJhSAM", + "name": "My file.txt", + "contentType": "", + "path": null, + "size": 6, + "fileStatus": 3, + "link": "https://ipfs-dev.apillon.io/ipfs/QmaufbAR2dX62TSiYYJUS5sV9KNFZLnxgP4ZMkKFoJhSAM" + } + ... + ], + "total": 10 + } +} +
Get file details
Gets details of a specific file inside a bucket.
GET /storage/buckets/:bucketUuid/files/:fileUuidURL parameters
Name Description required bucketUuid Unique key of a bucket. Key is displayed on developer dashboard. true fileUuid File UUID or CID. true Possible errors
Code Description 40406005 File does not exist. Response fields
Field Type Description createTime DateTime
File create time updateTime DateTime
File last update time fileUuid string
File UUID property CID string
File content identifier - label used to point to content in IPFS. name string
File name contentType string
File content type. Value is taken from file upload request path integer
Full path to file size integer
File size in bytes fileStatus number
File statuses are described in below table directoryUuid string
Uuid of directory where the file is located link string
Link on IPFS gateway. File statuses
Number Description 1 Request for upload to Apillon storage was generated. 2 File is uploaded to Apillon central server. 3 File is transferred to the IPFS node. 4 File is replicated to different IPFS nodes through Crust Network. curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/files/:fileUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "1beec975-9836-48b2-a284-591ae01f7a58", + "status": 200, + "data": { + "createTime": "2023-10-12T12:20:54.000Z", + "updateTime": "2023-10-12T12:21:17.000Z", + "fileUuid": "120afe0e-b146-45a5-82e0-52d2125df294", + "CID": "bafybeiefrfkhkevhdvacfjds7gw7mh2wlnuo66aeyffrik7wao5tlvfy3q", + "name": "Hello.txt", + "contentType": "", + "path": "Folder 1/", + "size": 11, + "fileStatus": 3, + "link": "https://ipfs-dev.apillon.io/ipfs/QmXKvPVY6jJ7e4oL3QcYjKFw6Bg7EKzzJAXCgXYjuCSyq5", + "directoryUuid": "d61753fd-26ba-45cb-9277-89e96d6cfd11" + } +} +
Delete file
Marks a file inside a bucket for deletion. The file will be completely deleted from the Apillon system and Apillon IPFS node after three (3) months. If a file is marked for deletion, it will not be renewed on Crust Network.
DELETE /storage/buckets/:bucketUuid/files/:fileUuidURL parameters
Name Description required bucketUuid Unique key of bucket. Key is displayed on developer dashboard. true fileUuid File unique identifier. true Possible errors
Code Description 40406005 File does not exist. 40006009 File is already marked for deletion. Response fields
The response of the delete function is a boolean value, depends on whether the deletion was successful.
curl --location --request DELETE "https://api.apillon.io/storage/buckets/:bucketUuid/files/:fileUuid" \ +--header "Authorization: Basic :credentials" \ +--data-raw "" +
{ + "id": "bc92ff8d-05f2-4380-bb13-75a1b6b7f388", + "status": 200, + "data": true +} +
Delete directory
Deletes a directory from the storage bucket.
DELETE storage/buckets/:bucketUuid/directories/:directoryUuidURL parameters
Name Description required bucketUuid Unique key of bucket. Key is displayed on developer dashboard. true directoryUuid Directory unique identifier. true Possible errors
Code Description 40406003 Directory does not exist. 40006007 Directory is already marked for deletion. Response fields
The response of the delete function is a boolean value, depends on whether the deletion was successful.
curl --location --request DELETE "https://api.apillon.io/storage/buckets/:bucketUuid/directories/:directoryUuid" \ +--header "Authorization: Basic :credentials" \ +--data-raw "" +
{ + "id": "bc92ff8d-05f2-4380-bb13-75a1b6b7f388", + "status": 200, + "data": true +} +
Get storage info
Gets overall storage info for a project.
Note: Available resources can be increased with a subscription to paid plans.
GET /storage/infoResponse fields
Field Type Description availableStorage integer
Available storage space in bytes usedStorage integer
Used storage in bytes. When usedStorage
reaches available storage, upload to buckets will be blocked (error 40006003)availableBandwidth integer
Monthly available bandwidth (upload and download) usedBandwidth integer
Bandwidth used in current month. If usedBandwidth
reaches available, requests to the IPFS gateway will be blockedcurl --location --request GET "https://api.apillon.io/storage/info" \ +--header "Authorization: Basic :credentials" +
{ + "id": "48e58f84-403a-43e4-bd81-fedeca195610", + "status": 200, + "data": { + "availableStorage": 3221225472, + "usedStorage": 1221225466, + "availableBandwidth": 3221225472, + "usedBandwidth": 56500 + } +} +
Get IPFS cluster info
Gets basic data of an IPFS cluster used by the project. IPFS clusters contain multiple IPFS nodes but expose a single gateway for accessing content via CID or IPNS. Apillon clusters (gateways) are not publicly accessible
Note: Each project has its own secret for the generation of the tokens to access content on the IPFS gateway.
GET /storage/ipfs-cluster-infoResponse fields
Field Type Description secret string
Secret for this project, which can be used to generate tokens to access content of IPFS gateway projectUuid string
Project unique identifier ipfsGateway string
Gateway that can used to access content via CIDs. ipnsGateway string
Gateway that can be used to access content via IPNS name. curl --location --request GET "https://api.apillon.io/storage/ipfs-cluster-info" \ +--header "Authorization: Basic :credentials" +
{ + "id": "0d7979c0-a00b-4502-9cb9-22228b24f71d", + "status": 200, + "data": { + "secret": "*********", + "project_uuid": "73f46f28-0d7c-43c4-9420-d4225b942ed1", + "ipfsGateway": "https://<CIDv1>.staging.web3approved.com", + "ipnsGateway": "https://<IPNS>.staging.web3approved.com" + } +} +
Get or generate link for IPFS
Apillon IPFS gateways are private and can only be accessible with a token. A token for specific address (CID) can be acquired via Apillon API request or can be generated with by using the
secret
andproject_uuid
properties from above requestGET /storage/link-on-ipfs/:cidURL parameters
Name Description required cid Ipfs content identifier. API will automatically detect the type (CIDv0, CIDv1 or IPNS) true Response fields
Field Type Description link string
Link where requested content can be accessed. How to generate token programmatically
Apillon IPFS gateways accept JWT token, which can be created using jsonwebtoken package.
The JWT sign method expects three (3) parameters:
- JWT payload:
{ + "cid": "CID or IPNS address", + "project_uuid": "Change with projectUuid value" +} +
- Secret: Use
secret
property from IPFS cluster info- Subject:
IPFS-token
For each CID, a new token should be generated. Append the generated JWT to URL request as
token
query parameter.curl --location --request GET "https://api.apillon.io/storage/link-on-ipfs/:cid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "3a3ea750-3f3a-41e3-b5cb-a5543c2b2283", + "status": 200, + "data": { + "link": "https://bafybeigjhyc2tpvqfqsuvf3byo4e4a4v6spi6jk4qqvvtlpca6rsaf2cqi.ipfs.web3approved.com/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOiJiYWZ5YmVpZ2poeWMydHB2cWZxc3V2ZjNieW80ZTRhNHY2c3BpNmprNHFxdnZ0bHBjYTZyc2FmMmNxaSIsInByb2plY3RfdXVpZCI6IjE0NmM5ZWU5LTEwMDgtNDdiNS05ZTJjLTQxZmIyN2ExZjY1NSIsImlhdCI6MTcwMjU1NTA2Mywic3ViIjoiSVBGUy10b2tlbiJ9.07tHk5jAuAbcRaDxiiA9zHNWD71pxAcQX9v7LbhZ0-E" + } +} +
IPNS
List IPNS names
API to list all IPNS names in a bucket. Items are paginated and can be filtered and ordered through query parameters. This is a listing request.
GET /storage/buckets/:bucketUuid/ipnsURL parameters
Name Description Required bucketUuid Unique key of storage bucket, from which IPNS will be listed true Query parameters
All query parameters from listing request plus:
Name Description Required ipnsName List IPNS names with specific name false ipnsValue List IPNS names that point to this value (CID) false Response fields (ipns)
Each item is an instance of the IPNF model, with the following properties:
Field Type Description createTime DateTime
Item create time updateTime DateTime
Item last update time ipnsUuid string
IPNS unique identifier name string
Informational IPNS name, which is set by a user to easily organize the IPNS records description string
IPNS description ipnsName string
IPNS name used to access IPNS content on IPFs gateway ipnsValue string
IPFS value (CID), to which this ipns points link string
IPNS link to Apillon IPFS gateway, allowing to access content to which this IPNS points curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/ipns" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/ipns?ipnsName=k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk" \ +--header "Authorization: Basic :credentials" +
{ + "id": "f0764846-41f4-4352-87b4-85f9c94a8af4", + "status": 200, + "data": { + "items": [ + { + "createTime": "2023-11-24T06:22:16.000Z", + "updateTime": "2023-11-24T06:22:16.000Z", + "ipnsUuid": "9c0a0020-5d87-4112-a0ce-4033c037e31a", + "name": "IPNS from Apillon API", + "description": null, + "ipnsName": null, + "ipnsValue": null, + "link": null + }, + { + "createTime": "2023-11-24T13:43:43.000Z", + "updateTime": "2023-11-24T13:43:45.000Z", + "ipnsUuid": "0b3c4ca8-3054-42a2-b5d4-1665646bbaa0", + "name": "Example ipns", + "description": null, + "ipnsName": "k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk", + "ipnsValue": "/ipfs/Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L", + "link": "https://ipfs-eu1.apillon.io/ipns/k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOiJrMms0cjhscXQwN2xzOXV5ejE0MW9mcWNsOTlrNGI4ZTYzbnMxZmg1MmliMWJ3aDA5ejBrNnZqayIsInByb2plY3RfdXVpZCI6ImQ3ZTlkZjQwLTcxNDgtNGYwZC1hMTEyLTM5YmYzMjY5NWFlNCIsImlhdCI6MTcwMDk4MTg3Niwic3ViIjoiSVBGUy10b2tlbiJ9.LMRhNNtsYF-0NlIcXFL1O85I58bsC_zHlbAepPz0hVM" + } + ], + "total": 2 + } +} +
Create new IPNS
API for creating a new IPNS record.
Note: IPNS becomes accessible on the IPFS gateway when content with CID is published to it. To access IPNS content on the IPFS gateway, use
ipnsName
.POST /storage/buckets/:bucketUuid/ipnsURL parameters
Name Description Required bucketUuid Unique key of storage bucket where IPNS will be created. Key is displayed on developer dashboard. true Body fields
Name Type Description Required name string
IPNS name. true description string
IPNS description. false cid string
CID to which the IPNS name will point. If this property is specified, API executes IPNS publish, which sets the ipnsName
andipnsValue
properties.false Possible errors
Code Description 42200026 Request body is missing a name
field.40406002 Bucket not found Response
Response is an instance of IPNS described above.
curl --location --request POST "https://api.apillon.io/storage/buckets/:bucketUuid/ipns" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"Example IPNS\", + \"cid\": \"Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L\" +}" +
{ + "id": "0f436448-7c05-4f29-ae49-c57f55e36705", + "status": 201, + "data": { + "createTime": "2023-11-24T12:14:31.127Z", + "updateTime": null, + "ipnsUuid": "0b3c4ca8-3054-42a2-b5d4-1665646bbaa0", + "projectUuid": "d7e9df40-7148-4f0d-a112-39bf32695ae4", + "bucketId": 11, + "name": "Example ipns", + "description": null, + "ipnsName": "k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk", + "ipnsValue": "/ipfs/Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L", + "link": "https://ipfs-eu1.apillon.io/ipns/k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOiJrMms0cjhscXQwN2xzOXV5ejE0MW9mcWNsOTlrNGI4ZTYzbnMxZmg1MmliMWJ3aDA5ejBrNnZqayIsInByb2plY3RfdXVpZCI6ImQ3ZTlkZjQwLTcxNDgtNGYwZC1hMTEyLTM5YmYzMjY5NWFlNCIsImlhdCI6MTcwMDk4MTg3Niwic3ViIjoiSVBGUy10b2tlbiJ9.LMRhNNtsYF-0NlIcXFL1O85I58bsC_zHlbAepPz0hVM" + } +} +
Get IPNS
API to get specific IPNS name by its UUID.
GET /storage/buckets/:bucketUuid/ipns/:ipnsUuidURL parameters
Name Description Required bucketUuid Unique key of storage bucket true ipnsUuid Unique key of IPNS name true Possible errors
Code Description 40406012 IPNS not found Response fields (IPNS)
Response is an instance of IPNS described above.
curl --location --request GET "https://api.apillon.io/storage/buckets/:bucketUuid/ipns/:ipnsUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "0f436448-7c05-4f29-ae49-c57f55e36705", + "status": 201, + "data": { + "createTime": "2023-11-24T12:14:31.127Z", + "updateTime": null, + "ipnsUuid": "0b3c4ca8-3054-42a2-b5d4-1665646bbaa0", + "projectUuid": "d7e9df40-7148-4f0d-a112-39bf32695ae4", + "bucketId": 11, + "name": "Example IPNS", + "description": null, + "ipnsName": "k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk", + "ipnsValue": "/ipfs/Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L", + "link": "https://ipfs-eu1.apillon.io/ipns/k2k4r8lqt07ls9uyz141ofqcl99k4b8e63ns1fh52ib1bwh09z0k6vjk/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOiJrMms0cjhscXQwN2xzOXV5ejE0MW9mcWNsOTlrNGI4ZTYzbnMxZmg1MmliMWJ3aDA5ejBrNnZqayIsInByb2plY3RfdXVpZCI6ImQ3ZTlkZjQwLTcxNDgtNGYwZC1hMTEyLTM5YmYzMjY5NWFlNCIsImlhdCI6MTcwMDk4MTg3Niwic3ViIjoiSVBGUy10b2tlbiJ9.LMRhNNtsYF-0NlIcXFL1O85I58bsC_zHlbAepPz0hVM" + } +} +
Publish IPNS
API for publishing IPNS on IPFS and linking it to CID.
Note: Multiple IPNS records can point to the same CID.
POST /storage/buckets/:bucketUuid/ipns/:ipnsUuid/publishURL parameters
Name Description Required bucketUuid Unique key of storage bucket. true ipnsUuid Unique key of IPNS record that will be published true Body fields
Name Type Description Required cid string
CID to which the IPNS name will point. true Possible errors
Code Description 42200030 Body is missing CID
property40406012 IPNS not found Response
The response is an instance of IPNS that was published. Properties are described above.
curl --location --request POST "https://api.apillon.io/storage/buckets/:bucketUuid/ipns/:ipnsUuid/publish" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"cid\": \"Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L\" +}" +
{ + "id": "14bfe999-ffc4-477b-bf10-4fe9ba9ab90a", + "status": 200, + "data": { + "createTime": "2023-11-26T07:13:32.000Z", + "updateTime": "2023-11-26T07:13:32.000Z", + "ipnsUuid": "df5c47b4-e00b-4163-877e-7c78042e7666", + "name": "My 3 IPNS", + "description": null, + "ipnsName": "k2k4r8jofss9us61kwlmq8flgdhj3a1tn5ikcc6m494kf2edifi2oh4z", + "ipnsValue": "/ipfs/Qma6zTc8ctd65U2SARH7Qkssm6KrwsqJnX1PtrSqhXcM9L", + "link": "https://ipfs-eu1.apillon.io/ipns/k2k4r8jofss9us61kwlmq8flgdhj3a1tn5ikcc6m494kf2edifi2oh4z/?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaWQiOiJrMms0cjhqb2Zzczl1czYxa3dsbXE4ZmxnZGhqM2ExdG41aWtjYzZtNDk0a2YyZWRpZmkyb2g0eiIsInByb2plY3RfdXVpZCI6ImQ3ZTlkZjQwLTcxNDgtNGYwZC1hMTEyLTM5YmYzMjY5NWFlNCIsImlhdCI6MTcwMTA3NTk3OCwic3ViIjoiSVBGUy10b2tlbiJ9.xJ0ZdUb0XqH9oe7AvG0yUnCnydKNoGlNnNsIYZEwAc0" + } +} +
Delete IPNS
API to delete IPNS record.
DELETE /storage/buckets/:bucketUuid/ipns/:ipnsUuidURL parameters
Name Description Required bucketUuid Unique key of storage bucket true ipnsUuid Unique key of IPNS record true Possible errors
Code Description 40406012 IPNS not found Response fields (IPNS)
The response is deleted IPNS record, an instance of IPNS described above.
curl --location --request DELETE "https://api.apillon.io/storage/buckets/:bucketUuid/ipns/:ipnsUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "302f036b-5ca5-488c-bbd5-a7cdd7674898", + "status": 200, + "data": { + "createTime": "2023-11-24T06:22:16.000Z", + "updateTime": "2023-11-24T06:22:16.000Z", + "ipnsUuid": "9c0a0020-5d87-4112-a0ce-4033c037e31a", + "name": "IPNS from Apillon API", + "description": null, + "ipnsName": null, + "ipnsValue": null + } +} +
Hosting API | Apillon Wiki + + + + ++ + + diff --git a/build/4-nfts-api.html b/build/4-nfts-api.html new file mode 100644 index 00000000..f418ff40 --- /dev/null +++ b/build/4-nfts-api.html @@ -0,0 +1,362 @@ + + + + + + + + +Apillon Wiki Hosting API
Hosting API provides endpoints for listing and deployment of websites. API can be used to implement CI/CD. To deploy page through Apillon API, follow below steps:
- Upload website files to Apillon cloud server.
- Request URLs for files upload
- Upload files to cloud server
- Trigger transfer into website
- Execute deployment to staging or production environment.
Note: You should first create a website on the Apillon dashboard.
In all cURL examples, parameters with a colon as a prefix should be replaced with real values.
List websites
API to list all websites in project. Items are paginated and can be filtered and ordered through query parameters as described here .
GET /hosting/websitesResponse fields (website)
Each item is an instance of website class, with below properties:
Field Type Description websiteUuid string
Website unique identifier name string
Website name description string
Website description domain string
Website domain. This property needs to be specified, so that Apillon is able to create SSL Certificates for IPFS gateway bucketUuid string
Uuid of bucket for file upload cidStaging string
Staging ipfs CID. Set if deployment to staging environment exists cidProduction string
Production ipfs CID. Set if deployment to production environment exists ipnsProduction string
Production IPNS. createTime DateTime
Item create time updateTime DateTime
Item last update time curl --location --request GET "https://api.apillon.io/hosting/websites" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets?search=My website" \ +--header "Authorization: Basic :credentials" +
{ + "id": "75095bf9-e976-45c8-8a9d-e013ca3b203a", + "status": 200, + "data": { + "items": [ + ... + { + "createTime": "2023-10-11T10:51:13.000Z", + "updateTime": "2023-10-11T10:51:13.000Z", + "websiteUuid": "5fc7df41-f311-410d-8cb3-998198999a48", + "name": "My website", + "description": null, + "domain": null, + "bucketUuid": "1938a45c-3a54-43ee-af08-3abe90265f46", + "ipnsProduction": null + } + ... + ], + "total": 10 + } +} +
Get website
Endpoint to get website. Endpoint returns basic website data, along with IPNS links.
GET /hosting/websites/:websiteUuidURL parameters
Name Description Required websiteUuid Website UUID, visible in developer console website overview true Possible errors
Code Description 40406010 Website does not exists Response fields
Response is an instance of website class, described above and additional properties described below. Those properties will receive value after deploy.
Field Type Description w3StagingLink string
Link to staging version of the website w3ProductionLink string
Link to production version of the website lastDeploymentUuid string
Website last deployment (to any environment) unique identifier lastDeploymentStatus string
Status of last deployment curl --location --request GET "https://api.apillon.io/hosting/websites/:websiteUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "a299ed8f-b682-4411-9fd9-eb3a3da31887", + "status": 200, + "data": { + "createTime": "2023-10-13T07:41:30.000Z", + "updateTime": "2023-10-13T07:41:30.000Z", + "websiteUuid": "1a15d258-bbc9-459f-b83f-97710da6b983", + "name": "My awesome website", + "description": "My unstoppable website", + "domain": "example-domain.io", + "bucketUuid": "cd299839-dae6-47d0-8fdc-40143163e156", + "cidStaging": null, + "cidProduction": null, + "ipnsProduction": null, + "w3StagingLink": null, + "w3ProductionLink": null, + "lastDeploymentUuid": null, + "lastDeploymentStatus": null + } +} +
Get URLs for files upload
API that creates file upload requests and returns URLs for files upload.
POST /hosting/websites/:websiteUuid/uploadURL parameters
Name Description Required websiteUuid Unique key of website bucket. Key is displayed on developer dashboard. true Body fields
Name Type Description Required files array
Array of files metadata. true sessionUuid string
Session unique key. If not specified, API generates new one. It is possible to use same sessionUuid in multiple requests. false Each file metadata object in
files
array, contain below properties.
Name Type Description Required fileName string
Full name (name and extension) of file to be uploaded true contentType string
File MIME type false path string
File path inside website. Empty for root. Must not contain fileName
.false Possible errors
Code Description 40406010 Website does not exists 42200040 Request body is missing a files
field.42200008 Request body file object is missing a fileName
field.50006003 Internal error - Apillon was unable to generate upload URL. Response
Name Type Description sessionUuid string
Session unique key, which is later used to end upload and transfer files to website. files array
Array of files metadata. Files in request body are returned in response
data.files
property. Each file is equipped withurl
andfileUuid
. All properties are displayed below.
Field Type Description url string
URL for file upload. Signed URL is unique for each file and is valid only for a limited time (1 min), so you should start with file upload as soon as possible.
Request should usePUT
method andbinary
body.
Binary data should be sent in body as-is, but with the appropriate Content-Type header (e.g., text/plain).fileUuid string
File unique identifier used to query file status, etc. fileName string
Full name (name and extension) of file to be uploaded contentType string
File MIME type path string
File path on the hosting bucket. curl --location --request POST "https://api.apillon.io/hosting/websites/:websiteUuid/upload" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"files\": [ + { + \"fileName\": \"index.html\", + \"contentType\": \"text/html\" + }, + { + \"fileName\": \"styles.css\", + \"contentType\": \"text/css\", + \"path\": \"assets/\" + } + + ] + +}" +
{ + "id": "7dd011ec-20e2-4c28-b585-da6c6f7fce8d", + "status": 201, + "data": { + "sessionUuid": "29ef6ca2-b171-440c-b934-db8aa88c3424", + "files": [ + { + "path": null, + "fileName": "index.html", + "contentType": "text/html", + "url": "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/HOSTING_sessions/70/29ef6ca2-b171-440c-b934-db8aa88c3424/index.html?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T105030Z&X-Amz-Expires=900&X-Amz-Signature=187035d2307bc089101eff3abbdd7baa3e8691b4d5d3bafa5aebb87e589e8c0c&X-Amz-SignedHeaders=host&x-id=PutObject", + "fileUuid": "e17436a1-5292-4380-ad91-eaac02a862b1" + }, + { + "path": "assets/", + "fileName": "styles.css", + "contentType": "text/css", + "url": "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/HOSTING_sessions/70/29ef6ca2-b171-440c-b934-db8aa88c3424/assets/styles.css?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T105030Z&X-Amz-Expires=900&X-Amz-Signature=f91b03a951fe3f99291802306be3e79812ca64e39effbb7dea1c19bb7cd1e42b&X-Amz-SignedHeaders=host&x-id=PutObject", + "fileUuid": "358c2942-4ced-421e-9a6f-edbf94c55dff" + } + ] + } +} +
Example for uploading to signed URL:
curl --location --request PUT "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/HOSTING_sessions/70/29ef6ca2-b171-440c-b934-db8aa88c3424/index.html?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T105030Z&X-Amz-Expires=900&X-Amz-Signature=187035d2307bc089101eff3abbdd7baa3e8691b4d5d3bafa5aebb87e589e8c0c&X-Amz-SignedHeaders=host&x-id=PutObject" \ +--header "Content-Type: text/plain" \ +--data-raw "<h1> +Welcome to my awesome website +</h1>" +
curl --location --request PUT "https://sync-to-ipfs-queue.s3.eu-west-1.amazonaws.com/HOSTING_sessions/70/29ef6ca2-b171-440c-b934-db8aa88c3424/index.html?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAQIMRRA6GJRL57L7G%2F20230215%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20230215T105030Z&X-Amz-Expires=900&X-Amz-Signature=187035d2307bc089101eff3abbdd7baa3e8691b4d5d3bafa5aebb87e589e8c0c&X-Amz-SignedHeaders=host&x-id=PutObject" \ +--header "Content-Type: text/plain" \ +--data-binary ":full path to file" +
End upload session
Transfer files to website bucket, which is used as source for deploy to staging(preview) environment.
POST /hosting/websites/:websiteUuid/upload/:sessionUuid/endURL parameters
Name Description Required websiteUuid Unique key of website. true sessionUuid Session uuid, passed or received in get URL for upload request true Possible errors
Code Description 40406004 Session does not exists 40006001 Files in this session were already transferred Response
Api respond with status
200 OK
, if operation is successfully executed.curl --location --request POST "https://api.apillon.io/hosting/websites/:websiteUuid/upload/:sessionUuid/end" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +
{ + "id": "b64b1c07-1a8a-4b05-9e3b-3c6a519d6ff7", + "status": 200, + "data": true +} +
Deploy website
Endpoint to trigger website deployment into specific environment.
POST /hosting/websites/:websiteUuid/deployURL parameters
Name Description Required websiteUuid Website UUID, visible in developer console website overview true Body fields
Name Type Description Required environment number
Possible environment
values are explained belowtrue Environments
Status Description 1 Uploaded files are deployed to staging(preview) environment. Website will be available through staging IPNS link 2 Files from current staging environment are deployed to production environment. Website is pinned to CRUST, replicated and available through production IPNS link 3 Same as 2
, only that the source are uploaded files, not files in staging environment.Possible errors
Code Description 42200039 Request body is missing an environment
field.40406010 Website does not exists 40006016 There are no files to deploy. 40006017 There are no changes to deploy. Response
Endpoint triggers deployment of website to specific environment. As result, deployment record with below field is returned. This deployment is now waiting to be processed.
Note: Deployment is processed in background, which may take several minutes. When deploying to
staging
environment, files are added to IPFS and wrapped to directory, which is then accessible in IPFS via IPNS or CID. Inproduction
, this CID is pinned to CRUST and replicated to other nodes.Deployment fields
Field Type Description deploymentUuid string
Deployment unique identifier environment number
Environment to where website will be deployed deploymentStatus number
Current status of deployment. Possible values are listed below. cid string
When deployment is successful, CID points to directory on IPFS, where this page is accessible cidv1 string
CID version 1 size number
Size of website number number
Deployment serial number - for this environment createTime DateTime
Deployment create time updateTime DateTime
Deployment last update time Website deployment statuses
Deployment goes through different stages and each stage updates
deploymentStatus
. Possible deployment statuses:
Status Description 0 Deployment initiated 1 In processing 2 In review 3 Website approved. Deployment will be executed 10 Deployment successful 100 Deployment failed 101 Deployment rejected Deployments (to environments 1 and 3) in projects without subscription go to review (
deploymentStatus 3
). Review can take some time (up to 1 day) and if the website passes it, then the deployment continues.Websites with illegal/phishing content goes to status
101
. The project owner is notified via mail and most likely banned from Apillon platform.To speed up deployment process, make sure that project has one of the subscription packages.
curl --location --request POST "https://api.apillon.io/hosting/websites/:websiteUuid/deploy" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"environment\": 1 +}" +
{ + "id": "dfe79ed9-e2fe-4195-b829-053dee1e6fd1", + "status": 200, + "data": { + "createTime": "2023-10-13T12:23:51.721Z", + "updateTime": "2023-10-13T12:23:51.721Z", + "deploymentUuid": "583790dc-7b56-4563-8a33-d88243eed11e", + "environment": 1, + "deploymentStatus": 0, + "cid": null, + "cidv1": null, + "size": null, + "number": 1 + } +} +
List website deployments
API to list website deployments. More about listing requests can be found here
GET /hosting/websites/:websiteUuid/deploymentsURL parameters
Name Description Required deploymentStatus Current deployment status false environment Deployment environment false Response fields
Each item in list is a deployment instance.
curl --location --request GET "https://api.apillon.io/hosting/websites/:websiteUuid/deployments" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/hosting/websites/:websiteUuid/deployments?orderBy=number" \ +--header "Authorization: Basic :credentials" +
{ + "id": "75095bf9-e976-45c8-8a9d-e013ca3b203a", + "status": 200, + "data": { + "items": [ + ... + { + "createTime": "2023-10-13T12:28:39.000Z", + "updateTime": "2023-10-13T12:29:15.000Z", + "deploymentUuid": "12b47aef-6a01-4799-a4da-79ea7595237d", + "environment": 2, + "deploymentStatus": 10, + "cid": "QmTF31ediusaBTNn2Z1Jtr5fF1iVp9oDA8EWz9my6aVx8V", + "cidv1": "bafybeici3ivncsgfszf7tbmttayyjk6hs25354zs5nczujv44rco4qiv7y", + "size": 41, + "number": 1 + }, + { + "createTime": "2023-10-13T12:23:51.000Z", + "updateTime": "2023-10-13T12:24:17.000Z", + "deploymentUuid": "583790dc-7b56-4563-8a33-d88243eed11e", + "environment": 1, + "deploymentStatus": 10, + "cid": "QmTF31ediusaBTNn2Z1Jtr5fF1iVp9oDA8EWz9my6aVx8V", + "cidv1": "bafybeici3ivncsgfszf7tbmttayyjk6hs25354zs5nczujv44rco4qiv7y", + "size": 41, + "number": 1 + } + ... + ], + "total": 10 + } +} +
Get deployment
Endpoint to get deployment.
GET /hosting/websites/:websiteUuid/deployments/:deployment_uuidURL parameters
Name Description Required websiteUuid Website UUID, visible in developer console website overview true deploymentUuid Deployment unique identifier, returned from deploy
website endpointtrue Possible errors
Code Description 40406011 Deployment does not exists Response fields
Data
property is a deployment instance.curl --location --request GET "https://api.apillon.io/hosting/websites/:websiteUuid/deployments/:deploymentUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "2d7d1b0c-15b1-4816-9aec-857182c7b617", + "status": 200, + "data": { + "createTime": "2023-10-13T12:23:51.000Z", + "updateTime": "2023-10-13T12:24:17.000Z", + "deploymentUuid": "583790dc-7b56-4563-8a33-d88243eed11e", + "environment": 1, + "deploymentStatus": 10, + "cid": "QmTF31ediusaBTNn2Z1Jtr5fF1iVp9oDA8EWz9my6aVx8V", + "cidv1": "bafybeici3ivncsgfszf7tbmttayyjk6hs25354zs5nczujv44rco4qiv7y", + "size": 41, + "number": 1 + } +} +
Generate short URL
Endpoint to generate a short URL for an IPFS link
POST /hosting/short-urlBody fields
Name Description Required targetUrl The target URL of the website the short URL will point to true Response fields
Field Type Description id string
The short URL slug url string
The full short URL targetUrl string
The target URL which the short link points to curl --location --request POST "https://api.apillon.io/hosting/short-url" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ \"targetUrl\": \"https://ipfs.apillon.io/ipfs/abc\" }" +
{ + "id": "2d7d1b0c-15b1-4816-9aec-857182c7b617", + "status": 201, + "data": { + "id": "A74WF", + "targetUrl": "https://ipfs.apillon.io/ipfs/abc", + "url": "https://go.web3approved.com/A74WF" + } +} +
NFTs API | Apillon Wiki + + + + ++ + + diff --git a/build/5-apillon-sdk.html b/build/5-apillon-sdk.html new file mode 100644 index 00000000..4b43345f --- /dev/null +++ b/build/5-apillon-sdk.html @@ -0,0 +1,375 @@ + + + + + + + + +Apillon Wiki NFTs API
API is for creating and managing NFTs. To prepare images and metadata for your NFT collection you can use the Storage API. To learn more about metadata standards you can visit: https://docs.opensea.io/docs/metadata-standards
Get NFT Collection
Get NFT collection by UUID
GET /nfts/collections/:uuidURL parameters
Name Description Required uuid Unique key of collection. Key is displayed in developer dashboard. true Possible errors
Code Description 40300000 Not allowed to access collection. 50012009 Collection does not exist. Response Fields
Name Type Description createTime DateTime
Collection create time. updateTime DateTime
Collection last update time. collectionType number
Type of smart contract to use for collection. Available types are described here. collectionUuid string
Unique key of a collection. symbol string
NFT collection symbol (usually 3-4 characters long). name string
NFT collection name. description string
NFT collection description. maxSupply number
Maximal number of NFTs ever in existence (0 stands for unlimited). bucketUuid string
UUID of the bucket where metadata is stored. baseUri string
Base URI for collection metadata (token id and file extension is appended to it). baseExtension string
File extension that is auto appended after token id to form a full URL. isSoulbound boolean
Soul bound tokens are NFTs that are bounded to wallet and not transferable. isRevokable boolean
For revocable collection owner can destroy NFTs at any time. isAutoIncrement boolean
If set to false, enables minting NFTs with a custom token ID royaltiesFees number
Percentage (between 0 and 100) of each NFT sale sent to wallet specified under royalties address. royaltiesAddress string
Address where royalties are sent to. collectionStatus number
Apillon internal/database collection status. contractAddress string
Smart address of contract for deployed collection. transactionHash string
Deployment transaction hash/id. deployerAddress string
Wallet address of deployer. chain number
Blockchain id on which you want to release your collection. drop boolean
Determines if collection is mintable by public. dropStart number
UNIX timestamp which determines public mint opening date and time. dropPrice number
Price of NFT at mint stage in token that is used on chain
.dropReserve number
Amount of NFTs reserved by owner. curl --location 'https://api.apillon.io/nfts/collections/:uuid' \ +--header 'Authorization: Basic :credentials' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": "a9425ff7-4802-4a38-b771-84a790112c30", + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": ".json", + "isSoulbound": false, + "isRevokable": true, + "royaltiesFees": 0.1, + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "collectionStatus": 0, + "contractAddress": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557", + "transactionHash": "0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26", + "deployerAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "chain": 1287, + "drop": true, + "dropStart": 1687251003, + "dropPrice": 0.1, + "dropReserve": 5 + } +} +
Collection Type
Number Description 0 Generic NFT collection. 1 Nestable NFT collection. Collection Statuses
Number Description 0 Collection was created. 1 Deploying collection was initiated. 2 Collection is being deployed. 3 Collection was deployed successfully. 4 Collection was transferred successfully. 5 Failed deploying collection. List NFT Collections
List NFT collections. Items are paginated and can be filtered and ordered through query parameters.
GET /nfts/collectionsQuery parameters
All query parameters from listing request plus:
Name Description Required collectionStatus Collection status. Find available statuses here. false Response
Response is a list of items described under Response Fields above.
curl --location 'https://api.apillon.io/nfts/collections' \ +--header 'Authorization: Basic :credentials' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "items": [ + { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": "a9425ff7-4802-4a38-b771-84a790112c30", + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": ".json", + "isSoulbound": false, + "isRevokable": true, + "royaltiesFees": 0.1, + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "collectionStatus": 0, + "contractAddress": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557", + "transactionHash": "0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26", + "deployerAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "chain": 1287, + "drop": true, + "dropStart": 1687251003, + "dropPrice": 0.1, + "dropReserve": 5 + } + ], + "total": 1 + } +} +
List Collection Transactions
List NFT collections. Items are paginated and can be filtered and ordered through query parameters.
GET /nfts/collections/:uuid/transactionsURL parameters
Name Description Required uuid Unique key of collection. Key is displayed in developer dashboard. true Query parameters
All query parameters from listing request plus:
Name Description Required transactionStatus Transaction status. false transactionType Transaction type. false Response Fields
Name Type Description chainId number
Blockchain id on which you want to release your collection. transactionType number
Transaction type. transactionStatus number
Transaction status transactionHash number
Transaction hash/id. updateTime DateTime
Transaction last update time. createTime DateTime
Transaction create time. curl --location 'https://api.apillon.io/nfts/collections/:uuid/transactions' \ +--header 'Authorization: Basic :credentials' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "items": [ + { + "chainId": 1287, + "transactionType": 1, + "transactionStatus": 1, + "transactionHash": "0xb988c8cda7ec8b441611b208360e0aace9c294e1ca5672375b21e815890a54d1", + "updateTime": "2023-06-13T10:15:58.000Z", + "createTime": "2023-06-13T10:15:58.000Z" + } + ], + "total": 1 + } +} +
Transaction Types
Number Description 1 Deploy Contract 2 Transfer Contract Ownership 3 Mint NFT 4 Set Collection Base URI 5 Burn NFT 6 Nest mint NFT Transaction Status
Number Description 1 Pending 2 Confirmed 3 Failed 4 Error Create NFT Collection
API endpoint that creates NFT collection and deploys it on selected network.
An NFT Collection can be created with a few features/functionalities:
- drop: collection can be minted/purchased by users
- revokable: NFTs can be revoked by collection owner who can burn them
- soulbound: NFTs are bound to wallet address and can't be transferred
- royalties: owner can enable royalties to earn specified percentage per each NFT trade
2 types of collections are supported:
- Generic collection, which represents an extension of the ERC-721 standard for EVM collections and the PSP-34 standard / Native NFTs for substrate collections. You can read more about these standards here
- Nestable collection which allows nesting NFTs under each other (based on RMRKs ERC-7401 NFT standard and Unique Native NFTs)
Additionally, 2 chain types/environments are supported: EVM and Substrate.
Create Substrate NFT Collection
POST /nfts/collections/substrateBody fields
Name Type Description Required collectionType number
Type of smart contract to use when deploying collection (1 for generic, 2 for nestable). true chain number
Blockchain ID on which you want to release your collection. Options: ( 8
- Astar)true symbol string
NFT collection symbol (usually 3-4 characters long). true name string
NFT collection name. true description string
NFT collection description. false maxSupply number
Maximal number of NFTs ever in existence (0 stands for unlimited). true baseUri string
Base URI for collection metadata (token id and file extension is appended to it). true baseExtension string
File extension that is auto appended after token id to form a full URL. true royaltiesAddress string
Address where royalties are sent to. true royaltiesFees number
Percentage of royalties earned per each NFT trade. true drop boolean
Determines if collection is mintable by public. true dropStart* number
UNIX timestamp (in seconds) which determines public mint opening date and time. true dropPrice* number
Price of NFT at mint stage. true dropReserve* number
Amount of NFTs reserved by owner. true Notes:
*
dropStart
,dropPrice
anddropReserve
are only used ifdrop
is set to booleantrue
.Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40012002 Collection quota reached 50012003 Failed deploying NFT contract on chain. 50012010 Failed to create bucket for storing metadata. Response
Response payload is described under Response Fields above.
curl --location 'https://api.apillon.io/nfts/collections/substrate' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{ + "collectionType": 1, + "chain": 8, + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection description", + "maxSupply": 1000, + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": "json", + "royaltiesAddress": "5TdmScYtgDGg13mG1pvQ5zAooMXMK45bHBt3meGDXrNBKua", + "royaltiesFees": 10, + "drop": true, + "dropStart": 1687251003, + "dropReserve": 5, + "dropPrice": 0.1 +}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "chain": 8, + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": "a9425ff7-4802-4a38-b771-84a790112c30", + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": ".json", + "isSoulbound": false, + "isRevokable": false, + "royaltiesFees": 0.1, + "royaltiesAddress": "5TdmScYtgDGg13mG1pvQ5zAooMXMK45bHBt3meGDXrNBKua", + "collectionStatus": 0, + "contractAddress": "XjuXMnFxcJoAgMCdUQKvvt2Daykq4H9rsCfYEVpF6noFP5u", + "transactionHash": "0xb59d8497feb121b0ca0b8480df72a456333edddc68ad65f23b6b8b9028e3a6b3", + "deployerAddress": "WmMcyrPY4fivB5FUPN85QPhCMKtnrjmUyAgtXC2oW2XbcnY", + "drop": true, + "dropStart": 1687251003, + "dropPrice": 0.1, + "dropReserve": 5 + } +} +
Create EVM NFT Collection
POST /nfts/collections/evmBody fields
All the fields from substrate collection, plus:
Name Type Description Required chain number
Blockchain ID on which you want to release your collection. Options: ( 1284
- Moonbeam,1287
- Moonbase,592
- Astar)true isRevokable boolean
For revocable collection owner can destroy NFTs at any time. (default: false) true isSoulbound boolean
Soul bound tokens are NFTs that are bound to wallet and not transferable. (default: false) true isAutoIncrement boolean
If set to false, enables minting NFTs with a custom token ID, otherwise defaults to isAutoIncrement = true false Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40012002 Collection quota reached 50012003 Failed deploying NFT contract on chain. 50012010 Failed to create bucket for storing metadata. Response
Response payload is described under Response Fields above.
curl --location 'https://api.apillon.io/nfts/collections/evm' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{ + "collectionType": 1, + "chain": 1287, + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection description", + "maxSupply": 1000, + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": "json", + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "royaltiesFees": 10, + "drop": true, + "dropStart": 1687251003, + "dropReserve": 5, + "dropPrice": 0.1, + "isRevokable": true, + "isSoulbound": true +}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "chain": 1287, + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": "a9425ff7-4802-4a38-b771-84a790112c30", + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": ".json", + "royaltiesFees": 0.1, + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "collectionStatus": 0, + "contractAddress": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557", + "transactionHash": "0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26", + "deployerAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "drop": true, + "dropStart": 1687251003, + "dropPrice": 0.1, + "dropReserve": 5, + "isRevokable": true, + "isSoulbound": true + } +} +
Create Unique NFT Collection
POST /nfts/collections/uniqueBody fields
Name Type Description Required collectionType number
Type of smart contract to use when deploying collection (1 for generic, 2 for nestable). true symbol string
NFT collection symbol (usually 3-4 characters long). true name string
NFT collection name. true description string
NFT collection description. false maxSupply number
Maximal number of NFTs ever in existence (0 stands for unlimited). true isRevokable boolean
For revocable collection owner can destroy NFTs at any time. (default: false) true isSoulbound boolean
Soul bound tokens are NFTs that are bound to wallet and not transferable. (default: false) true metadata object
Object containing metadata for different token ids (more details bellow). true Metadata field
Metadata field is an object with token ids as keys and token metadata as values. Here are the fields for each token metadata:
Name Type Description Required name string
NFT name. true description string
NFT description. false image string
NFT image URL. true image_details object
Additional details about the image from the image field (see table bellow). false attributes array
Array of NFT attributes (see table bellow). true animation_url string
NFT animation URL. false animation_details object
Additional details about the animation from the animation_url field (see table bellow). false youtube_url string
URL to a YouTube video associated with the NFT. false created_by string
Address of the creator of the NFT. false external_url string
URL to an external resource providing more information about the NFT. false background_color string
Background color of the NFT. false locale string
Locale of the NFT. false Metadata field attributes
Attributes field of metadata field is an array of NFT traits described bellow:
Name Type Description Required value string
Trait value. true trait_type string
Name of the trait. true display_type string
Type for displaying trait ( number
,date
,...).false Metadata field image_details and animation_details
Name Type Description Required name string
Name of the image (for captions, etc.). false type enum
Type of content ( image
,animation
,video
,audio
,spatial
,document
,other
)false bytes number
Size of the image file in bytes. false format string
Format of the image file (e.g., PNG, JPEG). false sha256 string
SHA-256 hash of the image file. false width number
Width of the image in pixels. false height number
Height of the image in pixels. false order number
Order of the image. false You can find more information about metadata in Unique docs.
Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40012002 Collection quota reached 50012003 Failed deploying NFT contract on chain. Response
Response payload is described under Response Fields above.
curl --location 'https://api.apillon.io/nfts/collections/unique' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{ + "collectionType": 1, + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection description", + "maxSupply": 1000, + "isRevokable": true, + "isSoulbound": true, + "metadata": { + "1": { + "name": "name", + "description": "description", + "image": "image", + "attributes": [ + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + } + ] + }, + "2": { + "name": "name", + "description": "description", + "image": "image", + "attributes": [ + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + }, + { + "value": "value", + "trait_type": "trait_type", + "display_type": "display_type" + } + ] + }, + } +}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "chain": 11, + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": null, + "baseUri": null, + "baseExtension": "", + "royaltiesFees": 0, + "royaltiesAddress": null, + "collectionStatus": 0, + "contractAddress": "XjuXMnFxcJoAgMCdUQKvvt2Daykq4H9rsCfYEVpF6noFP5u", + "transactionHash": "0xb59d8497feb121b0ca0b8480df72a456333edddc68ad65f23b6b8b9028e3a6b3", + "deployerAddress": "WmMcyrPY4fivB5FUPN85QPhCMKtnrjmUyAgtXC2oW2XbcnY", + "drop": false, + "dropStart": 0, + "dropPrice": 0, + "dropReserve": 0, + "isRevokable": true, + "isSoulbound": true, + "isAutoIncrement": true + } +} +
Transfer Collection
Transfer collection ownership from a wallet owned by caller to a new wallet address.
POST/nfts/collections/:uuid/transferURL parameters
Name Description Required uuid Unique key of collection. Key is displayed in developer dashboard. true Body fields
Name Type Description Required address string
Wallet address of a new owner. true Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40012003 Contract can't be transferred to wallet address that already owns this collection. 40012004 Transfer transaction already exists. 40300000 Not allowed to access collection 50012002 Collection doesn't exist, wasn't deployed or was already transferred. 50012004 Collection transfer failed. Response
Response payload is described under Response Fields above.
curl --location 'https://api.apillon.io/nfts/collections/:uuid/transfer' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{"address": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241551"}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "createTime": "2023-06-13T10:15:58.000Z", + "updateTime": "2023-06-13T10:15:58.000Z", + "collectionType": 1, + "collectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "symbol": "NFT", + "name": "NFT Collection", + "description": "NFT Collection Description", + "maxSupply": 1000, + "bucketUuid": "a9425ff7-4802-4a38-b771-84a790112c30", + "baseUri": "https://ipfs.apillon.io/metadata/", + "baseExtension": ".json", + "isSoulbound": false, + "isRevokable": true, + "royaltiesFees": 0.1, + "royaltiesAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "collectionStatus": 0, + "contractAddress": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557", + "transactionHash": "0x6b97424de3367cd0335b08265787b83053b62bee2d1c8bec1f776936bea4fb26", + "deployerAddress": "0x4156edbafc5091507de2dd2a53ded551a346f83b", + "chain": 1287, + "drop": true, + "dropStart": 1687251003, + "dropPrice": 0.1, + "dropReserve": 5 + } +} +
Mint Collection NFTs
Mint specified amount of NFTs to a wallet address provided in request.
Note: if the collection is set as
drop
this endpoint can only mint reserved NFTs.POST/nfts/collections/:uuid/mintURL parameters
Name Description Required uuid Unique key of collection. Key is displayed in developer dashboard. true Body fields
Name Type Description Required receivingAddress string
Wallet address of NFT receiver. true quantity number
Number of NFTs to mint. true Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40300000 Not allowed to access collection. 50012002 Collection doesn't exist, wasn't deployed or was already transferred. 50012005 Error minting NFT. 50012007 Total number of minted NFTs would exceed max supply for this collection. 50012008 All of the reserved NFTs were already minted. Response Fields
Field Type Description success boolean
Status of action. curl --location 'https://api.apillon.io/nfts/collections/:uuid/mint' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{"receivingAddress": "0x452101C96A1Cf2cBDfa5BB5353e4a7F235241557", "quantity": 1}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "success": true + } +} +
Nest Mint Collection NFTs
Nest mint specified amount of NFTs under a parent NFT defined by the parent collection UUID and token id.
POST/nfts/collections/:uuid/nest-mintURL parameters
Name Description Required uuid Unique key of (child) collection we are minting. true Body fields
Name Type Description Required parentCollectionUuid string
Collection UUID of NFT receiving nest-minted NFT. true parentNftId number
Token id of NFT receiving nest-minted NFT. true quantity number
Number of NFTs to nest-mint. true Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40300000 Not allowed to access collection. 50012002 Collection doesn't exist, wasn't deployed or was already transferred. 50012007 Total number of minted NFTs would exceed max supply for this collection. 50012008 All of the reserved NFTs were already minted. 50012013 Parrent collection doesn't support nesting. 50012014 Parrent and child collection chain missmatch. Response Fields
Field Type Description success boolean
Status of action. curl --location 'https://api.apillon.io/nfts/collections/:uuid/next-mint' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{"parentCollectionUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", "parentNftId": 1, "quantity": 1}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "success": true + } +} +
Burn Collection NFT
Burn specific NFT belonging to collection specified.
Note: burning NFTs is only available if
isRevokable
is enabled on collection.POST/nfts/collections/:uuid/burnURL parameters
Name Description Required uuid Unique key of collection. Key is displayed in developer dashboard. true Body fields
Name Type Description Required tokenId number
Non fungible token id that we are burning. true Possible errors
Beside validation errors (with 422 http status code) these are the error codes may be returned:
Code Description 40300000 Not allowed to access collection. 50012002 Collection doesn't exist, wasn't deployed or was already transferred. 50012012 Burning NFT failed. Response fields
Field Type Description success boolean
Status of action. curl --location 'https://api.apillon.io/nfts/collections/:uuid/burn' \ +--header 'Content-Type: application/json' \ +--header 'Authorization: Basic :credentials' \ +--data '{"tokenId": 1}' +
{ + "id": "b5935c73-204d-4365-9f9a-6a1792adab5b", + "status": 200, + "data": { + "status": true + } +} +
Apillon SDK | Apillon Wiki + + + + ++ + + diff --git a/build/6-apillon-cli.html b/build/6-apillon-cli.html new file mode 100644 index 00000000..f204e1ec --- /dev/null +++ b/build/6-apillon-cli.html @@ -0,0 +1,311 @@ + + + + + + + + +Apillon Wiki Apillon SDK
Libraries and tools for interacting with your Apillon integration. Apillon SDK reduces the amount of work required to use Apillons REST API. It reduces the boilerplate code you need to write as well as compresses multi step flows into single operations.
Requirements
- npm 10.0.0 or higher
- node.js 20.0.0 or higher
- Apillon API key and secret
Getting started
To be able to use Apillon SDK, you must register an account at Apillon.io, create a project and generate an API key with appropriate permissions.
SDK package is available on NPM and you can also check it out directly on GitHub.
Installation
npm install @apillon/sdk +
Initialization
import { Hosting } from '@apillon/sdk'; + +const hosting = new Hosting({ + key: '', + secret: '', +}); +
Apillon SDK consists of different modules depending on which service you want to use. All modules require the same initial config of
key
andsecret
shown above inHosting
module example.Alternatively, you can populate the
APILLON_API_KEY
andAPILLON_API_SECRET
environment variables.View each individual module examples in the sections below.
Detailed docs
This wiki only contains the basic installation and examples of SDK usage. For additional information on using the SDK, see the Detailed SDK documentation.
Examples
Examples for using Apillon can be found in a demo repo here. Instructions on running the examples are in the README file.
TIP
You can run examples directly in your browser via CodeSandbox.
Hosting
Hosting module encapsulates functionalities for Hosting service available on Apillon dashboard.
TIP
You can only create a new webpage through the dashboard hosting service.
The flow of deploying a new website looks like this:
- Upload new website files
- Trigger deploy to staging
- Trigger deploy from staging to production
You can also directly deploy uploaded files to production.
For detailed hosting SDK method, class and property documentation visit SDK hosting docs.
Usage example
import { + DeployToEnvironment, + DeploymentStatus, + Hosting, + LogLevel, +} from '@apillon/sdk'; +import * as fs from 'fs'; + +const hosting = new Hosting({ + key: 'yourApiKey', + secret: 'yourApiSecret', + logLevel: LogLevel.VERBOSE, +}); + +// list all websites +await hosting.listWebsites({ orderBy: 'createTime' }); + +// create an instance of a website via uuid +const webpage1 = hosting.website('uuid'); + +// gets website information +await webpage1.get(); + +// Upload files from local folder +await webpage1.uploadFromFolder('./public'); +// Or alternatively, send file buffers as upload parameters +const htmlBuffer = fs.readFileSync('./public/index.html'); +await webpage1.uploadFiles( + [ + { + fileName: 'index.html', + contentType: 'text/html', + content: htmlBuffer, + }, + ] +); + +// deploys uploaded files to staging environment +await webpage1.deploy(DeployToEnvironment.TO_STAGING); + +// lists all deployments of a website +await webpage1.listDeployments(); + +// gets a specific deployment +const deployment = await webpage1 + .deployment('3e0c66ea-317d-4e1f-bcd9-38026c3ea1ee') + .get(); + +// checks if deployment was successful +if (deployment.deploymentStatus === DeploymentStatus.SUCCESSFUL) { + // done +} +
Storage
Storage module encapsulates functionalities for Storage service available on Apillon dashboard.
For detailed storage SDK method, class and property documentation visit SDK storage docs.
Usage example
import { Storage, LogLevel, FileStatus } from '@apillon/sdk'; +import * as fs from 'fs'; + +const storage = new Storage({ + key: 'yourApiKey', + secret: 'yourApiSecret', + logLevel: LogLevel.VERBOSE, +}); + +// list buckets +await storage.listBuckets({ limit: 5 }); + +// create and instance of a bucket directly through uuid +const bucket = storage.bucket('uuid'); + +// Upload files from local folder +await bucket.uploadFromFolder('./my-folder/files/'); +// Or alternatively, send file buffers as upload parameters +const pdfBuffer = fs.readFileSync('./my-folder/files/document.pdf'); +await bucket.uploadFiles( + [ + { + fileName: 'document.pdf', + contentType: 'application/pdf', + content: pdfBuffer, + }, + ], + // Upload the files in a new subdirectory in the bucket instead of in the root of the bucket + { wrapWithDirectory: true, directoryPath: 'main/documents' } +); + +// list objects (files, folders) in a bucket +await bucket.listObjects({ + directoryUuid: 'eaff2672-3012-46fb-9278-5efacc6cb616', + markedForDeletion: false, + limit: 5, +}); + +// list all files in a bucket no matter if they are in a folder or not +await bucket.listFiles({ fileStatus: FileStatus.UPLOADED }); + +// generate an IPFS link for a CID +const cid = 'bafybeigjhyc2tpvqfqsuvf3byo4e4a4v6spi6jk4qqvvtlpca6rsaf2cqi'; +const link = await storage.generateIpfsLink(cid); + +// gets a specific file in a bucket directly through uuid +const file = await bucket.file('2195521d-15cc-4f6e-abf2-13866f9c6e03').get(); + +// deletes a file via uuid +await bucket.file('2195521d-15cc-4f6e-abf2-13866f9c6e03').delete(); +// deletes a directory via uuid +await bucket.directory('eddc52cf-92d2-436e-b6de-42d7cad621c3').delete(); +
IPNS methods
The Storage module additionally contains methods for manipulating IPNS records for a specific storage any.
For detailed IPNS SDK method, class and property documentation visit SDK IPNS docs.
import { Storage, LogLevel } from '@apillon/sdk'; + +const storage = new Storage({ + key: 'yourApiKey', + secret: 'yourApiSecret', + logLevel: LogLevel.VERBOSE, +}); + +// create and instance of a bucket directly through uuid +const bucket = storage.bucket('uuid'); +// list all existing IPNS records +const ipnsNames = await bucket.listIpnsNames({ ipnsName: 'Images IPNS' }); +// create a new IPNS record +const newIpns = await bucket.createIpns({ + name: 'Music IPNS', + description: 'IPNS for my music files', + cid: 'QmS5NL2Rc6SCjFx7pvZHdTD8WGWjDt25WQskC7DsNKAatW', +}); +// Get an IPNS record's details by UUID +const ipns = await bucket.ipns('ipns_uuid').get(); +// Publish an IPNS record to point to a given CID +await ipns.publish('QmajaeC15ZpcnjBpX4ARRBU127fpcZ2svYEfEBhFRkRZbN'); +// delete an IPNS record from the bucket +await ipns.delete(); +
NFTs
NFT module encapsulates functionalities for NFT service available on Apillon dashboard.
For detailed NFT SDK method, class and property documentation visit SDK NFT docs.
Warning When you transfer ownership of the collection to another account Apillon will lose the ability to perform actions in your name (mint, burn, etc.). Before you transfer ownership make sure you do not need those functionalities via Apillon anymore.
Usage example
import { + CollectionType, + EvmChain, + LogLevel, + Nft, + TransactionStatus, +} from '@apillon/sdk'; + +const nft = new Nft({ + key: 'yourApiKey', + secret: 'yourApiSecret', + logLevel: LogLevel.VERBOSE, +}); + +// create a new collection +let collection = await nft.create({ + collectionType: CollectionType.GENERIC, + chain: EvmChain.MOONBEAM, + name: 'SpaceExplorers', + symbol: 'SE', + description: 'A collection of unique space exploration NFTs.', + baseUri: 'https://moonbeamnfts.com/collections/spaceexplorers/', + baseExtension: 'json', + // If you omit the maxSupply parameter, the max supply will be unlimited + maxSupply: 1000, + isRevokable: false, + isSoulbound: false, + royaltiesAddress: '0x1234567890abcdef', + royaltiesFees: 5, + drop: true, + dropStart: 1679875200, + dropPrice: 0.05, + dropReserve: 100, +}); +// or create a substrate collection +const substrateCollection = await nft.createSubstrate({ + collectionType: CollectionType.GENERIC, + chain: SubstrateChain.ASTAR, + name: 'SpaceExplorers', + symbol: 'SE', + ... +}); + +// check if collection is deployed - available on chain +if (collection.collectionStatus == CollectionStatus.DEPLOYED) { + console.log('Collection deployed: ', collection.transactionHash); +} + +// search through collections +await nft.listCollections({ search: 'My NFT' }); + +// create and instance of collection directly through uuid +collection = await nft.collection('uuid').get(); + +// mint a new nft in the collection +await collection.mint({ + receivingAddress: '0x3fC91A3afd70395Cd496C647d5a6CC9D4B2b7FAD', + quantity: 1, +}); + +// nest mint a new nft if collection type is NESTABLE +await collection.nestMint(collection.uuid, 1, 1); + +// burn/destroy a specific NFT by its ID if collection is set as revokable +await collection.burn('1'); + +// list confirmed transactions on a collection +await collection.listTransactions({ + transactionStatus: TransactionStatus.CONFIRMED, +}); + +// transfer ownership of a collection away from apillon platform to an address +// NOTE that this will disable the ability to mint/burn etc. from the SDK/API since only the owner +// has this ability +await collection.transferOwnership( + '0x5BA8B0c24bA5307b67E619ad500a635204F73bF1' +); +
Identity
Identity module encapsulates functionalities for validating EVM and Polkadot wallet signatures, as well as fetching Polkadot Identity data for any wallet.
For detailed hosting SDK method, class and property documentation visit SDK identity docs.
Usage example
import { Identity, LogLevel } from '@apillon/sdk'; + +// Note: for signature-related methods API config is not required +const identity = new Identity({ + key: 'yourApiKey', + secret: 'yourApiSecret', + logLevel: LogLevel.VERBOSE, +}); + +// obtain on-chain identity data for a Polkadot wallet +const { polkadot, subsocial } = await identity.getWalletIdentity(address); + +async function validateEvmWalletSignature() { + // generate a custom message to be signed by the user's wallet + const { message, timestamp } = await identity.generateSigningMessage( + 'Custom display message here', + ); + + // alternatively, you can generate you own signing message with timestamp like this: + // const timestamp = new Date().getTime(); + // const message = 'Message from my Dapp'; + // const signingMessage = `${message}\n${timestamp}`; + + const walletAddress = '0xa79bg13g2...'; + + // validate an EVM wallet's signature for a given message + const { isValid, address } = await identity.validateEvmWalletSignature({ + message, + signature, // signature obtained from the user's wallet by the client app + walletAddress, + /* + * optional - check signature time validity by providing a timestamp + * which indicates when the signature was generated + */ + timestamp, + // additionally, specify for how many minutes the timestamp is valid + signatureValidityMinutes: 15, + }); + + console.log(isValid); // true + console.log(address.toLowerCase() === walletAddress.toLowerCase()); // true +} + +async function validatePolkadotWalletSignature() { + // If you wish to generate the message yourself and validate the timestamp, + // use a signing message as shown below: + const timestamp = new Date().getTime(); + const message = 'Message from my Dapp'; + const signingMessage = `${message}\n${timestamp}`; + + // validate a Polkadot wallet's signature for a given signing message + const { isValid } = await identity.validatePolkadotWalletSignature({ + message: signingMessage, + signature, // signature obtained from the user's wallet by the client app + walletAddress: '5HqHQDGcHqS...', + timestamp, + signatureValidityMinutes: 5, + }); +} + +
Computing
The Computing module provides functionalities for managing computing contracts, including creating contracts, listing contracts, and interacting with specific contracts for operations like encryption and ownership transfer.
Usage example
import { Computing } from '@apillon/sdk'; + +const computing = new Computing({ + key: 'yourApiKey', + secret: 'yourApiSecret', +}); + +// List all computing contracts +const contracts = await computing.listContracts(); + +// Create a new computing contract +const newContract = await computing.createContract({ + name: 'New Contract', + description: 'Description of the new contract', + bucket_uuid, + contractData: { + nftContractAddress: '0xabc...', + nftChainRpcUrl: ChainRpcUrl.ASTAR, + }, +}); + +// Interact with a specific computing contract +const contract = computing.contract(newContract.uuid); + +// Get details of the contract +const contractDetails = await contract.get(); + +// List transactions of the contract +const transactions = await contract.listTransactions(); + +// Encrypt a file and upload it to the associated bucket +const encryptionResult = await contract.encryptFile({ + fileName: 'example.txt', + content: Buffer.from('Hello, world!'), + nftId: 1, // NFT ID used for decryption authentication +}); + +// Transfer ownership of the contract +const newOwnerAddress = '0xNewOwnerAddress'; +const successResult = await contract.transferOwnership(newOwnerAddress); +console.log( + `Ownership transfer was ${successResult ? 'successful' : 'unsuccessful'}.`, +); +
Social
The Social module provides functionalities for managing social hubs and channels within the Apillon platform. This includes creating, listing, and interacting with hubs and channels. In the background it utilizes Grill.chat, a mobile-friendly, anonymous chat application powered by Subsocial.
Usage example
import { Social } from '@apillon/sdk'; + +const social = new Social({ key: 'yourApiKey', secret: 'yourApiSecret' }); +// Create a new hub +const hub = await social.createHub({ + name: 'Apillon Hub', + about: 'Hub for Apillon channels', + tags: 'apillon,web3,build', +}); + +// Get a specific hub by UUID +const hubDetails = await social.hub(hub.uuid).get(); +// List all Hubs +const hubs = await social.listHubs(); + +// Create a new channel within a hub +const channel = await social.createChannel({ + title: 'Web3 Channel', + body: "Let's discuss Web3", + tags: 'web3,crypto', + hubUuid: hub.uuid, +}); + +// Get a specific channel by UUID +const channelDetails = await social.channel(channel.uuid).get(); +// List all channels within a Hub +const channels = await social.listChannels({ hubUuid: hub.uuid }); +
Apillon CLI | Apillon Wiki + + + + ++ + + diff --git a/build/7-apillon-oauth-integration.html b/build/7-apillon-oauth-integration.html new file mode 100644 index 00000000..788f3dc3 --- /dev/null +++ b/build/7-apillon-oauth-integration.html @@ -0,0 +1,76 @@ + + + + + + + + +Apillon Wiki Apillon CLI
Apillon CLI is a command-line interface for using Apillon Web3 services.
Requirements
To be able to use Apillon CLI, you must register an account at Apillon.io, create a project and generate an API key with appropriate permissions. Also Node.js (version 16 or later) is required.
Installation
To install Apillon CLI run
npm install -g @apillon/cli +
Afterwards you can use CLI with command
apillon <command> [options] +
Alternately you don't need to install the Apillon CLI to use it. In that case run the desired command using
npx
:npx @apillon/cli <command> [options] +
Note that when running without installation, you have to use
@apillon/cli
instead ofapillon
execution command.Global Options
--key <api key>
: Apillon API key (can be set via theAPILLON_API_KEY
environment variable).--secret <api secret>
: Apillon API secret (can be set via theAPILLON_API_SECRET
environment variable).--debug
: Output execution logs when running commands.-V
,--version
: Output the version number.Environment Variables
You can use environment variables to set an API key, and an API secret:
APILLON_API_KEY
: Apillon API key.APILLON_API_SECRET
: Apillon API secret.If you have these variables set, you do not need to use the global options each time.
Help
To display the help information for the CLI or a specific command, use the
-h
or--help
option:apillon -h +apillon hosting -h +npx @apillon/cli hosting deploy-website --help +
List pagination options
For commands that return a list of results, for example
apillon storage list-files
, orapillon hosting list-websites
, there are global list pagination options that are available to use:
--limit <integer>
: Page limit--order-by <string>
: Page order by (can be any property from the response data)--page <integer>
: Page number--search <string>
: Search by name or other object identifierFor example responses and for an overview of all properties, refer to the Apillon API wiki. Note: CLI responses may be different from API responses.
Commands
The Apillon CLI currently supports the following commands:
Hosting Commands
hosting list-websites
Lists all websites associated with your project.
Example
apillon hosting list-websites --search "My-Website" --limit 1 +
Example response
{ + "items": [ + { + "createTime": "2023-10-25T10:41:06.000Z", + "updateTime": "2023-10-26T12:41:41.000Z", + "uuid": "5b908779-3687-4592-a073-9bebbf86afe2", + "name": "My Website", + "description": "My own website", + "domain": "https://my-website.com", + "bucketUuid": "47251013-37c6-4b30-be2b-8583dea25c4c", + "cidStaging": "bafybeidwxptqhokkmwgtzrjgj2pvcapmyce...", + "ipnsProduction": "k2k4r8pple7phwm9azqgxshxdzy..." + }, + ... + ], + "total": 3 +} +
hosting get-website
Retrieves information about a specific website.
Options
--uuid <string>
: UUID of the website to get details for.Example
apillon hosting get-website --uuid "123e4567-e89b-12d3-a456-426655440000" +
hosting deploy-website
Deploys a website from a local folder directly to Apillon hosting production environment.
Options
<file-path>
: Path to the folder containing your website files.--uuid <string>
: UUID of the website to upload files to.-p, --preview
: Deploy to staging environment instead.Example
apillon hosting deploy-website ./public_html --uuid "123e4567-e89b-12d3-a456-426655440000" -p +
hosting upload
Uploads a local folder's contents to a website deployment bucket.
Options
<path>
: Path to the folder containing your website files.--uuid <string>
: UUID of the website to upload files to.Example
apillon hosting upload ./public_html --uuid "123e4567-e89b-12d3-a456-426655440000" +
hosting start-deployment
Deploys a website to the specified environment, from files already uploaded to the hosting bucket.
Options
--uuid <string>
: UUID of the website to deploy.--env <integer>
: The environment to deploy to.Available choices:
TO_STAGING = 1 +STAGING_TO_PRODUCTION = 2 +DIRECTLY_TO_PRODUCTION = 3 +
Example
apillon hosting start-deployment --uuid "123e4567-e89b-12d3-a456-426655440000" --env 1 +
hosting list-deployments
Lists all deployments for a specific website.
Options
--uuid <string>
: UUID of the website to list deployments for.--status <integer>
: The status of the deployments (DeploymentStatus enum, optional).Available choices:
INITIATED = 0 +IN_PROGRESS = 1 +IN_REVIEW = 2 +APPROVED = 3 +SUCCESSFUL = 10 +FAILED = 100 +REJECTED = 101 +
--env <integer>
: The environment of the deployments (DeploymentStatus enum, optional).Available choices:
STAGING = 2 +PRODUCTION = 3 +
Example
apillon hosting list-deployments --uuid "58a16026-1356-405b-97f9-efcc9dfac1dd" --order-by createTime --desc true +
Example response
{ + "items": [ + { + "createTime": "2023-11-14T12:09:20.000Z", + "updateTime": "2023-11-14T12:09:42.000Z", + "uuid": "9b677fe2-1bb1-44d9-8956-e7749452f02d", + "websiteUuid": "58a16026-1356-405b-97f9-efcc9dfac1dd", + "cid": "QmPPBMsFccJVaLwvdhSh3zMbfEvonxoNSBLVd1kWK34Nps", + "cidv1": "bafybeizpqaa5xb5r46d2voj35qtokhb3c3bekof...", + "environment": "DIRECTLY_TO_PRODUCTION", + "deploymentStatus": "SUCCESSFUL", + "size": 7162, + "number": 1 + }, + ... + ], + "total": 7 +} +
hosting get-deployment
Retrieves information about a specific deployment.
Options
-w, --website-uuid <string>
: UUID of the website.-d, --deployment-uuid <string>
: UUID of the deploymentExample
apillon hosting get-deployment --website-uuid "123e4567-e89b-12d3-a456-426655440000" --deployment-uuid "987e6543-e21c-32f1-b123-426655441111" +
Storage Commands
storage list-buckets
Lists all storage buckets associated with your project.
Example
apillon storage list-buckets +
Example response
{ + "items": [ + { + "createTime": "2023-11-15T09:56:53.000Z", + "updateTime": "2023-11-23T08:55:46.000Z", + "uuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3", + "name": "My Storage Bucket", + "description": "For storing my images and videos", + "size": 23576 + }, + ... + ], + "total": 2 +} +
storage list-objects
Retrieves objects (files and folders) from a specific bucket or bucket directory.
Options
-b, --bucket-uuid <string>
: UUID of the bucket to retrieve objects from.-d, --directory-uuid <string>
: UUID of the directory to retrieve objects from (optional, default root folder).--deleted
: Include objects deleted from the bucket.Example
apillon storage list-objects --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --directory-uuid "987e6543-e21c-32f1-b123-426655441111" +
Example response
{ + "items": [ + { + "createTime": "2023-11-23T08:55:45.000Z", + "updateTime": "2023-11-23T08:55:46.000Z", + "uuid": "14a7a891-877c-41ac-900c-7382347e1e77", + "name": "index.html", + "CID": "bafybeidzrd7p5ddj67j2mud32cbnze2c7b2pvbhn...", + "status": "AVAILABLE_ON_IPFS_AND_REPLICATED", + "directoryUuid": null, + "type": "FILE", + "link": "https://ipfs.apillon.io/ipfs/bafybeidzrd7p5ddj67j...", + "path": null, + "bucketUuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3" + }, + ... + ], + "total": 16 +} +
storage list-files
Retrieves files from a specific bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket to retrieve files from.-s, --file-status <integer>
: Filter by file status (FileStatus enum, optional).Available choices:
UPLOAD_REQUEST_GENERATED = 1 +UPLOADED = 2 +AVAILABLE_ON_IPFS = 3 +AVAILABLE_ON_IPFS_AND_REPLICATED = 4 +
Example
apillon storage list-files --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" -s 2 +
Example response
{ + "items": [ + { + "createTime": "2023-11-15T09:58:04.000Z", + "updateTime": "2023-11-15T09:58:10.000Z", + "name": "style.css", + "CID": "bafybeidzrd7p5ddj67j2mud32cbnze2c7b2pvbhn...", + "status": "AVAILABLE_ON_IPFS_AND_REPLICATED", + "directoryUuid": null, + "type": "FILE", + "link": "https://ipfs.apillon.io/ipfs/bafybeidzrd7p...", + "path": null, + "bucketUuid": "91c57d55-e8e4-40b7-ad6a-81a82831bfb3" + }, + ... + ], + "total": 10 +} +
storage upload
Upload contents of a local folder to specified bucket.
Options
<folder-path>
: Path to the folder containing your files.-b, --bucket-uuid <string>
: UUID of the bucket to upload files to.-w, --wrap
: Wrap uploaded files to an IPFS directory-p, --path <string>
: Path to upload files to (e.g. main/subdir). Required when --wrap is supplied.--await
: await file CIDs to be resolvedExample
apillon storage upload ./my_folder --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --wrap --path "main/subdir" +
storage get-file
Retrieves information about a specific file in a bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-f, --file-uuid <string>
: UUID or CID of the file to retrieve.Example
apillon storage get-file --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --file-uuid "file_uuid_or_cid" +
storage delete-file
Deletes a specific file from a bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-f, --file-uuid <string>
: UUID or CID of the file to delete.Example
apillon storage delete-file --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --file-uuid "file_uuid_or_cid" +
storage delete-directory
Delete a directory from a storage bucket.
Options
-b, --bucket-uuid <string>
: UUID of the bucket.-d, --directory-uuid <string>
: UUID of the directoru to delete.Example
apillon storage delete-directory --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --directory-uuid "2c84048c-49a1-4ed2-9e1e-8920806ae968" +
IPNS Commands
storage ipns list
Lists all IPNS records for a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.Example
apillon storage ipns list --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" +
Example response
{ + "items": [ + { + "createTime": "2023-12-06T12:29:09.000Z", + "updateTime": "2023-12-06T12:29:21.000Z", + "uuid": "80383a54-1d86-4761-a5e4-26a2fab474c9", + "name": "Images IPNS", + "description": "IPNS for images folder", + "ipnsName": "k2k4r8jp1jnlbe3qv...", + "ipnsValue": "/ipfs/QmUz4...", + "link": "https://ipfs.apillon.io/ipns/k2k4r8jp1jnlbe3qv...", + "bucketUuid": "a26184d7-acf5-4d6c-9195-465e3a7a5240" + }, + { + "createTime": "2023-12-06T12:29:37.000Z", + "updateTime": "2023-12-06T12:29:52.000Z", + "uuid": "2045db5b-b347-4ea6-a4c0-4445e071180d", + "name": "JSON IPNS", + "description": "IPNS for metadata folder", + "ipnsName": "k2k4r8opkl3i2zq7bin8lis4...", + "ipnsValue": "/ipfs/QmUz5Z6RcMynfZWoC...", + "link": "https://ipfs.apillon.io/ipns/k2k4r8opkl3i2z...", + "bucketUuid": "a26184d7-acf5-4d6c-9195-465e3a7a5240" + } + ], + "total": 2 +} +
storage ipns create
Creates a new IPNS record for a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-n, --name <name>
: Name of the IPNS record.-d, --description <description>
: Description of the IPNS record (optional).-c, --cid <cid>
: CID to which this IPNS name will point.Example
apillon storage ipns create --bucket-uuid "123e4567-e89b-12d3-a456-426655440000" --name "my-ipns-record" --cid "QmWX5CcNvnaVmgGBn4o82XW9uW1uLvsHQDdNrANrQeSdXm" +
storage ipns get
Retrieves information about a specific IPNS record.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.Example
apillon storage ipns get --ipns-uuid "123e4567-e89b-12d3-a456-426655440000" +
storage ipns publish
Publishes an IPNS record to IPFS and links it to a CID.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.-c, --cid <string>
: CID to which this IPNS name will point.Example
apillon storage ipns publish --ipns-uuid "123e4567-e89b-12d3-a456-426655440000" --cid "QmWX5CcNvnaVmgGBn4o82XW9uW1uLvsHQDdNrANrQeSdXm" +
storage ipns delete
Deletes an IPNS record from a specific bucket.
Options
-b, --bucket-uuid <uuid>
: UUID of the bucket.-i, --ipns-uuid <uuid>
: UUID of the IPNS record.Example
apillon storage ipns delete --ipns-uuid "123e4567-e89b-12d3-a456-426655440000" +
NFT Commands
nfts list-collections
Lists all NFT collections owned by the project related to the API key.
Options
--status <integer>
: UUID of the collection to retrieve (CollectionStatus enum, optional).Available choices:
CREATED = 0 +DEPLOY_INITIATED = 1 +DEPLOYING = 2 +DEPLOYED = 3 +TRANSFERRED = 4 +FAILED = 5 +
Example
apillon nfts list-collections --status 3 +
Example response
{ + "items": [ + { + "createTime": "2023-11-20T10:21:12.000Z", + "updateTime": "2023-11-20T14:12:33.000Z", + "uuid": "2cda3a9b-01b1-4b5e-9709-7087129d55d0", + "symbol": "SE", + "name": "SpaceExplorers", + "description": "A collection of unique space exploration NFTs.", + "collectionType": "GENERIC", + "maxSupply": 1000, + "baseUri": "https://moonbeamnfts.com/collections/spaceexplorers/", + "baseExtension": ".json", + "isSoulbound": false, + "isRevokable": false, + "drop": false, + "dropPrice": 0.05, + "dropStart": 1679875200, + "dropReserve": 100, + "royaltiesFees": 5, + "royaltiesAddress": "0xaz5Bh6E56c5d3B58c944542de2bF18E7F65eED82", + "collectionStatus": "TRANSFERRED", + "contractAddress": "0x4e22162A6d0c91a088Cb57A72aB976ccA2A96B25", + "transactionHash": null, + "deployerAddress": "0xba015fgc6d80378a9a95f1687e9960857593983b", + "chain": "MOONBASE" + } + ], + "total": 1 +} +
nfts get-collection
Retrieves information about a specific NFT collection.
Options
--uuid <collection-uuid>
: UUID of the collection to retrieve.Example
apillon nfts get-collection --uuid "123e4567-e89b-12d3-a456-426655440000" +
nfts create-collection
Creates a new NFT collection. The JSON file needs to have the property structure as type ICreateCollection for EVM and ICreateSubstrateCollection for Substrate collections. An example object can be also seen on the NFT SDK docs.
Options
<file-path>
: Path to the JSON data file for the new collection.Example
apillon nfts create-collection ./nft-data.json +
nfts mint-nft
Mints NFTs for a collection with a specific UUID.
Options
--uuid <collection-uuid>
: UUID of the collection to mint NFTs to.-a, --address <string>
: Address which will receive minted NFTs.-q --quantity <integer>
: Number of NFTs to mint. (default 1).Example
apillon nfts mint-nft --uuid "123e4567-e89b-12d3-a456-426655440000" --address "0xdAC17F958D2ee523a2206206994597C13D831ec7" --quantity 2 +
nfts nest-mint-nft
Nest mints NFT child collection to a parent collection with a specific UUID and parent NFT with id.
Options
-c, --parent-collection-uuid <collection-uuid>
: Parent collection UUID to which child NFTs will be minted to.-p, --parent-nft-id <string>
: Parent collection NFT id to which child NFTs will be minted to.-q, --quantity <integer>
: Number of child NFTs to mint (default 1).Example
apillon nfts nest-mint-nft --parent-collection-uuid "123e4567-e89b-12d3-a456-426655440000" --parent-nft-id 5 --quantity 2 +
nfts burn-nft
Burns an NFT for a collection with a specific UUID.
Options
--uuid <collection-uuid>
: Collection UUID.-t, --token-id <integer>
: NFT id which will be burned.Example
apillon nfts burn-nft --uuid "123e4567-e89b-12d3-a456-426655440000" --token-id 123 +
nfts transfer-collection
Transfers NFT collection ownership to a new wallet address.
Options
--uuid <collection-uuid>
: Collection UUID.-a, --address <string>
: Address which you want to transfer collection ownership to.Example
apillon nfts transfer-collection --uuid "123e4567-e89b-12d3-a456-426655440000" --address "0xdAC17F958D2ee523a2206206994597C13D831ec7" +
nfts list-transactions
Lists NFT transactions for a specific collection UUID.
Options
--uuid <collection-uuid>
: Collection UUID.--status <integer>
: Transaction status (TransactionStatus enum, optional).Available choices:
PENDING = 1 +CONFIRMED = 2 +FAILED = 3 +ERROR = 4 +
--type <integer>
: Transaction type (TransactionType enum, optional).Available choices:
DEPLOY_CONTRACT = 1 +TRANSFER_CONTRACT_OWNERSHIP = 2 +MINT_NFT = 3 +SET_COLLECTION_BASE_URI = 4 +BURN_NFT = 5 +NEST_MINT_NFT = 6 +
Example
apillon nfts list-transactions --uuid "123e4567-e89b-12d3-a456-426655440000" +
Example response
{ + "items": [ + { + "createTime": "2023-11-20T10:21:22.000Z", + "updateTime": "2023-11-20T10:23:31.000Z", + "chainId": "MOONBEAM", + "transactionType": "DEPLOY_CONTRACT", + "transactionStatus": "CONFIRMED", + "transactionHash": "0xab99e630f9475df92768b1e5d73f4..." + }, + { + "createTime": "2023-11-20T11:55:13.000Z", + "updateTime": "2023-11-20T11:57:31.000Z", + "chainId": "MOONBEAM", + "transactionType": "MINT_NFT", + "transactionStatus": "CONFIRMED", + "transactionHash": "0x1ecfeeaeddfa0a39fc2ae1ec755d27..." + }, + ... + ], + "total": 4 +} +
Using in CI/CD tools
CLI is particularly useful for CI/CD builds and pipelines.
Deploying websites
Here's an example of how you can use the CLI tool in a CI/CD tool like GitHub Actions:
name: Deploy Website + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: 16 + + - name: Create dist folder + run: mkdir -p dist + + - name: Copy files + run: | + cp *.html dist/ + cp -r images dist/ + cp -r style dist/ + cp -r js dist/ + + #### + ## if you are using a framework for building web app, you can replace previous two step with the + ## appropriate command for generating static webpage, like the example below. + ## Find the correct command in your framework documentation. You may need to change the + ## name of the source folder in the last step (CLI call) + #### + # - name: Build app + # run: npm run build + - name: Deploy website + env: + APILLON_API_KEY: ${{ secrets.APILLON_API_KEY }} + APILLON_API_SECRET: ${{ secrets.APILLON_API_SECRET }} + WEBSITE_UUID: ${{ secrets.WEBSITE_UUID }} + run: npx --yes @apillon/cli hosting deploy-website ./dist --uuid $WEBSITE_UUID --key $APILLON_API_KEY --secret $APILLON_API_SECRET + # Or alternatively you can use the run configuration below + # run: | + # npm i -g @apillon/cli + # apillon hosting deploy-website ./dist --uuid $WEBSITE_UUID --key $APILLON_API_KEY --secret $APILLON_API_SECRET +
In this example, the GitHub Actions workflow is triggered when a push event occurs on the master branch. The workflow performs the following steps:
- Checks out the repository.
- Sets up Node.js with version 16.
- Creates a dist folder to store the website files.
- Copies the necessary files (HTML, images, styles, and JavaScript) to the dist folder.
- Deploys the website using the CLI tool. The required environment variables (APILLON_API_KEY, APILLON_API_SECRET, and WEBSITE_UUID) are provided as secrets. The npx command ensures that the latest version of the CLI tool is used.
Make sure to setup secret variables with the values from Apillon platform.
That's it! You can now use this example as a starting point to deploy your website using the CLI tool in a CI/CD pipeline with GitHub Actions.
You can also check a working example on Github
Apillon OAuth Integration | Apillon Wiki + + + + ++ + + diff --git a/build/8-computing-api.html b/build/8-computing-api.html new file mode 100644 index 00000000..78ec9389 --- /dev/null +++ b/build/8-computing-api.html @@ -0,0 +1,181 @@ + + + + + + + + +Apillon Wiki Apillon OAuth Integration
You can easily integrate Apillon's OAuth protocol into your own project or website. If you don't have an Apillon account or project already, get started on the Apillon dashboard.
Once you have created a project, navigate to the project's API keys section in your project settings. Generate an API key for the Authentication service with the KEY_EXECUTE permission. This API key will be used to interact with Apillon's API, generate an OAuth session, and verify a user log-in. Make sure you store your API key and your API key secret in a secure manner.
To integrate Apillon's OAuth protocol into your website, follow these steps:
Create an Apillon Account: If you don't have an Apillon account or project yet, create one on the Apillon dashboard.
Generate an API Key: Go to your project's settings and navigate to the API keys section. Generate an API key for the Authentication service with the KEY_EXECUTE permission.
Securely Store API Key: It's crucial to securely store your API key and its secret. These will be used to interact with Apillon's API, create OAuth sessions, and verify user log-ins. This should be done on the server side, as explained below.
For a complete NodeJS demo of the whole OAuth flow, refer to this Github repo
Client - OAuth popup & events
To initiate the OAuth flow for the user, use the following code to open Apillon's OAuth website as a pop-up and prompt your users to complete the OAuth flow. The session token passed as a query parameter is obtained from the Apillon API (see Server section below).
Additionally, an event listener is added for the main app/website to handle the successful completion of the OAuth flow by the user, which grants an authentication token to the user. The token is then used to verify the login through Apillon's API, which finally returns the user's email address on Apillon.
async function openOAuthPopup() { + const sessionToken = await getAuthToken(); + oAuthWindow = window.open( + `https://oauth.apillon.io/?embedded=1&token=${sessionToken}`, + 'Apillon OAuth Form', + `height=${900} width=${450} resizable=no` + ); +} + +window.addEventListener('message', async event => { + if (!event.origin?.includes('apillon.io')) return; + + if (!event.data.verified) { + throw new Error('Invalid OAuth verification'); + } + // Close OAuth popup window + oAuthWindow?.close(); + + verifyUserLogin(event.data.authToken); +}, false); +
Server - Auth API endpoints
The server-side part of the OAuth implementation contains the logic to query the Apillon API, obtain a session token to initiate the OAuth flow, and verify the user log-in when the flow is finished.
Obtain a session token
Obtain a session token from the Apillon API to interact with Apillon's OAuth protocol.
GET /auth/session-tokencurl --location --request GET "https://api.apillon.io/auth/session-token" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +
{ + "id": "0da29b5a-8a8b-473b-9f97-3183819263f4", + "status": 200, + "data": { + "sessionToken": "eyJhbGciOiJIUzI1..." + } +} +
Verify user login
After the user has completed the OAuth flow, verify they have successfully logged in with the generated OAuth token from the "message" event handler. As a response, receive the user's Apillon email address.
POST /auth/verify-logincurl --location --request POST "https://api.apillon.io/auth/verify-login" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"token\": \"eyJhbGciOiJIUzI1...\" +}" +
{ + "id": "de2cf1e7-0dfe-4378-ab77-98cbc9a00496", + "status": 200, + "data": { + "email": "apillon-user@mail.com" + } +} +
Computing API | Apillon Wiki + + + + ++ + + diff --git a/build/9-social-api.html b/build/9-social-api.html new file mode 100644 index 00000000..7add506e --- /dev/null +++ b/build/9-social-api.html @@ -0,0 +1,164 @@ + + + + + + + + +Apillon Wiki Computing API
The Computing Contracts API provides functionality for managing computing contracts, including creation, listing, encryption, ownership transfer, and assigning content identifiers (CIDs) to NFTs.
Create Computing Contract
Create a new computing contract with specified details.
POST /computing/contractsBody fields
Field Type Description Required contractType number
Type of the computing contract. Available options: 1 = SCHRODINGER Yes name string
Name of the computing contract Yes description string
Description of the computing contract No bucket_uuid string
UUID of the bucket for storing encrypted files from the computing contract. If this is not provided, a new bucket will be created No Data specific for Schrodinger's NFT contract type
Field Type Description Required contractData.nftContractAddress string
Contract address of the NFT collection whose tokens will be used for file decryption No contractData.nftChainRpcUrl string
RPC URL of the blockchain the NFT contract resides on Yes contractData.restrictToOwner boolean
If true, only the owner can encrypt files via the contract (Default: true) Yes Possible Errors
Code Description 40412003 Bucket from given bucket_uuid
param not found42200202 Contract type not present 42200203 Contract type not valid 42200204 Contract name not present 42200205 Contract name not valid (length in range 1-255) 42200206 Contract description not valid (length in range 1-1000) 42200210 Computing field not present 42200211 Computing contract data not valid 50012003 Error deploying contract Response
A response is an instance of the newly created contract.
curl --location --request POST "https://api.apillon.io/computing/contracts" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"My Computing Contract\", + \"description\": \"This contract is used for encrypting files associated with NFTs.\", + \"bucket_uuid\": \"def456...\", + \"contractType\": 1, + \"contractData\": { + \"nftContractAddress\": \"0x123456789abcdef0123456789abcdef0123456789\", + \"nftChainRpcUrl\": \"https://rpc.api.moonbeam.network/\", + \"restrictToOwner\": false + } +}" +
{ + "id": "0ac0bb74-5d78-4116-9e4f-1c3e8e92f032", + "status": 201, + "data": { + "createTime": "2024-02-20T13:59:06.290Z", + "updateTime": "2024-02-20T13:59:06.289Z", + "contractUuid": "defa1296-99f4-40de-8470-a2e8497e15ad", + "bucketUuid": "bf5940dc-673e-46bf-9207-e280c00d4f6b", + "name": "My Computing Contract", + "description": "This contract is used for encrypting files associated with NFTs.", + "contractType": 1, + "contractStatus": 1, + "contractAddress": null, + "deployerAddress": "44h63RRAv5PPjFJVp11uSa6v...", + "transactionHash": null, + "data": { + "nftContractAddress": "0xB601A99a1D1...", + "nftChainRpcUrl": "https://rpc.api.moonbeam.network/", + "restrictToOwner": false, + "ipfsGatewayUrl": "https://ipfs.web3approved.com/ipfs", + "clusterId": "0x0000000000000000000000000000000000000000000000000000000000000001" + } + } +} +
List Computing Contracts
List all computing contracts with optional filters.
GET /computing/contractsQuery Parameters
All query parameters from listing request, plus:
Field Type Description Required contractStatus number
0
(created),1
(deploy initiated),2
(deploying),3
(deployed),4
(transferring),5
(transferred),6
(failed)No Response
A list of computing contracts that match the query parameters. Each entry in the list contains details about the contract.
curl --location --request GET "https://api.apillon.io/computing/contracts?project_uuid=abc123&contract_uuid=def456&contractStatus=1" \ +--header "Authorization: Basic :credentials" +
{ + "id": "14cf1522-bfa2-4190-972a-918992102ec2", + "status": 200, + "data": { + "items": [ + { + "createTime": "2024-02-20T13:58:45.000Z", + "updateTime": "2024-02-20T14:01:07.000Z", + "contractUuid": "defa1296-99f4-40de-8470-a2e8497e15ad", + "projectUuid": "4e913623-247b-4000-b650-8272430a3970", + "bucketUuid": "bf5940dc-673e-46bf-9207-e280c00d4f6b", + "name": "My Computing Contract", + "description": "This contract is used for encrypting files associated with NFTs.", + "contractType": 1, + "contractStatus": 3, + "contractAbiId": 1, + "contractAddress": "0xbdec1edc9b45a3...", + "deployerAddress": "44h63RRAv5PPjFJVp11uSa6v...", + } + ], + "total": 1, + "page": 1, + "limit": 20 + } +} +
Get Computing Contract
Retrieve details of a specific computing contract by UUID.
GET /computing/contracts/:uuidURL Parameters
Field Type Description Required uuid string
The UUID of the computing contract Yes Response fields (Computing Contract)
Based on your request to generate a table for the response fields that matches the structure seen in the bucket API documentation, here is how you can format the response fields for the "Get Computing Contract" section:
Field Type Description contractUuid
string
The unique identifier of the computing contract. bucketUuid
string
The UUID of the bucket associated with this computing contract, where encrypted files are stored. name
string
The name of the computing contract. description
string
A description of what the computing contract is used for. contractType
number
The type of computing contract. For example, 1
could represent SCHRODINGER.contractStatus
number
The current status of the computing contract. Possible values: 0
(created),1
(deploy initiated),2
(deploying),3
(deployed),4
(transferring),5
(transferred),6
(failed)contractAddress
string
The blockchain address of the computing contract. This can be null
if not yet deployed.deployerAddress
string
The address of the entity that deployed the computing contract. transactionHash
string
The transaction hash of the contract deployment. This can be null
if not yet deployed.data
object
An object containing additional data related to the computing contract. data.nftContractAddress
string
The contract address of the NFT collection used for file decryption. data.nftChainRpcUrl
string
The RPC URL of the blockchain where the NFT contract resides. data.restrictToOwner
boolean
Indicates if only the owner can encrypt and decrypt files via the contract. data.ipfsGatewayUrl
string
The URL of the IPFS gateway used by the computing contract. data.clusterId
string
An identifier for the cluster used by the computing contract. curl --location --request GET "https://api.apillon.io/computing/contracts/defa1296-99f4-40de-8470-a2e8497e15ad" \ +--header "Authorization: Basic :credentials" +
{ + "status": 200, + "data": { + "createTime": "2024-02-20T13:58:45.000Z", + "updateTime": "2024-02-20T14:01:07.000Z", + "contractUuid": "defa1296-99f4-40de-8470-a2e8497e15ad", + "bucketUuid": "bf5940dc-673e-46bf-9207-e280c00d4f6b", + "name": "My Computing Contract", + "description": "This contract is used for encrypting files associated with NFTs.", + "contractType": 1, + "contractStatus": 3, + "contractAddress": "0xbdec1edc9b45a31e1ebd38b1d1e464bbbddeb4fcd2687a39928029306039e48a", + "deployerAddress": "44h63RRAv5PPjFJVp11uSa6v52wRLmW7S5fiMWAyp3tNLh82", + "transactionHash": "0x4ea088f466eb08dc27d9d079cba1c5a35aeb1b5ff342b73bd456b9625dcd7093", + "data": { + "clusterId": "0x0000000000000000000000000000000000000000000000000000000000000001", + "ipfsGatewayUrl": "https://ipfs.web3approved.com/ipfs", + "nftChainRpcUrl": "https://rpc.api.moonbeam.network/", + "restrictToOwner": false, + "nftContractAddress": "0xB601A99a1D1804c13780F9e53d661d8bEe6D3bF0" + } + } +} +
List Contract Transactions
List transactions for a specific computing contract.
GET /computing/contracts/:uuid/transactionsURL Parameters
Field Type Description Required uuid string
The UUID of the computing contract Yes Query Parameters
All query parameters from listing request, plus:
Field Type Description Required transactionType
number
The type of transaction. Possible values: 1
(deploy contract),2
(transfer contract ownership),3
(deposit to contract cluster),4
(assign cid to nft)transactionStatus
number
The current status of the transaction. Possible values: 1
(pending),2
(confirmed),3
(failed),4
(error),5
(worker success),6
(worker failed)Response fields
Field Type Description status
number
The status code of the transaction. walletAddress
string
The wallet address which initated the transaction. transactionType
number
The type of transaction. Possible values: 1
(deploy contract),2
(transfer contract ownership),3
(deposit to contract cluster),4
(assign cid to nft)transactionStatus
number
The current status of the transaction. Possible values: 1
(pending),2
(confirmed),3
(failed),4
(error),5
(worker success),6
(worker failed)transactionStatusMessage
string
A message providing more details about the transaction status. transactionHash
string
The hash of the transaction on the blockchain. curl --location --request GET "https://api.apillon.io/computing/contracts/defa1296-99f4-40de-8470-a2e8497e15ad/transactions" \ +--header "Authorization: Basic :credentials" +
{ + "id": "c761c325-ba82-4861-9a13-866623881b59", + "status": 200, + "data": { + "items": [ + { + "id": 11, + "status": 5, + "walletAddress": "44h63RRA....", + "contractId": 4, + "transactionType": 1, + "transactionStatus": 5, + "transactionStatusMessage": "instantiated", + "transactionHash": "0x4ea088..." + } + ], + "total": 1, + "page": 1, + "limit": 20 + } +} +
Transfer Ownership
Transfer ownership of a computing contract to another address.
POST /computing/contracts/:uuid/transfer-ownershipURL Parameters
Field Type Description Required uuid string
The UUID of the computing contract Yes Body fields
Field Type Description Required accountAddress string
Wallet address of the new owner Yes Possible Errors
Code Description 40012003 Invalid address to transfer to 40012004 Transaction for transfer already exists 50012004 Transfer contract server error 50012009 Contract not in status 3
(Deployed)50012010 Contract transferring or already transferred Response
Success status
curl --location --request POST "https://api.apillon.io/computing/contracts/defa1296-99f4-40de-8470-a2e8497e15ad/transfer-ownership" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{\"accountAddress\": \"0x456...\"}" +
{ + "status": 200, + "message": "Ownership transferred successfully", + "data": { + "success": true + } +} +
Encrypt Content
Encrypt content with the private key which is securely stored on the Schrodinger contract.
POST /computing/contracts/:uuid/encryptURL Parameters
Field Type Description Required uuid string
The UUID of the computing contract Yes Body fields
Field Type Description Required content string
Content to be encrypted. If the content is an image, the format needs to be base64. Yes Possible errors
Code Description 50012009 Contract not in status 3
(Deployed)50012011 Encrypt content server error Response
The encrypted content, which has been encrypted via the encryption key stored on the schrodinger contract
curl --location --request POST "https://api.apillon.io/computing/contracts/defa1296-99 + +f4-40de-8470-a2e8497e15ad/encrypt" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{\"content\": \"Hello World\"}" +
{ + "id": "10924c6e-7ad9-449f-bcef-6cbcbdbfcf32", + "status": 201, + "data": { + "encryptedContent": "ebc36a408a68d97150aa6e42e3496a109dc5773c7f5d" + } +} +
Assign CID to NFT
Assign a content identifier (CID) to an NFT within a computing contract. The given token ID represents the NFT which will be used to decrypt the content which is stored as the given CID on IPFS.
POST /computing/contracts/:uuid/assign-cid-to-nftURL Parameters
Field Type Description Required uuid string
The UUID of the computing contract Yes Body fields
Field Type Description Required cid string
CID of the file where the encrypted content is stored Yes nftId number
Token ID of the NFT which will be used for decryption Yes Possible errors
Code Description 50012009 Contract not in status 3
(Deployed)50012012 Assign CID to NFT server error Response
Success status
curl --location --request POST "https://api.apillon.io/computing/contracts/defa1296-99f4-40de-8470-a2e8497e15ad/assign-cid-to-nft" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{\"cid\": \"QmTzY...\", \"nftId\": 22}" +
{ + "id": "da911d30-bfca-479c-9fb5-3ffa338ddf88", + "status": 201, + "data": { + "success": true + } +} +
Social API | Apillon Wiki + + + + ++ + + diff --git a/fonts/CabinetGrotesk-Variable.ttf b/fonts/CabinetGrotesk-Variable.ttf new file mode 100644 index 00000000..29cffe03 Binary files /dev/null and b/fonts/CabinetGrotesk-Variable.ttf differ diff --git a/fonts/CabinetGrotesk-Variable.woff b/fonts/CabinetGrotesk-Variable.woff new file mode 100644 index 00000000..cfc7ed23 Binary files /dev/null and b/fonts/CabinetGrotesk-Variable.woff differ diff --git a/fonts/CabinetGrotesk-Variable.woff2 b/fonts/CabinetGrotesk-Variable.woff2 new file mode 100644 index 00000000..5462835e Binary files /dev/null and b/fonts/CabinetGrotesk-Variable.woff2 differ diff --git a/fonts/IBMPlexMono-Bold.ttf b/fonts/IBMPlexMono-Bold.ttf new file mode 100644 index 00000000..2ad2fa1d Binary files /dev/null and b/fonts/IBMPlexMono-Bold.ttf differ diff --git a/fonts/IBMPlexMono-Regular.ttf b/fonts/IBMPlexMono-Regular.ttf new file mode 100644 index 00000000..93331e26 Binary files /dev/null and b/fonts/IBMPlexMono-Regular.ttf differ diff --git a/fonts/IBMPlexSans-Bold.ttf b/fonts/IBMPlexSans-Bold.ttf new file mode 100644 index 00000000..e5389d83 Binary files /dev/null and b/fonts/IBMPlexSans-Bold.ttf differ diff --git a/fonts/IBMPlexSans-Regular.ttf b/fonts/IBMPlexSans-Regular.ttf new file mode 100644 index 00000000..b5819647 Binary files /dev/null and b/fonts/IBMPlexSans-Regular.ttf differ diff --git a/fonts/NewSpirit.otf b/fonts/NewSpirit.otf new file mode 100644 index 00000000..786eb600 Binary files /dev/null and b/fonts/NewSpirit.otf differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..3050dd2a --- /dev/null +++ b/index.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Social API
The Social API provides endpoints to list, get and create subsocial entities used in the Grill widget. Spaces and posts are the main entities provided by it, which may be a bit unfamiliar to a developer who is trying to include the Grill widget into a website. Apillon changes the naming of these entities into Hub and Channel, and takes care of the whole blockchain and IPFS aspect, the result being a simple configuration which can be used to setup a Grill widget on any website.
Note: You can also create channels and hubs in the Apillon dashboard.
Use the Social API to create hubs and channels from your application. For example: you can create a channel (chatroom) for each NFT collection in your marketplace.
In all cURL examples, parameters with a colon as a prefix should be replaced with real values.
Channels
By default, a channel is created inside a hub, therefore a hub can contain multiple channels. The grill widget displays hubs as a list of channels inside it, and a channel is displayed as a chatroom. A channel can be created inside Apillon's default hub or you can create your own hub and create channels within it.
List channels
API to list all channels. Items are paginated and can be filtered and ordered through query parameters as described here .
GET /social/channelsQuery parameters
All query parameters from listing request plus:
Name Description Required hubUuid Parent hub unique identifier false Response fields (channel)
Each item is an instance of channel class, with below properties:
Field Type Description channelUuid string
Channel unique identifier hubUuid string
Unique identifier of the channel's parent Hub channelId number
Channel id on Subsocial chain. This id is used in widget. status number
Channel status ( 1: draft - deploying to chain, 5: active, 100: error
)title string
Channel name body string
Channel body - short description tags string
Comma separated tags createTime DateTime
Item create time updateTime DateTime
Item last update time curl --location --request GET "https://api.apillon.io/social/channels" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/social/channels?search=My" \ +--header "Authorization: Basic :credentials" +
{ + "id": "d9ee5982-4292-40ee-b94f-b5c234fecb98", + "status": 200, + "data": { + "items": [ + { + "channelUuid": "6f08bafe-bfd2-4151-bae1-99e515bd6c55", + "hubUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "channelId": 512, + "status": 1, + "title": "My ApillonAPI channel", + "body": "ApillonAPI channel", + "tags": "web3,fun", + "createTime": "2024-03-05T13:23:20.000Z", + "updateTime": "2024-03-05T13:23:20.000Z", + }, + ... + ], + "total": 4, + "page": 1, + "limit": 20 + } +} +
Get channel
Endpoint to get a single channel. Returns basic channel data.
GET /social/channels/:channelUuidURL parameters
Name Description Required channelUuid Channel unique identifier true Possible errors
Code Description 40419001 Channel does not exists Response fields
Response is an instance of channel class, described above.
curl --location --request GET "https://api.apillon.io/social/channels/:channelUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "4a14a0de-6dd5-4863-b031-664aa9b4b13e", + "status": 200, + "data": { + "status": 1, + "createTime": "2024-03-05T13:23:20.000Z", + "updateTime": "2024-03-05T13:23:20.000Z", + "title": "My ApillonAPI channel", + "body": "ApillonAPI channel", + "tags": "web3,fun", + "channelUuid": "6f08bafe-bfd2-4151-bae1-99e515bd6c55", + "channelId": 512 + } +} +
Create channel
API that creates channel and transmits it to blockchain. Transaction can take a while and until confirmed, channel has
status
1.POST /social/channelsBody fields
Name Type Description Required title string
Channel name true body string
Channel content/description true tags string
Comma separated tags false hubUuid string
Hub unique identifier - if not specified the channel is created inside a default hub false Possible errors
Code Description 40419001 Specified hub does not exist 42219002 Body is missing required properties 50019004 Parent hub is in invalid state. It is probably not yet transmitted and confirmed on the chain (status = 1) 50019003 Internal error - Apillon was unable to create channel. Response
Response is an instance of channel class, described above.
curl --location --request POST "https://api.apillon.io/social/channels" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"title\": \"Apillon API channel\", + \"body\": \"Lets talk about apillon API\", + \"tags\": \"Apillon,API,WEB3\" +}" +
{ + "id": "68c32a2c-f2b0-4580-916b-2c1b12926228", + "status": 201, + "data": { + "status": 1, + "createTime": "2024-03-06T20:28:12.309Z", + "updateTime": null, + "title": "Apillon API channel", + "body": "Lets talk about apillon API", + "tags": "Apillon,API,WEB3", + "channelUuid": "c1d709b8-16fb-493e-a317-16d8b8ce623d", + "hubUuid": "d6355fd3-640d-4803-a4d9-79d875abcb5a", + "channelId": null + } +} +
Hubs
List hubs
API to list all hubs in project. Items are paginated and can be filtered and ordered through query parameters as described here .
GET /social/hubsResponse fields (hub)
Each item is an instance of hub class, with below properties:
Field Type Description hubUuid string
Hub unique identifier hubId number
Hub id on Subsocial chain. This id is used in widget or in grillapp.net. Example: https://grillapp.net/12927
.status number
Hub status ( 1: draft - deploying to chain, 5: active, 100: error
)name string
Hub name about string
Hub about - short description tags string
Comma separated tags numOfChannels number
Number of channels in hub createTime DateTime
Item create time updateTime DateTime
Item last update time curl --location --request GET "https://api.apillon.io/social/hubs" \ +--header "Authorization: Basic :credentials" +
curl --location --request GET "https://api.apillon.io/storage/buckets?search=My hub" \ +--header "Authorization: Basic :credentials" +
{ + "id": "88b3140f-035e-446d-bda7-1f95e7343619", + "status": 200, + "data": { + "items": [ + { + "hubUuid": "7b59dc14-5ea1-48df-b4c9-a8395690d225", + "hubId": "55545", + "status": 5, + "createTime": "2024-03-05T12:18:20.000Z", + "updateTime": "2024-03-05T13:21:25.000Z", + "name": "Apillon API hub", + "about": "Apillon API hub", + "tags": "web3,fun", + "numOfChannels": 4 + } + ... + ], + "total": 3, + "page": 1, + "limit": 20 + } +} +
Get hub
Endpoint to get hub. Endpoint returns basic hub data.
GET /social/hubs/:hubUuidURL parameters
Name Description Required hubUuid Hub UUID, visible in developer console true Possible errors
Code Description 40419001 Hub does not exists Response fields
Response is an instance of hub class, described above. Only difference is field
numOfChannels
, which is not returned by this endpoint.curl --location --request GET "https://api.apillon.io/social/hubs/:hubUuid" \ +--header "Authorization: Basic :credentials" +
{ + "id": "e4ec496a-121a-4033-9451-5b53ae3d0307", + "status": 200, + "data": { + "status": 5, + "createTime": "2024-03-05T12:18:20.000Z", + "updateTime": "2024-03-05T13:21:25.000Z", + "name": "Apillon API hub", + "about": "Apillon API hub", + "tags": "web3,fun", + "hubUuid": "7b59dc14-5ea1-48df-b4c9-a8395690d225", + "hubId": "55545" + } +} +
Create hub
Endpoint to create a hub and transmit it to blockchain. Transaction can take a while and until confirmed, the hub has
status
1 (Draft).POST /social/hubsBody fields
Name Type Description Required name string
Hub name. true about string
Hub description false tags string
Comma separated tags false Possible errors
Code Description 42219001 Body is missing required properties 50019002 Internal error - Apillon was unable to create hub. Response
Response is an instance of hub class, described above.
curl --location --request POST "https://api.apillon.io/social/hubs" \ +--header "Authorization: Basic :credentials" \ +--header "Content-Type: application/json" \ +--data-raw "{ + \"name\": \"Apillon API hub\", + \"about\": \"Apillon API hub\", + \"tags\": \"Apillon,API,WEB3\" +}" +
{ + "id": "6570cd41-4401-4ba4-92e8-060617f18f65", + "status": 201, + "data": { + "status": 1, + "createTime": "2024-03-06T20:28:12.309Z", + "updateTime": null, + "name": "Apillon API hub", + "about": "Apillon API hub", + "tags": "Apillon,API,WEB3", + "hubUuid": "65527f5b-054d-453a-a9a9-b29cd00b39bb", + "hubId": null + } +} +
Apillon Wiki + + + + ++ + + diff --git a/web3-services/1-good-to-know.html b/web3-services/1-good-to-know.html new file mode 100644 index 00000000..27723f55 --- /dev/null +++ b/web3-services/1-good-to-know.html @@ -0,0 +1,33 @@ + + + + + + + + +Good to know | Apillon Wiki + + + + ++ + + diff --git a/web3-services/10-web3-infrastructure.html b/web3-services/10-web3-infrastructure.html new file mode 100644 index 00000000..1e52fde9 --- /dev/null +++ b/web3-services/10-web3-infrastructure.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Good to know
The provision of Apillon Web3 services comes with certain specifics that are important to understand before using the Apillon dashboard.
Before jumping to the API section, please make sure you fully understand what to expect from each service so you can plan your Web3 application architecture and development accordingly.
Apillon integrates multiple Polkadot parachains and offers access to them in a unified way via modules on the developer dashboard and through Apillon APIs.
Concepts
Centralized vs. decentralized
In the current state, Apillon is a Web3 hybrid platform, meaning that some services are still run by centralized solutions. This sort of compromise is quite common in other Web3 solutions, especially where a choice had to be made between fast development and simple UX vs. full decentralization.
That said, Apillon’s back end is designed to evolve towards fully decentralized service and an unstoppable way of operation with each new update, slowly removing the hybrid compromise and becoming a fully Web3 platform.
If you are interested in the details of Apillon’s architecture and back-end, want to open a debate around it or contribute on GitHub, feel free to get in touch in the development channel on Apillon Discord.
Production vs. Beta
Apillon is currently in the Closed Beta stage. Anyone can register an account on Apillon but only assigned users may get access to test the platform’s Beta features.
To join the Apillon Closed Beta program, please follow the following steps.
- If you do not yet have an Apillon account, create one on https://app.apillon.io/register.
- Log in to your account.
- At the bottom of the welcome page, find an ID number assigned to your account.
- Copy the ID number and paste it to the closed-beta channel on Apillon Discord.
- Wait for an email with an invitation to join the Apillon Closed Beta program and access the platform’s features.
Note: Apillon Closed Beta delivers no guarantees related to functionalities or access and is intended for testing purposes only. Beta features also come with several limitations, which will be removed with each platform update as more and more users deliver feedback on Closed Beta and help improve the platform’s services.
Terminology and underlying technology
IPFS
IPFS is a distributed system for storing and accessing files, websites, applications, and data.
When you add a file to IPFS, your file gets split into smaller chunks, is cryptographically hashed, and is given a unique fingerprint called a content identifier (CID). This CID acts as a permanent record of your file as it is at that point in time.
When other nodes search your file, they ask peer nodes which one is storing the content referenced by the file's CID. When viewing or downloading your file, they cache a copy. This way, they become a new provider of your content until their cache is cleared.
Crust Network
Crust Network is a decentralized cloud storage provider that pursues three core Web3 values: decentralization, privacy, and assurance. Crust supports multiple storage-layer protocols, such as IPFS, and delivers instantly accessible on-chain storage functions. Crustʼs technical stack can also support data manipulation and computing.
Crust Network has three main functions: NFT and metaverse metadata storage, personal file storage, and website/dapp hosting.
Storage buckets
Storage buckets are Apillon’s Web3 Storage abstraction that allows developers to utilize IPFS and Crust to store files in an unstoppable, decentralized way.
Learn more about storage buckets.
Web3 infrastructure | Apillon Wiki + + + + ++ + + diff --git a/web3-services/2-web3-storage.html b/web3-services/2-web3-storage.html new file mode 100644 index 00000000..3950d7d0 --- /dev/null +++ b/web3-services/2-web3-storage.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 infrastructure
Introduction
Apillon's Infrastructure Service provides developers with the essential infrastructure required to build modern Web3 applications. Our infrastructure services currently include:
- RPC Service: Reliable and high-performance access to blockchain networks
- Indexing Service: Efficient data indexing and querying capabilities
These services are designed to simplify Web3 development while ensuring scalability and reliability for your decentralized applications.
RPC Service
The RPC (Remote Procedure Call) service in Apillon's infrastructure provides seamless connectivity to blockchain networks, allowing developers to interact with blockchain data and execute smart contracts. By utilizing Dwellir as the RPC provider, Apillon ensures reliable and efficient access to blockchain nodes. The service is designed for flexibility, enabling developers to create, manage, and optimize their own RPC endpoints through a user-friendly interface.
Dwellir
Dwellir is a highly reliable and scalable RPC (Remote Procedure Call) provider that powers the Apillon infrastructure, enabling developers to interact with various blockchain networks. Dwellir ensures secure, low-latency connections and high availability, allowing developers to execute smart contract functions, query blockchain data, and perform transactions seamlessly.
Core Services:
- Multi-Blockchain Support: Dwellir supports a wide range of blockchain networks, including popular ecosystems like EVM (Ethereum Virtual Machine), Substrate-based chains, and others, providing extensive coverage and flexibility.
- High Availability and Redundancy: Dwellir's infrastructure is designed with built-in redundancy and geo-distributed nodes, ensuring minimal downtime and reliable access to blockchain networks.
- Secure Connections: Supports both HTTPS and WSS (WebSocket Secure) protocols for encrypted communication, ensuring data privacy and integrity during transmission.
- API Key Management: Allows project owners to create, manage, and revoke API keys, offering fine-grained control over who can access RPC endpoints.
How it works
- Activate RPC Service for a Project: Project owner activates RPC service for their project in the Apillon dashboard.
- Create an RPC API Key: Developers can generate an API key from the Apillon dashboard, which is used to authenticate requests to the RPC service.
- Set Favorite Endpoints: Developers can mark the preferred RPC endpoints as "favorites" for selected API key to make them easily accessible through the Apillon dashboard.
- Manage API Keys: Project owners can manage API keys in the Apillon dashboard, allowing for flexible management of access to RPC endpoints.
- Monitor Usage: Developers can monitor the usage of their RPC keys in the Apillon dashboard, allowing for better control over their infrastructure costs.
Pricing
The RPC service is available with two main plants:
Free Plan (default):
- RPC Calls: Up to 5 million RPC calls per month
- API Keys: Allows a single API key per user
- Cost: Free of charge
Developer Plan:
- RPC Calls: Increases the limit to 25 million RPC calls per month
- API Keys: Allows up to 5 API keys per user
- Cost: 49.99€ per month
Indexing service
The Indexing Service is a crucial component of Apillon's infrastructure, designed to efficiently index and query blockchain data. It plays a vital role in powering our Web3 services and enhancing the overall user experience. In the background, Apillon uses the Subsquid indexing framework and Subsquid Cloud to run indexing nodes. Developers can create their own indexers or use one of the available templates, and can query more than 150 blockchain networks.
SQD (Subsquid) Web3 Data Infrastructure
SQD is a powerful Web3 data infrastructure platform that offers:
- High-Performance Data Indexing: Processes blockchain data up to 100x faster than traditional providers
- Comprehensive Network Coverage: Supports 150+ blockchain networks including EVM, SVM, Substrate, and more
- Cost-Efficient Infrastructure: Eliminates egress fees, users only pay for compute resources
- Core Services:
- SQD Network: A decentralized data lake for Web3
- Squid SDK: Advanced blockchain indexing toolkit
- SQD Cloud: Enterprise-grade hosted indexing service
Used by major projects like PancakeSwap, Railgun, and Chainsafe, SQD processes hundreds of thousands of terabytes of blockchain data while significantly reducing infrastructure costs.
Workflow
- Create an indexer: Developers create an indexer in the Apillon Indexer Dashboard.
- Adjust indexer source code: Use one of the available templates for squid indexer or write your own.
- Deploy indexer: Deploy your indexer through the Apillon CLI.
- Use indexer: Use the indexer in your application.
How it works
The indexing process follows a standardized workflow while allowing for flexible implementation approaches. Developers can leverage existing templates as a starting point and customize them according to their specific requirements. Before deployment, indexers can be thoroughly tested in a local environment to ensure proper functionality.
An indexer implementation consists of three core components:
- Indexer Processor: Handles data fetching and processing from the blockchain
- Indexer Database: Stores the processed blockchain data
- Indexer API: Provides GraphQL endpoint for querying the indexed data
To configure an indexer, developers need to specify:
- RPC Node Endpoint: Connection point to the blockchain network
- Starting Block: Initial block number from which to begin indexing
- Target Events and Fields: Specific blockchain events and data fields to monitor and process
The indexer processor continuously fetches new blocks from the specified starting point up to the latest block, processing the relevant data according to the configured rules and storing it in the indexer database.
The processed data becomes accessible through a GraphQL API, providing a flexible and efficient way to query the indexed blockchain data. This API supports complex queries, filtering, and data relationships, enabling developers to retrieve exactly the information they need for their applications.
Pricing
Indexers are billed based on the amount of processed and stored data and the number of queries made to the indexer API. Project need to have sufficient credit balance to deploy an indexer. The deployment itself is free of charge, Apillon charges for the working indexer only. Indexers are billed daily - each day Apillon calculates price for the indexer and uses project's credit balance to pay for it.
If project's credit balance is insufficient, indexer will be hibernated and later deleted after few days if no action is taken.
Conclusion
Apillon's Web3 Infrastructure services provide developers with powerful tools to build and scale decentralized applications. Through SQD integration, developers can efficiently index and query blockchain data across multiple networks, while maintaining cost-effectiveness and high performance. The platform's user-friendly approach, combined with its robust technical capabilities, makes it an ideal choice for projects of any size looking to leverage blockchain data effectively.
Web3 Storage | Apillon Wiki + + + + ++ + + diff --git a/web3-services/3-web3-hosting.html b/web3-services/3-web3-hosting.html new file mode 100644 index 00000000..280e6f9c --- /dev/null +++ b/web3-services/3-web3-hosting.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Storage
Apillon Web3 Storage is a Web3-based storage service that implements AWS S3 (as cache to optimize upload of large files), IPFS, and Crust Network (to pin files on multiple IPFS nodes).
To streamline the development experience, Apillon Web3 Storage service further introduces the concept of storage buckets.
Storage bucket
A storage bucket is a virtual container that holds directories and files in a hierarchical structure. Each directory can contain multiple subdirectories and multiple files, and so on for each subdirectory.
Before using the Apillon Web3 Storage service, a storage bucket should be created on the Apillon Dashboard. Once ready, it enables file storage from both the Apillon dashboard and the API endpoints.
File storage
The process below describes how files are stored with Apillon storage buckets.
- Uploaded files land on a reputable centralized cloud provider to ensure fast file capture.
- Once the files are received, they proceed to the decentralized Apillon IPFS gateway, where Crust Network initiates the pinning and replication process.
- Once the files are accessible on the IPFS network, Crust spreads them through multiple IPFS nodes globally, ensuring file distribution and decentralized accessibility.
File deletion
Each file hosting that passes through Crust’s pinning and replication service is paid upfront for a minimum period of 6 months. Apillon has no control over amending that period, so keep in mind that all files you deploy to Apillon storage buckets will remain accessible for that period of time.
If you decide to delete a file before the 6-month period expires, the file is marked for deletion. This means that Apillon does not extend the storage lease on Crust once the 6-month period expires, which leads to file deletion on all IPFS instances.
However, to make the storage service more dynamic, Apillon artificially lowers the file deletion period to 3 months. Once this period expires, the load of deleted files in your storage bucket is emptied, and the storage capacity is made available for uploading new files.
Note: These limitations are in the nature of the Apillon Closed Beta release, which is intended for testing purposes only. Once the Beta period is up, the limitations of Apillon Web3 services will be adjusted to more realistic production requirements.
Learn more: Web3 Storage FAQ
Web3 Hosting | Apillon Wiki + + + + ++ + + diff --git a/web3-services/4-nfts.html b/web3-services/4-nfts.html new file mode 100644 index 00000000..64930582 --- /dev/null +++ b/web3-services/4-nfts.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Hosting
Apillon Web3 Hosting is a Web3-based storage service that allows you to increase the accessibility of your website or app and make it unstoppable, as it gets hosted on a decentralized network of nodes worldwide.
Decentralized hosting of a website or an app on Apillon is very similar to the usage of storage buckets in decentralized storage. It implements AWS S3 (as cache to optimize upload of large files), IPFS, and Crust Network (to pin files on multiple IPFS nodes).
Website/app hosting
Note: At this point, only hosting of static websites is supported in Apillon Web3 Hosting service, while dynamic websites will be supported in future versions of Apillon.
The process below describes how a static website or app is hosted decentrally with Apillon Web3 Hosting.
- Uploaded files land on a reputable centralized cloud provider to ensure fast file capture.
- Once the files are received, they proceed to the Apillon node. They are accessible through the IPFS gateway until moved from staging to production.
- Once the files move from staging to production, they proceed to the decentralized Apillon IPFS gateway, where the pinning and replication process is started with Crust.
- At this point, a custom domain can be connected to the website/app, which starts the SSL certificate generation process in the Apillon gateway.
- Finally, the domain’s DNS records can be migrated to Apillon, and website or app can be launched using decentralized hosting.
Deployment
To deploy a Web3 website or application, follow the process below:
- Register an account on Apillon.
- Log in to your Apillon dashboard.
- In the menu on the left, under Services, navigate to Hosting, and click "Get started."
- Drag and drop your static website to the Hosting view and wait for the upload to finish.
- Once the upload is complete and the status turns to "successful," you can deploy the website to Staging.
- Click on the Staging tab to monitor the progress.
- Deployment of web files will go through several statuses, ending with "successful."
- Click "Deploy to production" to get files replicated and unstoppable with decentralized hosting.
- Once the deployment to production is finished, click "Add domain" and "Configure domain" to make the domain you own point to the Apillon hosting.
- Once DNS is updated, your unstoppable website will become available on the connected domain.
If you want to redeploy the website or app with new changes, repeat the process above simply by uploading the whole website or app via Apillon Hosting view.
Note: Repeat deployment to Apillon Hosting will continue spending the Hosting storage capacity. However, every 3 months, the capacity will be renewed after older versions are deleted.
Learn more: Web3 Hosting FAQ
File deletion
Each file hosting that passes through Crust’s pinning and replication service is paid upfront for a minimum period of 6 months. Apillon has no control over amending that period, so keep in mind that all files you deploy to Apillon storage buckets will remain accessible for that period of time.
If you decide to delete a file before the 6-month period expires, the file is marked for deletion. This means that Apillon does not extend the storage lease on Crust once the 6-month period expires, which leads to file deletion on all IPFS instances.
However, to make the hosting service more dynamic, Apillon artificially lowers the file deletion period to 3 months. Once this period expires, the load of deleted files in your storage bucket is emptied, and the storage capacity is made available for uploading new files and redeployment of website or app.
Note: In the Apillon Closed Beta stage, single file changes are not supported. Instead, hosting is treated as batch upload, meaning that with every new version of a website or app, its contents are rewritten, which leads to new files getting pinned and replicated on Crust. This limitation will be improved in future dashboard updates to enhance the developer experience. In case you need a larger storage capacity, feel free to get in touch on Apillon Discord, and we will grant you extra space or more storage buckets.
NFTs | Apillon Wiki + + + + ++ + + diff --git a/web3-services/5-web3-authentication.html b/web3-services/5-web3-authentication.html new file mode 100644 index 00000000..b5d0b1e0 --- /dev/null +++ b/web3-services/5-web3-authentication.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki NFTs
Apillon NFT service supports drag-and-drop compilation, deployment, and minting of non-fungible assets.
Service currently supports creating NFT collections on multiple EVM and substrate chains:
- Moonbeam Network (EVM and Substrate based NFTs)
- Astar Network (Substrate based NFTs)
- Unique Network (Substrate based NFTs)
NFT media
NFT media are at the front and center of an NFT collection.
Apillon NFT Service currently runs on the Moonbeam, Astar and Unique parachains, and supports ERC-721 and ERC-6059 standards for NFTs on EVM and PSP-34 standard and Unique Native NFTs for substrate.
The ERC-721 standard packs any file format into permanently stored content on the blockchain. Thanks to Moonbeam’s and Astar’s EVM compatibility, it can be deployed quickly and efficiently with Apillon.
Native NFTs on Unique Network are streamlined, blockchain-integrated tokens that offer simplicity, speed, cost-efficiency, and enhanced security, eliminating the complexities of traditional smart contract-based NFTs.
NFT metadata
NFT metadata is the backbone of an NFT collection and communicates the essential information of NFT files — the file name and format, date of creation, owner, etc.
It can also include certain attributes that make an NFT one of a kind.
As an essential component of NFT collections, metadata should be managed and stored carefully. To ensure its permanent access free of third-party intervention, Apillon stores it either on-chain via Unique metadata schema or on a decentralized network with Apillon Web3 Storage bucket, Crust Network, and IPFS.
Apillon supports metadata that is structured according to the official OpenSea metadata standard.
NFT deployment
To deploy an NFT collection on either the Moonbeam or Astar Network, follow the process below:
- Log in to your Apillon account.
- In the menu on the left, navigate to NFTs, and click "Start creating NFTs."
- Upload NFT metadata in CSV format to a decentralized network to keep it permanently accessible and prevent losing access to it. When uploaded using the drag-and-drop NFT wizard, the metadata file is automatically stored using the Apillon Web3 Storage bucket. It can also be uploaded manually in the Web3 Storage service and deployed by calling the metadata URI.
- Upload NFT files from local storage, and double-check if the number of files matches the file numbers in the metadata file.
- Preview NFTs, both in table and list view, to verify the parsing of the CSV metadata file. Check for potential mismatches between NFT files and their metadata.
- Choose the name, symbol, and network (Chain) to deploy your collection, either Moonbeam Mainnet, Moonbeam Testnet, or Astar Mainnet.
- Set unlimited or limited supply with the exact number of NFTs you wish to create. Determine your collection's behavior by making NFTs revokable (e.g., with limited-time NFTs) or soulbound to disable tradeability and tie them to the originator's address. Set the % of royalties to collect and the recipient's address. Optionally, you can set the date and details of the collection's public drop and make it publicly available for minting - reserve some for yourself to avoid having to pay for them. Without drop, only the creator can mint NFTs, not the general public. If you sourced metadata online, provide its base URI and extension.
- Preview and go back if needed. This is the last step that allows editing, as moving forward with the deployment inscribes NFTs on the blockchain and makes them immutable.
- Deploy on the blockchain. View the transaction on blockchain explorer or see its contents in the newly created Web3 Storage bucket.
- Display NFTs on a website. Fork or integrate the Apillon website template code in JavaScript, Vue or React on GitHub and add the NFT collection to any webpage. Customize the code, configure the logic, and update the configurable file with the NFT collection's own addresses. Run locally and redeploy to Apillon Web3 Hosting.
- Mint NFTs to trade them as assets on the blockchain. On the Apillon dashboard, click on the NFT collection name, and under Actions in the top right corner, click "Mint". Once minted, NFTs are linked to your wallet.
- List NFTs on marketplaces such as tofuNFT, display them locally on your website or dapp, or share them with intended recipients.
Note: Deploying NFTs on the blockchain makes them permanently immutable. To keep NFT metadata editable, upload it manually to Apillon Web3 Storage with IPNS.
Learn more:
Web3 Authentication | Apillon Wiki + + + + ++ + + diff --git a/web3-services/6-web3-social.html b/web3-services/6-web3-social.html new file mode 100644 index 00000000..76dba4d8 --- /dev/null +++ b/web3-services/6-web3-social.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Authentication
Apillon offers a method for users to integrate an alternative authentication approach using a decentralized identifier (DID) stored on the KILT parachain. KILT-powered decentralized identity includes a credential that comprises a user's email address, which can be attested by Apillon or SocialKYC. Any user can create their own decentralized identity, verify their email address through Apillon's OAuth protocol, and then use this decentralized account and credential to verify their identity on third-party platforms.
Authentication workflow
Email Verification: This is the initial step in the process of generating a decentralized identity, which also serves as part of the attestation process, as it attests ownership of the provided email address.
Account Generation: A KILT wallet address derived from a BIP39 mnemonic is created. This mnemonic serves as the master key for accessing the account. Users are prompted to store this mnemonic securely.
Identity Generation: This step typically takes one to five minutes. On the front end, the user signs the operation for DID creation with their Sporran wallet, which is then submitted to the blockchain. The result is a DID document. Once the process is complete, the DID document is queried from the blockchain and returned to the user. All querying occurs on the front end, ensuring that Apillon never gains access to the DID document or the generated mnemonic from the previous step. The user has the option to link their newly generated DID with their account, making it possible to retrieve a DID for an account and vice-versa.
Attestation: Attestation consists of two steps. The first is verifying a user's claim, which is the result of the initial email verification step. The second step involves creating a verifiable credential, signed by both Apillon and the claimer (using the authentication key derived from the generated mnemonic in the second step). This credential's root hash is then submitted to the blockchain. The combination of these steps is referred to as the attestation process, and the credential should be stored securely.
DID and Verifiable Credential Storage: The user is prompted to save the generated files. The generated credential can also be imported into the Sporran wallet for convenience and safekeeping.
Identity Revocation: The user has the option to request the revocation of their DID through Apillon's OAuth website.
The first step mirrors the registration process, where an email with a unique token is sent to the user.
A revocation operation for the DID document is issued to the blockchain, rendering the identity invalid. All associated verifiable credentials also become unusable as a result of this process. The wallet account generated in the second step of the registration process remains valid, and all tokens associated with this account address remain accessible and valid.
Credential Restore: The user can restore their previously generated credentials through Apillon's OAuth website in case they lose access to them. The first step is the same as the registration process and involves sending an email with a unique token. Upon following the verification email link, the user is redirected to a secure page, where the saved credential is returned to them.
Credential Verification: The verification process requires two parameters: a verifiable credential (which can be in JSON format or pasted as plain text in the text area) and the mnemonic passphrase used to sign the credential.
From the provided credential and mnemonic, a presentation is created. The presentation should only contain the user's email address, which is the single property requested by Apillon to complete the verification process. The verification process also checks whether the owner of the credential matches the address that signed the request. The presentation is considered valid if the integrity check mentioned above succeeds.
Alternatively, if a user has imported their previously generated credentials into the Sporran wallet, they can log in directly with Sporran without the need to provide the credentials in text or file format, or the mnemonic passphrase. This allows users to select an existing credential from their wallet and sign the request directly.
Read more: Guide - Log in to Apillon dashboard using KILT decentralized identity
Apillon Open Authentication (OAuth)
The OAuth flow begins when a user interacts with the page, triggering an action that opens the Apillon OAuth pop-up window and initiating the OAuth process. The user can then prove their identity either by providing a credential generated through Apillon and stored by the user or by verifying their credential directly through the Sporran wallet in case they have already imported their credential.
If a user does not yet have a generated decentralized identity (DID) stored on the KILT blockchain, they can also generate one using the OAuth pop-up window.
Once a user completes the verification process, the OAuth pop-up sends an event to the main web application, signaling the completion of the OAuth flow and providing an authentication token. This token can be used by the app to verify the user's identity through Apillon's API.
After this, the web app obtains the user's Apillon account's email address and can use this information to provide access to any services the site offers, ensuring that the user has successfully verified their identity using verifiable credentials attested by Apillon.
Projects, websites, or users interested in offering a decentralized log-in option via Apillon using a verifiable credential can follow the integration guide provided in the integration section.
Web3 Social | Apillon Wiki + + + + ++ + + diff --git a/web3-services/7-web3-compute.html b/web3-services/7-web3-compute.html new file mode 100644 index 00000000..4cdb819d --- /dev/null +++ b/web3-services/7-web3-compute.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Social
Apillon offers web3 alternatives for social networking between end users. This is powered by subsocial network.
Currently, Apillon offers a web3 chat alternative called grill chat that allows anonymous chatting in which content can be displayed anywhere integrating the subsocial grill chat.
Chat
You can create the chat rooms via Apillon dashboard and integrate the grill chat widget into your page via
html
andjavascript
. You can also manage your chat rooms via API and SDK for simple on the fly creation.You can create a single chat room or a hub containing multiple chat rooms.
Hub A hub is a container of multiple chat rooms. When integrating the grill chat widget you can either show a single chat or a whole hub containing multiple chat rooms that the end user selects to chat in.
Channel Channel is the actual chat room the users can talk in. s
Web3 Compute power | Apillon Wiki + + + + ++ + + diff --git a/web3-services/8-web3-cloud-functions.html b/web3-services/8-web3-cloud-functions.html new file mode 100644 index 00000000..6f5022cc --- /dev/null +++ b/web3-services/8-web3-cloud-functions.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Compute power
In the world of web3 we have smart contracts that power some core backend logic that should be on chain, we have ipfs hosting to host our webpages in an unstoppable manner. But running actual backend code in an decentralized manner is a missing piece. At Apillon we are tackling this problem and researching different options of how to provide fully distributed and unstoppable backend. Currently this results in a specific service for fully decentralized NFT gated file access powered by Phala.
NFT gated file access
Phala PHAT contracts are utilized to provide file encryption capabilities where no one can access the encryption key. However, a user with a specific NFT can utilize it. This results in a NFT gated fully encrypted file storage that is unstoppable in every way.
Through Apillon you can deploy and configure the PHAT contract and use preexisting frontend templates to fully use the functionalities.
For using the NFT gated file access there are a few prerequisites:
- You need to create a NFT collection. When deploying a PHAT contract you need to specify a NFT collection to which it is tied. And for each NFT you can either set the encrypted content that only the NFT owner will be able to access or make the NFT owner the one that can upload the file to storage.
- You need a IPFS storage bucket. Any content uploaded via PHAT contract will need to be stored somewhere. For this, you need to create an IPFS bucket (to make sure the content is distributed. Only encrypted content is ever stored).
With these prerequisites done you can then set this information and deploy your PHAT contract. Deployment and execution costs are handled by Apillon.
You can create a PHAT contract either through the dashboard or via API / SDK.
Web3 Cloud Functions | Apillon Wiki + + + + ++ + + diff --git a/web3-services/9-embedded-wallets.html b/web3-services/9-embedded-wallets.html new file mode 100644 index 00000000..f4291a1b --- /dev/null +++ b/web3-services/9-embedded-wallets.html @@ -0,0 +1,33 @@ + + + + + + + + +Apillon Wiki Web3 Cloud Functions
Introduction
Apillon's Cloud Function service provides developers with the ability to deploy decentralized computing tasks across a distributed network of mobile devices. This ensures that applications and scripts can run in a secure, unstoppable manner, avoiding reliance on centralized infrastructure. By utilizing Acurast's decentralized compute architecture, Apillon offers an alternative to traditional cloud services, ensuring privacy, resilience, and global scalability.
What is Acurast?
Acurast is a decentralized, serverless cloud framework that separates the layers of cloud infrastructure into distinct components: consensus, execution, and application. By using mobile devices as decentralized processors, Acurast enables verifiable and confidential computations. This design allows developers to deploy applications without needing to rely on centralized systems, ensuring privacy and data verifiability throughout the entire process.
Through Acurast, developers can run decentralized applications (dApps) that interact seamlessly with both Web3 and Web2 systems. Acurast matches computational jobs to a network of processors using its consensus layer, ensuring secure and efficient task execution. Learn more.
Core Features of Apillon's Cloud Function Service
Script Deployment and Execution Apillon Cloud Functions offer developers a familiar environment similar to centralized cloud providers like AWS or Google Cloud. Developers can deploy scripts (e.g., JavaScript or Node.js) as on-demand functions or long-running tasks. These scripts can handle tasks like calling APIs or hosting continuous services such as Discord bots. Apillon also supports scheduled executions through cron expressions, enabling automatic execution without manual intervention.
Decentralized, Verifiable Compute Apillon leverages Acurast’s execution layer, which includes both the Acurast Secure Hardware Runtime (ASHR) and Zero-Knowledge Proof (ZKP)-based runtimes. This setup allows for secure, tamper-proof execution of sensitive computations. Developers can store secrets like API keys or wallet private keys in encrypted environments, which are used as part of their cloud function deployments without the risk of exposure.
Unstoppable Application Execution Apillon ensures that once a cloud function is deployed on the decentralized network, it remains unstoppable by any central authority. By distributing the execution across multiple processors, Apillon guarantees that a single point of failure cannot disrupt the task. This makes Apillon especially suitable for decentralized applications (dApps) that require continuous, reliable execution.
Cross-Chain and Web3 Integration The Cloud Function service integrates smoothly with various blockchain ecosystems, including Ethereum, Tezos, and others. Developers can specify where the results of their computations are delivered, whether to a blockchain or a Web2 system. This cross-chain functionality allows Web3 developers to build highly interoperable, decentralized applications.
How It Works
Cloud Function Creation: Developers can create cloud functions via Apillon by providing parameters like the function name, description, and project UUID. This is done either through a simple API call or through Apillon’s developer console. Once created, the cloud function is registered on the decentralized network and ready to be executed on available processors.
Job Creation and Matching: After creating a cloud function, developers define specific tasks or jobs. These jobs include parameters like memory usage, storage needs, and scheduling details. Once a job is created, Acurast’s consensus layer matches it with appropriate processors based on their capabilities and reputation. Apillon automates aspects of job creation, such as uploading and pinning the script file to IPFS. Apillon also monitors job status, ensuring it is successfully matched with a processor, simplifying the entire deployment process.
Job Execution: Once matched, processors execute the jobs within Acurast’s secure hardware or ZKP-based runtimes. Apillon provides a dedicated API gateway for developers to trigger job executions, making it easy to initiate compute tasks just like with centralized cloud services. This seamless access eliminates the need for direct interaction with Acurast’s underlying infrastructure.
Environment Management: Developers can set up and manage runtime environments by defining environment variables, which are fully encrypted and securely handled by Apillon. If a new job is deployed under the same cloud function, Apillon automatically transfers the environment variables, ensuring continuity in execution without manual intervention.
Execution Control and Monitoring: Apillon offers real-time monitoring and execution control. Developers can track usage statistics, success rates, and deployment health through a dashboard. In the case of processor failure, Apillon’s health check mechanism automatically redeploys jobs to new processors, ensuring continuous execution without downtime.
Job Versioning: Apillon supports versioning, allowing developers to maintain multiple versions of their cloud functions. They can switch between versions or roll back to previous versions without disrupting the API endpoint. This ensures flexibility in managing application updates.
Load Balancing: Apillon implements a load balancing mechanism that distributes jobs across multiple processors. If a processor becomes overloaded or inaccessible, Apillon automatically switches to an alternative processor, ensuring uninterrupted service and optimal performance.
Conclusion
Apillon’s Cloud Function service provides a groundbreaking solution for developers seeking decentralized computing. By leveraging mobile devices and Acurast’s secure, verifiable compute architecture, Apillon allows developers to deploy unstoppable, cross-chain applications in a simple, seamless manner. Key benefits include easy integration with Web3 platforms, real-time monitoring, environment management, job versioning, and load balancing—all ensuring a reliable, privacy-focused, and scalable solution for decentralized computing.
Embedded Wallets | Apillon Wiki + + + + ++ + +Apillon Wiki Embedded Wallets
Introduction
Apillon's Embedded Wallet Service redefines crypto asset management by blending the simplicity of Web2 onboarding with the security of hardware wallets and the convenience of hot wallets. It offers a secure, non-custodial, and fully decentralized solution for managing crypto assets seamlessly within applications.
What is an Embedded Wallet?
An embedded wallet is an in-app wallet that provides a streamlined experience for generating and signing transactions with your private key, without requiring separate downloads or installations. By integrating directly into applications via an SDK, embedded wallets simplify onboarding, allowing users to log in with just their email and a verification code. This setup eliminates mnemonic phrases, making the experience accessible and secure.
How it Works
- Integration: Developers integrate the wallet using a lightweight SDK.
- Authentication: Users register with an email and verification code, bypassing mnemonic phrases. They log in using an email and passkey.
- Decentralization: Private keys are securely generated, encrypted, and managed within confidential smart contracts powered by Oasis Protocol.
- Transaction Security: Transactions are signed within the smart contract, with user authentication ensuring that private keys are never exposed.
Security of Embedded Wallets
- Passkey Authentication: Users log in using passkeys—unique cryptographic keys stored securely on their devices, which allow biometric data (fingerprint, face scan) for verification, ensuring top-level security.
- Decentralized Key Management: Managed by Oasis’s confidential smart contracts, private keys are never exposed or accessible to third parties.
- Phishing Protection: Passkey authentication prevents phishing attacks by eliminating password-based logins, usable only on the original website.
Workflow
- User Onboarding: New users log in with their email and create a passkey.
- Wallet Generation: The SDK requests a wallet from the Oasis Network, where a smart contract securely generates and encrypts the private key.
- Transaction Signing: Transactions are securely signed by the smart contract, ensuring the private key remains within the encrypted environment.
Comparison with Other Providers
Provider Wallet Name Security Method Authentication Methods Private Key Exposure Wallet Scope Decentralization thirdweb In-App Wallet Shamir's Secret Sharing with HSM Email, Social Media Exposed in browser Per app 2/3 keys managed by thirdweb Dynamic.xyz Email, Social Wallet Outsourced to Turnkey - secure enclaves Passkey, Email, Social Media None; allows export Per app Stored by Turnkey Coinbase Embedded Wallet Multi-party Computation Passkey None; allows export Per app Stored by Coinbase Apillon Embedded Wallet Oasis Confidential Smart Contract Passkey, Email, Password None; allows export Global Fully decentralized via Oasis Passkeys
Passkeys are secure cryptographic keys stored on a user’s device, enabling wallet access through biometric methods without traditional passwords. This allows for a secure and user-friendly experience that prioritizes privacy.
How Passkeys Work
Upon setting up a passkey, the user’s device generates a cryptographic key pair: a public key (shared with the service) and a private key (stored on the device). When logging in, the user authenticates biometrically, which unlocks the private key to sign the login request. The service verifies this signed request using the public key.
Benefits of Passkeys
- Enhanced Security: The private key remains on the device, reducing risk of theft.
- User Convenience: Biometric login removes the need to remember passwords.
- Phishing Protection: The private key is non-transferrable, making it immune to phishing attacks.
Apillon’s passkeys ensure wallets are protected with advanced biometric-based security, creating a seamless user experience.
Advantages of Apillon’s Embedded Wallet Service
- Seamless User Experience: Simplifies onboarding, requiring no wallet downloads.
- Secure Wallet Setup: No mnemonic keys are required. Passkeys offer protection, and private keys are exportable as needed.
- Multiple Authentication Options: Users can set up passkeys, email verification, and additional methods to ensure flexible access.
- High-Level Security: End-to-end encryption and decentralized key management.
- Global Scope: Apillon’s wallets work across applications, unlike some limited alternatives.
- Confidential Smart Contracts: Private keys remain secure and confidential within Oasis-managed smart contracts.
Conclusion
Apillon’s Embedded Wallet Service on the Oasis Network combines user-friendly onboarding, top-tier security, and decentralization. It removes the need for wallet downloads and mnemonic phrases, offering a smooth and secure way to manage crypto assets within applications. With Oasis’s confidential smart contracts, Apillon protects users’ private keys, delivering security on par with hardware wallets.