@ezcoder.dev/sdk 1.0.0 → 1.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/dist/DatabaseProvider-DalP-KHC.d.ts +167 -0
- package/dist/analytics/index.d.ts +22 -1
- package/dist/analytics/index.js +79 -4
- package/dist/analytics/index.js.map +1 -1
- package/dist/animation/index.js.map +1 -1
- package/dist/auth/index.d.ts +2 -1
- package/dist/auth/index.js +25 -6
- package/dist/auth/index.js.map +1 -1
- package/dist/chunk-CQKYANAW.js +44 -0
- package/dist/chunk-CQKYANAW.js.map +1 -0
- package/dist/{chunk-5XIZHBKE.js → chunk-HJ2EIZ4S.js} +23 -6
- package/dist/chunk-HJ2EIZ4S.js.map +1 -0
- package/dist/{chunk-G7XDUN3Z.js → chunk-I2YGB7Z6.js} +24 -44
- package/dist/chunk-I2YGB7Z6.js.map +1 -0
- package/dist/chunk-LIUE7M7K.js +72 -0
- package/dist/chunk-LIUE7M7K.js.map +1 -0
- package/dist/{chunk-YNDCD53D.js → chunk-QHB7LGCA.js} +123 -16
- package/dist/chunk-QHB7LGCA.js.map +1 -0
- package/dist/chunk-R4MDAYFO.js +642 -0
- package/dist/chunk-R4MDAYFO.js.map +1 -0
- package/dist/cms/index.js +4 -2
- package/dist/cms/index.js.map +1 -1
- package/dist/cron/index.d.ts +32 -0
- package/dist/cron/index.js +63 -0
- package/dist/cron/index.js.map +1 -0
- package/dist/database/index.d.ts +37 -0
- package/dist/database/index.js +32 -0
- package/dist/database/index.js.map +1 -0
- package/dist/email/index.d.ts +29 -0
- package/dist/email/index.js +60 -0
- package/dist/email/index.js.map +1 -0
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +176 -3
- package/dist/index.js +270 -6
- package/dist/index.js.map +1 -1
- package/dist/notifications/index.d.ts +35 -1
- package/dist/notifications/index.js +61 -4
- package/dist/notifications/index.js.map +1 -1
- package/dist/payments/index.d.ts +11 -3
- package/dist/payments/index.js +101 -7
- package/dist/payments/index.js.map +1 -1
- package/dist/roles/index.js +6 -4
- package/dist/roles/index.js.map +1 -1
- package/dist/seo/index.js.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.js +18 -9
- package/dist/storage/index.js.map +1 -1
- package/dist/{types-DtY5lp3P.d.ts → types-1uP3V_pe.d.ts} +5 -0
- package/package.json +120 -105
- package/dist/chunk-5XIZHBKE.js.map +0 -1
- package/dist/chunk-G7XDUN3Z.js.map +0 -1
- package/dist/chunk-YNDCD53D.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/notifications/useNotifications.ts","../../src/notifications/NotificationCenter.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\nimport { supabase } from '../core/supabase';\nimport { features } from '../core/config';\nimport { AuthContext } from '../auth/AuthProvider';\n\ninterface Notification {\n id: string;\n type: string;\n title: string;\n message: string;\n data?: Record<string, unknown>;\n read: boolean;\n read_at?: string;\n created_at: string;\n}\n\nconst DEMO_NOTIFICATIONS: Notification[] = [\n {\n id: 'demo-1',\n type: 'info',\n title: 'Welcome!',\n message: 'Connect a database to enable real-time notifications.',\n read: false,\n created_at: new Date().toISOString(),\n },\n];\n\ninterface UseNotificationsReturn {\n notifications: Notification[];\n unreadCount: number;\n loading: boolean;\n isConfigured: boolean;\n markAsRead: (notificationId: string) => Promise<void>;\n markAllAsRead: () => Promise<void>;\n deleteNotification: (notificationId: string) => Promise<void>;\n refetch: () => Promise<void>;\n}\n\nexport function useNotifications(): UseNotificationsReturn {\n const auth = useContext(AuthContext);\n const [notifications, setNotifications] = useState<Notification[]>([]);\n const [loading, setLoading] = useState(true);\n\n const userId = auth?.user?.id;\n\n const fetchNotifications = useCallback(async () => {\n if (!features.auth || !userId) {\n setNotifications(DEMO_NOTIFICATIONS);\n setLoading(false);\n return;\n }\n\n try {\n const { data, error } = await supabase\n .from('notifications')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false })\n .limit(50);\n\n if (error) {\n setNotifications(DEMO_NOTIFICATIONS);\n } else {\n setNotifications((data as Notification[]) || []);\n }\n } catch {\n setNotifications(DEMO_NOTIFICATIONS);\n } finally {\n setLoading(false);\n }\n }, [userId]);\n\n useEffect(() => {\n fetchNotifications();\n }, [fetchNotifications]);\n\n useEffect(() => {\n if (!features.auth || !userId) return;\n\n const channel = supabase\n .channel(`notifications_${userId}`)\n .on(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'postgres_changes' as any,\n {\n event: 'INSERT',\n schema: 'public',\n table: 'notifications',\n filter: `user_id=eq.${userId}`,\n },\n (payload: { new: Notification }) => {\n setNotifications((prev) => [payload.new, ...prev]);\n }\n )\n .subscribe();\n\n return () => {\n supabase.removeChannel(channel);\n };\n }, [userId]);\n\n const markAsRead = useCallback(async (notificationId: string) => {\n if (!features.auth) return;\n\n await supabase\n .from('notifications')\n .update({ read: true, read_at: new Date().toISOString() })\n .eq('id', notificationId);\n\n setNotifications((prev) =>\n prev.map((n) => (n.id === notificationId ? { ...n, read: true } : n))\n );\n }, []);\n\n const markAllAsRead = useCallback(async () => {\n if (!features.auth || !userId) return;\n\n await supabase\n .from('notifications')\n .update({ read: true, read_at: new Date().toISOString() })\n .eq('user_id', userId)\n .eq('read', false);\n\n setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));\n }, [userId]);\n\n const deleteNotification = useCallback(async (notificationId: string) => {\n if (!features.auth) return;\n\n await supabase.from('notifications').delete().eq('id', notificationId);\n setNotifications((prev) => prev.filter((n) => n.id !== notificationId));\n }, []);\n\n const unreadCount = notifications.filter((n) => !n.read).length;\n\n return {\n notifications,\n unreadCount,\n loading,\n isConfigured: features.auth,\n markAsRead,\n markAllAsRead,\n deleteNotification,\n refetch: fetchNotifications,\n };\n}\n","import { useState } from 'react';\nimport { useNotifications } from './useNotifications';\n\ninterface NotificationCenterProps {\n className?: string;\n}\n\nexport function NotificationCenter({ className = '' }: NotificationCenterProps) {\n const { notifications, unreadCount, markAsRead, markAllAsRead, deleteNotification } = useNotifications();\n const [open, setOpen] = useState(false);\n\n return (\n <div className={className} style={{ position: 'relative', display: 'inline-block' }}>\n <button\n onClick={() => setOpen(!open)}\n style={{\n background: 'none', border: 'none', cursor: 'pointer',\n position: 'relative', padding: '8px', fontSize: '20px',\n }}\n >\n 🔔\n {unreadCount > 0 && (\n <span style={{\n position: 'absolute', top: '2px', right: '2px',\n backgroundColor: '#dc2626', color: 'white', fontSize: '10px',\n borderRadius: '50%', width: '18px', height: '18px',\n display: 'flex', alignItems: 'center', justifyContent: 'center',\n }}>\n {unreadCount > 9 ? '9+' : unreadCount}\n </span>\n )}\n </button>\n\n {open && (\n <div style={{\n position: 'absolute', right: 0, top: '100%', width: '320px',\n backgroundColor: 'white', border: '1px solid #e5e7eb',\n borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)',\n zIndex: 50, maxHeight: '400px', overflow: 'auto',\n }}>\n <div style={{ padding: '12px 16px', borderBottom: '1px solid #e5e7eb', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <span style={{ fontWeight: 600 }}>Notifications</span>\n {unreadCount > 0 && (\n <button onClick={() => markAllAsRead()} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '12px' }}>\n Mark all read\n </button>\n )}\n </div>\n\n {notifications.length === 0 ? (\n <div style={{ padding: '24px', textAlign: 'center', color: '#9ca3af' }}>\n No notifications\n </div>\n ) : (\n notifications.map((n) => (\n <div\n key={n.id}\n style={{\n padding: '12px 16px', borderBottom: '1px solid #f3f4f6',\n backgroundColor: n.read ? 'transparent' : '#eff6ff',\n cursor: 'pointer',\n }}\n onClick={() => !n.read && markAsRead(n.id)}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>\n <div>\n <p style={{ fontWeight: 500, fontSize: '14px', marginBottom: '2px' }}>{n.title}</p>\n <p style={{ color: '#6b7280', fontSize: '13px' }}>{n.message}</p>\n <p style={{ color: '#9ca3af', fontSize: '11px', marginTop: '4px' }}>\n {new Date(n.created_at).toLocaleDateString()}\n </p>\n </div>\n <button\n onClick={(e) => { e.stopPropagation(); deleteNotification(n.id); }}\n style={{ background: 'none', border: 'none', color: '#9ca3af', cursor: 'pointer', fontSize: '16px' }}\n >\n ×\n </button>\n </div>\n </div>\n ))\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,UAAU,WAAW,aAAa,kBAAkB;AAgB7D,IAAM,qBAAqC;AAAA,EACzC;AAAA,IACE,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,OAAO;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AACF;AAaO,SAAS,mBAA2C;AACzD,QAAM,OAAO,WAAW,WAAW;AACnC,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAyB,CAAC,CAAC;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAE3C,QAAM,SAAS,MAAM,MAAM;AAE3B,QAAM,qBAAqB,YAAY,YAAY;AACjD,QAAI,CAAC,SAAS,QAAQ,CAAC,QAAQ;AAC7B,uBAAiB,kBAAkB;AACnC,iBAAW,KAAK;AAChB;AAAA,IACF;AAEA,QAAI;AACF,YAAM,EAAE,MAAM,MAAM,IAAI,MAAM,SAC3B,KAAK,eAAe,EACpB,OAAO,GAAG,EACV,GAAG,WAAW,MAAM,EACpB,MAAM,cAAc,EAAE,WAAW,MAAM,CAAC,EACxC,MAAM,EAAE;AAEX,UAAI,OAAO;AACT,yBAAiB,kBAAkB;AAAA,MACrC,OAAO;AACL,yBAAkB,QAA2B,CAAC,CAAC;AAAA,MACjD;AAAA,IACF,QAAQ;AACN,uBAAiB,kBAAkB;AAAA,IACrC,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,YAAU,MAAM;AACd,uBAAmB;AAAA,EACrB,GAAG,CAAC,kBAAkB,CAAC;AAEvB,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,QAAQ,CAAC,OAAQ;AAE/B,UAAM,UAAU,SACb,QAAQ,iBAAiB,MAAM,EAAE,EACjC;AAAA;AAAA,MAEC;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,QAAQ,cAAc,MAAM;AAAA,MAC9B;AAAA,MACA,CAAC,YAAmC;AAClC,yBAAiB,CAAC,SAAS,CAAC,QAAQ,KAAK,GAAG,IAAI,CAAC;AAAA,MACnD;AAAA,IACF,EACC,UAAU;AAEb,WAAO,MAAM;AACX,eAAS,cAAc,OAAO;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,aAAa,YAAY,OAAO,mBAA2B;AAC/D,QAAI,CAAC,SAAS,KAAM;AAEpB,UAAM,SACH,KAAK,eAAe,EACpB,OAAO,EAAE,MAAM,MAAM,UAAS,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC,EACxD,GAAG,MAAM,cAAc;AAE1B;AAAA,MAAiB,CAAC,SAChB,KAAK,IAAI,CAAC,MAAO,EAAE,OAAO,iBAAiB,EAAE,GAAG,GAAG,MAAM,KAAK,IAAI,CAAE;AAAA,IACtE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,gBAAgB,YAAY,YAAY;AAC5C,QAAI,CAAC,SAAS,QAAQ,CAAC,OAAQ;AAE/B,UAAM,SACH,KAAK,eAAe,EACpB,OAAO,EAAE,MAAM,MAAM,UAAS,oBAAI,KAAK,GAAE,YAAY,EAAE,CAAC,EACxD,GAAG,WAAW,MAAM,EACpB,GAAG,QAAQ,KAAK;AAEnB,qBAAiB,CAAC,SAAS,KAAK,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,KAAK,EAAE,CAAC;AAAA,EACpE,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,qBAAqB,YAAY,OAAO,mBAA2B;AACvE,QAAI,CAAC,SAAS,KAAM;AAEpB,UAAM,SAAS,KAAK,eAAe,EAAE,OAAO,EAAE,GAAG,MAAM,cAAc;AACrE,qBAAiB,CAAC,SAAS,KAAK,OAAO,CAAC,MAAM,EAAE,OAAO,cAAc,CAAC;AAAA,EACxE,GAAG,CAAC,CAAC;AAEL,QAAM,cAAc,cAAc,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE;AAEzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,cAAc,SAAS;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS;AAAA,EACX;AACF;;;ACjJA,SAAS,YAAAA,iBAAgB;AAanB,SASI,KATJ;AANC,SAAS,mBAAmB,EAAE,YAAY,GAAG,GAA4B;AAC9E,QAAM,EAAE,eAAe,aAAa,YAAY,eAAe,mBAAmB,IAAI,iBAAiB;AACvG,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,KAAK;AAEtC,SACE,qBAAC,SAAI,WAAsB,OAAO,EAAE,UAAU,YAAY,SAAS,eAAe,GAChF;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM,QAAQ,CAAC,IAAI;AAAA,QAC5B,OAAO;AAAA,UACL,YAAY;AAAA,UAAQ,QAAQ;AAAA,UAAQ,QAAQ;AAAA,UAC5C,UAAU;AAAA,UAAY,SAAS;AAAA,UAAO,UAAU;AAAA,QAClD;AAAA,QACD;AAAA;AAAA,UAEE,cAAc,KACb,oBAAC,UAAK,OAAO;AAAA,YACX,UAAU;AAAA,YAAY,KAAK;AAAA,YAAO,OAAO;AAAA,YACzC,iBAAiB;AAAA,YAAW,OAAO;AAAA,YAAS,UAAU;AAAA,YACtD,cAAc;AAAA,YAAO,OAAO;AAAA,YAAQ,QAAQ;AAAA,YAC5C,SAAS;AAAA,YAAQ,YAAY;AAAA,YAAU,gBAAgB;AAAA,UACzD,GACG,wBAAc,IAAI,OAAO,aAC5B;AAAA;AAAA;AAAA,IAEJ;AAAA,IAEC,QACC,qBAAC,SAAI,OAAO;AAAA,MACV,UAAU;AAAA,MAAY,OAAO;AAAA,MAAG,KAAK;AAAA,MAAQ,OAAO;AAAA,MACpD,iBAAiB;AAAA,MAAS,QAAQ;AAAA,MAClC,cAAc;AAAA,MAAO,WAAW;AAAA,MAChC,QAAQ;AAAA,MAAI,WAAW;AAAA,MAAS,UAAU;AAAA,IAC5C,GACE;AAAA,2BAAC,SAAI,OAAO,EAAE,SAAS,aAAa,cAAc,qBAAqB,SAAS,QAAQ,gBAAgB,iBAAiB,YAAY,SAAS,GAC5I;AAAA,4BAAC,UAAK,OAAO,EAAE,YAAY,IAAI,GAAG,2BAAa;AAAA,QAC9C,cAAc,KACb,oBAAC,YAAO,SAAS,MAAM,cAAc,GAAG,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,UAAU,OAAO,GAAG,2BAE9I;AAAA,SAEJ;AAAA,MAEC,cAAc,WAAW,IACxB,oBAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,UAAU,GAAG,8BAExE,IAEA,cAAc,IAAI,CAAC,MACjB;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO;AAAA,YACL,SAAS;AAAA,YAAa,cAAc;AAAA,YACpC,iBAAiB,EAAE,OAAO,gBAAgB;AAAA,YAC1C,QAAQ;AAAA,UACV;AAAA,UACA,SAAS,MAAM,CAAC,EAAE,QAAQ,WAAW,EAAE,EAAE;AAAA,UAEzC,+BAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,iBAAiB,YAAY,aAAa,GACvF;AAAA,iCAAC,SACC;AAAA,kCAAC,OAAE,OAAO,EAAE,YAAY,KAAK,UAAU,QAAQ,cAAc,MAAM,GAAI,YAAE,OAAM;AAAA,cAC/E,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,UAAU,OAAO,GAAI,YAAE,SAAQ;AAAA,cAC7D,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,UAAU,QAAQ,WAAW,MAAM,GAC9D,cAAI,KAAK,EAAE,UAAU,EAAE,mBAAmB,GAC7C;AAAA,eACF;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,CAAC,MAAM;AAAE,oBAAE,gBAAgB;AAAG,qCAAmB,EAAE,EAAE;AAAA,gBAAG;AAAA,gBACjE,OAAO,EAAE,YAAY,QAAQ,QAAQ,QAAQ,OAAO,WAAW,QAAQ,WAAW,UAAU,OAAO;AAAA,gBACpG;AAAA;AAAA,YAED;AAAA,aACF;AAAA;AAAA,QAtBK,EAAE;AAAA,MAuBT,CACD;AAAA,OAEL;AAAA,KAEJ;AAEJ;","names":["useState","useState"]}
|
|
1
|
+
{"version":3,"sources":["../../src/notifications/useNotifications.ts","../../src/notifications/NotificationCenter.tsx","../../src/notifications/sendNotification.ts"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\r\nimport { supabase } from '../core/supabase';\r\nimport { features } from '../core/config';\r\nimport { AuthContext } from '../auth/AuthProvider';\r\n\r\ninterface Notification {\r\n id: string;\r\n type: string;\r\n title: string;\r\n message: string;\r\n data?: Record<string, unknown>;\r\n read: boolean;\r\n read_at?: string;\r\n created_at: string;\r\n}\r\n\r\nconst DEMO_NOTIFICATIONS: Notification[] = [\r\n {\r\n id: 'demo-1',\r\n type: 'info',\r\n title: 'Welcome!',\r\n message: 'Connect a database to enable real-time notifications.',\r\n read: false,\r\n created_at: new Date().toISOString(),\r\n },\r\n];\r\n\r\ninterface UseNotificationsReturn {\r\n notifications: Notification[];\r\n unreadCount: number;\r\n loading: boolean;\r\n isConfigured: boolean;\r\n markAsRead: (notificationId: string) => Promise<void>;\r\n markAllAsRead: () => Promise<void>;\r\n deleteNotification: (notificationId: string) => Promise<void>;\r\n refetch: () => Promise<void>;\r\n}\r\n\r\nexport function useNotifications(): UseNotificationsReturn {\r\n const auth = useContext(AuthContext);\r\n const [notifications, setNotifications] = useState<Notification[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n\r\n const userId = auth?.user?.id;\r\n\r\n const fetchNotifications = useCallback(async () => {\r\n if (!features.auth || !userId) {\r\n setNotifications(DEMO_NOTIFICATIONS);\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n try {\r\n const { data, error } = await supabase\r\n .from('notifications')\r\n .select('*')\r\n .eq('user_id', userId)\r\n .order('created_at', { ascending: false })\r\n .limit(50);\r\n\r\n if (error) {\r\n setNotifications(DEMO_NOTIFICATIONS);\r\n } else {\r\n setNotifications((data as Notification[]) || []);\r\n }\r\n } catch {\r\n setNotifications(DEMO_NOTIFICATIONS);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [userId]);\r\n\r\n useEffect(() => {\r\n fetchNotifications();\r\n }, [fetchNotifications]);\r\n\r\n useEffect(() => {\r\n if (!features.auth || !userId) return;\r\n\r\n const channel = supabase\r\n .channel(`notifications_${userId}`)\r\n .on(\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n 'postgres_changes' as any,\r\n {\r\n event: 'INSERT',\r\n schema: 'public',\r\n table: 'notifications',\r\n filter: `user_id=eq.${userId}`,\r\n },\r\n (payload: { new: Notification }) => {\r\n setNotifications((prev) => [payload.new, ...prev]);\r\n }\r\n )\r\n .subscribe();\r\n\r\n return () => {\r\n supabase.removeChannel(channel);\r\n };\r\n }, [userId]);\r\n\r\n const markAsRead = useCallback(async (notificationId: string) => {\r\n if (!features.auth) return;\r\n\r\n await supabase\r\n .from('notifications')\r\n .update({ read: true, read_at: new Date().toISOString() })\r\n .eq('id', notificationId);\r\n\r\n setNotifications((prev) =>\r\n prev.map((n) => (n.id === notificationId ? { ...n, read: true } : n))\r\n );\r\n }, []);\r\n\r\n const markAllAsRead = useCallback(async () => {\r\n if (!features.auth || !userId) return;\r\n\r\n await supabase\r\n .from('notifications')\r\n .update({ read: true, read_at: new Date().toISOString() })\r\n .eq('user_id', userId)\r\n .eq('read', false);\r\n\r\n setNotifications((prev) => prev.map((n) => ({ ...n, read: true })));\r\n }, [userId]);\r\n\r\n const deleteNotification = useCallback(async (notificationId: string) => {\r\n if (!features.auth) return;\r\n\r\n await supabase.from('notifications').delete().eq('id', notificationId);\r\n setNotifications((prev) => prev.filter((n) => n.id !== notificationId));\r\n }, []);\r\n\r\n const unreadCount = notifications.filter((n) => !n.read).length;\r\n\r\n return {\r\n notifications,\r\n unreadCount,\r\n loading,\r\n isConfigured: features.auth,\r\n markAsRead,\r\n markAllAsRead,\r\n deleteNotification,\r\n refetch: fetchNotifications,\r\n };\r\n}\r\n","import { useState } from 'react';\r\nimport { useNotifications } from './useNotifications';\r\n\r\ninterface NotificationCenterProps {\r\n className?: string;\r\n}\r\n\r\nexport function NotificationCenter({ className = '' }: NotificationCenterProps) {\r\n const { notifications, unreadCount, markAsRead, markAllAsRead, deleteNotification } = useNotifications();\r\n const [open, setOpen] = useState(false);\r\n\r\n return (\r\n <div className={className} style={{ position: 'relative', display: 'inline-block' }}>\r\n <button\r\n onClick={() => setOpen(!open)}\r\n style={{\r\n background: 'none', border: 'none', cursor: 'pointer',\r\n position: 'relative', padding: '8px', fontSize: '20px',\r\n }}\r\n >\r\n 🔔\r\n {unreadCount > 0 && (\r\n <span style={{\r\n position: 'absolute', top: '2px', right: '2px',\r\n backgroundColor: '#dc2626', color: 'white', fontSize: '10px',\r\n borderRadius: '50%', width: '18px', height: '18px',\r\n display: 'flex', alignItems: 'center', justifyContent: 'center',\r\n }}>\r\n {unreadCount > 9 ? '9+' : unreadCount}\r\n </span>\r\n )}\r\n </button>\r\n\r\n {open && (\r\n <div style={{\r\n position: 'absolute', right: 0, top: '100%', width: '320px',\r\n backgroundColor: 'white', border: '1px solid #e5e7eb',\r\n borderRadius: '8px', boxShadow: '0 4px 12px rgba(0,0,0,0.1)',\r\n zIndex: 50, maxHeight: '400px', overflow: 'auto',\r\n }}>\r\n <div style={{ padding: '12px 16px', borderBottom: '1px solid #e5e7eb', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\r\n <span style={{ fontWeight: 600 }}>Notifications</span>\r\n {unreadCount > 0 && (\r\n <button onClick={() => markAllAsRead()} style={{ background: 'none', border: 'none', color: '#3b82f6', cursor: 'pointer', fontSize: '12px' }}>\r\n Mark all read\r\n </button>\r\n )}\r\n </div>\r\n\r\n {notifications.length === 0 ? (\r\n <div style={{ padding: '24px', textAlign: 'center', color: '#9ca3af' }}>\r\n No notifications\r\n </div>\r\n ) : (\r\n notifications.map((n) => (\r\n <div\r\n key={n.id}\r\n style={{\r\n padding: '12px 16px', borderBottom: '1px solid #f3f4f6',\r\n backgroundColor: n.read ? 'transparent' : '#eff6ff',\r\n cursor: 'pointer',\r\n }}\r\n onClick={() => !n.read && markAsRead(n.id)}\r\n >\r\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>\r\n <div>\r\n <p style={{ fontWeight: 500, fontSize: '14px', marginBottom: '2px' }}>{n.title}</p>\r\n <p style={{ color: '#6b7280', fontSize: '13px' }}>{n.message}</p>\r\n <p style={{ color: '#9ca3af', fontSize: '11px', marginTop: '4px' }}>\r\n {new Date(n.created_at).toLocaleDateString()}\r\n </p>\r\n </div>\r\n <button\r\n onClick={(e) => { e.stopPropagation(); deleteNotification(n.id); }}\r\n style={{ background: 'none', border: 'none', color: '#9ca3af', cursor: 'pointer', fontSize: '16px' }}\r\n >\r\n ×\r\n </button>\r\n </div>\r\n </div>\r\n ))\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n );\r\n}\r\n","/**\r\n * SDK sendNotification (B1).\r\n *\r\n * Routes to /api/project-notifications/send using the SERVER-class project\r\n * token.\r\n *\r\n * BEFORE B1, this function called a Supabase RPC (`sdk_create_notification`)\r\n * directly. That bypassed the platform auth surface entirely, so quota and\r\n * per-tier limits could not be enforced.\r\n *\r\n * AFTER B1:\r\n * - Reads EZC_PROJECT_TOKEN_SERVER from server-side env.\r\n * - Sends via `X-EzCoder-Server-Token` header to the new\r\n * /api/project-notifications/send endpoint.\r\n * - Refuses to run from browser bundles with a clear, actionable error.\r\n * - Per-project rate limits, audit logging, and the credential class check\r\n * are enforced server-side.\r\n *\r\n * For READING notifications (browser-friendly), see `useNotifications`,\r\n * which targets /api/project-notifications/list using the PUBLIC-class\r\n * token via `resolvePublicToken()`.\r\n */\r\n\r\nimport { env } from '../core/config';\r\nimport { resolveServerToken } from '../core/projectToken';\r\n\r\ninterface SendNotificationOptions {\r\n type?: 'info' | 'success' | 'warning' | 'error' | 'system';\r\n data?: Record<string, unknown>;\r\n}\r\n\r\ninterface SendNotificationResult {\r\n success: boolean;\r\n id?: string;\r\n error?: string;\r\n code?: string;\r\n}\r\n\r\nexport async function sendNotification(\r\n userId: string,\r\n title: string,\r\n message: string,\r\n options: SendNotificationOptions = {},\r\n): Promise<SendNotificationResult> {\r\n const apiUrl = env.EZCODER_API_URL;\r\n const projectId = env.EZC_PROJECT_ID;\r\n\r\n if (!apiUrl || !projectId) {\r\n return {\r\n success: false,\r\n error: 'EZCODER_API_URL and EZC_PROJECT_ID are required',\r\n code: 'sdk_misconfigured',\r\n };\r\n }\r\n\r\n const tokenResolution = resolveServerToken();\r\n if (!tokenResolution.ok) {\r\n return { success: false, error: tokenResolution.reason, code: 'no_server_token' };\r\n }\r\n\r\n try {\r\n const res = await fetch(`${apiUrl}/api/project-notifications/send`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'X-EzCoder-Server-Token': tokenResolution.token,\r\n },\r\n body: JSON.stringify({\r\n projectId,\r\n userId,\r\n title,\r\n message,\r\n type: options.type ?? 'info',\r\n data: options.data ?? {},\r\n }),\r\n });\r\n\r\n const raw: unknown = await res.json().catch(() => ({}));\r\n const data = (raw && typeof raw === 'object' ? raw : {}) as {\r\n id?: string;\r\n error?: string;\r\n code?: string;\r\n };\r\n\r\n if (!res.ok) {\r\n return {\r\n success: false,\r\n error: data.error ?? `HTTP ${res.status}`,\r\n code: data.code,\r\n };\r\n }\r\n\r\n return { success: true, id: data.id };\r\n } catch (err: unknown) {\r\n return {\r\n success: false,\r\n error: err instanceof Error ? err.message : 'Network error',\r\n code: 'network_error',\r\n };\r\n }\r\n}\r\n"],"mappings":"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","names":["useState","useState"]}
|
package/dist/payments/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { e as SubscriptionTier, d as SubscriptionStatus } from '../types-
|
|
1
|
+
import { e as SubscriptionTier, d as SubscriptionStatus } from '../types-1uP3V_pe.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
|
|
4
4
|
interface SubscriptionState {
|
|
@@ -83,7 +83,15 @@ interface ProtectedContentProps {
|
|
|
83
83
|
children: React.ReactNode;
|
|
84
84
|
fallback?: React.ReactNode;
|
|
85
85
|
loadingComponent?: React.ReactNode;
|
|
86
|
+
requiredTier?: SubscriptionTier;
|
|
86
87
|
}
|
|
87
|
-
declare function ProtectedContent({ children, fallback, loadingComponent }: ProtectedContentProps): react_jsx_runtime.JSX.Element;
|
|
88
|
+
declare function ProtectedContent({ children, fallback, loadingComponent, requiredTier }: ProtectedContentProps): react_jsx_runtime.JSX.Element;
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
interface InvoiceHistoryProps {
|
|
91
|
+
customerId?: string;
|
|
92
|
+
limit?: number;
|
|
93
|
+
className?: string;
|
|
94
|
+
}
|
|
95
|
+
declare function InvoiceHistory({ customerId, limit, className }: InvoiceHistoryProps): react_jsx_runtime.JSX.Element;
|
|
96
|
+
|
|
97
|
+
export { BuyButton, InvoiceHistory, ManageSubscriptionButton, PricingTable, ProtectedContent, SubscriptionManager, useCustomerAccess, useSubscription };
|
package/dist/payments/index.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AuthContext
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-QHB7LGCA.js";
|
|
4
4
|
import {
|
|
5
5
|
ezcoder
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-HJ2EIZ4S.js";
|
|
7
7
|
import {
|
|
8
|
-
features,
|
|
9
8
|
supabase
|
|
10
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-I2YGB7Z6.js";
|
|
10
|
+
import {
|
|
11
|
+
features
|
|
12
|
+
} from "../chunk-LIUE7M7K.js";
|
|
11
13
|
|
|
12
14
|
// src/payments/useSubscription.ts
|
|
13
15
|
import { useState, useEffect, useCallback, useContext } from "react";
|
|
@@ -386,18 +388,110 @@ function SubscriptionManager({ className = "" }) {
|
|
|
386
388
|
|
|
387
389
|
// src/payments/ProtectedContent.tsx
|
|
388
390
|
import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
|
|
389
|
-
function ProtectedContent({ children, fallback, loadingComponent }) {
|
|
390
|
-
const
|
|
391
|
+
function ProtectedContent({ children, fallback, loadingComponent, requiredTier }) {
|
|
392
|
+
const customerAccess = useCustomerAccess();
|
|
393
|
+
const subscription = useSubscription();
|
|
394
|
+
const loading = requiredTier ? subscription.loading : customerAccess.loading;
|
|
391
395
|
if (loading) {
|
|
392
396
|
return /* @__PURE__ */ jsx5(Fragment2, { children: loadingComponent || /* @__PURE__ */ jsx5("div", { style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "Loading..." }) });
|
|
393
397
|
}
|
|
398
|
+
const hasAccess = requiredTier ? subscription.isActive && subscription.canAccess(requiredTier) : customerAccess.hasAccess;
|
|
394
399
|
if (!hasAccess) {
|
|
395
|
-
return /* @__PURE__ */ jsx5(Fragment2, { children: fallback || /* @__PURE__ */ jsx5("div", { style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: "This content requires a subscription." }) });
|
|
400
|
+
return /* @__PURE__ */ jsx5(Fragment2, { children: fallback || /* @__PURE__ */ jsx5("div", { style: { padding: "20px", textAlign: "center", color: "#6b7280" }, children: requiredTier ? `This content requires a ${requiredTier} subscription or higher.` : "This content requires a subscription." }) });
|
|
396
401
|
}
|
|
397
402
|
return /* @__PURE__ */ jsx5(Fragment2, { children });
|
|
398
403
|
}
|
|
404
|
+
|
|
405
|
+
// src/payments/InvoiceHistory.tsx
|
|
406
|
+
import { useState as useState6, useEffect as useEffect3, useCallback as useCallback3 } from "react";
|
|
407
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
408
|
+
function InvoiceHistory({ customerId, limit = 10, className = "" }) {
|
|
409
|
+
const [invoices, setInvoices] = useState6([]);
|
|
410
|
+
const [loading, setLoading] = useState6(true);
|
|
411
|
+
const [error, setError] = useState6(null);
|
|
412
|
+
const fetchInvoices = useCallback3(async () => {
|
|
413
|
+
const id = customerId || (typeof localStorage !== "undefined" ? localStorage.getItem("stripeCustomerId") : null);
|
|
414
|
+
if (!id) {
|
|
415
|
+
setLoading(false);
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
setLoading(true);
|
|
419
|
+
setError(null);
|
|
420
|
+
try {
|
|
421
|
+
const result = await ezcoder.stripe.getInvoices(id, { limit });
|
|
422
|
+
if (result.success && result.invoices) {
|
|
423
|
+
setInvoices(result.invoices);
|
|
424
|
+
} else {
|
|
425
|
+
setError(result.error || "Failed to load invoices");
|
|
426
|
+
}
|
|
427
|
+
} catch (err) {
|
|
428
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
429
|
+
} finally {
|
|
430
|
+
setLoading(false);
|
|
431
|
+
}
|
|
432
|
+
}, [customerId, limit]);
|
|
433
|
+
useEffect3(() => {
|
|
434
|
+
fetchInvoices();
|
|
435
|
+
}, [fetchInvoices]);
|
|
436
|
+
if (loading) {
|
|
437
|
+
return /* @__PURE__ */ jsx6("div", { style: { padding: "20px", color: "#6b7280" }, children: "Loading invoices..." });
|
|
438
|
+
}
|
|
439
|
+
if (error) {
|
|
440
|
+
return /* @__PURE__ */ jsx6("div", { style: { padding: "20px", color: "#dc2626" }, children: error });
|
|
441
|
+
}
|
|
442
|
+
if (invoices.length === 0) {
|
|
443
|
+
return /* @__PURE__ */ jsx6("div", { style: { padding: "20px", color: "#6b7280" }, children: "No invoices found." });
|
|
444
|
+
}
|
|
445
|
+
const formatAmount = (amount, currency) => {
|
|
446
|
+
return new Intl.NumberFormat("en-US", { style: "currency", currency }).format(amount / 100);
|
|
447
|
+
};
|
|
448
|
+
const STATUS_COLORS2 = {
|
|
449
|
+
paid: "#059669",
|
|
450
|
+
open: "#3b82f6",
|
|
451
|
+
draft: "#6b7280",
|
|
452
|
+
void: "#9ca3af",
|
|
453
|
+
uncollectible: "#dc2626"
|
|
454
|
+
};
|
|
455
|
+
return /* @__PURE__ */ jsxs4("div", { className, style: { border: "1px solid #e5e7eb", borderRadius: "12px", overflow: "hidden" }, children: [
|
|
456
|
+
/* @__PURE__ */ jsx6("div", { style: { padding: "16px 24px", borderBottom: "1px solid #e5e7eb" }, children: /* @__PURE__ */ jsx6("h3", { style: { fontSize: "1.125rem", fontWeight: 600, margin: 0 }, children: "Invoice History" }) }),
|
|
457
|
+
/* @__PURE__ */ jsxs4("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: "14px" }, children: [
|
|
458
|
+
/* @__PURE__ */ jsx6("thead", { children: /* @__PURE__ */ jsxs4("tr", { style: { borderBottom: "1px solid #e5e7eb", background: "#f9fafb" }, children: [
|
|
459
|
+
/* @__PURE__ */ jsx6("th", { style: { padding: "10px 16px", textAlign: "left", fontWeight: 500, color: "#6b7280" }, children: "Invoice" }),
|
|
460
|
+
/* @__PURE__ */ jsx6("th", { style: { padding: "10px 16px", textAlign: "left", fontWeight: 500, color: "#6b7280" }, children: "Date" }),
|
|
461
|
+
/* @__PURE__ */ jsx6("th", { style: { padding: "10px 16px", textAlign: "right", fontWeight: 500, color: "#6b7280" }, children: "Amount" }),
|
|
462
|
+
/* @__PURE__ */ jsx6("th", { style: { padding: "10px 16px", textAlign: "center", fontWeight: 500, color: "#6b7280" }, children: "Status" }),
|
|
463
|
+
/* @__PURE__ */ jsx6("th", { style: { padding: "10px 16px", textAlign: "right", fontWeight: 500, color: "#6b7280" } })
|
|
464
|
+
] }) }),
|
|
465
|
+
/* @__PURE__ */ jsx6("tbody", { children: invoices.map((invoice) => /* @__PURE__ */ jsxs4("tr", { style: { borderBottom: "1px solid #f3f4f6" }, children: [
|
|
466
|
+
/* @__PURE__ */ jsx6("td", { style: { padding: "12px 16px" }, children: invoice.number || invoice.id.slice(0, 12) }),
|
|
467
|
+
/* @__PURE__ */ jsx6("td", { style: { padding: "12px 16px", color: "#6b7280" }, children: new Date(invoice.created * 1e3).toLocaleDateString() }),
|
|
468
|
+
/* @__PURE__ */ jsx6("td", { style: { padding: "12px 16px", textAlign: "right", fontWeight: 500 }, children: formatAmount(invoice.amount, invoice.currency) }),
|
|
469
|
+
/* @__PURE__ */ jsx6("td", { style: { padding: "12px 16px", textAlign: "center" }, children: /* @__PURE__ */ jsx6("span", { style: {
|
|
470
|
+
padding: "2px 8px",
|
|
471
|
+
borderRadius: "9999px",
|
|
472
|
+
fontSize: "12px",
|
|
473
|
+
fontWeight: 500,
|
|
474
|
+
color: STATUS_COLORS2[invoice.status] || "#6b7280",
|
|
475
|
+
background: `${STATUS_COLORS2[invoice.status] || "#6b7280"}15`,
|
|
476
|
+
textTransform: "capitalize"
|
|
477
|
+
}, children: invoice.status }) }),
|
|
478
|
+
/* @__PURE__ */ jsx6("td", { style: { padding: "12px 16px", textAlign: "right" }, children: invoice.pdfUrl && /* @__PURE__ */ jsx6(
|
|
479
|
+
"a",
|
|
480
|
+
{
|
|
481
|
+
href: invoice.pdfUrl,
|
|
482
|
+
target: "_blank",
|
|
483
|
+
rel: "noopener noreferrer",
|
|
484
|
+
style: { color: "#3b82f6", textDecoration: "none", fontSize: "13px" },
|
|
485
|
+
children: "PDF"
|
|
486
|
+
}
|
|
487
|
+
) })
|
|
488
|
+
] }, invoice.id)) })
|
|
489
|
+
] })
|
|
490
|
+
] });
|
|
491
|
+
}
|
|
399
492
|
export {
|
|
400
493
|
BuyButton,
|
|
494
|
+
InvoiceHistory,
|
|
401
495
|
ManageSubscriptionButton,
|
|
402
496
|
PricingTable,
|
|
403
497
|
ProtectedContent,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/payments/useSubscription.ts","../../src/payments/useCustomerAccess.ts","../../src/payments/BuyButton.tsx","../../src/payments/PricingTable.tsx","../../src/payments/ManageSubscriptionButton.tsx","../../src/payments/SubscriptionManager.tsx","../../src/payments/ProtectedContent.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\nimport { AuthContext } from '../auth/AuthProvider';\nimport { supabase } from '../core/supabase';\nimport { features } from '../core/config';\nimport type { SubscriptionTier, SubscriptionStatus } from '../core/types';\n\ninterface SubscriptionState {\n customerId: string | null;\n tier: SubscriptionTier;\n status: SubscriptionStatus | null;\n currentPeriodEnd: string | null;\n}\n\ninterface UseSubscriptionReturn {\n subscription: SubscriptionState | null;\n tier: SubscriptionTier;\n status: SubscriptionStatus | null;\n isActive: boolean;\n isPro: boolean;\n isBusiness: boolean;\n isEnterprise: boolean;\n canAccess: (requiredTier: SubscriptionTier) => boolean;\n loading: boolean;\n isConfigured: boolean;\n user: unknown;\n profile: unknown;\n isAuthenticated: boolean;\n refetch: () => Promise<void>;\n}\n\nconst TIER_LEVELS: Record<string, number> = {\n free: 0, starter: 1, creator: 2, pro: 3, business: 4, enterprise: 5,\n};\n\nexport function useSubscription(): UseSubscriptionReturn {\n const auth = useContext(AuthContext);\n const [subscription, setSubscription] = useState<SubscriptionState | null>(null);\n const [loading, setLoading] = useState(true);\n\n const fetchSubscription = useCallback(async () => {\n if (!auth?.profile) {\n setSubscription(null);\n setLoading(false);\n return;\n }\n\n const sub: SubscriptionState = {\n customerId: auth.profile.stripe_customer_id || null,\n tier: (auth.profile.subscription_tier as SubscriptionTier) || 'free',\n status: (auth.profile.subscription_status as SubscriptionStatus) || null,\n currentPeriodEnd: auth.profile.subscription_period_end || null,\n };\n\n setSubscription(sub);\n setLoading(false);\n }, [auth?.profile]);\n\n useEffect(() => {\n fetchSubscription();\n }, [fetchSubscription]);\n\n useEffect(() => {\n if (!features.auth || !auth?.user?.id) return;\n\n const channel = supabase\n .channel(`subscription_${auth.user.id}`)\n .on(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n 'postgres_changes' as any,\n {\n event: 'UPDATE',\n schema: 'public',\n table: 'user_profiles',\n filter: `id=eq.${auth.user.id}`,\n },\n () => {\n auth.refetchProfile(auth.user!.id);\n }\n )\n .subscribe();\n\n return () => {\n supabase.removeChannel(channel);\n };\n }, [auth?.user?.id, auth]);\n\n const tier = subscription?.tier || 'free';\n const status = subscription?.status || null;\n const isActive = !status || status === 'active' || status === 'trialing';\n const tierLevel = TIER_LEVELS[tier] ?? 0;\n\n return {\n subscription,\n tier,\n status,\n isActive,\n isPro: tierLevel >= TIER_LEVELS.pro,\n isBusiness: tierLevel >= TIER_LEVELS.business,\n isEnterprise: tierLevel >= TIER_LEVELS.enterprise,\n canAccess: (requiredTier: SubscriptionTier) => tierLevel >= (TIER_LEVELS[requiredTier] ?? 0),\n loading: loading || (auth?.loading ?? false),\n isConfigured: features.payments,\n user: auth?.user ?? null,\n profile: auth?.profile ?? null,\n isAuthenticated: Boolean(auth?.user),\n refetch: fetchSubscription,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { ezcoder } from '../core/platform';\n\ninterface CustomerAccessReturn {\n loading: boolean;\n hasAccess: boolean;\n customer: Record<string, unknown> | null;\n subscription: Record<string, unknown> | null;\n error: string | null;\n refresh: () => Promise<void>;\n logout: () => void;\n}\n\nexport function useCustomerAccess(): CustomerAccessReturn {\n const [loading, setLoading] = useState(true);\n const [hasAccess, setHasAccess] = useState(false);\n const [customer, setCustomer] = useState<Record<string, unknown> | null>(null);\n const [subscription, setSubscription] = useState<Record<string, unknown> | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const checkAccess = useCallback(async () => {\n setLoading(true);\n setError(null);\n\n try {\n const customerId = typeof localStorage !== 'undefined'\n ? localStorage.getItem('stripeCustomerId')\n : null;\n const email = typeof localStorage !== 'undefined'\n ? localStorage.getItem('customerEmail')\n : null;\n\n if (!customerId && !email) {\n setHasAccess(false);\n setLoading(false);\n return;\n }\n\n const result = await ezcoder.stripe.getCustomerStatus({ customerId: customerId || undefined, email: email || undefined });\n\n if (result.success) {\n setHasAccess(Boolean(result.hasAccess));\n setCustomer((result.customer as Record<string, unknown>) || null);\n setSubscription((result.subscription as Record<string, unknown>) || null);\n } else {\n setHasAccess(false);\n setError(result.error || 'Failed to check access');\n }\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : 'Unknown error');\n setHasAccess(false);\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n checkAccess();\n }, [checkAccess]);\n\n const logout = useCallback(() => {\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem('stripeCustomerId');\n localStorage.removeItem('customerEmail');\n }\n setHasAccess(false);\n setCustomer(null);\n setSubscription(null);\n }, []);\n\n return { loading, hasAccess, customer, subscription, error, refresh: checkAccess, logout };\n}\n","import { useState } from 'react';\nimport { ezcoder } from '../core/platform';\n\ninterface BuyButtonProps {\n priceId: string;\n productName?: string;\n className?: string;\n children?: React.ReactNode;\n disabled?: boolean;\n customerEmail?: string;\n quantity?: number;\n successUrl?: string;\n cancelUrl?: string;\n}\n\nexport function BuyButton({\n priceId,\n productName,\n className = '',\n children,\n disabled = false,\n customerEmail,\n quantity,\n successUrl,\n cancelUrl,\n}: BuyButtonProps) {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleClick = async () => {\n setError(null);\n setLoading(true);\n\n try {\n const result = await ezcoder.stripe.createCheckout(priceId, {\n customerEmail,\n quantity,\n successUrl,\n cancelUrl,\n redirect: true,\n });\n\n if (!result.success) {\n setError(result.error || 'Checkout failed');\n }\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : 'Checkout failed');\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div>\n <button\n onClick={handleClick}\n disabled={disabled || loading}\n className={className}\n style={!className ? {\n padding: '10px 20px',\n backgroundColor: disabled || loading ? '#9ca3af' : '#3b82f6',\n color: 'white',\n border: 'none',\n borderRadius: '6px',\n fontSize: '14px',\n fontWeight: 500,\n cursor: disabled || loading ? 'not-allowed' : 'pointer',\n } : undefined}\n >\n {loading ? 'Processing...' : children || `Buy ${productName || 'Now'}`}\n </button>\n {error && (\n <p style={{ color: '#dc2626', fontSize: '12px', marginTop: '4px' }}>{error}</p>\n )}\n </div>\n );\n}\n","import { useState } from 'react';\nimport { BuyButton } from './BuyButton';\n\ninterface PricingPlan {\n name: string;\n description: string;\n monthlyPriceId?: string;\n yearlyPriceId?: string;\n monthlyPrice: number;\n yearlyPrice?: number;\n features: string[];\n highlighted?: boolean;\n cta?: string;\n}\n\ninterface PricingTableProps {\n plans?: PricingPlan[];\n className?: string;\n customerEmail?: string;\n}\n\nconst DEFAULT_PLANS: PricingPlan[] = [\n {\n name: 'Starter',\n description: 'For individuals getting started',\n monthlyPrice: 0,\n features: ['Basic features', 'Community support'],\n cta: 'Get Started',\n },\n {\n name: 'Creator',\n description: 'For growing projects',\n monthlyPrice: 25,\n yearlyPrice: 270,\n features: ['All Starter features', 'Priority support', 'Advanced analytics'],\n highlighted: true,\n cta: 'Subscribe',\n },\n {\n name: 'Business',\n description: 'For teams and businesses',\n monthlyPrice: 50,\n yearlyPrice: 540,\n features: ['All Creator features', 'Team collaboration', 'Custom integrations'],\n cta: 'Subscribe',\n },\n {\n name: 'Enterprise',\n description: 'For large organizations',\n monthlyPrice: -1,\n features: ['All Business features', 'Dedicated support', 'SLA guarantee', 'Custom contracts'],\n cta: 'Contact Sales',\n },\n];\n\nexport function PricingTable({ plans = DEFAULT_PLANS, className = '', customerEmail }: PricingTableProps) {\n const [yearly, setYearly] = useState(false);\n\n return (\n <div className={className}>\n <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '32px', gap: '8px', alignItems: 'center' }}>\n <span style={{ fontSize: '14px', color: !yearly ? '#111' : '#6b7280', fontWeight: !yearly ? 600 : 400 }}>Monthly</span>\n <button\n onClick={() => setYearly(!yearly)}\n style={{\n width: '44px', height: '24px', borderRadius: '12px',\n backgroundColor: yearly ? '#3b82f6' : '#d1d5db',\n border: 'none', cursor: 'pointer', position: 'relative',\n }}\n >\n <span style={{\n width: '18px', height: '18px', borderRadius: '50%', backgroundColor: 'white',\n position: 'absolute', top: '3px', left: yearly ? '23px' : '3px',\n transition: 'left 0.2s',\n }} />\n </button>\n <span style={{ fontSize: '14px', color: yearly ? '#111' : '#6b7280', fontWeight: yearly ? 600 : 400 }}>\n Yearly <span style={{ color: '#059669', fontSize: '12px' }}>Save 10%</span>\n </span>\n </div>\n\n <div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(plans.length, 4)}, 1fr)`, gap: '24px', maxWidth: '1200px', margin: '0 auto' }}>\n {plans.map((plan) => {\n const price = yearly && plan.yearlyPrice !== undefined ? plan.yearlyPrice / 12 : plan.monthlyPrice;\n const priceId = yearly ? plan.yearlyPriceId : plan.monthlyPriceId;\n\n return (\n <div\n key={plan.name}\n style={{\n border: plan.highlighted ? '2px solid #3b82f6' : '1px solid #e5e7eb',\n borderRadius: '12px', padding: '24px',\n backgroundColor: plan.highlighted ? '#eff6ff' : 'white',\n }}\n >\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '4px' }}>{plan.name}</h3>\n <p style={{ color: '#6b7280', fontSize: '14px', marginBottom: '16px' }}>{plan.description}</p>\n\n <div style={{ marginBottom: '24px' }}>\n {plan.monthlyPrice === 0 ? (\n <span style={{ fontSize: '2rem', fontWeight: 700 }}>Free</span>\n ) : plan.monthlyPrice === -1 ? (\n <span style={{ fontSize: '1.5rem', fontWeight: 600 }}>Custom</span>\n ) : (\n <>\n <span style={{ fontSize: '2rem', fontWeight: 700 }}>${Math.round(price)}</span>\n <span style={{ color: '#6b7280', fontSize: '14px' }}>/mo</span>\n </>\n )}\n </div>\n\n <ul style={{ listStyle: 'none', padding: 0, marginBottom: '24px' }}>\n {plan.features.map((feature) => (\n <li key={feature} style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px', fontSize: '14px' }}>\n <span style={{ color: '#059669' }}>✓</span> {feature}\n </li>\n ))}\n </ul>\n\n {priceId ? (\n <BuyButton priceId={priceId} productName={plan.name} customerEmail={customerEmail}>\n {plan.cta || 'Subscribe'}\n </BuyButton>\n ) : plan.monthlyPrice === 0 ? (\n <button style={{\n width: '100%', padding: '10px', border: '1px solid #d1d5db',\n borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px',\n }}>\n {plan.cta || 'Get Started'}\n </button>\n ) : (\n <button style={{\n width: '100%', padding: '10px', border: '1px solid #d1d5db',\n borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px',\n }}>\n {plan.cta || 'Contact Sales'}\n </button>\n )}\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n","import { useState } from 'react';\nimport { ezcoder } from '../core/platform';\n\ninterface ManageSubscriptionButtonProps {\n children?: React.ReactNode;\n className?: string;\n customerId?: string;\n}\n\nexport function ManageSubscriptionButton({ children, className = '', customerId }: ManageSubscriptionButtonProps) {\n const [loading, setLoading] = useState(false);\n\n const handleClick = async () => {\n const id = customerId || (typeof localStorage !== 'undefined' ? localStorage.getItem('stripeCustomerId') : null);\n if (!id) return;\n\n setLoading(true);\n await ezcoder.stripe.createPortalSession(id, { redirect: true });\n setLoading(false);\n };\n\n return (\n <button\n onClick={handleClick}\n disabled={loading}\n className={className}\n style={!className ? {\n padding: '8px 16px',\n border: '1px solid #d1d5db',\n borderRadius: '6px',\n background: 'white',\n cursor: loading ? 'not-allowed' : 'pointer',\n fontSize: '14px',\n } : undefined}\n >\n {loading ? 'Loading...' : children || 'Manage Subscription'}\n </button>\n );\n}\n","import { useSubscription } from './useSubscription';\nimport { ManageSubscriptionButton } from './ManageSubscriptionButton';\n\ninterface SubscriptionManagerProps {\n className?: string;\n}\n\nconst STATUS_COLORS: Record<string, string> = {\n active: '#059669',\n trialing: '#3b82f6',\n past_due: '#d97706',\n canceled: '#dc2626',\n unpaid: '#dc2626',\n};\n\nexport function SubscriptionManager({ className = '' }: SubscriptionManagerProps) {\n const { subscription, tier, status, isActive, loading } = useSubscription();\n\n if (loading) {\n return <div style={{ padding: '20px', color: '#6b7280' }}>Loading subscription...</div>;\n }\n\n return (\n <div className={className} style={{ border: '1px solid #e5e7eb', borderRadius: '12px', padding: '24px' }}>\n <h3 style={{ fontSize: '1.125rem', fontWeight: 600, marginBottom: '16px' }}>Subscription</h3>\n\n <div style={{ display: 'grid', gap: '12px', marginBottom: '24px' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <span style={{ color: '#6b7280' }}>Plan</span>\n <span style={{ fontWeight: 500, textTransform: 'capitalize' }}>{tier}</span>\n </div>\n\n {status && (\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <span style={{ color: '#6b7280' }}>Status</span>\n <span style={{\n fontWeight: 500,\n color: STATUS_COLORS[status] || '#6b7280',\n textTransform: 'capitalize',\n }}>\n {status === 'past_due' ? 'Past Due' : status}\n </span>\n </div>\n )}\n\n {subscription?.currentPeriodEnd && (\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\n <span style={{ color: '#6b7280' }}>{isActive ? 'Renews' : 'Expires'}</span>\n <span>{new Date(subscription.currentPeriodEnd).toLocaleDateString()}</span>\n </div>\n )}\n </div>\n\n {subscription?.customerId && (\n <ManageSubscriptionButton customerId={subscription.customerId} />\n )}\n </div>\n );\n}\n","import { useCustomerAccess } from './useCustomerAccess';\n\ninterface ProtectedContentProps {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n loadingComponent?: React.ReactNode;\n}\n\nexport function ProtectedContent({ children, fallback, loadingComponent }: ProtectedContentProps) {\n const { loading, hasAccess } = useCustomerAccess();\n\n if (loading) {\n return <>{loadingComponent || <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Loading...</div>}</>;\n }\n\n if (!hasAccess) {\n return <>{fallback || <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>This content requires a subscription.</div>}</>;\n }\n\n return <>{children}</>;\n}\n"],"mappings":"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","names":["useState","useEffect","useCallback","useState","useCallback","useEffect","useState","useState","useState","jsx","jsxs","useState","useState","jsx","useState","jsx","jsxs","Fragment","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../../src/payments/useSubscription.ts","../../src/payments/useCustomerAccess.ts","../../src/payments/BuyButton.tsx","../../src/payments/PricingTable.tsx","../../src/payments/ManageSubscriptionButton.tsx","../../src/payments/SubscriptionManager.tsx","../../src/payments/ProtectedContent.tsx","../../src/payments/InvoiceHistory.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\r\nimport { AuthContext } from '../auth/AuthProvider';\r\nimport { supabase } from '../core/supabase';\r\nimport { features } from '../core/config';\r\nimport type { SubscriptionTier, SubscriptionStatus } from '../core/types';\r\n\r\ninterface SubscriptionState {\r\n customerId: string | null;\r\n tier: SubscriptionTier;\r\n status: SubscriptionStatus | null;\r\n currentPeriodEnd: string | null;\r\n}\r\n\r\ninterface UseSubscriptionReturn {\r\n subscription: SubscriptionState | null;\r\n tier: SubscriptionTier;\r\n status: SubscriptionStatus | null;\r\n isActive: boolean;\r\n isPro: boolean;\r\n isBusiness: boolean;\r\n isEnterprise: boolean;\r\n canAccess: (requiredTier: SubscriptionTier) => boolean;\r\n loading: boolean;\r\n isConfigured: boolean;\r\n user: unknown;\r\n profile: unknown;\r\n isAuthenticated: boolean;\r\n refetch: () => Promise<void>;\r\n}\r\n\r\nconst TIER_LEVELS: Record<string, number> = {\r\n free: 0, starter: 1, creator: 2, pro: 3, business: 4, enterprise: 5,\r\n};\r\n\r\nexport function useSubscription(): UseSubscriptionReturn {\r\n const auth = useContext(AuthContext);\r\n const [subscription, setSubscription] = useState<SubscriptionState | null>(null);\r\n const [loading, setLoading] = useState(true);\r\n\r\n const fetchSubscription = useCallback(async () => {\r\n if (!auth?.profile) {\r\n setSubscription(null);\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n const sub: SubscriptionState = {\r\n customerId: auth.profile.stripe_customer_id || null,\r\n tier: (auth.profile.subscription_tier as SubscriptionTier) || 'free',\r\n status: (auth.profile.subscription_status as SubscriptionStatus) || null,\r\n currentPeriodEnd: auth.profile.subscription_period_end || null,\r\n };\r\n\r\n setSubscription(sub);\r\n setLoading(false);\r\n }, [auth?.profile]);\r\n\r\n useEffect(() => {\r\n fetchSubscription();\r\n }, [fetchSubscription]);\r\n\r\n useEffect(() => {\r\n if (!features.auth || !auth?.user?.id) return;\r\n\r\n const channel = supabase\r\n .channel(`subscription_${auth.user.id}`)\r\n .on(\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n 'postgres_changes' as any,\r\n {\r\n event: 'UPDATE',\r\n schema: 'public',\r\n table: 'user_profiles',\r\n filter: `id=eq.${auth.user.id}`,\r\n },\r\n () => {\r\n auth.refetchProfile(auth.user!.id);\r\n }\r\n )\r\n .subscribe();\r\n\r\n return () => {\r\n supabase.removeChannel(channel);\r\n };\r\n }, [auth?.user?.id, auth]);\r\n\r\n const tier = subscription?.tier || 'free';\r\n const status = subscription?.status || null;\r\n const isActive = !status || status === 'active' || status === 'trialing';\r\n const tierLevel = TIER_LEVELS[tier] ?? 0;\r\n\r\n return {\r\n subscription,\r\n tier,\r\n status,\r\n isActive,\r\n isPro: tierLevel >= TIER_LEVELS.pro,\r\n isBusiness: tierLevel >= TIER_LEVELS.business,\r\n isEnterprise: tierLevel >= TIER_LEVELS.enterprise,\r\n canAccess: (requiredTier: SubscriptionTier) => tierLevel >= (TIER_LEVELS[requiredTier] ?? 0),\r\n loading: loading || (auth?.loading ?? false),\r\n isConfigured: features.payments,\r\n user: auth?.user ?? null,\r\n profile: auth?.profile ?? null,\r\n isAuthenticated: Boolean(auth?.user),\r\n refetch: fetchSubscription,\r\n };\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport { ezcoder } from '../core/platform';\r\n\r\ninterface CustomerAccessReturn {\r\n loading: boolean;\r\n hasAccess: boolean;\r\n customer: Record<string, unknown> | null;\r\n subscription: Record<string, unknown> | null;\r\n error: string | null;\r\n refresh: () => Promise<void>;\r\n logout: () => void;\r\n}\r\n\r\nexport function useCustomerAccess(): CustomerAccessReturn {\r\n const [loading, setLoading] = useState(true);\r\n const [hasAccess, setHasAccess] = useState(false);\r\n const [customer, setCustomer] = useState<Record<string, unknown> | null>(null);\r\n const [subscription, setSubscription] = useState<Record<string, unknown> | null>(null);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const checkAccess = useCallback(async () => {\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const customerId = typeof localStorage !== 'undefined'\r\n ? localStorage.getItem('stripeCustomerId')\r\n : null;\r\n const email = typeof localStorage !== 'undefined'\r\n ? localStorage.getItem('customerEmail')\r\n : null;\r\n\r\n if (!customerId && !email) {\r\n setHasAccess(false);\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n const result = await ezcoder.stripe.getCustomerStatus({ customerId: customerId || undefined, email: email || undefined });\r\n\r\n if (result.success) {\r\n setHasAccess(Boolean(result.hasAccess));\r\n setCustomer((result.customer as Record<string, unknown>) || null);\r\n setSubscription((result.subscription as Record<string, unknown>) || null);\r\n } else {\r\n setHasAccess(false);\r\n setError(result.error || 'Failed to check access');\r\n }\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Unknown error');\r\n setHasAccess(false);\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n useEffect(() => {\r\n checkAccess();\r\n }, [checkAccess]);\r\n\r\n const logout = useCallback(() => {\r\n if (typeof localStorage !== 'undefined') {\r\n localStorage.removeItem('stripeCustomerId');\r\n localStorage.removeItem('customerEmail');\r\n }\r\n setHasAccess(false);\r\n setCustomer(null);\r\n setSubscription(null);\r\n }, []);\r\n\r\n return { loading, hasAccess, customer, subscription, error, refresh: checkAccess, logout };\r\n}\r\n","import { useState } from 'react';\r\nimport { ezcoder } from '../core/platform';\r\n\r\ninterface BuyButtonProps {\r\n priceId: string;\r\n productName?: string;\r\n className?: string;\r\n children?: React.ReactNode;\r\n disabled?: boolean;\r\n customerEmail?: string;\r\n quantity?: number;\r\n successUrl?: string;\r\n cancelUrl?: string;\r\n}\r\n\r\nexport function BuyButton({\r\n priceId,\r\n productName,\r\n className = '',\r\n children,\r\n disabled = false,\r\n customerEmail,\r\n quantity,\r\n successUrl,\r\n cancelUrl,\r\n}: BuyButtonProps) {\r\n const [loading, setLoading] = useState(false);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const handleClick = async () => {\r\n setError(null);\r\n setLoading(true);\r\n\r\n try {\r\n const result = await ezcoder.stripe.createCheckout(priceId, {\r\n customerEmail,\r\n quantity,\r\n successUrl,\r\n cancelUrl,\r\n redirect: true,\r\n });\r\n\r\n if (!result.success) {\r\n setError(result.error || 'Checkout failed');\r\n }\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Checkout failed');\r\n } finally {\r\n setLoading(false);\r\n }\r\n };\r\n\r\n return (\r\n <div>\r\n <button\r\n onClick={handleClick}\r\n disabled={disabled || loading}\r\n className={className}\r\n style={!className ? {\r\n padding: '10px 20px',\r\n backgroundColor: disabled || loading ? '#9ca3af' : '#3b82f6',\r\n color: 'white',\r\n border: 'none',\r\n borderRadius: '6px',\r\n fontSize: '14px',\r\n fontWeight: 500,\r\n cursor: disabled || loading ? 'not-allowed' : 'pointer',\r\n } : undefined}\r\n >\r\n {loading ? 'Processing...' : children || `Buy ${productName || 'Now'}`}\r\n </button>\r\n {error && (\r\n <p style={{ color: '#dc2626', fontSize: '12px', marginTop: '4px' }}>{error}</p>\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { BuyButton } from './BuyButton';\r\n\r\ninterface PricingPlan {\r\n name: string;\r\n description: string;\r\n monthlyPriceId?: string;\r\n yearlyPriceId?: string;\r\n monthlyPrice: number;\r\n yearlyPrice?: number;\r\n features: string[];\r\n highlighted?: boolean;\r\n cta?: string;\r\n}\r\n\r\ninterface PricingTableProps {\r\n plans?: PricingPlan[];\r\n className?: string;\r\n customerEmail?: string;\r\n}\r\n\r\nconst DEFAULT_PLANS: PricingPlan[] = [\r\n {\r\n name: 'Starter',\r\n description: 'For individuals getting started',\r\n monthlyPrice: 0,\r\n features: ['Basic features', 'Community support'],\r\n cta: 'Get Started',\r\n },\r\n {\r\n name: 'Creator',\r\n description: 'For growing projects',\r\n monthlyPrice: 25,\r\n yearlyPrice: 270,\r\n features: ['All Starter features', 'Priority support', 'Advanced analytics'],\r\n highlighted: true,\r\n cta: 'Subscribe',\r\n },\r\n {\r\n name: 'Business',\r\n description: 'For teams and businesses',\r\n monthlyPrice: 50,\r\n yearlyPrice: 540,\r\n features: ['All Creator features', 'Team collaboration', 'Custom integrations'],\r\n cta: 'Subscribe',\r\n },\r\n {\r\n name: 'Enterprise',\r\n description: 'For large organizations',\r\n monthlyPrice: -1,\r\n features: ['All Business features', 'Dedicated support', 'SLA guarantee', 'Custom contracts'],\r\n cta: 'Contact Sales',\r\n },\r\n];\r\n\r\nexport function PricingTable({ plans = DEFAULT_PLANS, className = '', customerEmail }: PricingTableProps) {\r\n const [yearly, setYearly] = useState(false);\r\n\r\n return (\r\n <div className={className}>\r\n <div style={{ display: 'flex', justifyContent: 'center', marginBottom: '32px', gap: '8px', alignItems: 'center' }}>\r\n <span style={{ fontSize: '14px', color: !yearly ? '#111' : '#6b7280', fontWeight: !yearly ? 600 : 400 }}>Monthly</span>\r\n <button\r\n onClick={() => setYearly(!yearly)}\r\n style={{\r\n width: '44px', height: '24px', borderRadius: '12px',\r\n backgroundColor: yearly ? '#3b82f6' : '#d1d5db',\r\n border: 'none', cursor: 'pointer', position: 'relative',\r\n }}\r\n >\r\n <span style={{\r\n width: '18px', height: '18px', borderRadius: '50%', backgroundColor: 'white',\r\n position: 'absolute', top: '3px', left: yearly ? '23px' : '3px',\r\n transition: 'left 0.2s',\r\n }} />\r\n </button>\r\n <span style={{ fontSize: '14px', color: yearly ? '#111' : '#6b7280', fontWeight: yearly ? 600 : 400 }}>\r\n Yearly <span style={{ color: '#059669', fontSize: '12px' }}>Save 10%</span>\r\n </span>\r\n </div>\r\n\r\n <div style={{ display: 'grid', gridTemplateColumns: `repeat(${Math.min(plans.length, 4)}, 1fr)`, gap: '24px', maxWidth: '1200px', margin: '0 auto' }}>\r\n {plans.map((plan) => {\r\n const price = yearly && plan.yearlyPrice !== undefined ? plan.yearlyPrice / 12 : plan.monthlyPrice;\r\n const priceId = yearly ? plan.yearlyPriceId : plan.monthlyPriceId;\r\n\r\n return (\r\n <div\r\n key={plan.name}\r\n style={{\r\n border: plan.highlighted ? '2px solid #3b82f6' : '1px solid #e5e7eb',\r\n borderRadius: '12px', padding: '24px',\r\n backgroundColor: plan.highlighted ? '#eff6ff' : 'white',\r\n }}\r\n >\r\n <h3 style={{ fontSize: '1.25rem', fontWeight: 600, marginBottom: '4px' }}>{plan.name}</h3>\r\n <p style={{ color: '#6b7280', fontSize: '14px', marginBottom: '16px' }}>{plan.description}</p>\r\n\r\n <div style={{ marginBottom: '24px' }}>\r\n {plan.monthlyPrice === 0 ? (\r\n <span style={{ fontSize: '2rem', fontWeight: 700 }}>Free</span>\r\n ) : plan.monthlyPrice === -1 ? (\r\n <span style={{ fontSize: '1.5rem', fontWeight: 600 }}>Custom</span>\r\n ) : (\r\n <>\r\n <span style={{ fontSize: '2rem', fontWeight: 700 }}>${Math.round(price)}</span>\r\n <span style={{ color: '#6b7280', fontSize: '14px' }}>/mo</span>\r\n </>\r\n )}\r\n </div>\r\n\r\n <ul style={{ listStyle: 'none', padding: 0, marginBottom: '24px' }}>\r\n {plan.features.map((feature) => (\r\n <li key={feature} style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px', fontSize: '14px' }}>\r\n <span style={{ color: '#059669' }}>✓</span> {feature}\r\n </li>\r\n ))}\r\n </ul>\r\n\r\n {priceId ? (\r\n <BuyButton priceId={priceId} productName={plan.name} customerEmail={customerEmail}>\r\n {plan.cta || 'Subscribe'}\r\n </BuyButton>\r\n ) : plan.monthlyPrice === 0 ? (\r\n <button style={{\r\n width: '100%', padding: '10px', border: '1px solid #d1d5db',\r\n borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px',\r\n }}>\r\n {plan.cta || 'Get Started'}\r\n </button>\r\n ) : (\r\n <button style={{\r\n width: '100%', padding: '10px', border: '1px solid #d1d5db',\r\n borderRadius: '6px', background: 'white', cursor: 'pointer', fontSize: '14px',\r\n }}>\r\n {plan.cta || 'Contact Sales'}\r\n </button>\r\n )}\r\n </div>\r\n );\r\n })}\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { useState } from 'react';\r\nimport { ezcoder } from '../core/platform';\r\n\r\ninterface ManageSubscriptionButtonProps {\r\n children?: React.ReactNode;\r\n className?: string;\r\n customerId?: string;\r\n}\r\n\r\nexport function ManageSubscriptionButton({ children, className = '', customerId }: ManageSubscriptionButtonProps) {\r\n const [loading, setLoading] = useState(false);\r\n\r\n const handleClick = async () => {\r\n const id = customerId || (typeof localStorage !== 'undefined' ? localStorage.getItem('stripeCustomerId') : null);\r\n if (!id) return;\r\n\r\n setLoading(true);\r\n await ezcoder.stripe.createPortalSession(id, { redirect: true });\r\n setLoading(false);\r\n };\r\n\r\n return (\r\n <button\r\n onClick={handleClick}\r\n disabled={loading}\r\n className={className}\r\n style={!className ? {\r\n padding: '8px 16px',\r\n border: '1px solid #d1d5db',\r\n borderRadius: '6px',\r\n background: 'white',\r\n cursor: loading ? 'not-allowed' : 'pointer',\r\n fontSize: '14px',\r\n } : undefined}\r\n >\r\n {loading ? 'Loading...' : children || 'Manage Subscription'}\r\n </button>\r\n );\r\n}\r\n","import { useSubscription } from './useSubscription';\r\nimport { ManageSubscriptionButton } from './ManageSubscriptionButton';\r\n\r\ninterface SubscriptionManagerProps {\r\n className?: string;\r\n}\r\n\r\nconst STATUS_COLORS: Record<string, string> = {\r\n active: '#059669',\r\n trialing: '#3b82f6',\r\n past_due: '#d97706',\r\n canceled: '#dc2626',\r\n unpaid: '#dc2626',\r\n};\r\n\r\nexport function SubscriptionManager({ className = '' }: SubscriptionManagerProps) {\r\n const { subscription, tier, status, isActive, loading } = useSubscription();\r\n\r\n if (loading) {\r\n return <div style={{ padding: '20px', color: '#6b7280' }}>Loading subscription...</div>;\r\n }\r\n\r\n return (\r\n <div className={className} style={{ border: '1px solid #e5e7eb', borderRadius: '12px', padding: '24px' }}>\r\n <h3 style={{ fontSize: '1.125rem', fontWeight: 600, marginBottom: '16px' }}>Subscription</h3>\r\n\r\n <div style={{ display: 'grid', gap: '12px', marginBottom: '24px' }}>\r\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\r\n <span style={{ color: '#6b7280' }}>Plan</span>\r\n <span style={{ fontWeight: 500, textTransform: 'capitalize' }}>{tier}</span>\r\n </div>\r\n\r\n {status && (\r\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\r\n <span style={{ color: '#6b7280' }}>Status</span>\r\n <span style={{\r\n fontWeight: 500,\r\n color: STATUS_COLORS[status] || '#6b7280',\r\n textTransform: 'capitalize',\r\n }}>\r\n {status === 'past_due' ? 'Past Due' : status}\r\n </span>\r\n </div>\r\n )}\r\n\r\n {subscription?.currentPeriodEnd && (\r\n <div style={{ display: 'flex', justifyContent: 'space-between' }}>\r\n <span style={{ color: '#6b7280' }}>{isActive ? 'Renews' : 'Expires'}</span>\r\n <span>{new Date(subscription.currentPeriodEnd).toLocaleDateString()}</span>\r\n </div>\r\n )}\r\n </div>\r\n\r\n {subscription?.customerId && (\r\n <ManageSubscriptionButton customerId={subscription.customerId} />\r\n )}\r\n </div>\r\n );\r\n}\r\n","import { useCustomerAccess } from './useCustomerAccess';\r\nimport { useSubscription } from './useSubscription';\r\nimport type { SubscriptionTier } from '../core/types';\r\n\r\ninterface ProtectedContentProps {\r\n children: React.ReactNode;\r\n fallback?: React.ReactNode;\r\n loadingComponent?: React.ReactNode;\r\n requiredTier?: SubscriptionTier;\r\n}\r\n\r\nexport function ProtectedContent({ children, fallback, loadingComponent, requiredTier }: ProtectedContentProps) {\r\n const customerAccess = useCustomerAccess();\r\n const subscription = useSubscription();\r\n\r\n const loading = requiredTier ? subscription.loading : customerAccess.loading;\r\n\r\n if (loading) {\r\n return <>{loadingComponent || <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>Loading...</div>}</>;\r\n }\r\n\r\n const hasAccess = requiredTier\r\n ? subscription.isActive && subscription.canAccess(requiredTier)\r\n : customerAccess.hasAccess;\r\n\r\n if (!hasAccess) {\r\n return <>{fallback || <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280' }}>\r\n {requiredTier\r\n ? `This content requires a ${requiredTier} subscription or higher.`\r\n : 'This content requires a subscription.'}\r\n </div>}</>;\r\n }\r\n\r\n return <>{children}</>;\r\n}\r\n","import { useState, useEffect, useCallback } from 'react';\r\nimport { ezcoder } from '../core/platform';\r\n\r\ninterface Invoice {\r\n id: string;\r\n number: string | null;\r\n amount: number;\r\n currency: string;\r\n status: string;\r\n created: number;\r\n hostedUrl: string | null;\r\n pdfUrl: string | null;\r\n}\r\n\r\ninterface InvoiceHistoryProps {\r\n customerId?: string;\r\n limit?: number;\r\n className?: string;\r\n}\r\n\r\nexport function InvoiceHistory({ customerId, limit = 10, className = '' }: InvoiceHistoryProps) {\r\n const [invoices, setInvoices] = useState<Invoice[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const fetchInvoices = useCallback(async () => {\r\n const id = customerId || (typeof localStorage !== 'undefined' ? localStorage.getItem('stripeCustomerId') : null);\r\n if (!id) {\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const result = await ezcoder.stripe.getInvoices(id, { limit });\r\n if (result.success && result.invoices) {\r\n setInvoices(result.invoices as Invoice[]);\r\n } else {\r\n setError(result.error || 'Failed to load invoices');\r\n }\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Unknown error');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [customerId, limit]);\r\n\r\n useEffect(() => {\r\n fetchInvoices();\r\n }, [fetchInvoices]);\r\n\r\n if (loading) {\r\n return <div style={{ padding: '20px', color: '#6b7280' }}>Loading invoices...</div>;\r\n }\r\n\r\n if (error) {\r\n return <div style={{ padding: '20px', color: '#dc2626' }}>{error}</div>;\r\n }\r\n\r\n if (invoices.length === 0) {\r\n return <div style={{ padding: '20px', color: '#6b7280' }}>No invoices found.</div>;\r\n }\r\n\r\n const formatAmount = (amount: number, currency: string) => {\r\n return new Intl.NumberFormat('en-US', { style: 'currency', currency }).format(amount / 100);\r\n };\r\n\r\n const STATUS_COLORS: Record<string, string> = {\r\n paid: '#059669',\r\n open: '#3b82f6',\r\n draft: '#6b7280',\r\n void: '#9ca3af',\r\n uncollectible: '#dc2626',\r\n };\r\n\r\n return (\r\n <div className={className} style={{ border: '1px solid #e5e7eb', borderRadius: '12px', overflow: 'hidden' }}>\r\n <div style={{ padding: '16px 24px', borderBottom: '1px solid #e5e7eb' }}>\r\n <h3 style={{ fontSize: '1.125rem', fontWeight: 600, margin: 0 }}>Invoice History</h3>\r\n </div>\r\n <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '14px' }}>\r\n <thead>\r\n <tr style={{ borderBottom: '1px solid #e5e7eb', background: '#f9fafb' }}>\r\n <th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 500, color: '#6b7280' }}>Invoice</th>\r\n <th style={{ padding: '10px 16px', textAlign: 'left', fontWeight: 500, color: '#6b7280' }}>Date</th>\r\n <th style={{ padding: '10px 16px', textAlign: 'right', fontWeight: 500, color: '#6b7280' }}>Amount</th>\r\n <th style={{ padding: '10px 16px', textAlign: 'center', fontWeight: 500, color: '#6b7280' }}>Status</th>\r\n <th style={{ padding: '10px 16px', textAlign: 'right', fontWeight: 500, color: '#6b7280' }}></th>\r\n </tr>\r\n </thead>\r\n <tbody>\r\n {invoices.map((invoice) => (\r\n <tr key={invoice.id} style={{ borderBottom: '1px solid #f3f4f6' }}>\r\n <td style={{ padding: '12px 16px' }}>{invoice.number || invoice.id.slice(0, 12)}</td>\r\n <td style={{ padding: '12px 16px', color: '#6b7280' }}>\r\n {new Date(invoice.created * 1000).toLocaleDateString()}\r\n </td>\r\n <td style={{ padding: '12px 16px', textAlign: 'right', fontWeight: 500 }}>\r\n {formatAmount(invoice.amount, invoice.currency)}\r\n </td>\r\n <td style={{ padding: '12px 16px', textAlign: 'center' }}>\r\n <span style={{\r\n padding: '2px 8px',\r\n borderRadius: '9999px',\r\n fontSize: '12px',\r\n fontWeight: 500,\r\n color: STATUS_COLORS[invoice.status] || '#6b7280',\r\n background: `${STATUS_COLORS[invoice.status] || '#6b7280'}15`,\r\n textTransform: 'capitalize',\r\n }}>\r\n {invoice.status}\r\n </span>\r\n </td>\r\n <td style={{ padding: '12px 16px', textAlign: 'right' }}>\r\n {invoice.pdfUrl && (\r\n <a\r\n href={invoice.pdfUrl}\r\n target=\"_blank\"\r\n rel=\"noopener noreferrer\"\r\n style={{ color: '#3b82f6', textDecoration: 'none', fontSize: '13px' }}\r\n >\r\n PDF\r\n </a>\r\n )}\r\n </td>\r\n </tr>\r\n ))}\r\n </tbody>\r\n </table>\r\n </div>\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAAA,SAAS,UAAU,WAAW,aAAa,kBAAkB;AA8B7D,IAAM,cAAsC;AAAA,EAC1C,MAAM;AAAA,EAAG,SAAS;AAAA,EAAG,SAAS;AAAA,EAAG,KAAK;AAAA,EAAG,UAAU;AAAA,EAAG,YAAY;AACpE;AAEO,SAAS,kBAAyC;AACvD,QAAM,OAAO,WAAW,WAAW;AACnC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAmC,IAAI;AAC/E,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,IAAI;AAE3C,QAAM,oBAAoB,YAAY,YAAY;AAChD,QAAI,CAAC,MAAM,SAAS;AAClB,sBAAgB,IAAI;AACpB,iBAAW,KAAK;AAChB;AAAA,IACF;AAEA,UAAM,MAAyB;AAAA,MAC7B,YAAY,KAAK,QAAQ,sBAAsB;AAAA,MAC/C,MAAO,KAAK,QAAQ,qBAA0C;AAAA,MAC9D,QAAS,KAAK,QAAQ,uBAA8C;AAAA,MACpE,kBAAkB,KAAK,QAAQ,2BAA2B;AAAA,IAC5D;AAEA,oBAAgB,GAAG;AACnB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,MAAM,OAAO,CAAC;AAElB,YAAU,MAAM;AACd,sBAAkB;AAAA,EACpB,GAAG,CAAC,iBAAiB,CAAC;AAEtB,YAAU,MAAM;AACd,QAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,MAAM,GAAI;AAEvC,UAAM,UAAU,SACb,QAAQ,gBAAgB,KAAK,KAAK,EAAE,EAAE,EACtC;AAAA;AAAA,MAEC;AAAA,MACA;AAAA,QACE,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,QAAQ,SAAS,KAAK,KAAK,EAAE;AAAA,MAC/B;AAAA,MACA,MAAM;AACJ,aAAK,eAAe,KAAK,KAAM,EAAE;AAAA,MACnC;AAAA,IACF,EACC,UAAU;AAEb,WAAO,MAAM;AACX,eAAS,cAAc,OAAO;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,MAAM,MAAM,IAAI,IAAI,CAAC;AAEzB,QAAM,OAAO,cAAc,QAAQ;AACnC,QAAM,SAAS,cAAc,UAAU;AACvC,QAAM,WAAW,CAAC,UAAU,WAAW,YAAY,WAAW;AAC9D,QAAM,YAAY,YAAY,IAAI,KAAK;AAEvC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO,aAAa,YAAY;AAAA,IAChC,YAAY,aAAa,YAAY;AAAA,IACrC,cAAc,aAAa,YAAY;AAAA,IACvC,WAAW,CAAC,iBAAmC,cAAc,YAAY,YAAY,KAAK;AAAA,IAC1F,SAAS,YAAY,MAAM,WAAW;AAAA,IACtC,cAAc,SAAS;AAAA,IACvB,MAAM,MAAM,QAAQ;AAAA,IACpB,SAAS,MAAM,WAAW;AAAA,IAC1B,iBAAiB,QAAQ,MAAM,IAAI;AAAA,IACnC,SAAS;AAAA,EACX;AACF;;;AC3GA,SAAS,YAAAA,WAAU,aAAAC,YAAW,eAAAC,oBAAmB;AAa1C,SAAS,oBAA0C;AACxD,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,IAAI;AAC3C,QAAM,CAAC,WAAW,YAAY,IAAIA,UAAS,KAAK;AAChD,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAyC,IAAI;AAC7E,QAAM,CAAC,cAAc,eAAe,IAAIA,UAAyC,IAAI;AACrF,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,cAAcC,aAAY,YAAY;AAC1C,eAAW,IAAI;AACf,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,aAAa,OAAO,iBAAiB,cACvC,aAAa,QAAQ,kBAAkB,IACvC;AACJ,YAAM,QAAQ,OAAO,iBAAiB,cAClC,aAAa,QAAQ,eAAe,IACpC;AAEJ,UAAI,CAAC,cAAc,CAAC,OAAO;AACzB,qBAAa,KAAK;AAClB,mBAAW,KAAK;AAChB;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,QAAQ,OAAO,kBAAkB,EAAE,YAAY,cAAc,QAAW,OAAO,SAAS,OAAU,CAAC;AAExH,UAAI,OAAO,SAAS;AAClB,qBAAa,QAAQ,OAAO,SAAS,CAAC;AACtC,oBAAa,OAAO,YAAwC,IAAI;AAChE,wBAAiB,OAAO,gBAA4C,IAAI;AAAA,MAC1E,OAAO;AACL,qBAAa,KAAK;AAClB,iBAAS,OAAO,SAAS,wBAAwB;AAAA,MACnD;AAAA,IACF,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,eAAe;AAC7D,mBAAa,KAAK;AAAA,IACpB,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,EAAAC,WAAU,MAAM;AACd,gBAAY;AAAA,EACd,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,SAASD,aAAY,MAAM;AAC/B,QAAI,OAAO,iBAAiB,aAAa;AACvC,mBAAa,WAAW,kBAAkB;AAC1C,mBAAa,WAAW,eAAe;AAAA,IACzC;AACA,iBAAa,KAAK;AAClB,gBAAY,IAAI;AAChB,oBAAgB,IAAI;AAAA,EACtB,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,SAAS,WAAW,UAAU,cAAc,OAAO,SAAS,aAAa,OAAO;AAC3F;;;ACvEA,SAAS,YAAAE,iBAAgB;AAqDrB,SACE,KADF;AAtCG,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAmB;AACjB,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,cAAc,YAAY;AAC9B,aAAS,IAAI;AACb,eAAW,IAAI;AAEf,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,OAAO,eAAe,SAAS;AAAA,QAC1D;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU;AAAA,MACZ,CAAC;AAED,UAAI,CAAC,OAAO,SAAS;AACnB,iBAAS,OAAO,SAAS,iBAAiB;AAAA,MAC5C;AAAA,IACF,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,iBAAiB;AAAA,IACjE,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,UAAU,YAAY;AAAA,QACtB;AAAA,QACA,OAAO,CAAC,YAAY;AAAA,UAClB,SAAS;AAAA,UACT,iBAAiB,YAAY,UAAU,YAAY;AAAA,UACnD,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,QAAQ,YAAY,UAAU,gBAAgB;AAAA,QAChD,IAAI;AAAA,QAEH,oBAAU,kBAAkB,YAAY,OAAO,eAAe,KAAK;AAAA;AAAA,IACtE;AAAA,IACC,SACC,oBAAC,OAAE,OAAO,EAAE,OAAO,WAAW,UAAU,QAAQ,WAAW,MAAM,GAAI,iBAAM;AAAA,KAE/E;AAEJ;;;AC5EA,SAAS,YAAAC,iBAAgB;AA6DjB,SA2CU,UA3CV,OAAAC,MAeA,QAAAC,aAfA;AAxCR,IAAM,gBAA+B;AAAA,EACnC;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,IACd,UAAU,CAAC,kBAAkB,mBAAmB;AAAA,IAChD,KAAK;AAAA,EACP;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,UAAU,CAAC,wBAAwB,oBAAoB,oBAAoB;AAAA,IAC3E,aAAa;AAAA,IACb,KAAK;AAAA,EACP;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,UAAU,CAAC,wBAAwB,sBAAsB,qBAAqB;AAAA,IAC9E,KAAK;AAAA,EACP;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,IACd,UAAU,CAAC,yBAAyB,qBAAqB,iBAAiB,kBAAkB;AAAA,IAC5F,KAAK;AAAA,EACP;AACF;AAEO,SAAS,aAAa,EAAE,QAAQ,eAAe,YAAY,IAAI,cAAc,GAAsB;AACxG,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAS,KAAK;AAE1C,SACE,gBAAAD,MAAC,SAAI,WACH;AAAA,oBAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,UAAU,cAAc,QAAQ,KAAK,OAAO,YAAY,SAAS,GAC9G;AAAA,sBAAAD,KAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,OAAO,CAAC,SAAS,SAAS,WAAW,YAAY,CAAC,SAAS,MAAM,IAAI,GAAG,qBAAO;AAAA,MAChH,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,UAAU,CAAC,MAAM;AAAA,UAChC,OAAO;AAAA,YACL,OAAO;AAAA,YAAQ,QAAQ;AAAA,YAAQ,cAAc;AAAA,YAC7C,iBAAiB,SAAS,YAAY;AAAA,YACtC,QAAQ;AAAA,YAAQ,QAAQ;AAAA,YAAW,UAAU;AAAA,UAC/C;AAAA,UAEA,0BAAAA,KAAC,UAAK,OAAO;AAAA,YACX,OAAO;AAAA,YAAQ,QAAQ;AAAA,YAAQ,cAAc;AAAA,YAAO,iBAAiB;AAAA,YACrE,UAAU;AAAA,YAAY,KAAK;AAAA,YAAO,MAAM,SAAS,SAAS;AAAA,YAC1D,YAAY;AAAA,UACd,GAAG;AAAA;AAAA,MACL;AAAA,MACA,gBAAAC,MAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,OAAO,SAAS,SAAS,WAAW,YAAY,SAAS,MAAM,IAAI,GAAG;AAAA;AAAA,QAC9F,gBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,WAAW,UAAU,OAAO,GAAG,sBAAQ;AAAA,SACtE;AAAA,OACF;AAAA,IAEA,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,qBAAqB,UAAU,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC,UAAU,KAAK,QAAQ,UAAU,UAAU,QAAQ,SAAS,GAChJ,gBAAM,IAAI,CAAC,SAAS;AACnB,YAAM,QAAQ,UAAU,KAAK,gBAAgB,SAAY,KAAK,cAAc,KAAK,KAAK;AACtF,YAAM,UAAU,SAAS,KAAK,gBAAgB,KAAK;AAEnD,aACE,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO;AAAA,YACL,QAAQ,KAAK,cAAc,sBAAsB;AAAA,YACjD,cAAc;AAAA,YAAQ,SAAS;AAAA,YAC/B,iBAAiB,KAAK,cAAc,YAAY;AAAA,UAClD;AAAA,UAEA;AAAA,4BAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,WAAW,YAAY,KAAK,cAAc,MAAM,GAAI,eAAK,MAAK;AAAA,YACrF,gBAAAA,KAAC,OAAE,OAAO,EAAE,OAAO,WAAW,UAAU,QAAQ,cAAc,OAAO,GAAI,eAAK,aAAY;AAAA,YAE1F,gBAAAA,KAAC,SAAI,OAAO,EAAE,cAAc,OAAO,GAChC,eAAK,iBAAiB,IACrB,gBAAAA,KAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,YAAY,IAAI,GAAG,kBAAI,IACtD,KAAK,iBAAiB,KACxB,gBAAAA,KAAC,UAAK,OAAO,EAAE,UAAU,UAAU,YAAY,IAAI,GAAG,oBAAM,IAE5D,gBAAAC,MAAA,YACE;AAAA,8BAAAA,MAAC,UAAK,OAAO,EAAE,UAAU,QAAQ,YAAY,IAAI,GAAG;AAAA;AAAA,gBAAE,KAAK,MAAM,KAAK;AAAA,iBAAE;AAAA,cACxE,gBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,WAAW,UAAU,OAAO,GAAG,iBAAG;AAAA,eAC1D,GAEJ;AAAA,YAEA,gBAAAA,KAAC,QAAG,OAAO,EAAE,WAAW,QAAQ,SAAS,GAAG,cAAc,OAAO,GAC9D,eAAK,SAAS,IAAI,CAAC,YAClB,gBAAAC,MAAC,QAAiB,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,OAAO,cAAc,OAAO,UAAU,OAAO,GAClH;AAAA,8BAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,UAAU,GAAG,oBAAC;AAAA,cAAO;AAAA,cAAE;AAAA,iBADtC,OAET,CACD,GACH;AAAA,YAEC,UACC,gBAAAA,KAAC,aAAU,SAAkB,aAAa,KAAK,MAAM,eAClD,eAAK,OAAO,aACf,IACE,KAAK,iBAAiB,IACxB,gBAAAA,KAAC,YAAO,OAAO;AAAA,cACb,OAAO;AAAA,cAAQ,SAAS;AAAA,cAAQ,QAAQ;AAAA,cACxC,cAAc;AAAA,cAAO,YAAY;AAAA,cAAS,QAAQ;AAAA,cAAW,UAAU;AAAA,YACzE,GACG,eAAK,OAAO,eACf,IAEA,gBAAAA,KAAC,YAAO,OAAO;AAAA,cACb,OAAO;AAAA,cAAQ,SAAS;AAAA,cAAQ,QAAQ;AAAA,cACxC,cAAc;AAAA,cAAO,YAAY;AAAA,cAAS,QAAQ;AAAA,cAAW,UAAU;AAAA,YACzE,GACG,eAAK,OAAO,iBACf;AAAA;AAAA;AAAA,QAhDG,KAAK;AAAA,MAkDZ;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;;;AChJA,SAAS,YAAAG,iBAAgB;AAsBrB,gBAAAC,YAAA;AAbG,SAAS,yBAAyB,EAAE,UAAU,YAAY,IAAI,WAAW,GAAkC;AAChH,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAE5C,QAAM,cAAc,YAAY;AAC9B,UAAM,KAAK,eAAe,OAAO,iBAAiB,cAAc,aAAa,QAAQ,kBAAkB,IAAI;AAC3G,QAAI,CAAC,GAAI;AAET,eAAW,IAAI;AACf,UAAM,QAAQ,OAAO,oBAAoB,IAAI,EAAE,UAAU,KAAK,CAAC;AAC/D,eAAW,KAAK;AAAA,EAClB;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,OAAO,CAAC,YAAY;AAAA,QAClB,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,cAAc;AAAA,QACd,YAAY;AAAA,QACZ,QAAQ,UAAU,gBAAgB;AAAA,QAClC,UAAU;AAAA,MACZ,IAAI;AAAA,MAEH,oBAAU,eAAe,YAAY;AAAA;AAAA,EACxC;AAEJ;;;ACnBW,gBAAAE,MAQH,QAAAC,aARG;AAZX,IAAM,gBAAwC;AAAA,EAC5C,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AACV;AAEO,SAAS,oBAAoB,EAAE,YAAY,GAAG,GAA6B;AAChF,QAAM,EAAE,cAAc,MAAM,QAAQ,UAAU,QAAQ,IAAI,gBAAgB;AAE1E,MAAI,SAAS;AACX,WAAO,gBAAAD,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,OAAO,UAAU,GAAG,qCAAuB;AAAA,EACnF;AAEA,SACE,gBAAAC,MAAC,SAAI,WAAsB,OAAO,EAAE,QAAQ,qBAAqB,cAAc,QAAQ,SAAS,OAAO,GACrG;AAAA,oBAAAD,KAAC,QAAG,OAAO,EAAE,UAAU,YAAY,YAAY,KAAK,cAAc,OAAO,GAAG,0BAAY;AAAA,IAExF,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,KAAK,QAAQ,cAAc,OAAO,GAC/D;AAAA,sBAAAA,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,gBAAgB,GAC7D;AAAA,wBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,UAAU,GAAG,kBAAI;AAAA,QACvC,gBAAAA,KAAC,UAAK,OAAO,EAAE,YAAY,KAAK,eAAe,aAAa,GAAI,gBAAK;AAAA,SACvE;AAAA,MAEC,UACC,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,gBAAgB,GAC7D;AAAA,wBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,UAAU,GAAG,oBAAM;AAAA,QACzC,gBAAAA,KAAC,UAAK,OAAO;AAAA,UACX,YAAY;AAAA,UACZ,OAAO,cAAc,MAAM,KAAK;AAAA,UAChC,eAAe;AAAA,QACjB,GACG,qBAAW,aAAa,aAAa,QACxC;AAAA,SACF;AAAA,MAGD,cAAc,oBACb,gBAAAC,MAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,gBAAgB,gBAAgB,GAC7D;AAAA,wBAAAD,KAAC,UAAK,OAAO,EAAE,OAAO,UAAU,GAAI,qBAAW,WAAW,WAAU;AAAA,QACpE,gBAAAA,KAAC,UAAM,cAAI,KAAK,aAAa,gBAAgB,EAAE,mBAAmB,GAAE;AAAA,SACtE;AAAA,OAEJ;AAAA,IAEC,cAAc,cACb,gBAAAA,KAAC,4BAAyB,YAAY,aAAa,YAAY;AAAA,KAEnE;AAEJ;;;ACxCW,qBAAAE,WAAuB,OAAAC,YAAvB;AAPJ,SAAS,iBAAiB,EAAE,UAAU,UAAU,kBAAkB,aAAa,GAA0B;AAC9G,QAAM,iBAAiB,kBAAkB;AACzC,QAAM,eAAe,gBAAgB;AAErC,QAAM,UAAU,eAAe,aAAa,UAAU,eAAe;AAErE,MAAI,SAAS;AACX,WAAO,gBAAAA,KAAAD,WAAA,EAAG,8BAAoB,gBAAAC,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,UAAU,GAAG,wBAAU,GAAO;AAAA,EACzH;AAEA,QAAM,YAAY,eACd,aAAa,YAAY,aAAa,UAAU,YAAY,IAC5D,eAAe;AAEnB,MAAI,CAAC,WAAW;AACd,WAAO,gBAAAA,KAAAD,WAAA,EAAG,sBAAY,gBAAAC,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,WAAW,UAAU,OAAO,UAAU,GACxF,yBACG,2BAA2B,YAAY,6BACvC,yCACN,GAAO;AAAA,EACT;AAEA,SAAO,gBAAAA,KAAAD,WAAA,EAAG,UAAS;AACrB;;;AClCA,SAAS,YAAAE,WAAU,aAAAC,YAAW,eAAAC,oBAAmB;AAsDtC,gBAAAC,MA8BD,QAAAC,aA9BC;AAlCJ,SAAS,eAAe,EAAE,YAAY,QAAQ,IAAI,YAAY,GAAG,GAAwB;AAC9F,QAAM,CAAC,UAAU,WAAW,IAAIC,UAAoB,CAAC,CAAC;AACtD,QAAM,CAAC,SAAS,UAAU,IAAIA,UAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,IAAIA,UAAwB,IAAI;AAEtD,QAAM,gBAAgBC,aAAY,YAAY;AAC5C,UAAM,KAAK,eAAe,OAAO,iBAAiB,cAAc,aAAa,QAAQ,kBAAkB,IAAI;AAC3G,QAAI,CAAC,IAAI;AACP,iBAAW,KAAK;AAChB;AAAA,IACF;AAEA,eAAW,IAAI;AACf,aAAS,IAAI;AAEb,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,OAAO,YAAY,IAAI,EAAE,MAAM,CAAC;AAC7D,UAAI,OAAO,WAAW,OAAO,UAAU;AACrC,oBAAY,OAAO,QAAqB;AAAA,MAC1C,OAAO;AACL,iBAAS,OAAO,SAAS,yBAAyB;AAAA,MACpD;AAAA,IACF,SAAS,KAAc;AACrB,eAAS,eAAe,QAAQ,IAAI,UAAU,eAAe;AAAA,IAC/D,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,YAAY,KAAK,CAAC;AAEtB,EAAAC,WAAU,MAAM;AACd,kBAAc;AAAA,EAChB,GAAG,CAAC,aAAa,CAAC;AAElB,MAAI,SAAS;AACX,WAAO,gBAAAJ,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,OAAO,UAAU,GAAG,iCAAmB;AAAA,EAC/E;AAEA,MAAI,OAAO;AACT,WAAO,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,OAAO,UAAU,GAAI,iBAAM;AAAA,EACnE;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO,gBAAAA,KAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,OAAO,UAAU,GAAG,gCAAkB;AAAA,EAC9E;AAEA,QAAM,eAAe,CAAC,QAAgB,aAAqB;AACzD,WAAO,IAAI,KAAK,aAAa,SAAS,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,SAAS,GAAG;AAAA,EAC5F;AAEA,QAAMK,iBAAwC;AAAA,IAC5C,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,IACN,eAAe;AAAA,EACjB;AAEA,SACE,gBAAAJ,MAAC,SAAI,WAAsB,OAAO,EAAE,QAAQ,qBAAqB,cAAc,QAAQ,UAAU,SAAS,GACxG;AAAA,oBAAAD,KAAC,SAAI,OAAO,EAAE,SAAS,aAAa,cAAc,oBAAoB,GACpE,0BAAAA,KAAC,QAAG,OAAO,EAAE,UAAU,YAAY,YAAY,KAAK,QAAQ,EAAE,GAAG,6BAAe,GAClF;AAAA,IACA,gBAAAC,MAAC,WAAM,OAAO,EAAE,OAAO,QAAQ,gBAAgB,YAAY,UAAU,OAAO,GAC1E;AAAA,sBAAAD,KAAC,WACC,0BAAAC,MAAC,QAAG,OAAO,EAAE,cAAc,qBAAqB,YAAY,UAAU,GACpE;AAAA,wBAAAD,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,QAAQ,YAAY,KAAK,OAAO,UAAU,GAAG,qBAAO;AAAA,QAClG,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,QAAQ,YAAY,KAAK,OAAO,UAAU,GAAG,kBAAI;AAAA,QAC/F,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,SAAS,YAAY,KAAK,OAAO,UAAU,GAAG,oBAAM;AAAA,QAClG,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,UAAU,YAAY,KAAK,OAAO,UAAU,GAAG,oBAAM;AAAA,QACnG,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,SAAS,YAAY,KAAK,OAAO,UAAU,GAAG;AAAA,SAC9F,GACF;AAAA,MACA,gBAAAA,KAAC,WACE,mBAAS,IAAI,CAAC,YACb,gBAAAC,MAAC,QAAoB,OAAO,EAAE,cAAc,oBAAoB,GAC9D;AAAA,wBAAAD,KAAC,QAAG,OAAO,EAAE,SAAS,YAAY,GAAI,kBAAQ,UAAU,QAAQ,GAAG,MAAM,GAAG,EAAE,GAAE;AAAA,QAChF,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,OAAO,UAAU,GACjD,cAAI,KAAK,QAAQ,UAAU,GAAI,EAAE,mBAAmB,GACvD;AAAA,QACA,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,SAAS,YAAY,IAAI,GACpE,uBAAa,QAAQ,QAAQ,QAAQ,QAAQ,GAChD;AAAA,QACA,gBAAAA,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,SAAS,GACrD,0BAAAA,KAAC,UAAK,OAAO;AAAA,UACX,SAAS;AAAA,UACT,cAAc;AAAA,UACd,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,OAAOK,eAAc,QAAQ,MAAM,KAAK;AAAA,UACxC,YAAY,GAAGA,eAAc,QAAQ,MAAM,KAAK,SAAS;AAAA,UACzD,eAAe;AAAA,QACjB,GACG,kBAAQ,QACX,GACF;AAAA,QACA,gBAAAL,KAAC,QAAG,OAAO,EAAE,SAAS,aAAa,WAAW,QAAQ,GACnD,kBAAQ,UACP,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,QAAQ;AAAA,YACd,QAAO;AAAA,YACP,KAAI;AAAA,YACJ,OAAO,EAAE,OAAO,WAAW,gBAAgB,QAAQ,UAAU,OAAO;AAAA,YACrE;AAAA;AAAA,QAED,GAEJ;AAAA,WAhCO,QAAQ,EAiCjB,CACD,GACH;AAAA,OACF;AAAA,KACF;AAEJ;","names":["useState","useEffect","useCallback","useState","useCallback","useEffect","useState","useState","useState","jsx","jsxs","useState","useState","jsx","useState","jsx","jsxs","Fragment","jsx","useState","useEffect","useCallback","jsx","jsxs","useState","useCallback","useEffect","STATUS_COLORS"]}
|
package/dist/roles/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AuthContext
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-QHB7LGCA.js";
|
|
4
|
+
import "../chunk-HJ2EIZ4S.js";
|
|
5
5
|
import {
|
|
6
|
-
features,
|
|
7
6
|
supabase
|
|
8
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-I2YGB7Z6.js";
|
|
8
|
+
import {
|
|
9
|
+
features
|
|
10
|
+
} from "../chunk-LIUE7M7K.js";
|
|
9
11
|
|
|
10
12
|
// src/roles/useRoles.ts
|
|
11
13
|
import { useState, useEffect, useCallback, useContext } from "react";
|
package/dist/roles/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/roles/useRoles.ts","../../src/roles/RoleGate.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\nimport { supabase } from '../core/supabase';\nimport { features } from '../core/config';\nimport { AuthContext } from '../auth/AuthProvider';\n\ninterface RoleData {\n role_name: string;\n display_name: string;\n permissions: string[];\n can_access_routes: string[];\n}\n\ninterface UseRolesReturn {\n roles: string[];\n permissions: string[];\n accessibleRoutes: string[];\n loading: boolean;\n error: string | null;\n hasRole: (name: string) => boolean;\n hasAnyRole: (names: string[]) => boolean;\n hasAllRoles: (names: string[]) => boolean;\n hasPermission: (perm: string) => boolean;\n hasAnyPermission: (perms: string[]) => boolean;\n hasAllPermissions: (perms: string[]) => boolean;\n canAccessRoute: (path: string) => boolean;\n refreshRoles: () => Promise<void>;\n}\n\nexport function useRoles(): UseRolesReturn {\n const auth = useContext(AuthContext);\n const [roles, setRoles] = useState<string[]>([]);\n const [permissions, setPermissions] = useState<string[]>([]);\n const [accessibleRoutes, setAccessibleRoutes] = useState<string[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n\n const fetchRoles = useCallback(async () => {\n if (!auth?.user?.id || !features.auth) {\n setRoles([]);\n setPermissions([]);\n setAccessibleRoutes([]);\n setLoading(false);\n return;\n }\n\n try {\n const { data, error: rpcError } = await supabase.rpc('get_user_roles', {\n user_uuid: auth.user.id,\n });\n\n if (rpcError) {\n setError(rpcError.message);\n setLoading(false);\n return;\n }\n\n const roleData = (data || []) as RoleData[];\n const allRoles = roleData.map((r) => r.role_name);\n const allPerms = [...new Set(roleData.flatMap((r) => r.permissions || []))];\n const allRoutes = [...new Set(roleData.flatMap((r) => r.can_access_routes || []))];\n\n setRoles(allRoles);\n setPermissions(allPerms);\n setAccessibleRoutes(allRoutes);\n setError(null);\n } catch (err: unknown) {\n setError(err instanceof Error ? err.message : 'Failed to fetch roles');\n } finally {\n setLoading(false);\n }\n }, [auth?.user?.id]);\n\n useEffect(() => {\n fetchRoles();\n }, [fetchRoles]);\n\n const hasRole = useCallback((name: string) => roles.includes(name), [roles]);\n const hasAnyRole = useCallback((names: string[]) => names.some((n) => roles.includes(n)), [roles]);\n const hasAllRoles = useCallback((names: string[]) => names.every((n) => roles.includes(n)), [roles]);\n const hasPermission = useCallback((perm: string) => permissions.includes(perm), [permissions]);\n const hasAnyPermission = useCallback((perms: string[]) => perms.some((p) => permissions.includes(p)), [permissions]);\n const hasAllPermissions = useCallback((perms: string[]) => perms.every((p) => permissions.includes(p)), [permissions]);\n\n const canAccessRoute = useCallback((path: string) => {\n return accessibleRoutes.some((route) => {\n if (route.endsWith('/*')) {\n return path.startsWith(route.slice(0, -2));\n }\n return route === path;\n });\n }, [accessibleRoutes]);\n\n return {\n roles, permissions, accessibleRoutes, loading, error,\n hasRole, hasAnyRole, hasAllRoles, hasPermission, hasAnyPermission, hasAllPermissions,\n canAccessRoute, refreshRoles: fetchRoles,\n };\n}\n","import { useRoles } from './useRoles';\n\ninterface RoleGateProps {\n children: React.ReactNode;\n roles?: string[];\n permissions?: string[];\n requireAll?: boolean;\n fallback?: React.ReactNode;\n loadingFallback?: React.ReactNode;\n}\n\ninterface RouteGateProps {\n children: React.ReactNode;\n route: string;\n fallback?: React.ReactNode;\n loadingFallback?: React.ReactNode;\n}\n\nexport function RoleGate({\n children,\n roles: requiredRoles,\n permissions: requiredPerms,\n requireAll = false,\n fallback = null,\n loadingFallback = null,\n}: RoleGateProps) {\n const { hasRole, hasAnyRole, hasAllRoles, hasPermission, hasAnyPermission, hasAllPermissions, loading } = useRoles();\n\n if (loading) return <>{loadingFallback}</>;\n\n let hasAccess = true;\n\n if (requiredRoles?.length) {\n hasAccess = requireAll ? hasAllRoles(requiredRoles) : hasAnyRole(requiredRoles);\n }\n\n if (hasAccess && requiredPerms?.length) {\n hasAccess = requireAll ? hasAllPermissions(requiredPerms) : hasAnyPermission(requiredPerms);\n }\n\n if (!hasAccess && !requiredRoles?.length && !requiredPerms?.length) {\n hasAccess = true;\n }\n\n // Use individual checks to satisfy linter\n void hasRole;\n void hasPermission;\n\n return hasAccess ? <>{children}</> : <>{fallback}</>;\n}\n\nexport function RouteGate({ children, route, fallback = null, loadingFallback = null }: RouteGateProps) {\n const { canAccessRoute, loading } = useRoles();\n\n if (loading) return <>{loadingFallback}</>;\n\n return canAccessRoute(route) ? <>{children}</> : <>{fallback}</>;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/roles/useRoles.ts","../../src/roles/RoleGate.tsx"],"sourcesContent":["import { useState, useEffect, useCallback, useContext } from 'react';\r\nimport { supabase } from '../core/supabase';\r\nimport { features } from '../core/config';\r\nimport { AuthContext } from '../auth/AuthProvider';\r\n\r\ninterface RoleData {\r\n role_name: string;\r\n display_name: string;\r\n permissions: string[];\r\n can_access_routes: string[];\r\n}\r\n\r\ninterface UseRolesReturn {\r\n roles: string[];\r\n permissions: string[];\r\n accessibleRoutes: string[];\r\n loading: boolean;\r\n error: string | null;\r\n hasRole: (name: string) => boolean;\r\n hasAnyRole: (names: string[]) => boolean;\r\n hasAllRoles: (names: string[]) => boolean;\r\n hasPermission: (perm: string) => boolean;\r\n hasAnyPermission: (perms: string[]) => boolean;\r\n hasAllPermissions: (perms: string[]) => boolean;\r\n canAccessRoute: (path: string) => boolean;\r\n refreshRoles: () => Promise<void>;\r\n}\r\n\r\nexport function useRoles(): UseRolesReturn {\r\n const auth = useContext(AuthContext);\r\n const [roles, setRoles] = useState<string[]>([]);\r\n const [permissions, setPermissions] = useState<string[]>([]);\r\n const [accessibleRoutes, setAccessibleRoutes] = useState<string[]>([]);\r\n const [loading, setLoading] = useState(true);\r\n const [error, setError] = useState<string | null>(null);\r\n\r\n const fetchRoles = useCallback(async () => {\r\n if (!auth?.user?.id || !features.auth) {\r\n setRoles([]);\r\n setPermissions([]);\r\n setAccessibleRoutes([]);\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n try {\r\n const { data, error: rpcError } = await supabase.rpc('get_user_roles', {\r\n user_uuid: auth.user.id,\r\n });\r\n\r\n if (rpcError) {\r\n setError(rpcError.message);\r\n setLoading(false);\r\n return;\r\n }\r\n\r\n const roleData = (data || []) as RoleData[];\r\n const allRoles = roleData.map((r) => r.role_name);\r\n const allPerms = [...new Set(roleData.flatMap((r) => r.permissions || []))];\r\n const allRoutes = [...new Set(roleData.flatMap((r) => r.can_access_routes || []))];\r\n\r\n setRoles(allRoles);\r\n setPermissions(allPerms);\r\n setAccessibleRoutes(allRoutes);\r\n setError(null);\r\n } catch (err: unknown) {\r\n setError(err instanceof Error ? err.message : 'Failed to fetch roles');\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, [auth?.user?.id]);\r\n\r\n useEffect(() => {\r\n fetchRoles();\r\n }, [fetchRoles]);\r\n\r\n const hasRole = useCallback((name: string) => roles.includes(name), [roles]);\r\n const hasAnyRole = useCallback((names: string[]) => names.some((n) => roles.includes(n)), [roles]);\r\n const hasAllRoles = useCallback((names: string[]) => names.every((n) => roles.includes(n)), [roles]);\r\n const hasPermission = useCallback((perm: string) => permissions.includes(perm), [permissions]);\r\n const hasAnyPermission = useCallback((perms: string[]) => perms.some((p) => permissions.includes(p)), [permissions]);\r\n const hasAllPermissions = useCallback((perms: string[]) => perms.every((p) => permissions.includes(p)), [permissions]);\r\n\r\n const canAccessRoute = useCallback((path: string) => {\r\n return accessibleRoutes.some((route) => {\r\n if (route.endsWith('/*')) {\r\n return path.startsWith(route.slice(0, -2));\r\n }\r\n return route === path;\r\n });\r\n }, [accessibleRoutes]);\r\n\r\n return {\r\n roles, permissions, accessibleRoutes, loading, error,\r\n hasRole, hasAnyRole, hasAllRoles, hasPermission, hasAnyPermission, hasAllPermissions,\r\n canAccessRoute, refreshRoles: fetchRoles,\r\n };\r\n}\r\n","import { useRoles } from './useRoles';\r\n\r\ninterface RoleGateProps {\r\n children: React.ReactNode;\r\n roles?: string[];\r\n permissions?: string[];\r\n requireAll?: boolean;\r\n fallback?: React.ReactNode;\r\n loadingFallback?: React.ReactNode;\r\n}\r\n\r\ninterface RouteGateProps {\r\n children: React.ReactNode;\r\n route: string;\r\n fallback?: React.ReactNode;\r\n loadingFallback?: React.ReactNode;\r\n}\r\n\r\nexport function RoleGate({\r\n children,\r\n roles: requiredRoles,\r\n permissions: requiredPerms,\r\n requireAll = false,\r\n fallback = null,\r\n loadingFallback = null,\r\n}: RoleGateProps) {\r\n const { hasRole, hasAnyRole, hasAllRoles, hasPermission, hasAnyPermission, hasAllPermissions, loading } = useRoles();\r\n\r\n if (loading) return <>{loadingFallback}</>;\r\n\r\n let hasAccess = true;\r\n\r\n if (requiredRoles?.length) {\r\n hasAccess = requireAll ? hasAllRoles(requiredRoles) : hasAnyRole(requiredRoles);\r\n }\r\n\r\n if (hasAccess && requiredPerms?.length) {\r\n hasAccess = requireAll ? hasAllPermissions(requiredPerms) : hasAnyPermission(requiredPerms);\r\n }\r\n\r\n if (!hasAccess && !requiredRoles?.length && !requiredPerms?.length) {\r\n hasAccess = true;\r\n }\r\n\r\n // Use individual checks to satisfy linter\r\n void hasRole;\r\n void hasPermission;\r\n\r\n return hasAccess ? <>{children}</> : <>{fallback}</>;\r\n}\r\n\r\nexport function RouteGate({ children, route, fallback = null, loadingFallback = null }: RouteGateProps) {\r\n const { canAccessRoute, loading } = useRoles();\r\n\r\n if (loading) return <>{loadingFallback}</>;\r\n\r\n return canAccessRoute(route) ? <>{children}</> : <>{fallback}</>;\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/seo/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/seo/SEOHead.tsx"],"sourcesContent":["interface SEOHeadProps {\n title?: string;\n description?: string;\n keywords?: string;\n image?: string;\n url?: string;\n type?: string;\n twitterCard?: 'summary' | 'summary_large_image';\n author?: string;\n publishedTime?: string;\n modifiedTime?: string;\n noIndex?: boolean;\n children?: React.ReactNode;\n}\n\nexport function SEOHead({\n title,\n description,\n keywords,\n image,\n url,\n type = 'website',\n twitterCard = 'summary_large_image',\n author,\n publishedTime,\n modifiedTime,\n noIndex = false,\n children,\n}: SEOHeadProps) {\n // Uses react-helmet-async if available, otherwise falls back to document manipulation\n if (typeof document === 'undefined') return null;\n\n const setMeta = (name: string, content: string, property = false) => {\n const attr = property ? 'property' : 'name';\n let el = document.querySelector(`meta[${attr}=\"${name}\"]`) as HTMLMetaElement | null;\n if (!el) {\n el = document.createElement('meta');\n el.setAttribute(attr, name);\n document.head.appendChild(el);\n }\n el.content = content;\n };\n\n if (title) {\n document.title = title;\n setMeta('og:title', title, true);\n setMeta('twitter:title', title);\n }\n if (description) {\n setMeta('description', description);\n setMeta('og:description', description, true);\n setMeta('twitter:description', description);\n }\n if (keywords) setMeta('keywords', keywords);\n if (image) {\n setMeta('og:image', image, true);\n setMeta('twitter:image', image);\n }\n if (url) setMeta('og:url', url, true);\n setMeta('og:type', type, true);\n setMeta('twitter:card', twitterCard);\n if (author) setMeta('author', author);\n if (publishedTime) setMeta('article:published_time', publishedTime, true);\n if (modifiedTime) setMeta('article:modified_time', modifiedTime, true);\n if (noIndex) setMeta('robots', 'noindex, nofollow');\n\n return <>{children}</>;\n}\n\ninterface JsonLdProps {\n data: Record<string, unknown>;\n}\n\nexport function JsonLd({ data }: JsonLdProps) {\n return (\n <script\n type=\"application/ld+json\"\n dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}\n />\n );\n}\n\ninterface OrganizationJsonLdProps {\n name: string;\n url: string;\n logo?: string;\n sameAs?: string[];\n}\n\nexport function OrganizationJsonLd({ name, url, logo, sameAs }: OrganizationJsonLdProps) {\n return (\n <JsonLd data={{\n '@context': 'https://schema.org',\n '@type': 'Organization',\n name, url, logo, sameAs,\n }} />\n );\n}\n\ninterface ArticleJsonLdProps {\n title: string;\n description: string;\n url: string;\n image?: string;\n datePublished?: string;\n authorName?: string;\n}\n\nexport function ArticleJsonLd({ title, description, url, image, datePublished, authorName }: ArticleJsonLdProps) {\n return (\n <JsonLd data={{\n '@context': 'https://schema.org',\n '@type': 'Article',\n headline: title,\n description, url, image,\n datePublished,\n author: authorName ? { '@type': 'Person', name: authorName } : undefined,\n }} />\n );\n}\n"],"mappings":";AAkES;AAnDF,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,GAAiB;AAEf,MAAI,OAAO,aAAa,YAAa,QAAO;AAE5C,QAAM,UAAU,CAAC,MAAc,SAAiB,WAAW,UAAU;AACnE,UAAM,OAAO,WAAW,aAAa;AACrC,QAAI,KAAK,SAAS,cAAc,QAAQ,IAAI,KAAK,IAAI,IAAI;AACzD,QAAI,CAAC,IAAI;AACP,WAAK,SAAS,cAAc,MAAM;AAClC,SAAG,aAAa,MAAM,IAAI;AAC1B,eAAS,KAAK,YAAY,EAAE;AAAA,IAC9B;AACA,OAAG,UAAU;AAAA,EACf;AAEA,MAAI,OAAO;AACT,aAAS,QAAQ;AACjB,YAAQ,YAAY,OAAO,IAAI;AAC/B,YAAQ,iBAAiB,KAAK;AAAA,EAChC;AACA,MAAI,aAAa;AACf,YAAQ,eAAe,WAAW;AAClC,YAAQ,kBAAkB,aAAa,IAAI;AAC3C,YAAQ,uBAAuB,WAAW;AAAA,EAC5C;AACA,MAAI,SAAU,SAAQ,YAAY,QAAQ;AAC1C,MAAI,OAAO;AACT,YAAQ,YAAY,OAAO,IAAI;AAC/B,YAAQ,iBAAiB,KAAK;AAAA,EAChC;AACA,MAAI,IAAK,SAAQ,UAAU,KAAK,IAAI;AACpC,UAAQ,WAAW,MAAM,IAAI;AAC7B,UAAQ,gBAAgB,WAAW;AACnC,MAAI,OAAQ,SAAQ,UAAU,MAAM;AACpC,MAAI,cAAe,SAAQ,0BAA0B,eAAe,IAAI;AACxE,MAAI,aAAc,SAAQ,yBAAyB,cAAc,IAAI;AACrE,MAAI,QAAS,SAAQ,UAAU,mBAAmB;AAElD,SAAO,gCAAG,UAAS;AACrB;AAMO,SAAS,OAAO,EAAE,KAAK,GAAgB;AAC5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK,UAAU,IAAI,EAAE;AAAA;AAAA,EAC1D;AAEJ;AASO,SAAS,mBAAmB,EAAE,MAAM,KAAK,MAAM,OAAO,GAA4B;AACvF,SACE,oBAAC,UAAO,MAAM;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT;AAAA,IAAM;AAAA,IAAK;AAAA,IAAM;AAAA,EACnB,GAAG;AAEP;AAWO,SAAS,cAAc,EAAE,OAAO,aAAa,KAAK,OAAO,eAAe,WAAW,GAAuB;AAC/G,SACE,oBAAC,UAAO,MAAM;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,UAAU;AAAA,IACV;AAAA,IAAa;AAAA,IAAK;AAAA,IAClB;AAAA,IACA,QAAQ,aAAa,EAAE,SAAS,UAAU,MAAM,WAAW,IAAI;AAAA,EACjE,GAAG;AAEP;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/seo/SEOHead.tsx"],"sourcesContent":["interface SEOHeadProps {\r\n title?: string;\r\n description?: string;\r\n keywords?: string;\r\n image?: string;\r\n url?: string;\r\n type?: string;\r\n twitterCard?: 'summary' | 'summary_large_image';\r\n author?: string;\r\n publishedTime?: string;\r\n modifiedTime?: string;\r\n noIndex?: boolean;\r\n children?: React.ReactNode;\r\n}\r\n\r\nexport function SEOHead({\r\n title,\r\n description,\r\n keywords,\r\n image,\r\n url,\r\n type = 'website',\r\n twitterCard = 'summary_large_image',\r\n author,\r\n publishedTime,\r\n modifiedTime,\r\n noIndex = false,\r\n children,\r\n}: SEOHeadProps) {\r\n // Uses react-helmet-async if available, otherwise falls back to document manipulation\r\n if (typeof document === 'undefined') return null;\r\n\r\n const setMeta = (name: string, content: string, property = false) => {\r\n const attr = property ? 'property' : 'name';\r\n let el = document.querySelector(`meta[${attr}=\"${name}\"]`) as HTMLMetaElement | null;\r\n if (!el) {\r\n el = document.createElement('meta');\r\n el.setAttribute(attr, name);\r\n document.head.appendChild(el);\r\n }\r\n el.content = content;\r\n };\r\n\r\n if (title) {\r\n document.title = title;\r\n setMeta('og:title', title, true);\r\n setMeta('twitter:title', title);\r\n }\r\n if (description) {\r\n setMeta('description', description);\r\n setMeta('og:description', description, true);\r\n setMeta('twitter:description', description);\r\n }\r\n if (keywords) setMeta('keywords', keywords);\r\n if (image) {\r\n setMeta('og:image', image, true);\r\n setMeta('twitter:image', image);\r\n }\r\n if (url) setMeta('og:url', url, true);\r\n setMeta('og:type', type, true);\r\n setMeta('twitter:card', twitterCard);\r\n if (author) setMeta('author', author);\r\n if (publishedTime) setMeta('article:published_time', publishedTime, true);\r\n if (modifiedTime) setMeta('article:modified_time', modifiedTime, true);\r\n if (noIndex) setMeta('robots', 'noindex, nofollow');\r\n\r\n return <>{children}</>;\r\n}\r\n\r\ninterface JsonLdProps {\r\n data: Record<string, unknown>;\r\n}\r\n\r\nexport function JsonLd({ data }: JsonLdProps) {\r\n return (\r\n <script\r\n type=\"application/ld+json\"\r\n dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}\r\n />\r\n );\r\n}\r\n\r\ninterface OrganizationJsonLdProps {\r\n name: string;\r\n url: string;\r\n logo?: string;\r\n sameAs?: string[];\r\n}\r\n\r\nexport function OrganizationJsonLd({ name, url, logo, sameAs }: OrganizationJsonLdProps) {\r\n return (\r\n <JsonLd data={{\r\n '@context': 'https://schema.org',\r\n '@type': 'Organization',\r\n name, url, logo, sameAs,\r\n }} />\r\n );\r\n}\r\n\r\ninterface ArticleJsonLdProps {\r\n title: string;\r\n description: string;\r\n url: string;\r\n image?: string;\r\n datePublished?: string;\r\n authorName?: string;\r\n}\r\n\r\nexport function ArticleJsonLd({ title, description, url, image, datePublished, authorName }: ArticleJsonLdProps) {\r\n return (\r\n <JsonLd data={{\r\n '@context': 'https://schema.org',\r\n '@type': 'Article',\r\n headline: title,\r\n description, url, image,\r\n datePublished,\r\n author: authorName ? { '@type': 'Person', name: authorName } : undefined,\r\n }} />\r\n );\r\n}\r\n"],"mappings":";AAkES;AAnDF,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,GAAiB;AAEf,MAAI,OAAO,aAAa,YAAa,QAAO;AAE5C,QAAM,UAAU,CAAC,MAAc,SAAiB,WAAW,UAAU;AACnE,UAAM,OAAO,WAAW,aAAa;AACrC,QAAI,KAAK,SAAS,cAAc,QAAQ,IAAI,KAAK,IAAI,IAAI;AACzD,QAAI,CAAC,IAAI;AACP,WAAK,SAAS,cAAc,MAAM;AAClC,SAAG,aAAa,MAAM,IAAI;AAC1B,eAAS,KAAK,YAAY,EAAE;AAAA,IAC9B;AACA,OAAG,UAAU;AAAA,EACf;AAEA,MAAI,OAAO;AACT,aAAS,QAAQ;AACjB,YAAQ,YAAY,OAAO,IAAI;AAC/B,YAAQ,iBAAiB,KAAK;AAAA,EAChC;AACA,MAAI,aAAa;AACf,YAAQ,eAAe,WAAW;AAClC,YAAQ,kBAAkB,aAAa,IAAI;AAC3C,YAAQ,uBAAuB,WAAW;AAAA,EAC5C;AACA,MAAI,SAAU,SAAQ,YAAY,QAAQ;AAC1C,MAAI,OAAO;AACT,YAAQ,YAAY,OAAO,IAAI;AAC/B,YAAQ,iBAAiB,KAAK;AAAA,EAChC;AACA,MAAI,IAAK,SAAQ,UAAU,KAAK,IAAI;AACpC,UAAQ,WAAW,MAAM,IAAI;AAC7B,UAAQ,gBAAgB,WAAW;AACnC,MAAI,OAAQ,SAAQ,UAAU,MAAM;AACpC,MAAI,cAAe,SAAQ,0BAA0B,eAAe,IAAI;AACxE,MAAI,aAAc,SAAQ,yBAAyB,cAAc,IAAI;AACrE,MAAI,QAAS,SAAQ,UAAU,mBAAmB;AAElD,SAAO,gCAAG,UAAS;AACrB;AAMO,SAAS,OAAO,EAAE,KAAK,GAAgB;AAC5C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,yBAAyB,EAAE,QAAQ,KAAK,UAAU,IAAI,EAAE;AAAA;AAAA,EAC1D;AAEJ;AASO,SAAS,mBAAmB,EAAE,MAAM,KAAK,MAAM,OAAO,GAA4B;AACvF,SACE,oBAAC,UAAO,MAAM;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT;AAAA,IAAM;AAAA,IAAK;AAAA,IAAM;AAAA,EACnB,GAAG;AAEP;AAWO,SAAS,cAAc,EAAE,OAAO,aAAa,KAAK,OAAO,eAAe,WAAW,GAAuB;AAC/G,SACE,oBAAC,UAAO,MAAM;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,UAAU;AAAA,IACV;AAAA,IAAa;AAAA,IAAK;AAAA,IAClB;AAAA,IACA,QAAQ,aAAa,EAAE,SAAS,UAAU,MAAM,WAAW,IAAI;AAAA,EACjE,GAAG;AAEP;","names":[]}
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/supabase.ts","../../src/server/stripe.ts","../../src/server/storage.ts","../../src/server/middleware.ts"],"sourcesContent":["import { createClient, SupabaseClient } from '@supabase/supabase-js';\n\ninterface ServerSupabaseOptions {\n supabaseUrl?: string;\n supabaseServiceKey?: string;\n}\n\nexport function createServerSupabase(options: ServerSupabaseOptions = {}): SupabaseClient {\n const url = options.supabaseUrl || process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || '';\n const key = options.supabaseServiceKey || process.env.SUPABASE_SERVICE_ROLE_KEY || '';\n\n if (!url || !key) {\n throw new Error('Server Supabase requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\n }\n\n return createClient(url, key, {\n auth: {\n autoRefreshToken: false,\n persistSession: false,\n },\n });\n}\n","import { createServerSupabase } from './supabase';\n\ninterface WebhookRequest {\n headers: Record<string, string | string[] | undefined> | { get(name: string): string | null };\n body?: unknown;\n rawBody?: Buffer | string;\n text?: () => Promise<string>;\n}\n\ninterface StripeEvent {\n id: string;\n type: string;\n data: {\n object: Record<string, unknown>;\n };\n}\n\ninterface HandleOptions {\n supabaseServiceKey?: string;\n supabaseUrl?: string;\n}\n\nexport async function verifyStripeWebhook(\n req: WebhookRequest,\n webhookSecret?: string\n): Promise<StripeEvent> {\n const secret = webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\n if (!secret) {\n throw new Error('STRIPE_WEBHOOK_SECRET is required');\n }\n\n let rawBody: string;\n if (typeof req.rawBody === 'string') {\n rawBody = req.rawBody;\n } else if (req.rawBody instanceof Buffer) {\n rawBody = req.rawBody.toString('utf-8');\n } else if (typeof req.text === 'function') {\n rawBody = await req.text();\n } else if (typeof req.body === 'string') {\n rawBody = req.body;\n } else {\n rawBody = JSON.stringify(req.body);\n }\n\n // Dynamic import to keep stripe as optional peer dep\n const stripe = await import('stripe');\n const Stripe = stripe.default || stripe;\n const stripeClient = new (Stripe as unknown as new (key: string) => { webhooks: { constructEvent(body: string, sig: string, secret: string): StripeEvent } })(\n process.env.STRIPE_SECRET_KEY || ''\n );\n\n const sig = typeof req.headers === 'object' && 'get' in req.headers\n ? (req.headers as { get(name: string): string | null }).get('stripe-signature') || ''\n : (req.headers as Record<string, string | string[] | undefined>)['stripe-signature'] as string || '';\n\n return stripeClient.webhooks.constructEvent(rawBody, sig, secret);\n}\n\nexport async function handleSubscriptionEvent(\n event: StripeEvent,\n options: HandleOptions = {}\n): Promise<void> {\n const supabase = createServerSupabase(options);\n const obj = event.data.object;\n\n switch (event.type) {\n case 'checkout.session.completed': {\n const customerId = obj.customer as string;\n const subscriptionId = obj.subscription as string;\n const customerEmail = obj.customer_email as string;\n\n if (customerEmail) {\n await supabase\n .from('user_profiles')\n .update({\n stripe_customer_id: customerId,\n subscription_status: 'active',\n })\n .eq('email', customerEmail);\n }\n\n void subscriptionId;\n break;\n }\n\n case 'customer.subscription.created':\n case 'customer.subscription.updated': {\n const customerId = obj.customer as string;\n const status = obj.status as string;\n const priceId = ((obj.items as Record<string, unknown>)?.data as Array<Record<string, unknown>>)?.[0]?.price as Record<string, unknown>;\n const currentPeriodEnd = obj.current_period_end as number;\n\n const tier = mapPriceToTier(priceId?.id as string);\n\n await supabase\n .from('user_profiles')\n .update({\n subscription_tier: tier,\n subscription_status: status,\n subscription_period_end: currentPeriodEnd ? new Date(currentPeriodEnd * 1000).toISOString() : null,\n })\n .eq('stripe_customer_id', customerId);\n break;\n }\n\n case 'customer.subscription.deleted': {\n const customerId = obj.customer as string;\n\n await supabase\n .from('user_profiles')\n .update({\n subscription_tier: 'free',\n subscription_status: 'canceled',\n })\n .eq('stripe_customer_id', customerId);\n break;\n }\n\n case 'invoice.payment_succeeded': {\n const customerId = obj.customer as string;\n const subscriptionId = obj.subscription as string;\n\n if (subscriptionId) {\n await supabase\n .from('user_profiles')\n .update({\n subscription_status: 'active',\n last_payment_at: new Date().toISOString(),\n })\n .eq('stripe_customer_id', customerId);\n }\n break;\n }\n\n case 'invoice.payment_failed': {\n const customerId = obj.customer as string;\n\n await supabase\n .from('user_profiles')\n .update({ subscription_status: 'past_due' })\n .eq('stripe_customer_id', customerId);\n break;\n }\n }\n}\n\nfunction mapPriceToTier(priceId: string): string {\n if (!priceId) return 'free';\n\n const mapping: Record<string, string> = {};\n const envPrefixes = ['STRIPE_CREATOR', 'STRIPE_PRO', 'STRIPE_BUSINESS', 'STRIPE_ENTERPRISE'];\n const tierNames = ['creator', 'pro', 'business', 'enterprise'];\n\n envPrefixes.forEach((prefix, i) => {\n const monthly = process.env[`${prefix}_MONTHLY_PRICE_ID`];\n const yearly = process.env[`${prefix}_YEARLY_PRICE_ID`];\n if (monthly) mapping[monthly] = tierNames[i];\n if (yearly) mapping[yearly] = tierNames[i];\n });\n\n return mapping[priceId] || 'creator';\n}\n","import { createServerSupabase } from './supabase';\n\ninterface UploadRequest {\n body?: unknown;\n file?: { buffer: Buffer; originalname: string; mimetype: string; size: number };\n formData?: () => Promise<FormData>;\n}\n\ninterface HandleUploadOptions {\n supabaseServiceKey?: string;\n supabaseUrl?: string;\n maxSizeMB?: number;\n bucket?: string;\n allowedTypes?: string[];\n}\n\ninterface UploadResult {\n success: boolean;\n path?: string;\n url?: string;\n error?: string;\n}\n\nexport async function handleUpload(\n req: UploadRequest,\n options: HandleUploadOptions = {}\n): Promise<UploadResult> {\n const supabase = createServerSupabase(options);\n const bucket = options.bucket || 'uploads';\n const maxSize = (options.maxSizeMB || 10) * 1024 * 1024;\n\n try {\n let fileBuffer: Buffer;\n let fileName: string;\n let mimeType: string;\n let fileSize: number;\n\n if (req.file) {\n fileBuffer = req.file.buffer;\n fileName = req.file.originalname;\n mimeType = req.file.mimetype;\n fileSize = req.file.size;\n } else if (typeof req.formData === 'function') {\n const formData = await req.formData();\n const file = formData.get('file') as File | null;\n if (!file) return { success: false, error: 'No file provided' };\n\n fileBuffer = Buffer.from(await file.arrayBuffer());\n fileName = file.name;\n mimeType = file.type;\n fileSize = file.size;\n } else {\n return { success: false, error: 'No file in request' };\n }\n\n if (fileSize > maxSize) {\n return { success: false, error: `File exceeds ${options.maxSizeMB || 10}MB limit` };\n }\n\n if (options.allowedTypes?.length && !options.allowedTypes.includes(mimeType)) {\n return { success: false, error: `File type ${mimeType} not allowed` };\n }\n\n const path = `uploads/${Date.now()}_${fileName}`;\n\n const { error } = await supabase.storage\n .from(bucket)\n .upload(path, fileBuffer, {\n contentType: mimeType,\n cacheControl: '3600',\n });\n\n if (error) return { success: false, error: error.message };\n\n const { data: signedData } = await supabase.storage\n .from(bucket)\n .createSignedUrl(path, 3600);\n\n return {\n success: true,\n path,\n url: signedData?.signedUrl,\n };\n } catch (err: unknown) {\n return {\n success: false,\n error: err instanceof Error ? err.message : 'Upload failed',\n };\n }\n}\n","import { createServerSupabase } from './supabase';\n\ninterface AuthRequest {\n headers: Record<string, string | string[] | undefined> | { get(name: string): string | null };\n}\n\ninterface AuthUser {\n id: string;\n email?: string;\n role?: string;\n}\n\ninterface RequireAuthOptions {\n supabaseUrl?: string;\n supabaseServiceKey?: string;\n}\n\nexport async function requireAuth(\n req: AuthRequest,\n options: RequireAuthOptions = {}\n): Promise<AuthUser> {\n const authHeader = typeof req.headers === 'object' && 'get' in req.headers\n ? (req.headers as { get(name: string): string | null }).get('authorization')\n : (req.headers as Record<string, string | string[] | undefined>)['authorization'] as string;\n\n if (!authHeader?.startsWith('Bearer ')) {\n throw new Error('Missing or invalid Authorization header');\n }\n\n const token = authHeader.slice(7);\n const supabase = createServerSupabase(options);\n\n const { data: { user }, error } = await supabase.auth.getUser(token);\n\n if (error || !user) {\n throw new Error('Invalid or expired token');\n }\n\n return {\n id: user.id,\n email: user.email,\n role: user.role,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/server/supabase.ts","../../src/server/stripe.ts","../../src/server/storage.ts","../../src/server/middleware.ts"],"sourcesContent":["import { createClient, SupabaseClient } from '@supabase/supabase-js';\r\n\r\ninterface ServerSupabaseOptions {\r\n supabaseUrl?: string;\r\n supabaseServiceKey?: string;\r\n}\r\n\r\nexport function createServerSupabase(options: ServerSupabaseOptions = {}): SupabaseClient {\r\n const url = options.supabaseUrl || process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || '';\r\n const key = options.supabaseServiceKey || process.env.SUPABASE_SERVICE_ROLE_KEY || '';\r\n\r\n if (!url || !key) {\r\n throw new Error('Server Supabase requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY');\r\n }\r\n\r\n return createClient(url, key, {\r\n auth: {\r\n autoRefreshToken: false,\r\n persistSession: false,\r\n },\r\n });\r\n}\r\n","import { createServerSupabase } from './supabase';\r\n\r\ninterface WebhookRequest {\r\n headers: Record<string, string | string[] | undefined> | { get(name: string): string | null };\r\n body?: unknown;\r\n rawBody?: Buffer | string;\r\n text?: () => Promise<string>;\r\n}\r\n\r\ninterface StripeEvent {\r\n id: string;\r\n type: string;\r\n data: {\r\n object: Record<string, unknown>;\r\n };\r\n}\r\n\r\ninterface HandleOptions {\r\n supabaseServiceKey?: string;\r\n supabaseUrl?: string;\r\n}\r\n\r\nexport async function verifyStripeWebhook(\r\n req: WebhookRequest,\r\n webhookSecret?: string\r\n): Promise<StripeEvent> {\r\n const secret = webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;\r\n if (!secret) {\r\n throw new Error('STRIPE_WEBHOOK_SECRET is required');\r\n }\r\n\r\n let rawBody: string;\r\n if (typeof req.rawBody === 'string') {\r\n rawBody = req.rawBody;\r\n } else if (req.rawBody instanceof Buffer) {\r\n rawBody = req.rawBody.toString('utf-8');\r\n } else if (typeof req.text === 'function') {\r\n rawBody = await req.text();\r\n } else if (typeof req.body === 'string') {\r\n rawBody = req.body;\r\n } else {\r\n rawBody = JSON.stringify(req.body);\r\n }\r\n\r\n // Dynamic import to keep stripe as optional peer dep\r\n const stripe = await import('stripe');\r\n const Stripe = stripe.default || stripe;\r\n const stripeClient = new (Stripe as unknown as new (key: string) => { webhooks: { constructEvent(body: string, sig: string, secret: string): StripeEvent } })(\r\n process.env.STRIPE_SECRET_KEY || ''\r\n );\r\n\r\n const sig = typeof req.headers === 'object' && 'get' in req.headers\r\n ? (req.headers as { get(name: string): string | null }).get('stripe-signature') || ''\r\n : (req.headers as Record<string, string | string[] | undefined>)['stripe-signature'] as string || '';\r\n\r\n return stripeClient.webhooks.constructEvent(rawBody, sig, secret);\r\n}\r\n\r\nexport async function handleSubscriptionEvent(\r\n event: StripeEvent,\r\n options: HandleOptions = {}\r\n): Promise<void> {\r\n const supabase = createServerSupabase(options);\r\n const obj = event.data.object;\r\n\r\n switch (event.type) {\r\n case 'checkout.session.completed': {\r\n const customerId = obj.customer as string;\r\n const subscriptionId = obj.subscription as string;\r\n const customerEmail = obj.customer_email as string;\r\n\r\n if (customerEmail) {\r\n await supabase\r\n .from('user_profiles')\r\n .update({\r\n stripe_customer_id: customerId,\r\n subscription_status: 'active',\r\n })\r\n .eq('email', customerEmail);\r\n }\r\n\r\n void subscriptionId;\r\n break;\r\n }\r\n\r\n case 'customer.subscription.created':\r\n case 'customer.subscription.updated': {\r\n const customerId = obj.customer as string;\r\n const status = obj.status as string;\r\n const priceId = ((obj.items as Record<string, unknown>)?.data as Array<Record<string, unknown>>)?.[0]?.price as Record<string, unknown>;\r\n const currentPeriodEnd = obj.current_period_end as number;\r\n\r\n const tier = mapPriceToTier(priceId?.id as string);\r\n\r\n await supabase\r\n .from('user_profiles')\r\n .update({\r\n subscription_tier: tier,\r\n subscription_status: status,\r\n subscription_period_end: currentPeriodEnd ? new Date(currentPeriodEnd * 1000).toISOString() : null,\r\n })\r\n .eq('stripe_customer_id', customerId);\r\n break;\r\n }\r\n\r\n case 'customer.subscription.deleted': {\r\n const customerId = obj.customer as string;\r\n\r\n await supabase\r\n .from('user_profiles')\r\n .update({\r\n subscription_tier: 'free',\r\n subscription_status: 'canceled',\r\n })\r\n .eq('stripe_customer_id', customerId);\r\n break;\r\n }\r\n\r\n case 'invoice.payment_succeeded': {\r\n const customerId = obj.customer as string;\r\n const subscriptionId = obj.subscription as string;\r\n\r\n if (subscriptionId) {\r\n await supabase\r\n .from('user_profiles')\r\n .update({\r\n subscription_status: 'active',\r\n last_payment_at: new Date().toISOString(),\r\n })\r\n .eq('stripe_customer_id', customerId);\r\n }\r\n break;\r\n }\r\n\r\n case 'invoice.payment_failed': {\r\n const customerId = obj.customer as string;\r\n\r\n await supabase\r\n .from('user_profiles')\r\n .update({ subscription_status: 'past_due' })\r\n .eq('stripe_customer_id', customerId);\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction mapPriceToTier(priceId: string): string {\r\n if (!priceId) return 'free';\r\n\r\n const mapping: Record<string, string> = {};\r\n const envPrefixes = ['STRIPE_CREATOR', 'STRIPE_PRO', 'STRIPE_BUSINESS', 'STRIPE_ENTERPRISE'];\r\n const tierNames = ['creator', 'pro', 'business', 'enterprise'];\r\n\r\n envPrefixes.forEach((prefix, i) => {\r\n const monthly = process.env[`${prefix}_MONTHLY_PRICE_ID`];\r\n const yearly = process.env[`${prefix}_YEARLY_PRICE_ID`];\r\n if (monthly) mapping[monthly] = tierNames[i];\r\n if (yearly) mapping[yearly] = tierNames[i];\r\n });\r\n\r\n return mapping[priceId] || 'creator';\r\n}\r\n","import { createServerSupabase } from './supabase';\r\n\r\ninterface UploadRequest {\r\n body?: unknown;\r\n file?: { buffer: Buffer; originalname: string; mimetype: string; size: number };\r\n formData?: () => Promise<FormData>;\r\n}\r\n\r\ninterface HandleUploadOptions {\r\n supabaseServiceKey?: string;\r\n supabaseUrl?: string;\r\n maxSizeMB?: number;\r\n bucket?: string;\r\n allowedTypes?: string[];\r\n}\r\n\r\ninterface UploadResult {\r\n success: boolean;\r\n path?: string;\r\n url?: string;\r\n error?: string;\r\n}\r\n\r\nexport async function handleUpload(\r\n req: UploadRequest,\r\n options: HandleUploadOptions = {}\r\n): Promise<UploadResult> {\r\n const supabase = createServerSupabase(options);\r\n const bucket = options.bucket || 'uploads';\r\n const maxSize = (options.maxSizeMB || 10) * 1024 * 1024;\r\n\r\n try {\r\n let fileBuffer: Buffer;\r\n let fileName: string;\r\n let mimeType: string;\r\n let fileSize: number;\r\n\r\n if (req.file) {\r\n fileBuffer = req.file.buffer;\r\n fileName = req.file.originalname;\r\n mimeType = req.file.mimetype;\r\n fileSize = req.file.size;\r\n } else if (typeof req.formData === 'function') {\r\n const formData = await req.formData();\r\n const file = formData.get('file') as File | null;\r\n if (!file) return { success: false, error: 'No file provided' };\r\n\r\n fileBuffer = Buffer.from(await file.arrayBuffer());\r\n fileName = file.name;\r\n mimeType = file.type;\r\n fileSize = file.size;\r\n } else {\r\n return { success: false, error: 'No file in request' };\r\n }\r\n\r\n if (fileSize > maxSize) {\r\n return { success: false, error: `File exceeds ${options.maxSizeMB || 10}MB limit` };\r\n }\r\n\r\n if (options.allowedTypes?.length && !options.allowedTypes.includes(mimeType)) {\r\n return { success: false, error: `File type ${mimeType} not allowed` };\r\n }\r\n\r\n const path = `uploads/${Date.now()}_${fileName}`;\r\n\r\n const { error } = await supabase.storage\r\n .from(bucket)\r\n .upload(path, fileBuffer, {\r\n contentType: mimeType,\r\n cacheControl: '3600',\r\n });\r\n\r\n if (error) return { success: false, error: error.message };\r\n\r\n const { data: signedData } = await supabase.storage\r\n .from(bucket)\r\n .createSignedUrl(path, 3600);\r\n\r\n return {\r\n success: true,\r\n path,\r\n url: signedData?.signedUrl,\r\n };\r\n } catch (err: unknown) {\r\n return {\r\n success: false,\r\n error: err instanceof Error ? err.message : 'Upload failed',\r\n };\r\n }\r\n}\r\n","import { createServerSupabase } from './supabase';\r\n\r\ninterface AuthRequest {\r\n headers: Record<string, string | string[] | undefined> | { get(name: string): string | null };\r\n}\r\n\r\ninterface AuthUser {\r\n id: string;\r\n email?: string;\r\n role?: string;\r\n}\r\n\r\ninterface RequireAuthOptions {\r\n supabaseUrl?: string;\r\n supabaseServiceKey?: string;\r\n}\r\n\r\nexport async function requireAuth(\r\n req: AuthRequest,\r\n options: RequireAuthOptions = {}\r\n): Promise<AuthUser> {\r\n const authHeader = typeof req.headers === 'object' && 'get' in req.headers\r\n ? (req.headers as { get(name: string): string | null }).get('authorization')\r\n : (req.headers as Record<string, string | string[] | undefined>)['authorization'] as string;\r\n\r\n if (!authHeader?.startsWith('Bearer ')) {\r\n throw new Error('Missing or invalid Authorization header');\r\n }\r\n\r\n const token = authHeader.slice(7);\r\n const supabase = createServerSupabase(options);\r\n\r\n const { data: { user }, error } = await supabase.auth.getUser(token);\r\n\r\n if (error || !user) {\r\n throw new Error('Invalid or expired token');\r\n }\r\n\r\n return {\r\n id: user.id,\r\n email: user.email,\r\n role: user.role,\r\n };\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/storage/index.d.ts
CHANGED