@meycult/core 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -6
- package/src/brand/BrandName.tsx +4 -2
- package/src/brand/LaunchButton.tsx +5 -3
- package/src/brand/Logo.tsx +25 -6
- package/src/brand/PyramidName.tsx +10 -0
- package/src/brand/Sigil.tsx +10 -5
- package/src/brand/TokenIcons.tsx +12 -6
- package/src/brand.ts +4 -1
- package/src/components/CultCountdown.tsx +89 -14
- package/src/game/categories.ts +23 -0
- package/src/game/cults.ts +88 -0
- package/src/game/quests.ts +62 -0
- package/src/game/types.ts +27 -0
- package/src/index.ts +64 -21
- package/src/product.ts +17 -0
- package/src/styles/theme.css +97 -6
- package/src/tokens.ts +10 -2
- package/src/ui/CultButton.tsx +55 -0
- package/src/ui/RarityBadge.tsx +18 -0
- package/src/ui/animated-shiny-text.tsx +2 -2
- package/src/ui/badges.tsx +43 -0
- package/src/ui/card.tsx +20 -92
- package/src/ui/shimmer-button.tsx +5 -3
- package/src/ui/virtues.tsx +66 -0
- package/src/unveil/LaunchStage.tsx +3 -2
- package/src/unveil/bg.ts +20 -11
- package/src/unveil/bgStyles.ts +0 -1
- package/src/unveil/blocks.tsx +51 -14
- package/src/unveil/effects.tsx +182 -86
- package/src/unveil.ts +2 -21
- package/src/auth/Gate.tsx +0 -14
- package/src/auth/types.ts +0 -12
- package/src/brand/GodEmperor.tsx +0 -8
- package/src/cn.ts +0 -6
- package/src/lib/images.ts +0 -10
- package/src/lib/money.ts +0 -12
- package/src/lib/store.ts +0 -19
- package/src/shell/types.ts +0 -13
- package/src/supabase/browser.ts +0 -103
- package/src/supabase/callback.ts +0 -15
- package/src/supabase/proxy.ts +0 -36
- package/src/supabase/server.ts +0 -31
- package/src/ui/Callout.tsx +0 -33
package/src/supabase/browser.ts
DELETED
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
import { createClient, type SupabaseClient } from '@supabase/supabase-js'
|
|
2
|
-
|
|
3
|
-
export interface BrowserEnv {
|
|
4
|
-
url: string
|
|
5
|
-
anonKey: string
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Chunked cookie storage — shares the session across subdomains
|
|
10
|
-
* (e.g. app.meycult.com + shop.meycult.com via domain=.meycult.com)
|
|
11
|
-
* while staying under the ~4KB cookie limit.
|
|
12
|
-
*/
|
|
13
|
-
export function chunkedCookieStorage(
|
|
14
|
-
storageKey: string,
|
|
15
|
-
cookieDomain: string | null,
|
|
16
|
-
chunkSize = 3200,
|
|
17
|
-
): Pick<Storage, 'getItem' | 'setItem' | 'removeItem'> {
|
|
18
|
-
const domainAttr = cookieDomain ? `; domain=${cookieDomain}` : ''
|
|
19
|
-
|
|
20
|
-
function readCookie(name: string): string | null {
|
|
21
|
-
if (typeof document === 'undefined') return null
|
|
22
|
-
const match = document.cookie.match(
|
|
23
|
-
new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)'),
|
|
24
|
-
)
|
|
25
|
-
return match ? decodeURIComponent(match[1]) : null
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function writeCookie(name: string, value: string, maxAge = 60 * 60 * 24 * 30): void {
|
|
29
|
-
document.cookie = `${name}=${encodeURIComponent(value)}; path=/${domainAttr}; max-age=${maxAge}; SameSite=Lax; Secure`
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function deleteCookie(name: string): void {
|
|
33
|
-
document.cookie = `${name}=; path=/${domainAttr}; max-age=0; SameSite=Lax; Secure`
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function countKey(): string {
|
|
37
|
-
return `${storageKey}.n`
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return {
|
|
41
|
-
getItem(key: string): string | null {
|
|
42
|
-
const count = readCookie(countKey())
|
|
43
|
-
if (count) {
|
|
44
|
-
let out = ''
|
|
45
|
-
for (let i = 0; i < Number(count); i++) out += readCookie(`${key}.${i}`) ?? ''
|
|
46
|
-
return out || null
|
|
47
|
-
}
|
|
48
|
-
return readCookie(key)
|
|
49
|
-
},
|
|
50
|
-
setItem(key: string, value: string): void {
|
|
51
|
-
const prev = readCookie(countKey())
|
|
52
|
-
if (prev) for (let i = 0; i < Number(prev); i++) deleteCookie(`${key}.${i}`)
|
|
53
|
-
deleteCookie(key)
|
|
54
|
-
if (value.length <= chunkSize) {
|
|
55
|
-
writeCookie(key, value)
|
|
56
|
-
deleteCookie(countKey())
|
|
57
|
-
return
|
|
58
|
-
}
|
|
59
|
-
const parts = Math.ceil(value.length / chunkSize)
|
|
60
|
-
for (let i = 0; i < parts; i++) writeCookie(`${key}.${i}`, value.slice(i * chunkSize, (i + 1) * chunkSize))
|
|
61
|
-
writeCookie(countKey(), String(parts))
|
|
62
|
-
},
|
|
63
|
-
removeItem(key: string): void {
|
|
64
|
-
const count = readCookie(countKey())
|
|
65
|
-
if (count) for (let i = 0; i < Number(count); i++) deleteCookie(`${key}.${i}`)
|
|
66
|
-
deleteCookie(countKey())
|
|
67
|
-
deleteCookie(key)
|
|
68
|
-
},
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface BrowserOptions extends BrowserEnv {
|
|
73
|
-
/** e.g. 'meycult-auth'. Defaults to 'meycult-auth'. */
|
|
74
|
-
storageKey?: string
|
|
75
|
-
/** e.g. '.meycult.com' on prod, null on localhost. Defaults to hostname heuristic. */
|
|
76
|
-
cookieDomain?: string | null
|
|
77
|
-
detectSessionInUrl?: boolean
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function defaultCookieDomain(): string | null {
|
|
81
|
-
if (typeof window === 'undefined') return null
|
|
82
|
-
return window.location.hostname.endsWith('meycult.com') ? '.meycult.com' : null
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function createSupabaseBrowser(options: BrowserOptions): SupabaseClient {
|
|
86
|
-
const {
|
|
87
|
-
url,
|
|
88
|
-
anonKey,
|
|
89
|
-
storageKey = 'meycult-auth',
|
|
90
|
-
cookieDomain = defaultCookieDomain(),
|
|
91
|
-
detectSessionInUrl = true,
|
|
92
|
-
} = options
|
|
93
|
-
const onDomain = cookieDomain !== null
|
|
94
|
-
return createClient(url, anonKey, {
|
|
95
|
-
auth: {
|
|
96
|
-
storageKey,
|
|
97
|
-
persistSession: true,
|
|
98
|
-
autoRefreshToken: true,
|
|
99
|
-
detectSessionInUrl,
|
|
100
|
-
...(onDomain ? { storage: chunkedCookieStorage(storageKey, cookieDomain) } : {}),
|
|
101
|
-
},
|
|
102
|
-
})
|
|
103
|
-
}
|
package/src/supabase/callback.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* OAuth callback helper — host route calls this with its server client,
|
|
5
|
-
* then redirects to `next` (default '/').
|
|
6
|
-
*/
|
|
7
|
-
export async function exchangeCodeForSession(
|
|
8
|
-
supabase: SupabaseClient,
|
|
9
|
-
code: string | null,
|
|
10
|
-
next = '/',
|
|
11
|
-
): Promise<{ next: string; error: string | null }> {
|
|
12
|
-
if (!code) return { next, error: 'missing_code' }
|
|
13
|
-
const { error } = await supabase.auth.exchangeCodeForSession(code)
|
|
14
|
-
return { next, error: error ? error.message : null }
|
|
15
|
-
}
|
package/src/supabase/proxy.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { createServerClient } from '@supabase/ssr'
|
|
2
|
-
import { NextResponse, type NextRequest } from 'next/server'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Refresh the Supabase session on every request so Server Components
|
|
6
|
-
* always see a valid token. Wire into the host's proxy.ts:
|
|
7
|
-
* export default coreUpdateSession as middleware-style default export
|
|
8
|
-
*/
|
|
9
|
-
export async function updateSession(request: NextRequest) {
|
|
10
|
-
let supabaseResponse = NextResponse.next({ request })
|
|
11
|
-
|
|
12
|
-
const supabase = createServerClient(
|
|
13
|
-
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
14
|
-
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
|
|
15
|
-
{
|
|
16
|
-
cookies: {
|
|
17
|
-
getAll() {
|
|
18
|
-
return request.cookies.getAll()
|
|
19
|
-
},
|
|
20
|
-
setAll(
|
|
21
|
-
cookiesToSet: { name: string; value: string; options?: Record<string, unknown> }[],
|
|
22
|
-
) {
|
|
23
|
-
cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))
|
|
24
|
-
supabaseResponse = NextResponse.next({ request })
|
|
25
|
-
cookiesToSet.forEach(({ name, value, options }) =>
|
|
26
|
-
supabaseResponse.cookies.set(name, value, options),
|
|
27
|
-
)
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
await supabase.auth.getClaims()
|
|
34
|
-
|
|
35
|
-
return supabaseResponse
|
|
36
|
-
}
|
package/src/supabase/server.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { createServerClient } from '@supabase/ssr'
|
|
2
|
-
import { cookies } from 'next/headers'
|
|
3
|
-
|
|
4
|
-
/** Next.js Server Component / Route Handler / Server Action client. */
|
|
5
|
-
export async function createSupabaseServerClient() {
|
|
6
|
-
const cookieStore = await cookies()
|
|
7
|
-
|
|
8
|
-
return createServerClient(
|
|
9
|
-
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
|
10
|
-
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
|
|
11
|
-
{
|
|
12
|
-
cookies: {
|
|
13
|
-
getAll() {
|
|
14
|
-
return cookieStore.getAll()
|
|
15
|
-
},
|
|
16
|
-
setAll(
|
|
17
|
-
cookiesToSet: { name: string; value: string; options?: Record<string, unknown> }[],
|
|
18
|
-
) {
|
|
19
|
-
try {
|
|
20
|
-
cookiesToSet.forEach(({ name, value, options }) =>
|
|
21
|
-
cookieStore.set(name, value, options),
|
|
22
|
-
)
|
|
23
|
-
} catch {
|
|
24
|
-
// Called from a Server Component — read-only there.
|
|
25
|
-
// The proxy refreshes sessions on every request.
|
|
26
|
-
}
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
)
|
|
31
|
-
}
|
package/src/ui/Callout.tsx
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { AlertTriangle, CheckCircle, Info } from "lucide-react";
|
|
2
|
-
|
|
3
|
-
type CalloutType = "info" | "warning" | "success" | "danger";
|
|
4
|
-
|
|
5
|
-
const icons: Record<CalloutType, React.ReactNode> = {
|
|
6
|
-
info: <Info className="h-5 w-5" />,
|
|
7
|
-
warning: <AlertTriangle className="h-5 w-5" />,
|
|
8
|
-
success: <CheckCircle className="h-5 w-5" />,
|
|
9
|
-
danger: <AlertTriangle className="h-5 w-5" />,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
const styles: Record<CalloutType, string> = {
|
|
13
|
-
info: "border-accent bg-accent/10 text-text",
|
|
14
|
-
warning: "border-amber-500 bg-amber-950/30 text-amber-100",
|
|
15
|
-
success: "border-green-500 bg-green-950/30 text-green-100",
|
|
16
|
-
danger: "border-red-500 bg-red-950/30 text-red-100",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
interface CalloutProps {
|
|
20
|
-
type?: CalloutType;
|
|
21
|
-
children: React.ReactNode;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function Callout({ type = "info", children }: CalloutProps) {
|
|
25
|
-
return (
|
|
26
|
-
<div className={`my-6 rounded-lg border-l-4 p-4 not-prose ${styles[type]}`}>
|
|
27
|
-
<div className="flex items-start gap-3">
|
|
28
|
-
<span className="mt-0.5">{icons[type]}</span>
|
|
29
|
-
<div className="[&>p]:m-0">{children}</div>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
);
|
|
33
|
-
}
|