@ezcoder.dev/sdk 1.0.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/analytics/index.d.ts +18 -0
- package/dist/analytics/index.js +76 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/animation/index.d.ts +172 -0
- package/dist/animation/index.js +81 -0
- package/dist/animation/index.js.map +1 -0
- package/dist/auth/index.d.ts +80 -0
- package/dist/auth/index.js +463 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/chunk-5XIZHBKE.js +372 -0
- package/dist/chunk-5XIZHBKE.js.map +1 -0
- package/dist/chunk-G7XDUN3Z.js +141 -0
- package/dist/chunk-G7XDUN3Z.js.map +1 -0
- package/dist/chunk-YNDCD53D.js +212 -0
- package/dist/chunk-YNDCD53D.js.map +1 -0
- package/dist/cms/index.d.ts +44 -0
- package/dist/cms/index.js +106 -0
- package/dist/cms/index.js.map +1 -0
- package/dist/errors/index.d.ts +20 -0
- package/dist/errors/index.js +61 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/notifications/index.d.ts +30 -0
- package/dist/notifications/index.js +191 -0
- package/dist/notifications/index.js.map +1 -0
- package/dist/payments/index.d.ts +89 -0
- package/dist/payments/index.js +408 -0
- package/dist/payments/index.js.map +1 -0
- package/dist/roles/index.d.ts +37 -0
- package/dist/roles/index.js +120 -0
- package/dist/roles/index.js.map +1 -0
- package/dist/seo/index.d.ts +39 -0
- package/dist/seo/index.js +89 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/server/index.d.ts +72 -0
- package/dist/server/index.js +191 -0
- package/dist/server/index.js.map +1 -0
- package/dist/storage/index.d.ts +52 -0
- package/dist/storage/index.js +212 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/types-DtY5lp3P.d.ts +90 -0
- package/package.json +105 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthContext
|
|
3
|
+
} from "../chunk-YNDCD53D.js";
|
|
4
|
+
import "../chunk-5XIZHBKE.js";
|
|
5
|
+
import {
|
|
6
|
+
features,
|
|
7
|
+
supabase
|
|
8
|
+
} from "../chunk-G7XDUN3Z.js";
|
|
9
|
+
|
|
10
|
+
// src/storage/useStorage.ts
|
|
11
|
+
import { useState, useCallback, useContext } from "react";
|
|
12
|
+
var TIER_RETENTION_DAYS = {
|
|
13
|
+
free: 7,
|
|
14
|
+
starter: 30,
|
|
15
|
+
pro: 90,
|
|
16
|
+
creator: 90,
|
|
17
|
+
business: 365,
|
|
18
|
+
enterprise: -1
|
|
19
|
+
};
|
|
20
|
+
function useStorage() {
|
|
21
|
+
const auth = useContext(AuthContext);
|
|
22
|
+
const [provider] = useState(features.storage ? "supabase" : "stub");
|
|
23
|
+
const tier = auth?.profile?.subscription_tier || "free";
|
|
24
|
+
const retentionDays = TIER_RETENTION_DAYS[tier] ?? 7;
|
|
25
|
+
const getUserPath = useCallback((path) => {
|
|
26
|
+
const userId = auth?.user?.id;
|
|
27
|
+
const basePath = userId ? `user/${userId}` : "public";
|
|
28
|
+
return path ? `${basePath}/${path}` : basePath;
|
|
29
|
+
}, [auth?.user?.id]);
|
|
30
|
+
const upload = useCallback(async (file, options = {}) => {
|
|
31
|
+
if (!features.storage) {
|
|
32
|
+
throw new Error("Storage is not configured. Set SUPABASE_URL to enable file storage.");
|
|
33
|
+
}
|
|
34
|
+
const bucket = options.bucket || "uploads";
|
|
35
|
+
const filePath = getUserPath(options.path || `${Date.now()}_${file.name}`);
|
|
36
|
+
const { data, error } = await supabase.storage.from(bucket).upload(filePath, file, {
|
|
37
|
+
cacheControl: "3600",
|
|
38
|
+
upsert: false
|
|
39
|
+
});
|
|
40
|
+
if (error) throw error;
|
|
41
|
+
let url;
|
|
42
|
+
if (options.public) {
|
|
43
|
+
const { data: urlData } = supabase.storage.from(bucket).getPublicUrl(filePath);
|
|
44
|
+
url = urlData.publicUrl;
|
|
45
|
+
} else {
|
|
46
|
+
const { data: signedData, error: signedError } = await supabase.storage.from(bucket).createSignedUrl(filePath, 3600);
|
|
47
|
+
if (signedError) throw signedError;
|
|
48
|
+
url = signedData.signedUrl;
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
path: data.path,
|
|
52
|
+
url,
|
|
53
|
+
size: file.size,
|
|
54
|
+
type: file.type
|
|
55
|
+
};
|
|
56
|
+
}, [getUserPath]);
|
|
57
|
+
const download = useCallback(async (path, bucket = "uploads") => {
|
|
58
|
+
if (!features.storage) throw new Error("Storage is not configured");
|
|
59
|
+
const { data, error } = await supabase.storage.from(bucket).download(path);
|
|
60
|
+
if (error) throw error;
|
|
61
|
+
return data;
|
|
62
|
+
}, []);
|
|
63
|
+
const getUrl = useCallback(async (path, options = {}) => {
|
|
64
|
+
if (!features.storage) return "";
|
|
65
|
+
const bucket = options.bucket || "uploads";
|
|
66
|
+
if (options.signed !== false) {
|
|
67
|
+
const { data: data2, error } = await supabase.storage.from(bucket).createSignedUrl(path, options.expiresIn || 3600);
|
|
68
|
+
if (error) throw error;
|
|
69
|
+
return data2.signedUrl;
|
|
70
|
+
}
|
|
71
|
+
const { data } = supabase.storage.from(bucket).getPublicUrl(path);
|
|
72
|
+
return data.publicUrl;
|
|
73
|
+
}, []);
|
|
74
|
+
const list = useCallback(async (prefix, bucket = "uploads") => {
|
|
75
|
+
if (!features.storage) return [];
|
|
76
|
+
const searchPath = prefix || getUserPath();
|
|
77
|
+
const { data, error } = await supabase.storage.from(bucket).list(searchPath);
|
|
78
|
+
if (error) throw error;
|
|
79
|
+
return (data || []).map((item) => ({
|
|
80
|
+
name: item.name,
|
|
81
|
+
path: `${searchPath}/${item.name}`,
|
|
82
|
+
size: item.metadata?.size || 0,
|
|
83
|
+
type: item.metadata?.mimetype || "",
|
|
84
|
+
created_at: item.created_at || "",
|
|
85
|
+
updated_at: item.updated_at || item.created_at || ""
|
|
86
|
+
}));
|
|
87
|
+
}, [getUserPath]);
|
|
88
|
+
const remove = useCallback(async (path, bucket = "uploads") => {
|
|
89
|
+
if (!features.storage) throw new Error("Storage is not configured");
|
|
90
|
+
const { error } = await supabase.storage.from(bucket).remove([path]);
|
|
91
|
+
if (error) throw error;
|
|
92
|
+
}, []);
|
|
93
|
+
return { upload, download, getUrl, list, remove, isConfigured: features.storage, provider, retentionDays };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/storage/FileUpload.tsx
|
|
97
|
+
import { useState as useState2, useRef, useCallback as useCallback2 } from "react";
|
|
98
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
99
|
+
function FileUpload({
|
|
100
|
+
onUpload,
|
|
101
|
+
onError,
|
|
102
|
+
accept,
|
|
103
|
+
maxSize = 10 * 1024 * 1024,
|
|
104
|
+
multiple = false,
|
|
105
|
+
children,
|
|
106
|
+
className = "",
|
|
107
|
+
bucket,
|
|
108
|
+
public: isPublic = false
|
|
109
|
+
}) {
|
|
110
|
+
const { upload, isConfigured } = useStorage();
|
|
111
|
+
const [uploading, setUploading] = useState2(false);
|
|
112
|
+
const [dragOver, setDragOver] = useState2(false);
|
|
113
|
+
const fileInputRef = useRef(null);
|
|
114
|
+
const handleFiles = useCallback2(async (files) => {
|
|
115
|
+
if (!files || files.length === 0) return;
|
|
116
|
+
setUploading(true);
|
|
117
|
+
for (const file of Array.from(files)) {
|
|
118
|
+
if (file.size > maxSize) {
|
|
119
|
+
onError?.(new Error(`File ${file.name} exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`));
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
try {
|
|
123
|
+
const result = await upload(file, { bucket, public: isPublic });
|
|
124
|
+
onUpload?.(result);
|
|
125
|
+
} catch (err) {
|
|
126
|
+
onError?.(err instanceof Error ? err : new Error("Upload failed"));
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
setUploading(false);
|
|
130
|
+
}, [upload, maxSize, onUpload, onError, bucket, isPublic]);
|
|
131
|
+
const handleDrop = useCallback2((e) => {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
setDragOver(false);
|
|
134
|
+
handleFiles(e.dataTransfer.files);
|
|
135
|
+
}, [handleFiles]);
|
|
136
|
+
if (!isConfigured) {
|
|
137
|
+
return /* @__PURE__ */ jsx("div", { style: { padding: "20px", textAlign: "center", color: "#6b7280", border: "1px dashed #d1d5db", borderRadius: "8px" }, children: "Storage is not configured" });
|
|
138
|
+
}
|
|
139
|
+
return /* @__PURE__ */ jsxs(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
className,
|
|
143
|
+
onDrop: handleDrop,
|
|
144
|
+
onDragOver: (e) => {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
setDragOver(true);
|
|
147
|
+
},
|
|
148
|
+
onDragLeave: () => setDragOver(false),
|
|
149
|
+
onClick: () => fileInputRef.current?.click(),
|
|
150
|
+
style: {
|
|
151
|
+
border: `2px dashed ${dragOver ? "#3b82f6" : "#d1d5db"}`,
|
|
152
|
+
borderRadius: "8px",
|
|
153
|
+
padding: "24px",
|
|
154
|
+
textAlign: "center",
|
|
155
|
+
cursor: "pointer",
|
|
156
|
+
backgroundColor: dragOver ? "#eff6ff" : "transparent",
|
|
157
|
+
transition: "all 0.2s"
|
|
158
|
+
},
|
|
159
|
+
children: [
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
"input",
|
|
162
|
+
{
|
|
163
|
+
ref: fileInputRef,
|
|
164
|
+
type: "file",
|
|
165
|
+
accept,
|
|
166
|
+
multiple,
|
|
167
|
+
onChange: (e) => handleFiles(e.target.files),
|
|
168
|
+
style: { display: "none" }
|
|
169
|
+
}
|
|
170
|
+
),
|
|
171
|
+
children || /* @__PURE__ */ jsx("div", { children: uploading ? /* @__PURE__ */ jsx("p", { style: { color: "#3b82f6" }, children: "Uploading..." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
172
|
+
/* @__PURE__ */ jsx("p", { style: { fontWeight: 500, marginBottom: "4px" }, children: "Drop files here or click to upload" }),
|
|
173
|
+
/* @__PURE__ */ jsxs("p", { style: { color: "#9ca3af", fontSize: "14px" }, children: [
|
|
174
|
+
"Max size: ",
|
|
175
|
+
Math.round(maxSize / 1024 / 1024),
|
|
176
|
+
"MB"
|
|
177
|
+
] })
|
|
178
|
+
] }) })
|
|
179
|
+
]
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/storage/ImagePreview.tsx
|
|
185
|
+
import { useState as useState3, useEffect } from "react";
|
|
186
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
187
|
+
function ImagePreview({ path, alt = "", className = "", width, height, bucket, signed = true }) {
|
|
188
|
+
const { getUrl, isConfigured } = useStorage();
|
|
189
|
+
const [url, setUrl] = useState3("");
|
|
190
|
+
const [loading, setLoading] = useState3(true);
|
|
191
|
+
const [error, setError] = useState3(false);
|
|
192
|
+
useEffect(() => {
|
|
193
|
+
if (!isConfigured || !path) {
|
|
194
|
+
setLoading(false);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
getUrl(path, { signed, bucket }).then(setUrl).catch(() => setError(true)).finally(() => setLoading(false));
|
|
198
|
+
}, [path, signed, bucket, getUrl, isConfigured]);
|
|
199
|
+
if (loading) {
|
|
200
|
+
return /* @__PURE__ */ jsx2("div", { style: { width: width || "100%", height: height || "200px", backgroundColor: "#f3f4f6", borderRadius: "8px", display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2("span", { style: { color: "#9ca3af" }, children: "Loading..." }) });
|
|
201
|
+
}
|
|
202
|
+
if (error || !url) {
|
|
203
|
+
return /* @__PURE__ */ jsx2("div", { style: { width: width || "100%", height: height || "200px", backgroundColor: "#f3f4f6", borderRadius: "8px", display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ jsx2("span", { style: { color: "#9ca3af" }, children: "Image not available" }) });
|
|
204
|
+
}
|
|
205
|
+
return /* @__PURE__ */ jsx2("img", { src: url, alt, className, style: { width, height, objectFit: "cover", borderRadius: "8px" } });
|
|
206
|
+
}
|
|
207
|
+
export {
|
|
208
|
+
FileUpload,
|
|
209
|
+
ImagePreview,
|
|
210
|
+
useStorage
|
|
211
|
+
};
|
|
212
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/storage/useStorage.ts","../../src/storage/FileUpload.tsx","../../src/storage/ImagePreview.tsx"],"sourcesContent":["import { useState, useCallback, useContext } from 'react';\nimport { supabase } from '../core/supabase';\nimport { features } from '../core/config';\nimport { AuthContext } from '../auth/AuthProvider';\nimport type { StorageResult, StorageFile } from '../core/types';\n\ntype StorageProvider = 'supabase' | 'stub';\n\nconst TIER_RETENTION_DAYS: Record<string, number> = {\n free: 7,\n starter: 30,\n pro: 90,\n creator: 90,\n business: 365,\n enterprise: -1,\n};\n\ninterface UploadOptions {\n path?: string;\n public?: boolean;\n bucket?: string;\n}\n\ninterface UrlOptions {\n signed?: boolean;\n expiresIn?: number;\n}\n\ninterface UseStorageReturn {\n upload: (file: File, options?: UploadOptions) => Promise<StorageResult>;\n download: (path: string, bucket?: string) => Promise<Blob>;\n getUrl: (path: string, options?: UrlOptions & { bucket?: string }) => Promise<string>;\n list: (prefix?: string, bucket?: string) => Promise<StorageFile[]>;\n remove: (path: string, bucket?: string) => Promise<void>;\n isConfigured: boolean;\n provider: StorageProvider;\n retentionDays: number;\n}\n\nexport function useStorage(): UseStorageReturn {\n const auth = useContext(AuthContext);\n const [provider] = useState<StorageProvider>(features.storage ? 'supabase' : 'stub');\n const tier = (auth?.profile as unknown as Record<string, unknown>)?.subscription_tier as string || 'free';\n const retentionDays = TIER_RETENTION_DAYS[tier] ?? 7;\n\n const getUserPath = useCallback((path?: string): string => {\n const userId = auth?.user?.id;\n const basePath = userId ? `user/${userId}` : 'public';\n return path ? `${basePath}/${path}` : basePath;\n }, [auth?.user?.id]);\n\n const upload = useCallback(async (file: File, options: UploadOptions = {}): Promise<StorageResult> => {\n if (!features.storage) {\n throw new Error('Storage is not configured. Set SUPABASE_URL to enable file storage.');\n }\n\n const bucket = options.bucket || 'uploads';\n const filePath = getUserPath(options.path || `${Date.now()}_${file.name}`);\n\n const { data, error } = await supabase.storage\n .from(bucket)\n .upload(filePath, file, {\n cacheControl: '3600',\n upsert: false,\n });\n\n if (error) throw error;\n\n let url: string;\n if (options.public) {\n const { data: urlData } = supabase.storage.from(bucket).getPublicUrl(filePath);\n url = urlData.publicUrl;\n } else {\n const { data: signedData, error: signedError } = await supabase.storage\n .from(bucket)\n .createSignedUrl(filePath, 3600);\n if (signedError) throw signedError;\n url = signedData.signedUrl;\n }\n\n return {\n path: data.path,\n url,\n size: file.size,\n type: file.type,\n };\n }, [getUserPath]);\n\n const download = useCallback(async (path: string, bucket = 'uploads'): Promise<Blob> => {\n if (!features.storage) throw new Error('Storage is not configured');\n\n const { data, error } = await supabase.storage.from(bucket).download(path);\n if (error) throw error;\n return data;\n }, []);\n\n const getUrl = useCallback(async (path: string, options: UrlOptions & { bucket?: string } = {}): Promise<string> => {\n if (!features.storage) return '';\n\n const bucket = options.bucket || 'uploads';\n\n if (options.signed !== false) {\n const { data, error } = await supabase.storage\n .from(bucket)\n .createSignedUrl(path, options.expiresIn || 3600);\n if (error) throw error;\n return data.signedUrl;\n }\n\n const { data } = supabase.storage.from(bucket).getPublicUrl(path);\n return data.publicUrl;\n }, []);\n\n const list = useCallback(async (prefix?: string, bucket = 'uploads'): Promise<StorageFile[]> => {\n if (!features.storage) return [];\n\n const searchPath = prefix || getUserPath();\n const { data, error } = await supabase.storage.from(bucket).list(searchPath);\n if (error) throw error;\n\n return (data || []).map((item) => ({\n name: item.name,\n path: `${searchPath}/${item.name}`,\n size: (item.metadata as Record<string, unknown>)?.size as number || 0,\n type: (item.metadata as Record<string, unknown>)?.mimetype as string || '',\n created_at: item.created_at || '',\n updated_at: item.updated_at || item.created_at || '',\n }));\n }, [getUserPath]);\n\n const remove = useCallback(async (path: string, bucket = 'uploads'): Promise<void> => {\n if (!features.storage) throw new Error('Storage is not configured');\n\n const { error } = await supabase.storage.from(bucket).remove([path]);\n if (error) throw error;\n }, []);\n\n return { upload, download, getUrl, list, remove, isConfigured: features.storage, provider, retentionDays };\n}\n","import { useState, useRef, useCallback } from 'react';\nimport { useStorage } from './useStorage';\nimport type { StorageResult } from '../core/types';\n\ninterface FileUploadProps {\n onUpload?: (result: StorageResult) => void;\n onError?: (error: Error) => void;\n accept?: string;\n maxSize?: number;\n multiple?: boolean;\n children?: React.ReactNode;\n className?: string;\n bucket?: string;\n public?: boolean;\n}\n\nexport function FileUpload({\n onUpload,\n onError,\n accept,\n maxSize = 10 * 1024 * 1024,\n multiple = false,\n children,\n className = '',\n bucket,\n public: isPublic = false,\n}: FileUploadProps) {\n const { upload, isConfigured } = useStorage();\n const [uploading, setUploading] = useState(false);\n const [dragOver, setDragOver] = useState(false);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n const handleFiles = useCallback(async (files: FileList | null) => {\n if (!files || files.length === 0) return;\n\n setUploading(true);\n\n for (const file of Array.from(files)) {\n if (file.size > maxSize) {\n onError?.(new Error(`File ${file.name} exceeds maximum size of ${Math.round(maxSize / 1024 / 1024)}MB`));\n continue;\n }\n\n try {\n const result = await upload(file, { bucket, public: isPublic });\n onUpload?.(result);\n } catch (err: unknown) {\n onError?.(err instanceof Error ? err : new Error('Upload failed'));\n }\n }\n\n setUploading(false);\n }, [upload, maxSize, onUpload, onError, bucket, isPublic]);\n\n const handleDrop = useCallback((e: React.DragEvent) => {\n e.preventDefault();\n setDragOver(false);\n handleFiles(e.dataTransfer.files);\n }, [handleFiles]);\n\n if (!isConfigured) {\n return (\n <div style={{ padding: '20px', textAlign: 'center', color: '#6b7280', border: '1px dashed #d1d5db', borderRadius: '8px' }}>\n Storage is not configured\n </div>\n );\n }\n\n return (\n <div\n className={className}\n onDrop={handleDrop}\n onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}\n onDragLeave={() => setDragOver(false)}\n onClick={() => fileInputRef.current?.click()}\n style={{\n border: `2px dashed ${dragOver ? '#3b82f6' : '#d1d5db'}`,\n borderRadius: '8px',\n padding: '24px',\n textAlign: 'center',\n cursor: 'pointer',\n backgroundColor: dragOver ? '#eff6ff' : 'transparent',\n transition: 'all 0.2s',\n }}\n >\n <input\n ref={fileInputRef}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n onChange={(e) => handleFiles(e.target.files)}\n style={{ display: 'none' }}\n />\n\n {children || (\n <div>\n {uploading ? (\n <p style={{ color: '#3b82f6' }}>Uploading...</p>\n ) : (\n <>\n <p style={{ fontWeight: 500, marginBottom: '4px' }}>Drop files here or click to upload</p>\n <p style={{ color: '#9ca3af', fontSize: '14px' }}>\n Max size: {Math.round(maxSize / 1024 / 1024)}MB\n </p>\n </>\n )}\n </div>\n )}\n </div>\n );\n}\n","import { useState, useEffect } from 'react';\nimport { useStorage } from './useStorage';\n\ninterface ImagePreviewProps {\n path: string;\n alt?: string;\n className?: string;\n width?: number | string;\n height?: number | string;\n bucket?: string;\n signed?: boolean;\n}\n\nexport function ImagePreview({ path, alt = '', className = '', width, height, bucket, signed = true }: ImagePreviewProps) {\n const { getUrl, isConfigured } = useStorage();\n const [url, setUrl] = useState<string>('');\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n if (!isConfigured || !path) {\n setLoading(false);\n return;\n }\n\n getUrl(path, { signed, bucket })\n .then(setUrl)\n .catch(() => setError(true))\n .finally(() => setLoading(false));\n }, [path, signed, bucket, getUrl, isConfigured]);\n\n if (loading) {\n return (\n <div style={{ width: width || '100%', height: height || '200px', backgroundColor: '#f3f4f6', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <span style={{ color: '#9ca3af' }}>Loading...</span>\n </div>\n );\n }\n\n if (error || !url) {\n return (\n <div style={{ width: width || '100%', height: height || '200px', backgroundColor: '#f3f4f6', borderRadius: '8px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>\n <span style={{ color: '#9ca3af' }}>Image not available</span>\n </div>\n );\n }\n\n return <img src={url} alt={alt} className={className} style={{ width, height, objectFit: 'cover', borderRadius: '8px' }} />;\n}\n"],"mappings":"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","names":["data","useState","useCallback","useState","useCallback","useState","jsx","useState"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
interface AnalyticsResult {
|
|
2
|
+
success: boolean;
|
|
3
|
+
error?: string;
|
|
4
|
+
}
|
|
5
|
+
interface CheckoutOptions {
|
|
6
|
+
successUrl?: string;
|
|
7
|
+
cancelUrl?: string;
|
|
8
|
+
customerEmail?: string;
|
|
9
|
+
quantity?: number;
|
|
10
|
+
redirect?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface EzcoderClient {
|
|
13
|
+
isConfigured: () => boolean;
|
|
14
|
+
analytics: {
|
|
15
|
+
track: (eventType: string, properties?: Record<string, unknown>) => Promise<AnalyticsResult>;
|
|
16
|
+
pageView: (path?: string) => Promise<AnalyticsResult>;
|
|
17
|
+
identify: (userId: string, traits?: Record<string, unknown>) => Promise<AnalyticsResult>;
|
|
18
|
+
error: (message: string, context?: Record<string, unknown>) => Promise<AnalyticsResult>;
|
|
19
|
+
};
|
|
20
|
+
stripe: {
|
|
21
|
+
createCheckout: (priceId: string, options?: CheckoutOptions) => Promise<AnalyticsResult & {
|
|
22
|
+
url?: string;
|
|
23
|
+
}>;
|
|
24
|
+
getProducts: () => Promise<{
|
|
25
|
+
products: unknown[];
|
|
26
|
+
message: string;
|
|
27
|
+
}>;
|
|
28
|
+
verifySession: (sessionId: string) => Promise<AnalyticsResult & Record<string, unknown>>;
|
|
29
|
+
getCustomerStatus: (options?: {
|
|
30
|
+
customerId?: string;
|
|
31
|
+
email?: string;
|
|
32
|
+
}) => Promise<AnalyticsResult & Record<string, unknown>>;
|
|
33
|
+
createPortalSession: (customerId: string, options?: {
|
|
34
|
+
returnUrl?: string;
|
|
35
|
+
redirect?: boolean;
|
|
36
|
+
}) => Promise<AnalyticsResult & {
|
|
37
|
+
url?: string;
|
|
38
|
+
}>;
|
|
39
|
+
};
|
|
40
|
+
users: {
|
|
41
|
+
trackSignup: (userId: string, email: string, role?: string | null) => Promise<AnalyticsResult>;
|
|
42
|
+
trackLogin: (userId: string) => Promise<AnalyticsResult>;
|
|
43
|
+
trackLogout: (userId: string) => Promise<AnalyticsResult>;
|
|
44
|
+
trackRoleChange: (userId: string, oldRole: string, newRole: string) => Promise<AnalyticsResult>;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
interface AuthUser {
|
|
48
|
+
id?: string;
|
|
49
|
+
email?: string;
|
|
50
|
+
user_metadata?: {
|
|
51
|
+
full_name?: string;
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
interface AuthIntegration {
|
|
55
|
+
onLogin: (user: AuthUser) => void;
|
|
56
|
+
onSignup: (user: AuthUser) => void;
|
|
57
|
+
onLogout: (userId: string) => void;
|
|
58
|
+
}
|
|
59
|
+
interface UserProfile {
|
|
60
|
+
id: string;
|
|
61
|
+
external_id?: string;
|
|
62
|
+
email?: string;
|
|
63
|
+
display_name?: string;
|
|
64
|
+
avatar_url?: string;
|
|
65
|
+
metadata?: Record<string, unknown>;
|
|
66
|
+
subscription_tier?: string;
|
|
67
|
+
subscription_status?: string;
|
|
68
|
+
stripe_customer_id?: string;
|
|
69
|
+
subscription_period_end?: string;
|
|
70
|
+
created_at?: string;
|
|
71
|
+
updated_at?: string;
|
|
72
|
+
}
|
|
73
|
+
interface StorageResult {
|
|
74
|
+
path: string;
|
|
75
|
+
url: string;
|
|
76
|
+
size: number;
|
|
77
|
+
type: string;
|
|
78
|
+
}
|
|
79
|
+
interface StorageFile {
|
|
80
|
+
name: string;
|
|
81
|
+
path: string;
|
|
82
|
+
size: number;
|
|
83
|
+
type: string;
|
|
84
|
+
created_at: string;
|
|
85
|
+
updated_at: string;
|
|
86
|
+
}
|
|
87
|
+
type SubscriptionTier = 'free' | 'starter' | 'creator' | 'pro' | 'business' | 'enterprise';
|
|
88
|
+
type SubscriptionStatus = 'active' | 'trialing' | 'past_due' | 'canceled' | 'unpaid' | 'incomplete';
|
|
89
|
+
|
|
90
|
+
export type { AuthIntegration as A, CheckoutOptions as C, EzcoderClient as E, StorageFile as S, UserProfile as U, AnalyticsResult as a, AuthUser as b, StorageResult as c, SubscriptionStatus as d, SubscriptionTier as e };
|
package/package.json
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ezcoder.dev/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "EzCoder Platform SDK — auth, payments, storage, analytics, and more with zero configuration",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./auth": {
|
|
14
|
+
"types": "./dist/auth/index.d.ts",
|
|
15
|
+
"import": "./dist/auth/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./payments": {
|
|
18
|
+
"types": "./dist/payments/index.d.ts",
|
|
19
|
+
"import": "./dist/payments/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./storage": {
|
|
22
|
+
"types": "./dist/storage/index.d.ts",
|
|
23
|
+
"import": "./dist/storage/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./analytics": {
|
|
26
|
+
"types": "./dist/analytics/index.d.ts",
|
|
27
|
+
"import": "./dist/analytics/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./roles": {
|
|
30
|
+
"types": "./dist/roles/index.d.ts",
|
|
31
|
+
"import": "./dist/roles/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./seo": {
|
|
34
|
+
"types": "./dist/seo/index.d.ts",
|
|
35
|
+
"import": "./dist/seo/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./errors": {
|
|
38
|
+
"types": "./dist/errors/index.d.ts",
|
|
39
|
+
"import": "./dist/errors/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./notifications": {
|
|
42
|
+
"types": "./dist/notifications/index.d.ts",
|
|
43
|
+
"import": "./dist/notifications/index.js"
|
|
44
|
+
},
|
|
45
|
+
"./cms": {
|
|
46
|
+
"types": "./dist/cms/index.d.ts",
|
|
47
|
+
"import": "./dist/cms/index.js"
|
|
48
|
+
},
|
|
49
|
+
"./animation": {
|
|
50
|
+
"types": "./dist/animation/index.d.ts",
|
|
51
|
+
"import": "./dist/animation/index.js"
|
|
52
|
+
},
|
|
53
|
+
"./server": {
|
|
54
|
+
"types": "./dist/server/index.d.ts",
|
|
55
|
+
"import": "./dist/server/index.js"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"typesVersions": {
|
|
59
|
+
"*": {
|
|
60
|
+
"auth": ["dist/auth/index.d.ts"],
|
|
61
|
+
"payments": ["dist/payments/index.d.ts"],
|
|
62
|
+
"storage": ["dist/storage/index.d.ts"],
|
|
63
|
+
"analytics": ["dist/analytics/index.d.ts"],
|
|
64
|
+
"roles": ["dist/roles/index.d.ts"],
|
|
65
|
+
"seo": ["dist/seo/index.d.ts"],
|
|
66
|
+
"errors": ["dist/errors/index.d.ts"],
|
|
67
|
+
"notifications": ["dist/notifications/index.d.ts"],
|
|
68
|
+
"cms": ["dist/cms/index.d.ts"],
|
|
69
|
+
"animation": ["dist/animation/index.d.ts"],
|
|
70
|
+
"server": ["dist/server/index.d.ts"]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"files": [
|
|
74
|
+
"dist"
|
|
75
|
+
],
|
|
76
|
+
"scripts": {
|
|
77
|
+
"build": "tsup",
|
|
78
|
+
"dev": "tsup --watch",
|
|
79
|
+
"typecheck": "tsc --noEmit",
|
|
80
|
+
"clean": "rm -rf dist"
|
|
81
|
+
},
|
|
82
|
+
"peerDependencies": {
|
|
83
|
+
"react": "^18.0.0",
|
|
84
|
+
"react-dom": "^18.0.0",
|
|
85
|
+
"@supabase/supabase-js": "^2.0.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependenciesMeta": {
|
|
88
|
+
"framer-motion": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"react-helmet-async": {
|
|
92
|
+
"optional": true
|
|
93
|
+
},
|
|
94
|
+
"stripe": {
|
|
95
|
+
"optional": true
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"devDependencies": {
|
|
99
|
+
"tsup": "^8.0.0",
|
|
100
|
+
"typescript": "^5.5.0",
|
|
101
|
+
"@types/react": "^18.0.0",
|
|
102
|
+
"@types/react-dom": "^18.0.0"
|
|
103
|
+
},
|
|
104
|
+
"license": "MIT"
|
|
105
|
+
}
|