diff --git a/mirror-2/.env.example b/mirror-2/.env.example index 9dc553d7..07783698 100644 --- a/mirror-2/.env.example +++ b/mirror-2/.env.example @@ -4,5 +4,5 @@ NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321 NEXT_PUBLIC_SUPABASE_ANON_KEY=SUPABASE_CLIENT_API_KEY NEXT_PUBLIC_APP_NAME="The Mirror" # only use The Mirror or Reflekt NEXT_PUBLIC_DISCORD_INVITE_URL=https://themirror.space/discord -NEXT_PUBLIC_GA_KEY_GAME_PUBLIC= -NEXT_PUBLIC_GA_KEY_SECRET= # I asked about this to GA support; why secret public?? Using throwaway keys for now +NEXT_PUBLIC_VERSION_NAME="JavaScript" +NEXT_PUBLIC_AMPLITUDE_PUBLIC_KEY= diff --git a/mirror-2/.prettierignore b/mirror-2/.prettierignore new file mode 100644 index 00000000..a10c0d6c --- /dev/null +++ b/mirror-2/.prettierignore @@ -0,0 +1,6 @@ +# Ignore artifacts: +build +coverage +dist +# ignore JS for now because of vanilla JS file imports might mess up some text replacement. Can revisit in the future but not high priority +*.js diff --git a/mirror-2/.prettierrc b/mirror-2/.prettierrc new file mode 100644 index 00000000..ffca9292 --- /dev/null +++ b/mirror-2/.prettierrc @@ -0,0 +1,6 @@ +{ + "singleQuote": true, + "trailingComma": "none", + "semi": false, + "endOfLine": "auto" +} diff --git a/mirror-2/.vscode/extensions.json b/mirror-2/.vscode/extensions.json deleted file mode 100644 index 74baffcc..00000000 --- a/mirror-2/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["denoland.vscode-deno"] -} diff --git a/mirror-2/.vscode/launch.json b/mirror-2/.vscode/launch.json new file mode 100644 index 00000000..d184594a --- /dev/null +++ b/mirror-2/.vscode/launch.json @@ -0,0 +1,16 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Next.js: debug full stack", + "type": "node-terminal", + "request": "launch", + "command": "yarn dev", + "serverReadyAction": { + "pattern": "- Local:.+(https?://.+)", + "uriFormat": "%s", + "action": "debugWithChrome" + } + } + ] +} diff --git a/mirror-2/.vscode/settings.json b/mirror-2/.vscode/settings.json index 3ecdef9d..68adb827 100644 --- a/mirror-2/.vscode/settings.json +++ b/mirror-2/.vscode/settings.json @@ -17,7 +17,7 @@ "net" ], "[typescript]": { - "editor.defaultFormatter": "denoland.vscode-deno" + "editor.defaultFormatter": "esbenp.prettier-vscode" }, "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/mirror-2/LICENSE.txt b/mirror-2/LICENSE.txt index 5c4c3c82..f3078b4f 100644 --- a/mirror-2/LICENSE.txt +++ b/mirror-2/LICENSE.txt @@ -1,4 +1,4 @@ -RevShare/ChainShare: A Source Available License +RevShare: A Source Available License Copyright (c) 2024-Present The Mirror Megaverse Inc. @@ -11,7 +11,7 @@ If any revenue is generated through the use of the Software, including but not l If revenue is generated in fiat currency (e.g., USD, EUR), the user agrees to remit payments to the Company based on the fee structure listed on the Company’s website. Failure to comply with these payment terms will result in the revocation of the license. 3. Payment in Cryptocurrency and Royalties for Non-Fungible Tokens -Cryptocurrency integrations are exclusive to the Reflekt version of the Software, a separate brand of The Mirror. In contrast, The Mirror version of the Software does not support cryptocurrency usage. This structure is designed to give developers the flexibility to choose between traditional web2 approaches and blockchain-integrated games. +Cryptocurrency integrations are exclusive to the Reflekt version of the Software, a separate fork of The Mirror. In contrast, The Mirror version of the Software does not support cryptocurrency usage. This structure is designed to give developers the flexibility to choose between traditional web2 approaches and blockchain-integrated games. Direct Cryptocurrency Transactions: If revenue is generated directly through the Software in the form of cryptocurrency (e.g., in-game transactions, purchases, or other forms of monetization), the user agrees to pay a 10% fee on all such transactions. Payments must be made to the Company’s wallet address as specified on its website. Users are responsible for ensuring accurate and timely payments to the listed address. @@ -21,3 +21,26 @@ Non-Fungible Token Royalties: If the Software is used to issue or mint Non-Fungi THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. By using the Software, you agree to the terms outlined above. These terms are subject to change due to early versions of the Software and the team is open to feedback! + +--- +The below copyright notice and MIT license is included for compliance with the MIT license of the PlayCanvas Engine: https://github.com/playcanvas/engine + +Copyright (c) 2011-2024 PlayCanvas Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/mirror-2/actions/auth.ts b/mirror-2/actions/auth.ts index 70613771..0d416682 100644 --- a/mirror-2/actions/auth.ts +++ b/mirror-2/actions/auth.ts @@ -1,150 +1,150 @@ -"use server"; +'use server' -import { createServerClient } from "@/utils/supabase/server"; -import { encodedRedirect } from "@/utils/utils"; -import { headers } from "next/headers"; -import { redirect } from "next/navigation"; +import { createServerClient } from '@/utils/supabase/server' +import { encodedRedirect } from '@/utils/utils' +import { headers } from 'next/headers' +import { redirect } from 'next/navigation' export const createAccountAction = async (formData: FormData) => { - const email = formData.get("email")?.toString(); - const password = formData.get("password")?.toString(); - const supabase = createServerClient(); - const origin = headers().get("origin"); + const email = formData.get('email')?.toString() + const password = formData.get('password')?.toString() + const supabase = createServerClient() + const origin = headers().get('origin') if (!email || !password) { - return { error: "Email and password are required" }; + return { error: 'Email and password are required' } } const { error } = await supabase.auth.signUp({ email, password, options: { - emailRedirectTo: `${origin}/auth/callback`, - }, - }); + emailRedirectTo: `${origin}/auth/callback` + } + }) if (error) { - console.error(error.code + " " + error.message); - return encodedRedirect("error", "/create-account", error.message); + console.error(error.code + ' ' + error.message) + return encodedRedirect('error', '/create-account', error.message) } else { return encodedRedirect( - "success", - "/create-account", - "Thanks for signing up! Please check your email for a verification link." - ); + 'success', + '/create-account', + 'Thanks for signing up! Please check your email for a verification link.' + ) } -}; +} export const loginAction = async (formData: FormData) => { - const email = formData.get("email") as string; - const password = formData.get("password") as string; - const supabase = createServerClient(); + const email = formData.get('email') as string + const password = formData.get('password') as string + const supabase = createServerClient() const { error } = await supabase.auth.signInWithPassword({ email, - password, - }); + password + }) if (error) { - return encodedRedirect("error", "/login", error.message); + return encodedRedirect('error', '/login', error.message) } - return redirect("/home"); -}; + return redirect('/home') +} export const forgotPasswordAction = async (formData: FormData) => { - const email = formData.get("email")?.toString(); - const supabase = createServerClient(); - const origin = headers().get("origin"); - const callbackUrl = formData.get("callbackUrl")?.toString(); + const email = formData.get('email')?.toString() + const supabase = createServerClient() + const origin = headers().get('origin') + const callbackUrl = formData.get('callbackUrl')?.toString() if (!email) { - return encodedRedirect("error", "/forgot-password", "Email is required"); + return encodedRedirect('error', '/forgot-password', 'Email is required') } const { error } = await supabase.auth.resetPasswordForEmail(email, { - redirectTo: `${origin}/auth/callback?redirect_to=/protected/reset-password`, - }); + redirectTo: `${origin}/auth/callback?redirect_to=/protected/reset-password` + }) if (error) { - console.error(error.message); + console.error(error.message) return encodedRedirect( - "error", - "/forgot-password", - "Could not reset password" - ); + 'error', + '/forgot-password', + 'Could not reset password' + ) } if (callbackUrl) { - return redirect(callbackUrl); + return redirect(callbackUrl) } return encodedRedirect( - "success", - "/forgot-password", - "Check your email for a link to reset your password." - ); -}; + 'success', + '/forgot-password', + 'Check your email for a link to reset your password.' + ) +} export const resetPasswordAction = async (formData: FormData) => { - const supabase = createServerClient(); + const supabase = createServerClient() - const password = formData.get("password") as string; - const confirmPassword = formData.get("confirmPassword") as string; + const password = formData.get('password') as string + const confirmPassword = formData.get('confirmPassword') as string if (!password || !confirmPassword) { encodedRedirect( - "error", - "/protected/reset-password", - "Password and confirm password are required" - ); + 'error', + '/protected/reset-password', + 'Password and confirm password are required' + ) } if (password !== confirmPassword) { encodedRedirect( - "error", - "/protected/reset-password", - "Passwords do not match" - ); + 'error', + '/protected/reset-password', + 'Passwords do not match' + ) } const { error } = await supabase.auth.updateUser({ - password: password, - }); + password: password + }) if (error) { encodedRedirect( - "error", - "/protected/reset-password", - "Password update failed" - ); + 'error', + '/protected/reset-password', + 'Password update failed' + ) } - encodedRedirect("success", "/protected/reset-password", "Password updated"); -}; + encodedRedirect('success', '/protected/reset-password', 'Password updated') +} export const resetEmailAction = async (formData: FormData) => { - const supabase = createServerClient(); + const supabase = createServerClient() - const email = formData.get("email") as string; - const password = formData.get("password") as string; + const email = formData.get('email') as string + const password = formData.get('password') as string if (!email || !password) { encodedRedirect( - "error", - "/protected/reset-password", - "Email and password are required" - ); + 'error', + '/protected/reset-password', + 'Email and password are required' + ) } //NOTE: Need to match current password with entered password before updating the user's email. const { error } = await supabase.auth.updateUser({ - email, - }); + email + }) if (error) { - encodedRedirect("error", "/protected/reset-email", "Email update failed"); + encodedRedirect('error', '/protected/reset-email', 'Email update failed') } - encodedRedirect("success", "/protected/reset-email", "Email updated"); -}; + encodedRedirect('success', '/protected/reset-email', 'Email updated') +} diff --git a/mirror-2/actions/name-generator.ts b/mirror-2/actions/name-generator.ts index ee88cff9..fe7dcb61 100644 --- a/mirror-2/actions/name-generator.ts +++ b/mirror-2/actions/name-generator.ts @@ -1,11 +1,15 @@ -"use server" -import { uniqueNamesGenerator, Config, adjectives, colors, animals } from 'unique-names-generator'; - +'use server' +import { + uniqueNamesGenerator, + Config, + adjectives, + colors, + animals +} from 'unique-names-generator' const randomName: string = uniqueNamesGenerator({ dictionaries: [adjectives, animals] -}); - +}) export async function generateSpaceName() { const customConfig: Config = { @@ -13,11 +17,10 @@ export async function generateSpaceName() { separator: ' ', length: 2, style: 'capital' - }; - -return uniqueNamesGenerator(customConfig); -} + } + return uniqueNamesGenerator(customConfig) +} export async function generateSceneName() { const customConfig: Config = { @@ -25,8 +28,7 @@ export async function generateSceneName() { separator: ' ', length: 1, style: 'capital' - }; - - return uniqueNamesGenerator(customConfig); } - \ No newline at end of file + + return uniqueNamesGenerator(customConfig) +} diff --git a/mirror-2/ampli.json b/mirror-2/ampli.json new file mode 100644 index 00000000..f1cce44f --- /dev/null +++ b/mirror-2/ampli.json @@ -0,0 +1,14 @@ +{ + "Zone": "us", + "OrgId": "308710", + "WorkspaceId": "a2da908b-27c1-4013-b214-f7ce5531bbe7", + "SourceId": "b077387d-b743-4f18-bd57-94effffd3ad1", + "Runtime": "browser:typescript-ampli-v2", + "Platform": "Browser", + "Language": "TypeScript", + "SDK": "@amplitude/analytics-browser@^1.0", + "Branch": "main", + "Version": "1.0.0", + "VersionId": "84e8930d-d0e7-4c92-b6c6-629ff838c9a6", + "Path": "./src/ampli" +} \ No newline at end of file diff --git a/mirror-2/app/(auth-pages)/create-account/page.tsx b/mirror-2/app/(auth-pages)/create-account/page.tsx index ee1f8a9b..ad893381 100644 --- a/mirror-2/app/(auth-pages)/create-account/page.tsx +++ b/mirror-2/app/(auth-pages)/create-account/page.tsx @@ -1,26 +1,26 @@ -"use client"; -import { createAccountAction, loginAction } from "@/actions/auth"; -import { FormMessage, Message } from "@/components/form-message"; -import { SubmitButton } from "@/components/submit-button"; +'use client' +import { createAccountAction, loginAction } from '@/actions/auth' +import { FormMessage, Message } from '@/components/form-message' +import { SubmitButton } from '@/components/submit-button' import { Card, CardHeader, CardTitle, CardContent, - CardFooter, -} from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import { useRedirectToHomeIfSignedIn } from "@/hooks/auth"; -import { AppLogoImageMedium } from "@/lib/theme-service"; -import Link from "next/link"; + CardFooter +} from '@/components/ui/card' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import { useRedirectToHomeIfSignedIn } from '@/hooks/auth' +import { AppLogoImageMedium } from '@/lib/theme-service' +import Link from 'next/link' export default function CreateAccount({ - searchParams, + searchParams }: { - searchParams: Message; + searchParams: Message }) { - useRedirectToHomeIfSignedIn(); + useRedirectToHomeIfSignedIn() return (
- ); + ) } diff --git a/mirror-2/app/(auth-pages)/forgot-password/page.tsx b/mirror-2/app/(auth-pages)/forgot-password/page.tsx index c94ce608..09938fff 100644 --- a/mirror-2/app/(auth-pages)/forgot-password/page.tsx +++ b/mirror-2/app/(auth-pages)/forgot-password/page.tsx @@ -1,15 +1,15 @@ -import { forgotPasswordAction } from "@/actions/auth"; -import { FormMessage, Message } from "@/components/form-message"; -import { SubmitButton } from "@/components/submit-button"; -import { Input } from "@/components/ui/input"; -import { Label } from "@/components/ui/label"; -import Link from "next/link"; -import { SmtpMessage } from "../smtp-message"; +import { forgotPasswordAction } from '@/actions/auth' +import { FormMessage, Message } from '@/components/form-message' +import { SubmitButton } from '@/components/submit-button' +import { Input } from '@/components/ui/input' +import { Label } from '@/components/ui/label' +import Link from 'next/link' +import { SmtpMessage } from '../smtp-message' export default function ForgotPassword({ - searchParams, + searchParams }: { - searchParams: Message; + searchParams: Message }) { return ( <> @@ -17,7 +17,7 @@ export default function ForgotPassword({
- Already have an account?{" "}
+ Already have an account?{' '}
Login
@@ -34,5 +34,5 @@ export default function ForgotPassword({
{album.artist}