@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,39 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface SEOHeadProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
keywords?: string;
|
|
7
|
+
image?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
type?: string;
|
|
10
|
+
twitterCard?: 'summary' | 'summary_large_image';
|
|
11
|
+
author?: string;
|
|
12
|
+
publishedTime?: string;
|
|
13
|
+
modifiedTime?: string;
|
|
14
|
+
noIndex?: boolean;
|
|
15
|
+
children?: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
declare function SEOHead({ title, description, keywords, image, url, type, twitterCard, author, publishedTime, modifiedTime, noIndex, children, }: SEOHeadProps): react_jsx_runtime.JSX.Element | null;
|
|
18
|
+
interface JsonLdProps {
|
|
19
|
+
data: Record<string, unknown>;
|
|
20
|
+
}
|
|
21
|
+
declare function JsonLd({ data }: JsonLdProps): react_jsx_runtime.JSX.Element;
|
|
22
|
+
interface OrganizationJsonLdProps {
|
|
23
|
+
name: string;
|
|
24
|
+
url: string;
|
|
25
|
+
logo?: string;
|
|
26
|
+
sameAs?: string[];
|
|
27
|
+
}
|
|
28
|
+
declare function OrganizationJsonLd({ name, url, logo, sameAs }: OrganizationJsonLdProps): react_jsx_runtime.JSX.Element;
|
|
29
|
+
interface ArticleJsonLdProps {
|
|
30
|
+
title: string;
|
|
31
|
+
description: string;
|
|
32
|
+
url: string;
|
|
33
|
+
image?: string;
|
|
34
|
+
datePublished?: string;
|
|
35
|
+
authorName?: string;
|
|
36
|
+
}
|
|
37
|
+
declare function ArticleJsonLd({ title, description, url, image, datePublished, authorName }: ArticleJsonLdProps): react_jsx_runtime.JSX.Element;
|
|
38
|
+
|
|
39
|
+
export { ArticleJsonLd, JsonLd, OrganizationJsonLd, SEOHead };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/seo/SEOHead.tsx
|
|
2
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
function SEOHead({
|
|
4
|
+
title,
|
|
5
|
+
description,
|
|
6
|
+
keywords,
|
|
7
|
+
image,
|
|
8
|
+
url,
|
|
9
|
+
type = "website",
|
|
10
|
+
twitterCard = "summary_large_image",
|
|
11
|
+
author,
|
|
12
|
+
publishedTime,
|
|
13
|
+
modifiedTime,
|
|
14
|
+
noIndex = false,
|
|
15
|
+
children
|
|
16
|
+
}) {
|
|
17
|
+
if (typeof document === "undefined") return null;
|
|
18
|
+
const setMeta = (name, content, property = false) => {
|
|
19
|
+
const attr = property ? "property" : "name";
|
|
20
|
+
let el = document.querySelector(`meta[${attr}="${name}"]`);
|
|
21
|
+
if (!el) {
|
|
22
|
+
el = document.createElement("meta");
|
|
23
|
+
el.setAttribute(attr, name);
|
|
24
|
+
document.head.appendChild(el);
|
|
25
|
+
}
|
|
26
|
+
el.content = content;
|
|
27
|
+
};
|
|
28
|
+
if (title) {
|
|
29
|
+
document.title = title;
|
|
30
|
+
setMeta("og:title", title, true);
|
|
31
|
+
setMeta("twitter:title", title);
|
|
32
|
+
}
|
|
33
|
+
if (description) {
|
|
34
|
+
setMeta("description", description);
|
|
35
|
+
setMeta("og:description", description, true);
|
|
36
|
+
setMeta("twitter:description", description);
|
|
37
|
+
}
|
|
38
|
+
if (keywords) setMeta("keywords", keywords);
|
|
39
|
+
if (image) {
|
|
40
|
+
setMeta("og:image", image, true);
|
|
41
|
+
setMeta("twitter:image", image);
|
|
42
|
+
}
|
|
43
|
+
if (url) setMeta("og:url", url, true);
|
|
44
|
+
setMeta("og:type", type, true);
|
|
45
|
+
setMeta("twitter:card", twitterCard);
|
|
46
|
+
if (author) setMeta("author", author);
|
|
47
|
+
if (publishedTime) setMeta("article:published_time", publishedTime, true);
|
|
48
|
+
if (modifiedTime) setMeta("article:modified_time", modifiedTime, true);
|
|
49
|
+
if (noIndex) setMeta("robots", "noindex, nofollow");
|
|
50
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
51
|
+
}
|
|
52
|
+
function JsonLd({ data }) {
|
|
53
|
+
return /* @__PURE__ */ jsx(
|
|
54
|
+
"script",
|
|
55
|
+
{
|
|
56
|
+
type: "application/ld+json",
|
|
57
|
+
dangerouslySetInnerHTML: { __html: JSON.stringify(data) }
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
function OrganizationJsonLd({ name, url, logo, sameAs }) {
|
|
62
|
+
return /* @__PURE__ */ jsx(JsonLd, { data: {
|
|
63
|
+
"@context": "https://schema.org",
|
|
64
|
+
"@type": "Organization",
|
|
65
|
+
name,
|
|
66
|
+
url,
|
|
67
|
+
logo,
|
|
68
|
+
sameAs
|
|
69
|
+
} });
|
|
70
|
+
}
|
|
71
|
+
function ArticleJsonLd({ title, description, url, image, datePublished, authorName }) {
|
|
72
|
+
return /* @__PURE__ */ jsx(JsonLd, { data: {
|
|
73
|
+
"@context": "https://schema.org",
|
|
74
|
+
"@type": "Article",
|
|
75
|
+
headline: title,
|
|
76
|
+
description,
|
|
77
|
+
url,
|
|
78
|
+
image,
|
|
79
|
+
datePublished,
|
|
80
|
+
author: authorName ? { "@type": "Person", name: authorName } : void 0
|
|
81
|
+
} });
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
ArticleJsonLd,
|
|
85
|
+
JsonLd,
|
|
86
|
+
OrganizationJsonLd,
|
|
87
|
+
SEOHead
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":[]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
|
+
|
|
3
|
+
interface ServerSupabaseOptions {
|
|
4
|
+
supabaseUrl?: string;
|
|
5
|
+
supabaseServiceKey?: string;
|
|
6
|
+
}
|
|
7
|
+
declare function createServerSupabase(options?: ServerSupabaseOptions): SupabaseClient;
|
|
8
|
+
|
|
9
|
+
interface WebhookRequest {
|
|
10
|
+
headers: Record<string, string | string[] | undefined> | {
|
|
11
|
+
get(name: string): string | null;
|
|
12
|
+
};
|
|
13
|
+
body?: unknown;
|
|
14
|
+
rawBody?: Buffer | string;
|
|
15
|
+
text?: () => Promise<string>;
|
|
16
|
+
}
|
|
17
|
+
interface StripeEvent {
|
|
18
|
+
id: string;
|
|
19
|
+
type: string;
|
|
20
|
+
data: {
|
|
21
|
+
object: Record<string, unknown>;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
interface HandleOptions {
|
|
25
|
+
supabaseServiceKey?: string;
|
|
26
|
+
supabaseUrl?: string;
|
|
27
|
+
}
|
|
28
|
+
declare function verifyStripeWebhook(req: WebhookRequest, webhookSecret?: string): Promise<StripeEvent>;
|
|
29
|
+
declare function handleSubscriptionEvent(event: StripeEvent, options?: HandleOptions): Promise<void>;
|
|
30
|
+
|
|
31
|
+
interface UploadRequest {
|
|
32
|
+
body?: unknown;
|
|
33
|
+
file?: {
|
|
34
|
+
buffer: Buffer;
|
|
35
|
+
originalname: string;
|
|
36
|
+
mimetype: string;
|
|
37
|
+
size: number;
|
|
38
|
+
};
|
|
39
|
+
formData?: () => Promise<FormData>;
|
|
40
|
+
}
|
|
41
|
+
interface HandleUploadOptions {
|
|
42
|
+
supabaseServiceKey?: string;
|
|
43
|
+
supabaseUrl?: string;
|
|
44
|
+
maxSizeMB?: number;
|
|
45
|
+
bucket?: string;
|
|
46
|
+
allowedTypes?: string[];
|
|
47
|
+
}
|
|
48
|
+
interface UploadResult {
|
|
49
|
+
success: boolean;
|
|
50
|
+
path?: string;
|
|
51
|
+
url?: string;
|
|
52
|
+
error?: string;
|
|
53
|
+
}
|
|
54
|
+
declare function handleUpload(req: UploadRequest, options?: HandleUploadOptions): Promise<UploadResult>;
|
|
55
|
+
|
|
56
|
+
interface AuthRequest {
|
|
57
|
+
headers: Record<string, string | string[] | undefined> | {
|
|
58
|
+
get(name: string): string | null;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
interface AuthUser {
|
|
62
|
+
id: string;
|
|
63
|
+
email?: string;
|
|
64
|
+
role?: string;
|
|
65
|
+
}
|
|
66
|
+
interface RequireAuthOptions {
|
|
67
|
+
supabaseUrl?: string;
|
|
68
|
+
supabaseServiceKey?: string;
|
|
69
|
+
}
|
|
70
|
+
declare function requireAuth(req: AuthRequest, options?: RequireAuthOptions): Promise<AuthUser>;
|
|
71
|
+
|
|
72
|
+
export { createServerSupabase, handleSubscriptionEvent, handleUpload, requireAuth, verifyStripeWebhook };
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// src/server/supabase.ts
|
|
2
|
+
import { createClient } from "@supabase/supabase-js";
|
|
3
|
+
function createServerSupabase(options = {}) {
|
|
4
|
+
const url = options.supabaseUrl || process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || "";
|
|
5
|
+
const key = options.supabaseServiceKey || process.env.SUPABASE_SERVICE_ROLE_KEY || "";
|
|
6
|
+
if (!url || !key) {
|
|
7
|
+
throw new Error("Server Supabase requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY");
|
|
8
|
+
}
|
|
9
|
+
return createClient(url, key, {
|
|
10
|
+
auth: {
|
|
11
|
+
autoRefreshToken: false,
|
|
12
|
+
persistSession: false
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// src/server/stripe.ts
|
|
18
|
+
async function verifyStripeWebhook(req, webhookSecret) {
|
|
19
|
+
const secret = webhookSecret || process.env.STRIPE_WEBHOOK_SECRET;
|
|
20
|
+
if (!secret) {
|
|
21
|
+
throw new Error("STRIPE_WEBHOOK_SECRET is required");
|
|
22
|
+
}
|
|
23
|
+
let rawBody;
|
|
24
|
+
if (typeof req.rawBody === "string") {
|
|
25
|
+
rawBody = req.rawBody;
|
|
26
|
+
} else if (req.rawBody instanceof Buffer) {
|
|
27
|
+
rawBody = req.rawBody.toString("utf-8");
|
|
28
|
+
} else if (typeof req.text === "function") {
|
|
29
|
+
rawBody = await req.text();
|
|
30
|
+
} else if (typeof req.body === "string") {
|
|
31
|
+
rawBody = req.body;
|
|
32
|
+
} else {
|
|
33
|
+
rawBody = JSON.stringify(req.body);
|
|
34
|
+
}
|
|
35
|
+
const stripe = await import("stripe");
|
|
36
|
+
const Stripe = stripe.default || stripe;
|
|
37
|
+
const stripeClient = new Stripe(
|
|
38
|
+
process.env.STRIPE_SECRET_KEY || ""
|
|
39
|
+
);
|
|
40
|
+
const sig = typeof req.headers === "object" && "get" in req.headers ? req.headers.get("stripe-signature") || "" : req.headers["stripe-signature"] || "";
|
|
41
|
+
return stripeClient.webhooks.constructEvent(rawBody, sig, secret);
|
|
42
|
+
}
|
|
43
|
+
async function handleSubscriptionEvent(event, options = {}) {
|
|
44
|
+
const supabase = createServerSupabase(options);
|
|
45
|
+
const obj = event.data.object;
|
|
46
|
+
switch (event.type) {
|
|
47
|
+
case "checkout.session.completed": {
|
|
48
|
+
const customerId = obj.customer;
|
|
49
|
+
const subscriptionId = obj.subscription;
|
|
50
|
+
const customerEmail = obj.customer_email;
|
|
51
|
+
if (customerEmail) {
|
|
52
|
+
await supabase.from("user_profiles").update({
|
|
53
|
+
stripe_customer_id: customerId,
|
|
54
|
+
subscription_status: "active"
|
|
55
|
+
}).eq("email", customerEmail);
|
|
56
|
+
}
|
|
57
|
+
void subscriptionId;
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "customer.subscription.created":
|
|
61
|
+
case "customer.subscription.updated": {
|
|
62
|
+
const customerId = obj.customer;
|
|
63
|
+
const status = obj.status;
|
|
64
|
+
const priceId = obj.items?.data?.[0]?.price;
|
|
65
|
+
const currentPeriodEnd = obj.current_period_end;
|
|
66
|
+
const tier = mapPriceToTier(priceId?.id);
|
|
67
|
+
await supabase.from("user_profiles").update({
|
|
68
|
+
subscription_tier: tier,
|
|
69
|
+
subscription_status: status,
|
|
70
|
+
subscription_period_end: currentPeriodEnd ? new Date(currentPeriodEnd * 1e3).toISOString() : null
|
|
71
|
+
}).eq("stripe_customer_id", customerId);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "customer.subscription.deleted": {
|
|
75
|
+
const customerId = obj.customer;
|
|
76
|
+
await supabase.from("user_profiles").update({
|
|
77
|
+
subscription_tier: "free",
|
|
78
|
+
subscription_status: "canceled"
|
|
79
|
+
}).eq("stripe_customer_id", customerId);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case "invoice.payment_succeeded": {
|
|
83
|
+
const customerId = obj.customer;
|
|
84
|
+
const subscriptionId = obj.subscription;
|
|
85
|
+
if (subscriptionId) {
|
|
86
|
+
await supabase.from("user_profiles").update({
|
|
87
|
+
subscription_status: "active",
|
|
88
|
+
last_payment_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
89
|
+
}).eq("stripe_customer_id", customerId);
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
case "invoice.payment_failed": {
|
|
94
|
+
const customerId = obj.customer;
|
|
95
|
+
await supabase.from("user_profiles").update({ subscription_status: "past_due" }).eq("stripe_customer_id", customerId);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function mapPriceToTier(priceId) {
|
|
101
|
+
if (!priceId) return "free";
|
|
102
|
+
const mapping = {};
|
|
103
|
+
const envPrefixes = ["STRIPE_CREATOR", "STRIPE_PRO", "STRIPE_BUSINESS", "STRIPE_ENTERPRISE"];
|
|
104
|
+
const tierNames = ["creator", "pro", "business", "enterprise"];
|
|
105
|
+
envPrefixes.forEach((prefix, i) => {
|
|
106
|
+
const monthly = process.env[`${prefix}_MONTHLY_PRICE_ID`];
|
|
107
|
+
const yearly = process.env[`${prefix}_YEARLY_PRICE_ID`];
|
|
108
|
+
if (monthly) mapping[monthly] = tierNames[i];
|
|
109
|
+
if (yearly) mapping[yearly] = tierNames[i];
|
|
110
|
+
});
|
|
111
|
+
return mapping[priceId] || "creator";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/server/storage.ts
|
|
115
|
+
async function handleUpload(req, options = {}) {
|
|
116
|
+
const supabase = createServerSupabase(options);
|
|
117
|
+
const bucket = options.bucket || "uploads";
|
|
118
|
+
const maxSize = (options.maxSizeMB || 10) * 1024 * 1024;
|
|
119
|
+
try {
|
|
120
|
+
let fileBuffer;
|
|
121
|
+
let fileName;
|
|
122
|
+
let mimeType;
|
|
123
|
+
let fileSize;
|
|
124
|
+
if (req.file) {
|
|
125
|
+
fileBuffer = req.file.buffer;
|
|
126
|
+
fileName = req.file.originalname;
|
|
127
|
+
mimeType = req.file.mimetype;
|
|
128
|
+
fileSize = req.file.size;
|
|
129
|
+
} else if (typeof req.formData === "function") {
|
|
130
|
+
const formData = await req.formData();
|
|
131
|
+
const file = formData.get("file");
|
|
132
|
+
if (!file) return { success: false, error: "No file provided" };
|
|
133
|
+
fileBuffer = Buffer.from(await file.arrayBuffer());
|
|
134
|
+
fileName = file.name;
|
|
135
|
+
mimeType = file.type;
|
|
136
|
+
fileSize = file.size;
|
|
137
|
+
} else {
|
|
138
|
+
return { success: false, error: "No file in request" };
|
|
139
|
+
}
|
|
140
|
+
if (fileSize > maxSize) {
|
|
141
|
+
return { success: false, error: `File exceeds ${options.maxSizeMB || 10}MB limit` };
|
|
142
|
+
}
|
|
143
|
+
if (options.allowedTypes?.length && !options.allowedTypes.includes(mimeType)) {
|
|
144
|
+
return { success: false, error: `File type ${mimeType} not allowed` };
|
|
145
|
+
}
|
|
146
|
+
const path = `uploads/${Date.now()}_${fileName}`;
|
|
147
|
+
const { error } = await supabase.storage.from(bucket).upload(path, fileBuffer, {
|
|
148
|
+
contentType: mimeType,
|
|
149
|
+
cacheControl: "3600"
|
|
150
|
+
});
|
|
151
|
+
if (error) return { success: false, error: error.message };
|
|
152
|
+
const { data: signedData } = await supabase.storage.from(bucket).createSignedUrl(path, 3600);
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
path,
|
|
156
|
+
url: signedData?.signedUrl
|
|
157
|
+
};
|
|
158
|
+
} catch (err) {
|
|
159
|
+
return {
|
|
160
|
+
success: false,
|
|
161
|
+
error: err instanceof Error ? err.message : "Upload failed"
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// src/server/middleware.ts
|
|
167
|
+
async function requireAuth(req, options = {}) {
|
|
168
|
+
const authHeader = typeof req.headers === "object" && "get" in req.headers ? req.headers.get("authorization") : req.headers["authorization"];
|
|
169
|
+
if (!authHeader?.startsWith("Bearer ")) {
|
|
170
|
+
throw new Error("Missing or invalid Authorization header");
|
|
171
|
+
}
|
|
172
|
+
const token = authHeader.slice(7);
|
|
173
|
+
const supabase = createServerSupabase(options);
|
|
174
|
+
const { data: { user }, error } = await supabase.auth.getUser(token);
|
|
175
|
+
if (error || !user) {
|
|
176
|
+
throw new Error("Invalid or expired token");
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
id: user.id,
|
|
180
|
+
email: user.email,
|
|
181
|
+
role: user.role
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
export {
|
|
185
|
+
createServerSupabase,
|
|
186
|
+
handleSubscriptionEvent,
|
|
187
|
+
handleUpload,
|
|
188
|
+
requireAuth,
|
|
189
|
+
verifyStripeWebhook
|
|
190
|
+
};
|
|
191
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { c as StorageResult, S as StorageFile } from '../types-DtY5lp3P.js';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
|
|
4
|
+
type StorageProvider = 'supabase' | 'stub';
|
|
5
|
+
interface UploadOptions {
|
|
6
|
+
path?: string;
|
|
7
|
+
public?: boolean;
|
|
8
|
+
bucket?: string;
|
|
9
|
+
}
|
|
10
|
+
interface UrlOptions {
|
|
11
|
+
signed?: boolean;
|
|
12
|
+
expiresIn?: number;
|
|
13
|
+
}
|
|
14
|
+
interface UseStorageReturn {
|
|
15
|
+
upload: (file: File, options?: UploadOptions) => Promise<StorageResult>;
|
|
16
|
+
download: (path: string, bucket?: string) => Promise<Blob>;
|
|
17
|
+
getUrl: (path: string, options?: UrlOptions & {
|
|
18
|
+
bucket?: string;
|
|
19
|
+
}) => Promise<string>;
|
|
20
|
+
list: (prefix?: string, bucket?: string) => Promise<StorageFile[]>;
|
|
21
|
+
remove: (path: string, bucket?: string) => Promise<void>;
|
|
22
|
+
isConfigured: boolean;
|
|
23
|
+
provider: StorageProvider;
|
|
24
|
+
retentionDays: number;
|
|
25
|
+
}
|
|
26
|
+
declare function useStorage(): UseStorageReturn;
|
|
27
|
+
|
|
28
|
+
interface FileUploadProps {
|
|
29
|
+
onUpload?: (result: StorageResult) => void;
|
|
30
|
+
onError?: (error: Error) => void;
|
|
31
|
+
accept?: string;
|
|
32
|
+
maxSize?: number;
|
|
33
|
+
multiple?: boolean;
|
|
34
|
+
children?: React.ReactNode;
|
|
35
|
+
className?: string;
|
|
36
|
+
bucket?: string;
|
|
37
|
+
public?: boolean;
|
|
38
|
+
}
|
|
39
|
+
declare function FileUpload({ onUpload, onError, accept, maxSize, multiple, children, className, bucket, public: isPublic, }: FileUploadProps): react_jsx_runtime.JSX.Element;
|
|
40
|
+
|
|
41
|
+
interface ImagePreviewProps {
|
|
42
|
+
path: string;
|
|
43
|
+
alt?: string;
|
|
44
|
+
className?: string;
|
|
45
|
+
width?: number | string;
|
|
46
|
+
height?: number | string;
|
|
47
|
+
bucket?: string;
|
|
48
|
+
signed?: boolean;
|
|
49
|
+
}
|
|
50
|
+
declare function ImagePreview({ path, alt, className, width, height, bucket, signed }: ImagePreviewProps): react_jsx_runtime.JSX.Element;
|
|
51
|
+
|
|
52
|
+
export { FileUpload, ImagePreview, useStorage };
|