This is the full developer documentation for MikanDev Docs # MikanDev Docs > Documentation for MikanDev projects # Domains list ## Hosted Domains [Section titled “Hosted Domains”](#hosted-domains) MikanDev hosts its content on the following domains: * * * * * All front-facing pages are available on the following domains: * * All other domains are used for internal purposes only. Any other related domains are not related to MikanDev. ## Domain Parking [Section titled “Domain Parking”](#domain-parking) MikanDev may also own domains from previous services or projects. These domains are parked and not in use.\ We may also acquire expired domains to prevent misuse.\ We do not intend to squat on these domains, so if you have a legitimate use for a domain we own, please contact us, and we will be happy to transfer it to you.\ Parked domains will show a parking page that looks like this: ![Domain Parking](https://sukushocloud.mdusercontent.com/rms0e6ro8pps/bbbcae2535229a6b9f246106e0409291.png) # Hello! ### Welcome to MikanDev’s documentation site. [Section titled “Welcome to MikanDev’s documentation site.”](#welcome-to-mikandevs-documentation-site) <- Use the sidebar or search to find what you need :) # JDA Icons React # Legal Documentation * [Privacy Policy](/legal/privacy) * [Terms Of Service](/legal/terms) * [特定商取引法に基づく表記(Specified Commerce Terms, JP only)](/legal/jp-payments) * [General DPA (GDPR Compliance, EU only)](/legal/dpa) # 特定商取引法に基づく表記 ## 事業者名 [Section titled “事業者名”](#事業者名) MikanDev ## 責任者 [Section titled “責任者”](#責任者) 省略\* ## 所在地 [Section titled “所在地”](#所在地) 大阪府(詳細は諸略)\* ## 電話番号 [Section titled “電話番号”](#電話番号) 090-9276-3628 ## メールアドレス [Section titled “メールアドレス”](#メールアドレス) ## 販売URL [Section titled “販売URL”](#販売url) * ## お支払い方法 [Section titled “お支払い方法”](#お支払い方法) * クレジットカード * Google Pay * Amazonギフトカード * 銀行振込 ## 商品代金以外の必要金額 [Section titled “商品代金以外の必要金額”](#商品代金以外の必要金額) なし ## 販売数量 [Section titled “販売数量”](#販売数量) 自由 ## 商品の引渡時期 [Section titled “商品の引渡時期”](#商品の引渡時期) 決済が完了し、APIまたは手動でアプリケーションへ決済が通知された時点 ## 商品引渡し方法 [Section titled “商品引渡し方法”](#商品引渡し方法) デジタル ## 交換および返品(返金ポリシー) [Section titled “交換および返品(返金ポリシー)”](#交換および返品返金ポリシー) 特別な理由が無い限り、返金、及びキャンセルを受け付けることは基本的にありません。 ## \*省略表記について [Section titled “\*省略表記について”](#省略表記について) 省略表記されている部分については、消費者様(購入者)様からの請求があった場合に遅滞なく開示いたします。 # Privacy Policy Last updated: September 4, 2024 # The gist [Section titled “The gist”](#the-gist) * We only use your personal information for proper provision of our services. * We collect some basic personal information, such as your name, E-mail, and social media IDs. These help make our job easier, and make the experience better for you. * We don’t share your information with any third parties. That would be a shitty thing to do. * We don’t provide services to children under 13. If we have done so accidentally, you can [request deletion.](#delete-your-personal-data) * You can [contact us](#contact-us) if you have any further questions. You can also do so if you want to delete your information. # Stuff to show your lawyer [Section titled “Stuff to show your lawyer”](#stuff-to-show-your-lawyer) ## Interpretation and Definitions [Section titled “Interpretation and Definitions”](#interpretation-and-definitions) ### Interpretation [Section titled “Interpretation”](#interpretation) The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural. ### Definitions [Section titled “Definitions”](#definitions) For the purposes of this Privacy Policy: * **Account** means a unique account created for You to access our Service or parts of our Service. * **Affiliate** means an entity that controls, is controlled by or is under common control with a party, where “control” means a strategic partnership with MikanDev. * **Company** (referred to as either “the Company”, “We”, “Us” or “Our” in this Agreement) refers to MikanDev, Osaka. * **Cookies** are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses. * **Country** refers to: Japan * **Device** means any device that can access the Service such as a computer, a cellphone or a digital tablet. * **Personal Data** is any information that relates to an identified or identifiable individual. * **Service** refers to the Website. * **Service Provider** means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used. * **Third-party Social Media Service** refers to any website or any social network website through which a User can log in or create an account to use the Service. * **Usage Data** refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit). * **Website** refers to MikanDev, accessible from * **You** means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable. ## Collecting and Using Your Personal Data [Section titled “Collecting and Using Your Personal Data”](#collecting-and-using-your-personal-data) ### Types of Data Collected [Section titled “Types of Data Collected”](#types-of-data-collected) #### Personal Data [Section titled “Personal Data”](#personal-data) While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to: * Email address * Usage Data #### Usage Data [Section titled “Usage Data”](#usage-data) Usage Data is collected automatically when using the Service. Usage Data may include information such as Your Device’s Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data. When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data. We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device. #### Information from Third-Party Social Media Services [Section titled “Information from Third-Party Social Media Services”](#information-from-third-party-social-media-services) The Company allows You to create an account and log in to use the Service through the following Third-party Social Media Services: * Discord If You decide to register through or otherwise grant us access to a Third-Party Social Media Service, We may collect Personal data that is already associated with Your Third-Party Social Media Service’s account, such as Your name, Your email address, Your activities or Your contact list associated with that account. You may also have the option of sharing additional information with the Company through Your Third-Party Social Media Service’s account. If You choose to provide such information and Personal Data, during registration or otherwise, You are giving the Company permission to use, share, and store it in a manner consistent with this Privacy Policy. #### Tracking Technologies and Cookies [Section titled “Tracking Technologies and Cookies”](#tracking-technologies-and-cookies) We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include: * **Cookies or Browser Cookies.** A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies. * **Web Beacons.** Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity). Cookies can be “Persistent” or “Session” Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. We use both Session and Persistent Cookies for the purposes set out below: * **Necessary / Essential Cookies** Type: Session Cookies Administered by: Us Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services. * **Cookies Policy / Notice Acceptance Cookies** Type: Persistent Cookies Administered by: Us Purpose: These Cookies identify if users have accepted the use of cookies on the Website. * **Functionality Cookies** Type: Persistent Cookies Administered by: Us Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website. For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy. ### Use of Your Personal Data [Section titled “Use of Your Personal Data”](#use-of-your-personal-data) The Company may use Personal Data for the following purposes: * **To provide and maintain our Service**, including to monitor the usage of our Service. * **To manage Your Account:** to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user. * **For the performance of a contract:** the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service. * **To contact You:** To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application’s push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation. * **To provide You** with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information. * **To manage Your requests:** To attend and manage Your requests to Us. * **For business transfers:** We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred. * **For other purposes**: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience. We may share Your personal information in the following situations: * **With Service Providers:** We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You. * **For business transfers:** We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company. * **With Affiliates:** We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us. * **With business partners:** We may share Your information with Our business partners to offer You certain products, services or promotions. * **With other users:** when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside. If You interact with other users or register through a Third-Party Social Media Service, Your contacts on the Third-Party Social Media Service may see Your name, profile, pictures and description of Your activity. Similarly, other users will be able to view descriptions of Your activity, communicate with You and view Your profile. * **With Your consent**: We may disclose Your personal information for any other purpose with Your consent. ### Retention of Your Personal Data [Section titled “Retention of Your Personal Data”](#retention-of-your-personal-data) The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies. The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods. ### Transfer of Your Personal Data [Section titled “Transfer of Your Personal Data”](#transfer-of-your-personal-data) Your information, including Personal Data, is processed at the Company’s operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction. Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer. The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information. ### Delete Your Personal Data [Section titled “Delete Your Personal Data”](#delete-your-personal-data) You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You. Our Service may give You the ability to delete certain information about You from within the Service. You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us. Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so. ### Disclosure of Your Personal Data [Section titled “Disclosure of Your Personal Data”](#disclosure-of-your-personal-data) #### Business Transactions [Section titled “Business Transactions”](#business-transactions) If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy. #### Law enforcement [Section titled “Law enforcement”](#law-enforcement) Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency). #### Other legal requirements [Section titled “Other legal requirements”](#other-legal-requirements) The Company may disclose Your Personal Data in the good faith belief that such action is necessary to: * Comply with a legal obligation * Protect and defend the rights or property of the Company * Prevent or investigate possible wrongdoing in connection with the Service * Protect the personal safety of Users of the Service or the public * Protect against legal liability ### Security of Your Personal Data [Section titled “Security of Your Personal Data”](#security-of-your-personal-data) The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security. ## Children’s Privacy [Section titled “Children’s Privacy”](#childrens-privacy) Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers. If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent’s consent before We collect and use that information. ## Links to Other Websites [Section titled “Links to Other Websites”](#links-to-other-websites) Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party’s site. We strongly advise You to review the Privacy Policy of every site You visit. We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services. ## Changes to this Privacy Policy [Section titled “Changes to this Privacy Policy”](#changes-to-this-privacy-policy) We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page. We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the “Last updated” date at the top of this Privacy Policy. You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page. ## Contact Us [Section titled “Contact Us”](#contact-us) If you have any questions about this Privacy Policy, You can contact us: * By email: * By visiting this page on our website: * By phone number: +81 09092763628 # General Refund Policy * Every product that we offer has either a free trial or a free tier. We encourage users to take advantage of these options to evaluate our products before making a purchase. * However, if you do decide to make a purchase and are not satisfied with the product, we offer a refund within 28 days of the purchase date. * To request a refund, please contact us with your order details and the reason for the refund request. We will process your request as quickly as possible. * We may also offer refunds outside the 28-day window on a case-by-case basis, at our discretion. # Terms of Service *Last updated: November 28, 2025* Thanks for using MikanDev services! These Terms of Service (“Terms”) govern your use of our website, products, and services (collectively, the “Services”). By accessing or using our Services, you agree to be bound by these Terms. If you do not agree to these Terms, please cease continued usage our Services. # The gist [Section titled “The gist”](#the-gist) * Use our Services lawfully and responsibly. * Create and maintain a secure account if required. * Pay any fees associated with paid Services promptly. * Respect our intellectual property and the rights of others. * Understand that our Services are provided “as is” without warranties. * We may update these Terms, and your continued use constitutes acceptance of those changes. # Stuff to show your lawyer [Section titled “Stuff to show your lawyer”](#stuff-to-show-your-lawyer) ## 1. Use of Services [Section titled “1. Use of Services”](#1-use-of-services) You agree to use our Services only for lawful purposes and in accordance with these Terms. You must not use our Services in any way that could damage, disable, overburden, or impair our servers or networks. ## 2. Account Registration [Section titled “2. Account Registration”](#2-account-registration) * To access certain features of our Services, you may be required to create an account. You agree to provide accurate and complete information during the registration process and to keep your account information up to date. * You are responsible for maintaining the confidentiality of your account credentials and for all activities that occur under your account. * Do not create multiple accounts for circumventing usage limits or for any other reason. ## 3. Payments and Subscriptions [Section titled “3. Payments and Subscriptions”](#3-payments-and-subscriptions) * Some of our Services may require payment. By subscribing to a paid service, you agree to pay all applicable fees and taxes. * We reserve the right to change our pricing and payment policies at any time, with notice provided to you. * All payments are subject to our refund policy, which can be found [here](/legal/refunds). * We reserve the right to suspend or terminate your access to paid Services if your payment is not received or if there are issues with your payment method. * You are responsible for any fees associated with currency conversion or international transactions. ## 3a. Third-Party payment processors [Section titled “3a. Third-Party payment processors”](#3a-third-party-payment-processors) * Our order process is conducted by our online reseller Paddle.com. Paddle.com is the Merchant of Record for all our orders. Paddle provides all customer service inquiries and handles returns. ## 4. Intellectual Property [Section titled “4. Intellectual Property”](#4-intellectual-property) * All content and materials provided through our Services, including but not limited to text, graphics, logos, images, and software, are the property of MikanDev or its licensors and are protected by intellectual property laws. * You may not use, reproduce, distribute, or create derivative works from our content without our express written permission. * However, any [open-source components](https://github.com/mikndotdev) included in our Services are subject to their respective licenses. ## 5. User-Generated Content [Section titled “5. User-Generated Content”](#5-user-generated-content) * You may have the opportunity to submit, upload, or share content through our Services (“User Content”). You retain ownership of your User Content, but by submitting it, you grant us a worldwide, non-exclusive, royalty-free license to use, reproduce, modify, and distribute your User Content in connection with our Services. * You are solely responsible for your User Content and agree not to submit content that is unlawful, harmful, defamatory, or infringes on the rights of others. * We reserve the right to remove or disable access to any User Content that violates these Terms or is deemed inappropriate. ## 6. Privacy [Section titled “6. Privacy”](#6-privacy) Your use of our Services is also governed by our [Privacy Policy](/legal/privacy), which outlines how we collect, use, and protect your personal information. ## 7. Disclaimers and Limitation of Liability [Section titled “7. Disclaimers and Limitation of Liability”](#7-disclaimers-and-limitation-of-liability) * We strive to provide reliable and secure Services, but we cannot guarantee that our Services will always be available or error-free. * Our Services are provided “as is” and “as available” without warranties of any kind, either express or implied. * We do not guarantee that our Services will be uninterrupted, error-free, or free of viruses or other harmful components. * To the fullest extent permitted by law, MikanDev shall not be liable for any indirect, incidental, special, consequential, or punitive damages arising out of or related to your use of our Services. * If you are dissatisfied with our Services, your sole and exclusive remedy is to discontinue using our Services, and receive a refund if applicable under our refund policy. ## 8. Modifications to Terms [Section titled “8. Modifications to Terms”](#8-modifications-to-terms) We reserve the right to modify these Terms at any time. We will notify you of any changes by posting the updated Terms on our website. Your continued use of our Services after such changes constitutes your acceptance of the new Terms. # kontol # Big kontol [Section titled “Big kontol”](#big-kontol) ## Medium kontol [Section titled “Medium kontol”](#medium-kontol) ### smol kontol [Section titled “smol kontol”](#smol-kontol) # Introduction ![](https://cdn.mikn.dev/branding/mikan-vtube.svg) JWT-based Discord authentication for Next.js that doesn't suck * Works with Next.js 15 * No database required * Returns **all** user data from Discord * Fully server-side * Support for Server Actions and Route Handlers * Designed for easy migration from AuthJS ## Why? [Section titled “Why?”](#why) There are many good auth libraries for Next.js, but most of them don’t provide good Discord support, or require a database, or are just plain bad. * [Better Auth](httpe://better-auth.com) is great, but requires a database making it complicated for simple projects. * SST’s [OpenAuth](https://openauth.js.org) also requires a database. * [AuthJS](https://authjs.dev) does allow fully JWT-based sessions, but does not provide the Discord user ID out of the box (rendering it basically useless), and requires [a hacky workaround](https://github.com/nextauthjs/next-auth/issues/7122) to get it working. * [Clerk](https://clerk.dev) is great if you like vendor lock-in :P This package aims to provide a simple, server-side solution for Discord authentication that works out of the box with Next.js. ## Demo [Section titled “Demo”](#demo) You can see a live demo of this package in action at\ ## Open Source [Section titled “Open Source”](#open-source) This package is open source and available under the [WTFPL License](https://wtfpl.net/).\ Feel free to [contribute](https://github.com/mikndotdev/next-discord-auth) or use it in your projects! # Client-Side Usage Note Client-side hooks are useful when you need to access session data in Client Components, or when you want real-time session updates without page refreshes. ## Why Client-Side Hooks? [Section titled “Why Client-Side Hooks?”](#why-client-side-hooks) While this package is primarily designed for server-side authentication, sometimes you need to access session data in Client Components: * Building interactive UIs that depend on user data * Displaying user information in client-side navigation * Implementing real-time session updates * Using third-party libraries that require client components ## Create a Session Provider Route [Section titled “Create a Session Provider Route”](#create-a-session-provider-route) First, create an API route that will serve session data to your client components. This route handler strips out sensitive tokens before sending the session to the client. Create a route handler, for example at `src/app/api/auth/me/route.ts`: ```ts import { createSessionProviderRoute } from "@mikandev/next-discord-auth/server-actions"; import "@/auth"; export const GET = createSessionProviderRoute; ``` Caution This route automatically excludes `accessToken` and `refreshToken` from the response, ensuring sensitive credentials are never exposed to the client. ## Wrap Your App with the Provider [Section titled “Wrap Your App with the Provider”](#wrap-your-app-with-the-provider) In your root layout or a client component wrapper, add the `UserInfoProvider`: ```tsx // src/app/layout.tsx or src/components/providers.tsx "use client"; import { UserInfoProvider } from "@mikandev/next-discord-auth/client"; import { ReactNode } from "react"; export function Providers({ children }: { children: ReactNode }) { return {children}; } ``` Then use it in your root layout: src/app/layout.tsx ```tsx import { Providers } from "@/components/providers"; export default function RootLayout({ children }: { children: ReactNode }) { return ( {children} ); } ``` Tip The `path` prop should match the route you created in the previous step. You can customize this path to fit your routing structure. ## Use the Hook in Client Components [Section titled “Use the Hook in Client Components”](#use-the-hook-in-client-components) Now you can use the `useUserInfo()` hook in any client component within your provider: ```tsx "use client"; import { useUserInfo } from "@mikandev/next-discord-auth/client"; export function UserProfile() { const { session, isLoading, isError, mutate } = useUserInfo(); if (isLoading) { return
Loading...
; } if (isError) { return
Error loading session
; } if (!session) { return
Not signed in
; } return (
Avatar Welcome, {session.user.name}! ID: {session.user.id}
); } ``` ## Hook API Reference [Section titled “Hook API Reference”](#hook-api-reference) The `useUserInfo()` hook returns an object with the following properties: * `session`: The current session object (without `accessToken` and `refreshToken`), or `null` if not authenticated * `isLoading`: Boolean indicating if the session is being loaded * `isError`: Boolean indicating if there was an error loading the session * `mutate`: Function to manually revalidate the session data Note The session data is cached and automatically revalidated on reconnect. You can manually trigger a refresh by calling the `mutate()` function. ## Security Considerations [Section titled “Security Considerations”](#security-considerations) Danger **Important**: Never expose `accessToken` or `refreshToken` to client components. The `createSessionProviderRoute` function automatically strips these sensitive fields before sending the session to the client. The client-side session object only contains: * `user`: User information (id, name, email, avatar) * `expires`: Session expiration timestamp Sensitive tokens remain server-side only and are never exposed to the browser. ## Example: Navigation Bar [Section titled “Example: Navigation Bar”](#example-navigation-bar) Here’s a complete example of a navigation bar using the client-side hooks: ```tsx "use client"; import { useUserInfo } from "@mikandev/next-discord-auth/client"; import Link from "next/link"; export function Navbar() { const { session, isLoading } = useUserInfo(); return ( ); } ``` Tip For sign in/sign out actions, you still need to use server actions as shown in the [Usage](/solutions/developers/next-discord-auth/usage#sign-in-and-sign-out) section. The client-side hooks are only for reading session data. # Setup ## Install and Configure [Section titled “Install and Configure”](#install-and-configure) * Install the package: - npm ```sh npm install @mikandev/next-discord-auth ``` - pnpm ```sh pnpm install @mikandev/next-discord-auth ``` - bun ```sh bun install @mikandev/next-discord-auth ``` * Create an Auth configuration file somewhere in your project, for example `src/auth.ts`: ```ts import { setup } from "@mikandev/next-discord-auth"; await setup({ clientId: process.env.DISCORD_CLIENT_ID as string, clientSecret: process.env.DISCORD_CLIENT_SECRET as string, redirectUri: process.env.DISCORD_REDIRECT_URI as string, scopes: ["identify", "email"], jwtSecret: process.env.JWT_SECRET as string, }); ``` * `clientId`: Your Discord application’s client ID. * `clientSecret`: Your Discord application’s client secret. * `redirectUri`: The URI to redirect to after authentication. This should match the redirect URI set in your Discord application settings. * `scopes`: The scopes to request from Discord. Defaults to `["identify", "email"]`. Read the [Discord Developer Docs](https://discord.com/developers/docs/topics/oauth2) for more information on scopes. * `jwtSecret`: A secret used to sign the JWT tokens. This should be a long, random string. Try using `openssl rand -base64 32` to generate one, or just hit random keys on your keyboard and hope for the best :3 Danger Do **NOT** put your secrets directly in this file! Use environment variables instead. You can use a `.env` file to store them locally, and set them in your deployment environment. This package will also infer [AuthJS Environment variables](https://authjs.dev/getting-started/providers/discord#environment-variables), so if you have those set, you don’t need to set the `clientId` and `clientSecret` options. ## Create a Callback Route [Section titled “Create a Callback Route”](#create-a-callback-route) * Create a Route Handler on your callback route, for example `src/app/auth/callback/route.ts`: ```ts import { handleRedirect } from "@mikandev/next-discord-auth/redirect"; import { NextRequest } from "next/server"; import { redirect } from "next/navigation"; import "@/auth"; export const GET = async (request: NextRequest) => { await handleRedirect(request); redirect("/"); }; ``` Make sure to set your Discord application’s redirect URI to match this route, in this case `http://localhost:3000/auth/callback` You are now ready to [use the package](/solutions/developers/next-discord-auth/usage)! # Usage Note By default, This package doesn’t provide support for Client Components; the recommended approach is to use server components for any pages that require authentication. However, if you need to access session data in Client Components, you can set up a session provider route and use client-side hooks as described in the [Client-Side Usage](/solutions/developers/next-discord-auth/client) section. ## Get Session [Section titled “Get Session”](#get-session) * import the `getSession` function from the package, as well as call the `setup` function in your auth configuration file (as shown in the [Setup](/solutions/developers/next-discord-auth/setup) section): ```ts import { getSession } from "@mikandev/next-discord-auth/server-actions"; import "@/auth"; ``` * You can now use the `getSession` function in your server components, server actions, or route handlers: ```tsx export default async function Page() { const session = await getSession(); return (
Avatar Welcome, {session.user.name}! (ID: {session.user.id})
{ "use server"; await signOut(); }} >
View Session Data
); } ``` Note The Session object is designed to be AuthJS-compatible, so you can use it like you would with AuthJS’s `Session` type. * You can check if the user is authenticated by checking if the session is `null`: ```tsx export default async function Page() { const session = await getSession(); if (!session) { return

You are not signed in.

; } return

Welcome, {session.user.name}!

; } ``` ## Sign In and Sign Out [Section titled “Sign In and Sign Out”](#sign-in-and-sign-out) * import the `signIn` and `signOut` function from the package, as well as call the `setup` function in your auth configuration file (as shown in the [Setup](/solutions/developers/next-discord-auth/setup) section): ```ts import { signIn, signOut } from "@mikandev/next-discord-auth/server-actions"; import "@/auth"; ``` * You can now use the `signIn` and `signOut` functions in your server components, server actions, or route handlers: Note Use a Form to call the `signIn` and `signOut` functions from within a page, as they are server actions. ```tsx export default async function Home() { const session = await getSession(); if (!session) { return (

You are not signed in.

{ "use server"; await signIn(); }} >
); } return (
Avatar Welcome, {session.user.name}! (ID: {session.user.id})
{ "use server"; await signOut(); }} >
View Session Data
); ``` ## Handle Callbacks [Section titled “Handle Callbacks”](#handle-callbacks) * If you followed the [Setup](/solutions/developers/next-discord-auth/setup) section, you already have a callback route set up. If not, make sure to create a route handler on your callback route, as shown in the [Setup](/solutions/developers/next-discord-auth/setup#create-a-callback-route) section. # rssfetch A simple RSS feed fetcher and parser built with [Elysia.js](https://elysiajs.com) and [Bun](https://bun.sh). A free instance is hosted at: [rssfetch.vercel.app](https://rssfetch.vercel.app). Feel free to use it! ## Deployment [Section titled “Deployment”](#deployment) ### Vercel [Section titled “Vercel”](#vercel) * This project can be directly deployed to Vercel with no additional configuration needed. * Click the button below to deploy: [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/mikndotdev/rssfetch) ### Cloudflare Workers [Section titled “Cloudflare Workers”](#cloudflare-workers) * This project can also be deployed to Cloudflare Workers, but requires some manual setup. * Follow the instructions in the [Elysia Cloudflare Workers documentation](https://elysiajs.com/integrations/cloudflare-worker.html). ### Docker [Section titled “Docker”](#docker) * Docker images are available on [GHCR](https://github.com/mikndotdev/rssfetch/pkgs/container/rssfetch). ## Manual Setup [Section titled “Manual Setup”](#manual-setup) 1. Install dependencies: ```bash bun install ``` 2. Start the server: ```bash bun start ``` The server will start on port 3000 by default. ## API Usage [Section titled “API Usage”](#api-usage) ### Fetch RSS Feed [Section titled “Fetch RSS Feed”](#fetch-rss-feed) **Endpoint:** `GET /` **Query Parameters:** | Parameter | Type | Required | Description | Default | | --------- | -------- | -------- | ---------------------------------------------- | -------- | | `url` | `string` | **Yes** | The URL of the RSS feed to fetch. | - | | `type` | `string` | No | Sort order for articles: `latest` or `oldest`. | `latest` | | `count` | `number` | No | The number of articles to return. | `1` | | `step` | `number` | No | The offset for pagination (items to skip). | `0` | **Example Request:** Fetch the latest 3 articles from an RSS feed: ```bash curl "http://localhost:3000/?url=https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml&count=3" ``` **Example Response:** ```json { "title": "NYT > Top Stories", "description": "The New York Times: Top Stories", "link": "https://www.nytimes.com", "articles": [ { "title": "Example Article Title", "link": "https://www.nytimes.com/2024/01/01/example.html", "description": "Brief description of the article content.", "pubDate": "Mon, 01 Jan 2024 12:00:00 GMT" } // ... 2 more articles ] } ``` # CustomRP ### Custom Discord Rich Presence, no software download required! [Section titled “Custom Discord Rich Presence, no software download required!”](#custom-discord-rich-presence-no-software-download-required) # MD Chat ## Auth backend [Section titled “Auth backend”](#auth-backend) * MD Chat relies on [Logto](https://logto.io/) as the authentication backend, which is a powerful open-source identity and access management solution. * You may choose to [self-host Logto](https://docs.logto.io/logto-oss/get-started-with-oss) or use their [cloud service](https://cloud.logto.io). Note MD Chat has only been tested to work with a self-hosted Logto instance, but Logto Cloud *should* work just as well. * Once you have Logto set up, create a Traditional Web app with the following settings: * **Name**: A name for your app, e.g. “MD Chat” * **Redirect URI**: `http://(your-app-url)/callback` * Keep the Client ID and Client Secret handy, as you will need them to configure MD Chat. ## Deployment [Section titled “Deployment”](#deployment) Caution Due to a reliance on a traditional Postgres database, MD Chat is designed to be deployed as a Docker container and may not work on serverless platforms like Vercel or Cloudflare Workers. To start, you will need the following: * A Logto instance and app credentials as described above. * A Postgres database * A Redis instance * An S3-compatible object storage (e.g. AWS S3, Tigris, Cloudflare R2, etc.) for storing uploaded files. The Docker image is available on [GitHub](https://ghcr.io/mikndotdev/chat), and can be pulled with the following command: ```bash docker pull ghcr.io/mikndotdev/chat:latest ``` Setup the environment variables in your Docker container. A sample `.env` file might look like this: ```bash DATABASE_URL="postgres://postgres:password@1.2.3.4:5402/postgres" REDIS_URL="redis://:username@5.6.7.8:5409/0" LOGTO_APP_ID="your-logto-app-id" LOGTO_APP_SECRET="your-logto-app-secret" LOGTO_ENDPOINT="https://(your-logto-instance).logto.io" LOGTO_COOKIE_SECRET="a-random-secret-string" S3_ENDPOINT="https://s3.example.com" S3_ACCESS_KEY_ID="your-s3-access-key-id" S3_SECRET_ACCESS_KEY="your-s3-secret-access-key" S3_BUCKET_NAME="your-s3-bucket-name" S3_REGION="your-s3-region" S3_UPLOAD_DIR="any-directory-you-want" S3_PUBLIC_URL="https://s3.example.com/your-s3-bucket-name/" ``` Note Make sure to set the `S3_PUBLIC_URL` to the public URL of your S3 bucket, as this is used to serve uploaded files. If you have a seperate CDN behind your bucket, set that as the public URL. You can then run the container with the following command: ```bash docker run -d \ --name md-chat \ -p 3000:80 \ --env-file .env \ ghcr.io/mikndotdev/chat:latest ``` * This will start the MD Chat server on port 3000, and you can access it at `http://localhost:3000`. * Make sure to adjust the port and other settings as needed for your deployment environment. Tip I’m a huge fan of [Coolify](https://coolify.io), which is an amazing piece of free software makes deploying, managing and proxiying Docker containers to your infrstructure a breeze. It’s what the MD Chat demo and MikanDev’s Logto instance is running on, and I highly recommend it for self-hosting! ## Docker Compose [Section titled “Docker Compose”](#docker-compose) Caution While this setup is great to quickly get started, for production deployments it is recommended to manually set up each service and configure them according to your needs. * An example Docker Compose file is available in the [repository](https://github.com/mikndotdev/chat/blob/master/compose.yml), which has all the necessary services configured except for Logto and S3. * You can use this file to quickly set up a local development environment with MD Chat, and the databases. # ShortFlare Note This service is still a work-in-progress, and some features may not work properly. ## Introduction [Section titled “Introduction”](#introduction) Shorten and track URLs on your domain for completely free with your Cloudflare account! * Unlimited URLs * Ultra low-latency redirects thanks to Cloudflare’s 275+ locations * Free unlimited geo-located analytics (up to Workers Free limit off 100k per day) * Manage your links with an API, or a dashboard * No need to [sign up for three billion different SaaS products](https://github.com/dubinc/dub?tab=readme-ov-file#tech-stack), all you need is that Cloudflare account you already have * Easy (ish) setup ## Setup the Worker [Section titled “Setup the Worker”](#setup-the-worker) 1. [Go create a Cloudflare Account](https://cloudflare.com/) (lets be honest, you probably already have one) 2. Go to “D1” under the “Workers and Pages” tab ![Go to D1](/_astro/select-d1.ON9bwKXI_1JkIkk.webp) 3. Create a D1 database with any name you want ![Create D1 database](/_astro/create-d1.DOhj3zXY_1RnrSG.webp) 4. Once the database has been created, create a table with; * the name “urls” * the columns “slug” and “destination” (both text) ![Add columns](/_astro/d1-columns.BRGUA_dz_1awtOe.webp) 5. Go to the “Workers” tab, and create a new worker, and continue to project 6. Under the “settings” tab, add the following environment variables: | Key | Value | | -------------------- | ------------------------------------------------- | | API\_TOKEN | Your API token | | NOT\_FOUND\_URL | The URL to redirect to if the slug is not found | | TRACKING\_API\_TOKEN | Your tracking API token | | TRACKING\_API\_URL | Your tracking API URL (leave as anything for now) | Note Use a password generator for the API tokens (or just smash your keyboard and hope for the best), and keep them safe! 7. Bind the D1 database we created before to the worker, with the variable name “DB” ![Bind D1 database](/_astro/bind-d1.D92u9mNW_Z1qDJXr.webp) 8. Save the changes, and now go to “Edit Code” on the top right 9. Replace `index.js` with the following; [skip to below](#the-worker-is-now-set-up) index.js ```js export default { async fetch(request, env) { return await handleRequest(request, env); }, }; async function handleRequest(request, env) { const url = new URL(request.url); const path = url.pathname; // Check if it's an API endpoint if (path.startsWith("/api/")) { // Verify Bearer token const authHeader = request.headers.get("Authorization"); if (!authHeader || !authHeader.startsWith("Bearer ")) { return new Response("Unauthorized", { status: 401 }); } const token = authHeader.split(" ")[1]; if (token !== env.API_TOKEN) { return new Response("Unauthorized", { status: 401 }); } // Handle API endpoints try { if (path === "/api/add" && request.method === "POST") { return handleAdd(request, env); } else if (path === "/api/delete" && request.method === "POST") { return handleDelete(request, env); } else if (path === "/api/list" && request.method === "GET") { return handleList(env); } else { return new Response("Not Found", { status: 404 }); } } catch (error) { if (error.message === "No JSON in request") { return new Response("Bad Request: No JSON found in request body", { status: 400 }); } throw error; // Re-throw other errors } } // Handle redirect for short URLs return handleRedirect(request, env); } async function getJSONFromRequest(request) { const contentType = request.headers.get("content-type"); if (!contentType || !contentType.includes("application/json")) { throw new Error("No JSON in request"); } try { return await request.json(); } catch (error) { throw new Error("No JSON in request"); } } async function handleAdd(request, env) { const { slug, destination } = await getJSONFromRequest(request); if (!slug || !destination) { return new Response("Missing slug or destination", { status: 400 }); } try { // Check if the slug already exists const existingSlug = await env.DB.prepare("SELECT slug FROM urls WHERE slug = ?") .bind(slug) .first(); if (existingSlug) { return new Response("Slug already exists", { status: 409 }); } // If the slug doesn't exist, proceed with insertion await env.DB.prepare("INSERT INTO urls (slug, destination) VALUES (?, ?)") .bind(slug, destination) .run(); return new Response("URL added successfully", { status: 200 }); } catch (error) { return new Response("Error adding URL: " + error.message, { status: 500 }); } } async function handleDelete(request, env) { const { slug } = await getJSONFromRequest(request); if (!slug) { return new Response("Missing slug", { status: 400 }); } try { // First, check if the slug exists const checkResult = await env.DB.prepare("SELECT slug FROM urls WHERE slug = ?") .bind(slug) .first(); if (!checkResult) { return new Response("Slug not found", { status: 404 }); } // If the slug exists, proceed with deletion await env.DB.prepare("DELETE FROM urls WHERE slug = ?").bind(slug).run(); return new Response("URL deleted successfully", { status: 200 }); } catch (error) { console.error("Error deleting URL:", error); return new Response("Error deleting URL: " + error.message, { status: 500 }); } } async function handleList(env) { try { const result = await env.DB.prepare("SELECT * FROM urls").all(); return new Response(JSON.stringify(result.results), { status: 200, headers: { "Content-Type": "application/json" }, }); } catch (error) { return new Response("Error listing URLs: " + error.message, { status: 500 }); } } async function trackVisit(slug, request, env) { const country = request.headers.get("CF-IPCountry") || "Unknown"; console.log(env.TRACKING_API_URL); try { await fetch(env.TRACKING_API_URL, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${env.TRACKING_API_TOKEN}`, }, body: JSON.stringify({ slug, country, }), }); } catch (error) { // Log the error, but don't prevent the redirect console.error("Error tracking visit:", error); } } async function handleRedirect(request, env) { const url = new URL(request.url); const slug = url.pathname.slice(1); // Remove leading slash if (!slug) { return Response.redirect(env.NOT_FOUND_URL, 302); } try { const result = await env.DB.prepare("SELECT destination FROM urls WHERE slug = ?") .bind(slug) .first(); if (result && result.destination) { // Track the visit before redirecting await trackVisit(slug, request, env); return Response.redirect(result.destination, 302); } else { return Response.redirect(env.NOT_FOUND_URL, 302); } } catch (error) { console.error("Error redirecting:", error); return Response.redirect(env.NOT_FOUND_URL, 302); } } ``` ## The worker is now set up! [Section titled “The worker is now set up!”](#the-worker-is-now-set-up) You can now either; * [Continue to setup the frontend](#frontend-setup) * [Use the API directly with no further setup](#api-usage) ## Frontend Setup [Section titled “Frontend Setup”](#frontend-setup) Set the following environment variables in your frontend: | Key | Value | | ----------------------- | -------------------------------------------- | | PASSWORD | A password to protect the frontend | | WORKER\_URL | The URL of your worker | | WORKER\_API\_TOKEN | The API token you set in the worker | | WORKER\_TRACKING\_TOKEN | The tracking API token you set in the worker | | NEXTAUTH\_SECRET | A secret for NextAuth (random string) | * [Deploy the frontend to your server with Coolify](https://coolify.io/docs/knowledge-base/git/gitea/integration/#public-repositories) (recommended) * Set the Install command to `bun i` and the build command to `bun run build` * Set the start command to `bun start` * Manual setup * Coming soon! Once you have deployed the frontend, you can access it at the URL you deployed it to. Login with the password you set in the environment variables, and have fun! ### Analytics Setup [Section titled “Analytics Setup”](#analytics-setup) * Set the `TRACKING_API_URL` environment variable in the worker to: * `https://your-frontend-url/api/worker/analytics` ## API Usage [Section titled “API Usage”](#api-usage) ### Add a URL [Section titled “Add a URL”](#add-a-url) * Endpoint: `https://your-worker-url/api/add` * Method: `POST` * Headers: * `Authorization: Bearer YOUR_API_TOKEN` * Body: ```json { "slug": "your-slug", "destination": "https://your-destination-url" } ``` ### Delete a URL [Section titled “Delete a URL”](#delete-a-url) * Endpoint: `https://your-worker-url/api/delete` * Method: `POST` * Headers: * `Authorization: Bearer YOUR_API_TOKEN` * Body: ```json { "slug": "slug to delete" } ``` ### List all URLs [Section titled “List all URLs”](#list-all-urls) * Endpoint: `https://your-worker-url/api/list` * Method: `GET` * Headers: * `Authorization: Bearer YOUR_API_TOKEN`