From 931b4e144a807cb00cff781c077945d3facd895a Mon Sep 17 00:00:00 2001 From: Karrix Date: Sun, 14 Jan 2024 20:11:32 +0800 Subject: [PATCH 01/11] feat: pricing plan & gpu ui --- .../pricing/components/gpuPricingTable.tsx | 81 ++++++++ .../pricing/components/pricingPlanTable.tsx | 191 ++++++++++++++++++ web/src/app/(app)/pricing/loading.tsx | 9 + web/src/app/(app)/pricing/page.tsx | 13 ++ 4 files changed, 294 insertions(+) create mode 100644 web/src/app/(app)/pricing/components/gpuPricingTable.tsx create mode 100644 web/src/app/(app)/pricing/components/pricingPlanTable.tsx create mode 100644 web/src/app/(app)/pricing/loading.tsx create mode 100644 web/src/app/(app)/pricing/page.tsx diff --git a/web/src/app/(app)/pricing/components/gpuPricingTable.tsx b/web/src/app/(app)/pricing/components/gpuPricingTable.tsx new file mode 100644 index 0000000..a4c4c63 --- /dev/null +++ b/web/src/app/(app)/pricing/components/gpuPricingTable.tsx @@ -0,0 +1,81 @@ +const people = [ + { + name: "Nvidia T4 GPU", + gpu: "1x", + ram: "16GB", + price: "$0.000225/sec", + }, + { + name: "Nvidia A40 GPU", + gpu: "1x", + ram: "48GB", + price: "$0.000575/sec", + }, +]; + +export function GpuPricingPlan() { + return ( +
+
+ + + + + + + + + + + {people.map((person) => ( + + + + + + + ))} + +
+ GPU + + No. + + RAM + + Price +
+ {person.name} +
+
No.
+
+ {person.gpu} +
+
RAM
+
+ {person.ram} +
+
+
+ {person.gpu} + + {person.ram} + + {person.price} +
+
+
+ ); +} diff --git a/web/src/app/(app)/pricing/components/pricingPlanTable.tsx b/web/src/app/(app)/pricing/components/pricingPlanTable.tsx new file mode 100644 index 0000000..ca49212 --- /dev/null +++ b/web/src/app/(app)/pricing/components/pricingPlanTable.tsx @@ -0,0 +1,191 @@ +import { cn } from "@/lib/utils"; +import { RadioGroup } from "@headlessui/react"; +import { useState } from "react"; + +// Define a type for the frequency options +type FrequencyOption = { + value: keyof TierPrice; // Use 'keyof TierPrice' instead of string + label: string; + priceSuffix: string; +}; + +// Define a type for the tier prices +type TierPrice = { + monthly: string; + annually: string; +}; + +// Define a type for the tier options +type TierOption = { + name: string; + id: string; + href: string; + price: TierPrice; + description: string; + features: string[]; + mostPopular: boolean; +}; + +// Define an interface for the pricing structure +interface Pricing { + frequencies: FrequencyOption[]; + tiers: TierOption[]; +} + +const checkMarkIcon = ( + +); + +const pricing: Pricing = { + frequencies: [ + { value: "monthly", label: "Monthly", priceSuffix: "/month" }, + { value: "annually", label: "Annually", priceSuffix: "/year" }, + ], + tiers: [ + { + name: "Hobby", + id: "tier-hobby", + href: "#", + price: { monthly: "$15", annually: "$144" }, + description: "The essentials to provide your best work for clients.", + features: ["5 products", "Up to 1,000 subscribers", "Basic analytics"], + mostPopular: false, + }, + { + name: "Startup", + id: "tier-startup", + href: "#", + price: { monthly: "$60", annually: "$576" }, + description: "A plan that scales with your rapidly growing business.", + features: [ + "25 products", + "Up to 10,000 subscribers", + "Advanced analytics", + "24-hour support response time", + "Marketing automations", + ], + mostPopular: true, + }, + ], +}; + +export function PricingPlan() { + const [frequency, setFrequency] = useState( + pricing.frequencies[0] + ); + + return ( +
+
+
+

+ Pricing +

+

+ Pricing plans for teams of all sizes +

+
+

+ Choose an affordable plan that’s packed with the best features for + engaging your audience, creating customer loyalty, and driving sales. +

+
+ + + Payment frequency + + {pricing.frequencies.map((option) => ( + { + return cn( + checked ? "bg-indigo-600 text-white" : "text-gray-500", + "cursor-pointer rounded-full px-2.5 py-1" + ); + }} + > + {option.label} + + ))} + +
+
+ {pricing.tiers.map((tier) => ( +
+

+ {tier.name} +

+

+ {tier.description} +

+

+ + {tier.price[frequency.value]} + + + {frequency.priceSuffix} + +

+ + Buy plan + +
    + {tier.features.map((feature) => ( +
  • +
    + {checkMarkIcon} +
    + {feature} +
  • + ))} +
+
+ ))} +
+
+
+ ); +} diff --git a/web/src/app/(app)/pricing/loading.tsx b/web/src/app/(app)/pricing/loading.tsx new file mode 100644 index 0000000..9ff4783 --- /dev/null +++ b/web/src/app/(app)/pricing/loading.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { LoadingPageWrapper } from "@/components/LoadingWrapper"; +import { usePathname } from "next/navigation"; + +export default function Loading() { + const pathName = usePathname(); + return ; +} diff --git a/web/src/app/(app)/pricing/page.tsx b/web/src/app/(app)/pricing/page.tsx new file mode 100644 index 0000000..3d237bd --- /dev/null +++ b/web/src/app/(app)/pricing/page.tsx @@ -0,0 +1,13 @@ +"use client"; + +import { GpuPricingPlan } from "@/app/(app)/pricing/components/gpuPricingTable"; +import { PricingPlan } from "@/app/(app)/pricing/components/pricingPlanTable"; + +export default function Home() { + return ( +
+ + +
+ ); +} From 9cbf0760a02c3054428cdb176ace9f4a547e7d89 Mon Sep 17 00:00:00 2001 From: Karrix Date: Tue, 16 Jan 2024 02:38:44 +0800 Subject: [PATCH 02/11] feat: implement lemonsqueezy to pricing table --- web/package.json | 1 + .../pricing/components/pricePlanList.tsx | 133 ++++++++++++ .../pricing/components/pricingPlanTable.tsx | 191 ------------------ web/src/app/(app)/pricing/const/Icon.tsx | 15 ++ web/src/app/(app)/pricing/page.tsx | 4 +- web/src/server/linkToPricing.ts | 12 ++ 6 files changed, 163 insertions(+), 193 deletions(-) create mode 100644 web/src/app/(app)/pricing/components/pricePlanList.tsx delete mode 100644 web/src/app/(app)/pricing/components/pricingPlanTable.tsx create mode 100644 web/src/app/(app)/pricing/const/Icon.tsx create mode 100644 web/src/server/linkToPricing.ts diff --git a/web/package.json b/web/package.json index 588cbb8..1df4f33 100644 --- a/web/package.json +++ b/web/package.json @@ -26,6 +26,7 @@ "@hono/zod-openapi": "^0.9.5", "@hono/zod-validator": "^0.1.11", "@hookform/resolvers": "^3.3.2", + "@lemonsqueezy/lemonsqueezy.js": "^1.2.5", "@mdx-js/loader": "^3.0.0", "@mdx-js/react": "^3.0.0", "@neondatabase/serverless": "^0.6.0", diff --git a/web/src/app/(app)/pricing/components/pricePlanList.tsx b/web/src/app/(app)/pricing/components/pricePlanList.tsx new file mode 100644 index 0000000..19d30c9 --- /dev/null +++ b/web/src/app/(app)/pricing/components/pricePlanList.tsx @@ -0,0 +1,133 @@ +import { checkMarkIcon } from "../const/Icon"; +import { cn } from "@/lib/utils"; +import { getPricing } from "@/server/linkToPricing"; +import { useEffect, useState } from "react"; + +type Tier = { + name: string; + id: string; + href: string; + priceMonthly: string; + description: string; + features: string[]; + featured: boolean; +}; + +export default function PricingList() { + const [productTiers, setProductTiers] = useState(); + + useEffect(() => { + (async () => { + const product = await getPricing(); + + if (!product) return; + + const newProductTiers: Tier[] = product.data.map((item) => { + // Create a new DOMParser instance + const parser = new DOMParser(); + // Parse the description HTML string to a new document + const doc = parser.parseFromString( + item.attributes.description, + "text/html" + ); + // Extract the description and features + const description = doc.querySelector("p")?.textContent || ""; + const features = Array.from(doc.querySelectorAll("ul > li")).map( + (li) => li.textContent || "" + ); + + return { + name: item.attributes.name, + id: item.id, + href: item.attributes.buy_now_url, + priceMonthly: item.attributes.price_formatted.split("/")[0], + description: description, + features: features, + + // if name contains pro, it's featured + featured: item.attributes.name.toLowerCase().includes("pro"), + }; + }); + + console.log(newProductTiers); + setProductTiers(newProductTiers); + })(); + }, []); + + return ( +
+
+

+ Pricing +

+

+ The right price for you, whoever you are +

+
+

+ Qui iusto aut est earum eos quae. Eligendi est at nam aliquid ad quo + reprehenderit in aliquid fugiat dolorum voluptatibus. +

+
+ {productTiers && + productTiers.map((tier, tierIdx) => ( +
+

+ {tier.name} +

+

+ + {tier.priceMonthly} + + /month +

+

+ {tier.description} +

+
    + {tier.features.map((feature) => ( +
  • +
    + {checkMarkIcon} +
    + {feature} +
  • + ))} +
+ + Get started today + +
+ ))} +
+
+ ); +} diff --git a/web/src/app/(app)/pricing/components/pricingPlanTable.tsx b/web/src/app/(app)/pricing/components/pricingPlanTable.tsx deleted file mode 100644 index ca49212..0000000 --- a/web/src/app/(app)/pricing/components/pricingPlanTable.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import { cn } from "@/lib/utils"; -import { RadioGroup } from "@headlessui/react"; -import { useState } from "react"; - -// Define a type for the frequency options -type FrequencyOption = { - value: keyof TierPrice; // Use 'keyof TierPrice' instead of string - label: string; - priceSuffix: string; -}; - -// Define a type for the tier prices -type TierPrice = { - monthly: string; - annually: string; -}; - -// Define a type for the tier options -type TierOption = { - name: string; - id: string; - href: string; - price: TierPrice; - description: string; - features: string[]; - mostPopular: boolean; -}; - -// Define an interface for the pricing structure -interface Pricing { - frequencies: FrequencyOption[]; - tiers: TierOption[]; -} - -const checkMarkIcon = ( - -); - -const pricing: Pricing = { - frequencies: [ - { value: "monthly", label: "Monthly", priceSuffix: "/month" }, - { value: "annually", label: "Annually", priceSuffix: "/year" }, - ], - tiers: [ - { - name: "Hobby", - id: "tier-hobby", - href: "#", - price: { monthly: "$15", annually: "$144" }, - description: "The essentials to provide your best work for clients.", - features: ["5 products", "Up to 1,000 subscribers", "Basic analytics"], - mostPopular: false, - }, - { - name: "Startup", - id: "tier-startup", - href: "#", - price: { monthly: "$60", annually: "$576" }, - description: "A plan that scales with your rapidly growing business.", - features: [ - "25 products", - "Up to 10,000 subscribers", - "Advanced analytics", - "24-hour support response time", - "Marketing automations", - ], - mostPopular: true, - }, - ], -}; - -export function PricingPlan() { - const [frequency, setFrequency] = useState( - pricing.frequencies[0] - ); - - return ( -
-
-
-

- Pricing -

-

- Pricing plans for teams of all sizes -

-
-

- Choose an affordable plan that’s packed with the best features for - engaging your audience, creating customer loyalty, and driving sales. -

-
- - - Payment frequency - - {pricing.frequencies.map((option) => ( - { - return cn( - checked ? "bg-indigo-600 text-white" : "text-gray-500", - "cursor-pointer rounded-full px-2.5 py-1" - ); - }} - > - {option.label} - - ))} - -
-
- {pricing.tiers.map((tier) => ( -
-

- {tier.name} -

-

- {tier.description} -

-

- - {tier.price[frequency.value]} - - - {frequency.priceSuffix} - -

- - Buy plan - -
    - {tier.features.map((feature) => ( -
  • -
    - {checkMarkIcon} -
    - {feature} -
  • - ))} -
-
- ))} -
-
-
- ); -} diff --git a/web/src/app/(app)/pricing/const/Icon.tsx b/web/src/app/(app)/pricing/const/Icon.tsx new file mode 100644 index 0000000..2142282 --- /dev/null +++ b/web/src/app/(app)/pricing/const/Icon.tsx @@ -0,0 +1,15 @@ +export const checkMarkIcon = ( + +); diff --git a/web/src/app/(app)/pricing/page.tsx b/web/src/app/(app)/pricing/page.tsx index 3d237bd..fd94f22 100644 --- a/web/src/app/(app)/pricing/page.tsx +++ b/web/src/app/(app)/pricing/page.tsx @@ -1,12 +1,12 @@ "use client"; import { GpuPricingPlan } from "@/app/(app)/pricing/components/gpuPricingTable"; -import { PricingPlan } from "@/app/(app)/pricing/components/pricingPlanTable"; +import PricingList from "@/app/(app)/pricing/components/pricePlanList"; export default function Home() { return (
- +
); diff --git a/web/src/server/linkToPricing.ts b/web/src/server/linkToPricing.ts new file mode 100644 index 0000000..bc4d5c3 --- /dev/null +++ b/web/src/server/linkToPricing.ts @@ -0,0 +1,12 @@ +"use server"; + +import { LemonSqueezy } from "@lemonsqueezy/lemonsqueezy.js"; +import "server-only"; + +const ls = new LemonSqueezy(process.env.LEMONSQUEEZY_API_KEY || ""); + +export async function getPricing() { + const products = await ls.getProducts(); + + return products; +} From 8a134ed39e21c6a9997fc7792e3de3563b2d2d1c Mon Sep 17 00:00:00 2001 From: Karrix Date: Tue, 16 Jan 2024 02:39:09 +0800 Subject: [PATCH 03/11] fix: gpu table width too large --- web/src/app/(app)/pricing/components/gpuPricingTable.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/src/app/(app)/pricing/components/gpuPricingTable.tsx b/web/src/app/(app)/pricing/components/gpuPricingTable.tsx index a4c4c63..912f099 100644 --- a/web/src/app/(app)/pricing/components/gpuPricingTable.tsx +++ b/web/src/app/(app)/pricing/components/gpuPricingTable.tsx @@ -15,8 +15,8 @@ const people = [ export function GpuPricingPlan() { return ( -
-
+
+
From ac8f6e2808aae0fe2cb5e94c59a84e4751f16ded Mon Sep 17 00:00:00 2001 From: Karrix Date: Sun, 21 Jan 2024 15:35:14 +0800 Subject: [PATCH 04/11] update: pricing plan with usage base --- .../pricing/components/pricePlanList.tsx | 82 +++++++++++++++++-- web/src/app/(app)/pricing/const/Icon.tsx | 22 +++++ web/src/components/Navbar.tsx | 7 ++ web/src/db/schema.ts | 15 ++++ web/src/server/linkToPricing.ts | 33 ++++++++ 5 files changed, 152 insertions(+), 7 deletions(-) diff --git a/web/src/app/(app)/pricing/components/pricePlanList.tsx b/web/src/app/(app)/pricing/components/pricePlanList.tsx index 19d30c9..d097741 100644 --- a/web/src/app/(app)/pricing/components/pricePlanList.tsx +++ b/web/src/app/(app)/pricing/components/pricePlanList.tsx @@ -1,6 +1,11 @@ -import { checkMarkIcon } from "../const/Icon"; +import { checkMarkIcon, crossMarkIcon } from "../const/Icon"; import { cn } from "@/lib/utils"; -import { getPricing } from "@/server/linkToPricing"; +import { + getPricing, + getSubscriptionItem, + getUsage, + setUsage, +} from "@/server/linkToPricing"; import { useEffect, useState } from "react"; type Tier = { @@ -11,10 +16,18 @@ type Tier = { description: string; features: string[]; featured: boolean; + priority?: TierPriority; }; +enum TierPriority { + Free = "free", + Pro = "pro", + Enterprise = "enterprise", +} + export default function PricingList() { const [productTiers, setProductTiers] = useState(); + const [userUsageId, setUserUsageId] = useState(0); useEffect(() => { (async () => { @@ -40,26 +53,81 @@ export default function PricingList() { name: item.attributes.name, id: item.id, href: item.attributes.buy_now_url, - priceMonthly: item.attributes.price_formatted.split("/")[0], + priceMonthly: + item.attributes.price_formatted.split("/")[0] == "Usage-based" + ? "$20.00" + : item.attributes.price_formatted.split("/")[0], description: description, features: features, // if name contains pro, it's featured featured: item.attributes.name.toLowerCase().includes("pro"), + + // give priority if name contain in enum + priority: Object.values(TierPriority).find((priority) => + item.attributes.name.toLowerCase().includes(priority) + ), }; }); - console.log(newProductTiers); + // sort newProductTiers by priority + newProductTiers.sort((a, b) => { + if (!a.priority) return 1; + if (!b.priority) return -1; + return ( + Object.values(TierPriority).indexOf(a.priority) - + Object.values(TierPriority).indexOf(b.priority) + ); + }); + setProductTiers(newProductTiers); })(); }, []); + useEffect(() => { + (async () => { + // const currentUser = await getUserData(); + + const userUsage = await getUsage(); + const userSubscription = await getSubscriptionItem(); + + // const setUserUsage = await setUsage(236561, 10); + + // console.log(currentUser); + console.log(userSubscription); + })(); + }, []); + + const setUserUsage = async (id: number, quantity: number) => { + try { + const response = await setUsage(id, quantity); + console.log(response); + } catch (error) { + console.error(error); + } + }; + return (

Pricing

+ +
+ + +
+

The right price for you, whoever you are

@@ -68,7 +136,7 @@ export default function PricingList() { Qui iusto aut est earum eos quae. Eligendi est at nam aliquid ad quo reprehenderit in aliquid fugiat dolorum voluptatibus.

-
+
{productTiers && productTiers.map((tier, tierIdx) => (
(
  • - {checkMarkIcon} + {feature.includes("[x]") ? crossMarkIcon : checkMarkIcon}
    - {feature} + {feature.replace("[x]", "")}
  • ))} diff --git a/web/src/app/(app)/pricing/const/Icon.tsx b/web/src/app/(app)/pricing/const/Icon.tsx index 2142282..2257aee 100644 --- a/web/src/app/(app)/pricing/const/Icon.tsx +++ b/web/src/app/(app)/pricing/const/Icon.tsx @@ -13,3 +13,25 @@ export const checkMarkIcon = ( /> ); + +export const crossMarkIcon = ( + + + + +); diff --git a/web/src/components/Navbar.tsx b/web/src/components/Navbar.tsx index 52be0c8..fa5bdf0 100644 --- a/web/src/components/Navbar.tsx +++ b/web/src/components/Navbar.tsx @@ -85,6 +85,13 @@ export function Navbar() {
    {isDesktop && } + + {pricingPlanFlagEnable && ( + + )} From f948fca78cdef5fc90bac2347012694ccf4e389f Mon Sep 17 00:00:00 2001 From: Karrix Date: Tue, 23 Jan 2024 01:58:05 +0800 Subject: [PATCH 06/11] add: add unit (per second) to lemonsqueezy after run, and sync to db table --- web/bun.lockb | Bin 498075 -> 498484 bytes web/drizzle/0033_fantastic_marvel_boy.sql | 13 + web/drizzle/0034_previous_viper.sql | 2 + web/drizzle/meta/0033_snapshot.json | 834 +++++++++++++++++ web/drizzle/meta/0034_snapshot.json | 842 ++++++++++++++++++ web/drizzle/meta/_journal.json | 14 + web/src/app/(app)/api/update-run/route.ts | 65 +- .../pricing/components/pricePlanList.tsx | 7 +- web/src/db/schema.ts | 120 +-- 9 files changed, 1831 insertions(+), 66 deletions(-) create mode 100644 web/drizzle/0033_fantastic_marvel_boy.sql create mode 100644 web/drizzle/0034_previous_viper.sql create mode 100644 web/drizzle/meta/0033_snapshot.json create mode 100644 web/drizzle/meta/0034_snapshot.json diff --git a/web/bun.lockb b/web/bun.lockb index c5cc14e81f695aabf0c4d68e96314844fb7b95d8..1af90ac5bb77bea12ee4d1cc2b7c653032569e37 100755 GIT binary patch delta 80747 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

    q_9>%XkhN2uU*eyAnoPOpv9XQHcsS)jW3 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 delta 80409 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 diff --git a/web/drizzle/0033_fantastic_marvel_boy.sql b/web/drizzle/0033_fantastic_marvel_boy.sql new file mode 100644 index 0000000..088987b --- /dev/null +++ b/web/drizzle/0033_fantastic_marvel_boy.sql @@ -0,0 +1,13 @@ +CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "user_id" text NOT NULL, + "usage_time" real DEFAULT 0 NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/web/drizzle/0034_previous_viper.sql b/web/drizzle/0034_previous_viper.sql new file mode 100644 index 0000000..5953e59 --- /dev/null +++ b/web/drizzle/0034_previous_viper.sql @@ -0,0 +1,2 @@ +ALTER TABLE "comfyui_deploy"."user_usage" RENAME COLUMN "updated_at" TO "ended_at";--> statement-breakpoint +ALTER TABLE "comfyui_deploy"."user_usage" ADD COLUMN "org_id" text; \ No newline at end of file diff --git a/web/drizzle/meta/0033_snapshot.json b/web/drizzle/meta/0033_snapshot.json new file mode 100644 index 0000000..2c75c2a --- /dev/null +++ b/web/drizzle/meta/0033_snapshot.json @@ -0,0 +1,834 @@ +{ + "id": "91bb0461-452a-4e59-abf4-8757fcd75a89", + "prevId": "1425ee00-66fb-4541-8da7-19b217944545", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0034_snapshot.json b/web/drizzle/meta/0034_snapshot.json new file mode 100644 index 0000000..de5f69b --- /dev/null +++ b/web/drizzle/meta/0034_snapshot.json @@ -0,0 +1,842 @@ +{ + "id": "fad17dc9-86c5-4081-8e73-47c113f48936", + "prevId": "91bb0461-452a-4e59-abf4-8757fcd75a89", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": { + "\"comfyui_deploy\".\"user_usage\".\"updated_at\"": "\"comfyui_deploy\".\"user_usage\".\"ended_at\"" + } + } +} \ No newline at end of file diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json index a262f43..abc42ef 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -232,6 +232,20 @@ "when": 1705806921697, "tag": "0032_shallow_vermin", "breakpoints": true + }, + { + "idx": 33, + "version": "5", + "when": 1705824362978, + "tag": "0033_fantastic_marvel_boy", + "breakpoints": true + }, + { + "idx": 34, + "version": "5", + "when": 1705840184127, + "tag": "0034_previous_viper", + "breakpoints": true } ] } \ No newline at end of file diff --git a/web/src/app/(app)/api/update-run/route.ts b/web/src/app/(app)/api/update-run/route.ts index e712eb1..e4b98db 100644 --- a/web/src/app/(app)/api/update-run/route.ts +++ b/web/src/app/(app)/api/update-run/route.ts @@ -1,6 +1,13 @@ import { parseDataSafe } from "../../../../lib/parseDataSafe"; import { db } from "@/db/db"; -import { workflowRunOutputs, workflowRunsTable } from "@/db/schema"; +import { + userUsageTable, + workflowRunOutputs, + workflowRunsTable, + workflowTable, +} from "@/db/schema"; +import { getDuration } from "@/lib/getRelativeTime"; +import { getSubscription, setUsage } from "@/server/linkToPricing"; import { eq } from "drizzle-orm"; import { NextResponse } from "next/server"; import { z } from "zod"; @@ -27,7 +34,6 @@ export async function POST(request: Request) { data: output_data, }); } else if (status) { - // console.log("status", status); const workflow_run = await db .update(workflowRunsTable) .set({ @@ -35,8 +41,15 @@ export async function POST(request: Request) { ended_at: status === "success" || status === "failed" ? new Date() : null, }) - .where(eq(workflowRunsTable.id, run_id)) - .returning(); + .where(eq(workflowRunsTable.id, run_id)); + + // get data from workflowRunsTable + const userUsageTime = await importUserUsageData(run_id); + + if (userUsageTime) { + // get the usage_time from userUsage + await addSubscriptionUnit(userUsageTime); + } } // const workflow_version = await db.query.workflowVersionTable.findFirst({ @@ -54,3 +67,47 @@ export async function POST(request: Request) { } ); } + +async function addSubscriptionUnit(userUsageTime: number) { + const subscription = await getSubscription(); + + // round up userUsageTime to the nearest integer + const roundedUsageTime = Math.ceil(userUsageTime); + + if (subscription) { + const usage = await setUsage( + subscription.data[0].attributes.first_subscription_item.id, + roundedUsageTime + ); + } +} + +async function importUserUsageData(run_id: string) { + const workflowRuns = await db.query.workflowRunsTable.findFirst({ + where: eq(workflowRunsTable.id, run_id), + }); + + if (!workflowRuns?.workflow_id) return; + + // find if workflowTable id column contains workflowRunsTable workflow_id + const workflow = await db.query.workflowTable.findFirst({ + where: eq(workflowTable.id, workflowRuns.workflow_id), + }); + + if (workflowRuns?.ended_at === null || workflow == null) return; + + const usageTime = parseFloat( + getDuration((workflowRuns?.ended_at - workflowRuns?.started_at) / 1000) + ); + + // add data to userUsageTable + const user_usage = await db.insert(userUsageTable).values({ + user_id: workflow.user_id, + created_at: workflowRuns.ended_at, + org_id: workflow.org_id, + ended_at: workflowRuns.ended_at, + usage_time: usageTime, + }); + + return usageTime; +} diff --git a/web/src/app/(app)/pricing/components/pricePlanList.tsx b/web/src/app/(app)/pricing/components/pricePlanList.tsx index d097741..19f255b 100644 --- a/web/src/app/(app)/pricing/components/pricePlanList.tsx +++ b/web/src/app/(app)/pricing/components/pricePlanList.tsx @@ -2,6 +2,7 @@ import { checkMarkIcon, crossMarkIcon } from "../const/Icon"; import { cn } from "@/lib/utils"; import { getPricing, + getSubscription, getSubscriptionItem, getUsage, setUsage, @@ -89,12 +90,14 @@ export default function PricingList() { // const currentUser = await getUserData(); const userUsage = await getUsage(); - const userSubscription = await getSubscriptionItem(); + const userSubscription = await getSubscription(); // const setUserUsage = await setUsage(236561, 10); // console.log(currentUser); - console.log(userSubscription); + console.log( + userSubscription.data[0].attributes.first_subscription_item.id + ); })(); }, []); diff --git a/web/src/db/schema.ts b/web/src/db/schema.ts index 4db5091..64df610 100644 --- a/web/src/db/schema.ts +++ b/web/src/db/schema.ts @@ -1,14 +1,14 @@ import { type InferSelectModel, relations } from "drizzle-orm"; import { - boolean, - integer, - jsonb, - pgEnum, - pgSchema, - text, - timestamp, - uuid, - real, + boolean, + integer, + jsonb, + pgEnum, + pgSchema, + text, + timestamp, + uuid, + real, } from "drizzle-orm/pg-core"; import { createInsertSchema } from "drizzle-zod"; import { z } from "zod"; @@ -131,30 +131,30 @@ export const machinesStatus = pgEnum("machine_status", [ // We still want to keep the workflow run record. export const workflowRunsTable = dbSchema.table("workflow_runs", { - id: uuid("id").primaryKey().defaultRandom().notNull(), - // when workflow version deleted, still want to keep this record - workflow_version_id: uuid("workflow_version_id").references( - () => workflowVersionTable.id, - { - onDelete: "set null", - }, - ), - workflow_inputs: - jsonb("workflow_inputs").$type>(), - workflow_id: uuid("workflow_id") - .notNull() - .references(() => workflowTable.id, { - onDelete: "cascade", - }), - // when machine deleted, still want to keep this record - machine_id: uuid("machine_id").references(() => machinesTable.id, { - onDelete: "set null", - }), - origin: workflowRunOrigin("origin").notNull().default("api"), - status: workflowRunStatus("status").notNull().default("not-started"), - ended_at: timestamp("ended_at"), - created_at: timestamp("created_at").defaultNow().notNull(), - started_at: timestamp("started_at"), + id: uuid("id").primaryKey().defaultRandom().notNull(), + // when workflow version deleted, still want to keep this record + workflow_version_id: uuid("workflow_version_id").references( + () => workflowVersionTable.id, + { + onDelete: "set null", + } + ), + workflow_inputs: + jsonb("workflow_inputs").$type>(), + workflow_id: uuid("workflow_id") + .notNull() + .references(() => workflowTable.id, { + onDelete: "cascade", + }), + // when machine deleted, still want to keep this record + machine_id: uuid("machine_id").references(() => machinesTable.id, { + onDelete: "set null", + }), + origin: workflowRunOrigin("origin").notNull().default("api"), + status: workflowRunStatus("status").notNull().default("not-started"), + ended_at: timestamp("ended_at"), + created_at: timestamp("created_at").defaultNow().notNull(), + started_at: timestamp("started_at"), }); export const workflowRunRelations = relations( @@ -258,31 +258,31 @@ export const showcaseMediaNullable = z .nullable(); export const deploymentsTable = dbSchema.table("deployments", { - id: uuid("id").primaryKey().defaultRandom().notNull(), - user_id: text("user_id") - .references(() => usersTable.id, { - onDelete: "cascade", - }) - .notNull(), - org_id: text("org_id"), - workflow_version_id: uuid("workflow_version_id") - .notNull() - .references(() => workflowVersionTable.id), - workflow_id: uuid("workflow_id") - .notNull() - .references(() => workflowTable.id, { - onDelete: "cascade", - }), - machine_id: uuid("machine_id") - .notNull() - .references(() => machinesTable.id), - share_slug: text("share_slug").unique(), - description: text("description"), - showcase_media: - jsonb("showcase_media").$type>(), - environment: deploymentEnvironment("environment").notNull(), - created_at: timestamp("created_at").defaultNow().notNull(), - updated_at: timestamp("updated_at").defaultNow().notNull(), + id: uuid("id").primaryKey().defaultRandom().notNull(), + user_id: text("user_id") + .references(() => usersTable.id, { + onDelete: "cascade", + }) + .notNull(), + org_id: text("org_id"), + workflow_version_id: uuid("workflow_version_id") + .notNull() + .references(() => workflowVersionTable.id), + workflow_id: uuid("workflow_id") + .notNull() + .references(() => workflowTable.id, { + onDelete: "cascade", + }), + machine_id: uuid("machine_id") + .notNull() + .references(() => machinesTable.id), + share_slug: text("share_slug").unique(), + description: text("description"), + showcase_media: + jsonb("showcase_media").$type>(), + environment: deploymentEnvironment("environment").notNull(), + created_at: timestamp("created_at").defaultNow().notNull(), + updated_at: timestamp("updated_at").defaultNow().notNull(), }); export const publicShareDeployment = z.object({ @@ -334,15 +334,15 @@ export const apiKeyTable = dbSchema.table("api_keys", { export const userUsageTable = dbSchema.table("user_usage", { id: uuid("id").primaryKey().defaultRandom().notNull(), + org_id: text("org_id"), user_id: text("user_id") .references(() => usersTable.id, { onDelete: "cascade", }) .notNull(), usage_time: real("usage_time").default(0).notNull(), - created_at: timestamp("created_at").defaultNow().notNull(), - updated_at: timestamp("updated_at").defaultNow().notNull(), + ended_at: timestamp("ended_at").defaultNow().notNull(), }); export type UserType = InferSelectModel; From a9f46b084619fd7d6d7cb1ac182d9a31b1893a34 Mon Sep 17 00:00:00 2001 From: Karrix Date: Tue, 23 Jan 2024 02:00:19 +0800 Subject: [PATCH 07/11] chore: old testing code in pricing page --- .../pricing/components/pricePlanList.tsx | 49 +------------------ 1 file changed, 1 insertion(+), 48 deletions(-) diff --git a/web/src/app/(app)/pricing/components/pricePlanList.tsx b/web/src/app/(app)/pricing/components/pricePlanList.tsx index 19f255b..89f4358 100644 --- a/web/src/app/(app)/pricing/components/pricePlanList.tsx +++ b/web/src/app/(app)/pricing/components/pricePlanList.tsx @@ -1,12 +1,6 @@ import { checkMarkIcon, crossMarkIcon } from "../const/Icon"; import { cn } from "@/lib/utils"; -import { - getPricing, - getSubscription, - getSubscriptionItem, - getUsage, - setUsage, -} from "@/server/linkToPricing"; +import { getPricing } from "@/server/linkToPricing"; import { useEffect, useState } from "react"; type Tier = { @@ -28,7 +22,6 @@ enum TierPriority { export default function PricingList() { const [productTiers, setProductTiers] = useState(); - const [userUsageId, setUserUsageId] = useState(0); useEffect(() => { (async () => { @@ -85,52 +78,12 @@ export default function PricingList() { })(); }, []); - useEffect(() => { - (async () => { - // const currentUser = await getUserData(); - - const userUsage = await getUsage(); - const userSubscription = await getSubscription(); - - // const setUserUsage = await setUsage(236561, 10); - - // console.log(currentUser); - console.log( - userSubscription.data[0].attributes.first_subscription_item.id - ); - })(); - }, []); - - const setUserUsage = async (id: number, quantity: number) => { - try { - const response = await setUsage(id, quantity); - console.log(response); - } catch (error) { - console.error(error); - } - }; - return (

    Pricing

    - -
    - - -
    -

    The right price for you, whoever you are

    From 7a7ced3e0818920ef658e3c7079233abde9f484e Mon Sep 17 00:00:00 2001 From: BennyKok Date: Tue, 23 Jan 2024 11:41:28 +0800 Subject: [PATCH 08/11] drop migration for merge --- web/drizzle/0033_fantastic_marvel_boy.sql | 13 - web/drizzle/0034_previous_viper.sql | 2 - web/drizzle/meta/0033_snapshot.json | 834 --------------------- web/drizzle/meta/0034_snapshot.json | 842 ---------------------- web/drizzle/meta/_journal.json | 252 +------ 5 files changed, 1 insertion(+), 1942 deletions(-) delete mode 100644 web/drizzle/0033_fantastic_marvel_boy.sql delete mode 100644 web/drizzle/0034_previous_viper.sql delete mode 100644 web/drizzle/meta/0033_snapshot.json delete mode 100644 web/drizzle/meta/0034_snapshot.json diff --git a/web/drizzle/0033_fantastic_marvel_boy.sql b/web/drizzle/0033_fantastic_marvel_boy.sql deleted file mode 100644 index 088987b..0000000 --- a/web/drizzle/0033_fantastic_marvel_boy.sql +++ /dev/null @@ -1,13 +0,0 @@ -CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" ( - "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, - "user_id" text NOT NULL, - "usage_time" real DEFAULT 0 NOT NULL, - "created_at" timestamp DEFAULT now() NOT NULL, - "updated_at" timestamp DEFAULT now() NOT NULL -); ---> statement-breakpoint -DO $$ BEGIN - ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action; -EXCEPTION - WHEN duplicate_object THEN null; -END $$; diff --git a/web/drizzle/0034_previous_viper.sql b/web/drizzle/0034_previous_viper.sql deleted file mode 100644 index 5953e59..0000000 --- a/web/drizzle/0034_previous_viper.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE "comfyui_deploy"."user_usage" RENAME COLUMN "updated_at" TO "ended_at";--> statement-breakpoint -ALTER TABLE "comfyui_deploy"."user_usage" ADD COLUMN "org_id" text; \ No newline at end of file diff --git a/web/drizzle/meta/0033_snapshot.json b/web/drizzle/meta/0033_snapshot.json deleted file mode 100644 index 2c75c2a..0000000 --- a/web/drizzle/meta/0033_snapshot.json +++ /dev/null @@ -1,834 +0,0 @@ -{ - "id": "91bb0461-452a-4e59-abf4-8757fcd75a89", - "prevId": "1425ee00-66fb-4541-8da7-19b217944545", - "version": "5", - "dialect": "pg", - "tables": { - "api_keys": { - "name": "api_keys", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "key": { - "name": "key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "revoked": { - "name": "revoked", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "api_keys_user_id_users_id_fk": { - "name": "api_keys_user_id_users_id_fk", - "tableFrom": "api_keys", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "api_keys_key_unique": { - "name": "api_keys_key_unique", - "nullsNotDistinct": false, - "columns": [ - "key" - ] - } - } - }, - "deployments": { - "name": "deployments", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "workflow_version_id": { - "name": "workflow_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "machine_id": { - "name": "machine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "share_slug": { - "name": "share_slug", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "showcase_media": { - "name": "showcase_media", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "environment": { - "name": "environment", - "type": "deployment_environment", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "deployments_user_id_users_id_fk": { - "name": "deployments_user_id_users_id_fk", - "tableFrom": "deployments", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployments_workflow_version_id_workflow_versions_id_fk": { - "name": "deployments_workflow_version_id_workflow_versions_id_fk", - "tableFrom": "deployments", - "tableTo": "workflow_versions", - "columnsFrom": [ - "workflow_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "deployments_workflow_id_workflows_id_fk": { - "name": "deployments_workflow_id_workflows_id_fk", - "tableFrom": "deployments", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployments_machine_id_machines_id_fk": { - "name": "deployments_machine_id_machines_id_fk", - "tableFrom": "deployments", - "tableTo": "machines", - "columnsFrom": [ - "machine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "deployments_share_slug_unique": { - "name": "deployments_share_slug_unique", - "nullsNotDistinct": false, - "columns": [ - "share_slug" - ] - } - } - }, - "machines": { - "name": "machines", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "endpoint": { - "name": "endpoint", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "disabled": { - "name": "disabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "auth_token": { - "name": "auth_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "machine_type", - "primaryKey": false, - "notNull": true, - "default": "'classic'" - }, - "status": { - "name": "status", - "type": "machine_status", - "primaryKey": false, - "notNull": true, - "default": "'ready'" - }, - "snapshot": { - "name": "snapshot", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "models": { - "name": "models", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "gpu": { - "name": "gpu", - "type": "machine_gpu", - "primaryKey": false, - "notNull": false - }, - "build_machine_instance_id": { - "name": "build_machine_instance_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "build_log": { - "name": "build_log", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "machines_user_id_users_id_fk": { - "name": "machines_user_id_users_id_fk", - "tableFrom": "machines", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user_usage": { - "name": "user_usage", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "usage_time": { - "name": "usage_time", - "type": "real", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "user_usage_user_id_users_id_fk": { - "name": "user_usage_user_id_users_id_fk", - "tableFrom": "user_usage", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users": { - "name": "users", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_run_outputs": { - "name": "workflow_run_outputs", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "run_id": { - "name": "run_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_run_outputs_run_id_workflow_runs_id_fk": { - "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", - "tableFrom": "workflow_run_outputs", - "tableTo": "workflow_runs", - "columnsFrom": [ - "run_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_runs": { - "name": "workflow_runs", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workflow_version_id": { - "name": "workflow_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "workflow_inputs": { - "name": "workflow_inputs", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "machine_id": { - "name": "machine_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "origin": { - "name": "origin", - "type": "workflow_run_origin", - "primaryKey": false, - "notNull": true, - "default": "'api'" - }, - "status": { - "name": "status", - "type": "workflow_run_status", - "primaryKey": false, - "notNull": true, - "default": "'not-started'" - }, - "ended_at": { - "name": "ended_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_runs_workflow_version_id_workflow_versions_id_fk": { - "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "workflow_versions", - "columnsFrom": [ - "workflow_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "workflow_runs_workflow_id_workflows_id_fk": { - "name": "workflow_runs_workflow_id_workflows_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "workflow_runs_machine_id_machines_id_fk": { - "name": "workflow_runs_machine_id_machines_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "machines", - "columnsFrom": [ - "machine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflows": { - "name": "workflows", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflows_user_id_users_id_fk": { - "name": "workflows_user_id_users_id_fk", - "tableFrom": "workflows", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_versions": { - "name": "workflow_versions", - "schema": "comfyui_deploy", - "columns": { - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workflow": { - "name": "workflow", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "workflow_api": { - "name": "workflow_api", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "snapshot": { - "name": "snapshot", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_versions_workflow_id_workflows_id_fk": { - "name": "workflow_versions_workflow_id_workflows_id_fk", - "tableFrom": "workflow_versions", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": { - "deployment_environment": { - "name": "deployment_environment", - "values": { - "staging": "staging", - "production": "production", - "public-share": "public-share" - } - }, - "machine_gpu": { - "name": "machine_gpu", - "values": { - "T4": "T4", - "A10G": "A10G", - "A100": "A100" - } - }, - "machine_status": { - "name": "machine_status", - "values": { - "ready": "ready", - "building": "building", - "error": "error" - } - }, - "machine_type": { - "name": "machine_type", - "values": { - "classic": "classic", - "runpod-serverless": "runpod-serverless", - "modal-serverless": "modal-serverless", - "comfy-deploy-serverless": "comfy-deploy-serverless" - } - }, - "workflow_run_origin": { - "name": "workflow_run_origin", - "values": { - "manual": "manual", - "api": "api", - "public-share": "public-share" - } - }, - "workflow_run_status": { - "name": "workflow_run_status", - "values": { - "not-started": "not-started", - "running": "running", - "uploading": "uploading", - "success": "success", - "failed": "failed" - } - } - }, - "schemas": { - "comfyui_deploy": "comfyui_deploy" - }, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - } -} \ No newline at end of file diff --git a/web/drizzle/meta/0034_snapshot.json b/web/drizzle/meta/0034_snapshot.json deleted file mode 100644 index de5f69b..0000000 --- a/web/drizzle/meta/0034_snapshot.json +++ /dev/null @@ -1,842 +0,0 @@ -{ - "id": "fad17dc9-86c5-4081-8e73-47c113f48936", - "prevId": "91bb0461-452a-4e59-abf4-8757fcd75a89", - "version": "5", - "dialect": "pg", - "tables": { - "api_keys": { - "name": "api_keys", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "key": { - "name": "key", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "revoked": { - "name": "revoked", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "api_keys_user_id_users_id_fk": { - "name": "api_keys_user_id_users_id_fk", - "tableFrom": "api_keys", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "api_keys_key_unique": { - "name": "api_keys_key_unique", - "nullsNotDistinct": false, - "columns": [ - "key" - ] - } - } - }, - "deployments": { - "name": "deployments", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "workflow_version_id": { - "name": "workflow_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "machine_id": { - "name": "machine_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "share_slug": { - "name": "share_slug", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "description": { - "name": "description", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "showcase_media": { - "name": "showcase_media", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "environment": { - "name": "environment", - "type": "deployment_environment", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "deployments_user_id_users_id_fk": { - "name": "deployments_user_id_users_id_fk", - "tableFrom": "deployments", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployments_workflow_version_id_workflow_versions_id_fk": { - "name": "deployments_workflow_version_id_workflow_versions_id_fk", - "tableFrom": "deployments", - "tableTo": "workflow_versions", - "columnsFrom": [ - "workflow_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - }, - "deployments_workflow_id_workflows_id_fk": { - "name": "deployments_workflow_id_workflows_id_fk", - "tableFrom": "deployments", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "deployments_machine_id_machines_id_fk": { - "name": "deployments_machine_id_machines_id_fk", - "tableFrom": "deployments", - "tableTo": "machines", - "columnsFrom": [ - "machine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "no action", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": { - "deployments_share_slug_unique": { - "name": "deployments_share_slug_unique", - "nullsNotDistinct": false, - "columns": [ - "share_slug" - ] - } - } - }, - "machines": { - "name": "machines", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "endpoint": { - "name": "endpoint", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "disabled": { - "name": "disabled", - "type": "boolean", - "primaryKey": false, - "notNull": true, - "default": false - }, - "auth_token": { - "name": "auth_token", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "type": { - "name": "type", - "type": "machine_type", - "primaryKey": false, - "notNull": true, - "default": "'classic'" - }, - "status": { - "name": "status", - "type": "machine_status", - "primaryKey": false, - "notNull": true, - "default": "'ready'" - }, - "snapshot": { - "name": "snapshot", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "models": { - "name": "models", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "gpu": { - "name": "gpu", - "type": "machine_gpu", - "primaryKey": false, - "notNull": false - }, - "build_machine_instance_id": { - "name": "build_machine_instance_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "build_log": { - "name": "build_log", - "type": "text", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "machines_user_id_users_id_fk": { - "name": "machines_user_id_users_id_fk", - "tableFrom": "machines", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "user_usage": { - "name": "user_usage", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "usage_time": { - "name": "usage_time", - "type": "real", - "primaryKey": false, - "notNull": true, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "ended_at": { - "name": "ended_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "user_usage_user_id_users_id_fk": { - "name": "user_usage_user_id_users_id_fk", - "tableFrom": "user_usage", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "users": { - "name": "users", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true - }, - "username": { - "name": "username", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_run_outputs": { - "name": "workflow_run_outputs", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "run_id": { - "name": "run_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "data": { - "name": "data", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_run_outputs_run_id_workflow_runs_id_fk": { - "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", - "tableFrom": "workflow_run_outputs", - "tableTo": "workflow_runs", - "columnsFrom": [ - "run_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_runs": { - "name": "workflow_runs", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workflow_version_id": { - "name": "workflow_version_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "workflow_inputs": { - "name": "workflow_inputs", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "machine_id": { - "name": "machine_id", - "type": "uuid", - "primaryKey": false, - "notNull": false - }, - "origin": { - "name": "origin", - "type": "workflow_run_origin", - "primaryKey": false, - "notNull": true, - "default": "'api'" - }, - "status": { - "name": "status", - "type": "workflow_run_status", - "primaryKey": false, - "notNull": true, - "default": "'not-started'" - }, - "ended_at": { - "name": "ended_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "started_at": { - "name": "started_at", - "type": "timestamp", - "primaryKey": false, - "notNull": false - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_runs_workflow_version_id_workflow_versions_id_fk": { - "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "workflow_versions", - "columnsFrom": [ - "workflow_version_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - }, - "workflow_runs_workflow_id_workflows_id_fk": { - "name": "workflow_runs_workflow_id_workflows_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "workflow_runs_machine_id_machines_id_fk": { - "name": "workflow_runs_machine_id_machines_id_fk", - "tableFrom": "workflow_runs", - "tableTo": "machines", - "columnsFrom": [ - "machine_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "set null", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflows": { - "name": "workflows", - "schema": "comfyui_deploy", - "columns": { - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "user_id": { - "name": "user_id", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "org_id": { - "name": "org_id", - "type": "text", - "primaryKey": false, - "notNull": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflows_user_id_users_id_fk": { - "name": "workflows_user_id_users_id_fk", - "tableFrom": "workflows", - "tableTo": "users", - "columnsFrom": [ - "user_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "workflow_versions": { - "name": "workflow_versions", - "schema": "comfyui_deploy", - "columns": { - "workflow_id": { - "name": "workflow_id", - "type": "uuid", - "primaryKey": false, - "notNull": true - }, - "id": { - "name": "id", - "type": "uuid", - "primaryKey": true, - "notNull": true, - "default": "gen_random_uuid()" - }, - "workflow": { - "name": "workflow", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "workflow_api": { - "name": "workflow_api", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "version": { - "name": "version", - "type": "integer", - "primaryKey": false, - "notNull": true - }, - "snapshot": { - "name": "snapshot", - "type": "jsonb", - "primaryKey": false, - "notNull": false - }, - "created_at": { - "name": "created_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - }, - "updated_at": { - "name": "updated_at", - "type": "timestamp", - "primaryKey": false, - "notNull": true, - "default": "now()" - } - }, - "indexes": {}, - "foreignKeys": { - "workflow_versions_workflow_id_workflows_id_fk": { - "name": "workflow_versions_workflow_id_workflows_id_fk", - "tableFrom": "workflow_versions", - "tableTo": "workflows", - "columnsFrom": [ - "workflow_id" - ], - "columnsTo": [ - "id" - ], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": { - "deployment_environment": { - "name": "deployment_environment", - "values": { - "staging": "staging", - "production": "production", - "public-share": "public-share" - } - }, - "machine_gpu": { - "name": "machine_gpu", - "values": { - "T4": "T4", - "A10G": "A10G", - "A100": "A100" - } - }, - "machine_status": { - "name": "machine_status", - "values": { - "ready": "ready", - "building": "building", - "error": "error" - } - }, - "machine_type": { - "name": "machine_type", - "values": { - "classic": "classic", - "runpod-serverless": "runpod-serverless", - "modal-serverless": "modal-serverless", - "comfy-deploy-serverless": "comfy-deploy-serverless" - } - }, - "workflow_run_origin": { - "name": "workflow_run_origin", - "values": { - "manual": "manual", - "api": "api", - "public-share": "public-share" - } - }, - "workflow_run_status": { - "name": "workflow_run_status", - "values": { - "not-started": "not-started", - "running": "running", - "uploading": "uploading", - "success": "success", - "failed": "failed" - } - } - }, - "schemas": { - "comfyui_deploy": "comfyui_deploy" - }, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": { - "\"comfyui_deploy\".\"user_usage\".\"updated_at\"": "\"comfyui_deploy\".\"user_usage\".\"ended_at\"" - } - } -} \ No newline at end of file diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json index abc42ef..d028999 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -1,251 +1 @@ -{ - "version": "5", - "dialect": "pg", - "entries": [ - { - "idx": 0, - "version": "5", - "when": 1702033790765, - "tag": "0000_quiet_ulik", - "breakpoints": true - }, - { - "idx": 1, - "version": "5", - "when": 1702034015507, - "tag": "0001_silly_arachne", - "breakpoints": true - }, - { - "idx": 2, - "version": "5", - "when": 1702044546478, - "tag": "0002_clean_khan", - "breakpoints": true - }, - { - "idx": 3, - "version": "5", - "when": 1702212969930, - "tag": "0003_oval_mockingbird", - "breakpoints": true - }, - { - "idx": 4, - "version": "5", - "when": 1702357291227, - "tag": "0004_zippy_freak", - "breakpoints": true - }, - { - "idx": 5, - "version": "5", - "when": 1702545286004, - "tag": "0005_worthless_dakota_north", - "breakpoints": true - }, - { - "idx": 6, - "version": "5", - "when": 1702556119574, - "tag": "0006_chief_mariko_yashida", - "breakpoints": true - }, - { - "idx": 7, - "version": "5", - "when": 1702609665746, - "tag": "0007_thin_greymalkin", - "breakpoints": true - }, - { - "idx": 8, - "version": "5", - "when": 1702615888467, - "tag": "0008_futuristic_adam_destine", - "breakpoints": true - }, - { - "idx": 9, - "version": "5", - "when": 1702632471725, - "tag": "0009_easy_banshee", - "breakpoints": true - }, - { - "idx": 10, - "version": "5", - "when": 1702708886828, - "tag": "0010_organic_marten_broadcloak", - "breakpoints": true - }, - { - "idx": 11, - "version": "5", - "when": 1702960221042, - "tag": "0011_peaceful_william_stryker", - "breakpoints": true - }, - { - "idx": 12, - "version": "5", - "when": 1703136669370, - "tag": "0012_exotic_sumo", - "breakpoints": true - }, - { - "idx": 13, - "version": "5", - "when": 1703338425429, - "tag": "0013_stormy_starbolt", - "breakpoints": true - }, - { - "idx": 14, - "version": "5", - "when": 1703403388113, - "tag": "0014_short_sunfire", - "breakpoints": true - }, - { - "idx": 15, - "version": "5", - "when": 1703409502387, - "tag": "0015_simple_killmonger", - "breakpoints": true - }, - { - "idx": 16, - "version": "5", - "when": 1704092053001, - "tag": "0016_overrated_cable", - "breakpoints": true - }, - { - "idx": 17, - "version": "5", - "when": 1704126972289, - "tag": "0017_tiresome_zaladane", - "breakpoints": true - }, - { - "idx": 18, - "version": "5", - "when": 1704129070951, - "tag": "0018_remarkable_the_leader", - "breakpoints": true - }, - { - "idx": 19, - "version": "5", - "when": 1704174903117, - "tag": "0019_damp_stick", - "breakpoints": true - }, - { - "idx": 20, - "version": "5", - "when": 1704350033885, - "tag": "0020_complete_black_tom", - "breakpoints": true - }, - { - "idx": 21, - "version": "5", - "when": 1704380757696, - "tag": "0021_aromatic_sabra", - "breakpoints": true - }, - { - "idx": 22, - "version": "5", - "when": 1704453649633, - "tag": "0022_petite_bishop", - "breakpoints": true - }, - { - "idx": 23, - "version": "5", - "when": 1704540132567, - "tag": "0023_fair_ikaris", - "breakpoints": true - }, - { - "idx": 24, - "version": "5", - "when": 1704632758591, - "tag": "0024_smiling_triton", - "breakpoints": true - }, - { - "idx": 25, - "version": "5", - "when": 1704640269305, - "tag": "0025_hard_jean_grey", - "breakpoints": true - }, - { - "idx": 26, - "version": "5", - "when": 1704979846175, - "tag": "0026_premium_rocket_raccoon", - "breakpoints": true - }, - { - "idx": 27, - "version": "5", - "when": 1705228261543, - "tag": "0027_eminent_lilith", - "breakpoints": true - }, - { - "idx": 28, - "version": "5", - "when": 1705642345817, - "tag": "0028_futuristic_lady_deathstrike", - "breakpoints": true - }, - { - "idx": 29, - "version": "5", - "when": 1705662714161, - "tag": "0029_large_frightful_four", - "breakpoints": true - }, - { - "idx": 30, - "version": "5", - "when": 1705716303820, - "tag": "0030_kind_doorman", - "breakpoints": true - }, - { - "idx": 31, - "version": "5", - "when": 1705763980972, - "tag": "0031_fast_lyja", - "breakpoints": true - }, - { - "idx": 32, - "version": "5", - "when": 1705806921697, - "tag": "0032_shallow_vermin", - "breakpoints": true - }, - { - "idx": 33, - "version": "5", - "when": 1705824362978, - "tag": "0033_fantastic_marvel_boy", - "breakpoints": true - }, - { - "idx": 34, - "version": "5", - "when": 1705840184127, - "tag": "0034_previous_viper", - "breakpoints": true - } - ] -} \ No newline at end of file +{"version":"5","dialect":"pg","entries":[{"idx":0,"version":"5","when":1702033790765,"tag":"0000_quiet_ulik","breakpoints":true},{"idx":1,"version":"5","when":1702034015507,"tag":"0001_silly_arachne","breakpoints":true},{"idx":2,"version":"5","when":1702044546478,"tag":"0002_clean_khan","breakpoints":true},{"idx":3,"version":"5","when":1702212969930,"tag":"0003_oval_mockingbird","breakpoints":true},{"idx":4,"version":"5","when":1702357291227,"tag":"0004_zippy_freak","breakpoints":true},{"idx":5,"version":"5","when":1702545286004,"tag":"0005_worthless_dakota_north","breakpoints":true},{"idx":6,"version":"5","when":1702556119574,"tag":"0006_chief_mariko_yashida","breakpoints":true},{"idx":7,"version":"5","when":1702609665746,"tag":"0007_thin_greymalkin","breakpoints":true},{"idx":8,"version":"5","when":1702615888467,"tag":"0008_futuristic_adam_destine","breakpoints":true},{"idx":9,"version":"5","when":1702632471725,"tag":"0009_easy_banshee","breakpoints":true},{"idx":10,"version":"5","when":1702708886828,"tag":"0010_organic_marten_broadcloak","breakpoints":true},{"idx":11,"version":"5","when":1702960221042,"tag":"0011_peaceful_william_stryker","breakpoints":true},{"idx":12,"version":"5","when":1703136669370,"tag":"0012_exotic_sumo","breakpoints":true},{"idx":13,"version":"5","when":1703338425429,"tag":"0013_stormy_starbolt","breakpoints":true},{"idx":14,"version":"5","when":1703403388113,"tag":"0014_short_sunfire","breakpoints":true},{"idx":15,"version":"5","when":1703409502387,"tag":"0015_simple_killmonger","breakpoints":true},{"idx":16,"version":"5","when":1704092053001,"tag":"0016_overrated_cable","breakpoints":true},{"idx":17,"version":"5","when":1704126972289,"tag":"0017_tiresome_zaladane","breakpoints":true},{"idx":18,"version":"5","when":1704129070951,"tag":"0018_remarkable_the_leader","breakpoints":true},{"idx":19,"version":"5","when":1704174903117,"tag":"0019_damp_stick","breakpoints":true},{"idx":20,"version":"5","when":1704350033885,"tag":"0020_complete_black_tom","breakpoints":true},{"idx":21,"version":"5","when":1704380757696,"tag":"0021_aromatic_sabra","breakpoints":true},{"idx":22,"version":"5","when":1704453649633,"tag":"0022_petite_bishop","breakpoints":true},{"idx":23,"version":"5","when":1704540132567,"tag":"0023_fair_ikaris","breakpoints":true},{"idx":24,"version":"5","when":1704632758591,"tag":"0024_smiling_triton","breakpoints":true},{"idx":25,"version":"5","when":1704640269305,"tag":"0025_hard_jean_grey","breakpoints":true},{"idx":26,"version":"5","when":1704979846175,"tag":"0026_premium_rocket_raccoon","breakpoints":true},{"idx":27,"version":"5","when":1705228261543,"tag":"0027_eminent_lilith","breakpoints":true},{"idx":28,"version":"5","when":1705642345817,"tag":"0028_futuristic_lady_deathstrike","breakpoints":true},{"idx":29,"version":"5","when":1705662714161,"tag":"0029_large_frightful_four","breakpoints":true},{"idx":30,"version":"5","when":1705716303820,"tag":"0030_kind_doorman","breakpoints":true},{"idx":31,"version":"5","when":1705763980972,"tag":"0031_fast_lyja","breakpoints":true},{"idx":32,"version":"5","when":1705806921697,"tag":"0032_shallow_vermin","breakpoints":true}]} \ No newline at end of file From f1b68164c6942a590d7279ab05344618454f2910 Mon Sep 17 00:00:00 2001 From: BennyKok Date: Wed, 24 Jan 2024 06:17:28 +0000 Subject: [PATCH 09/11] fix: Update comfyui snapshot hash --- web/src/server/addMachineSchema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/server/addMachineSchema.ts b/web/src/server/addMachineSchema.ts index 89505d4..14cfecb 100644 --- a/web/src/server/addMachineSchema.ts +++ b/web/src/server/addMachineSchema.ts @@ -14,7 +14,7 @@ export const insertCustomMachineSchema = createInsertSchema(machinesTable, { gpu: (schema) => schema.gpu.default("T4"), snapshot: (schema) => schema.snapshot.default({ - comfyui: "8e3ee6468f4c2801c4736c139fd5632c25fbcab7", + comfyui: "d0165d819afe76bd4e6bdd710eb5f3e571b6a804", git_custom_nodes: { "https://github.com/BennyKok/comfyui-deploy.git": { hash: "43fe0a384aa5fa9e141d4a264b2ed40a73b817bc", From 763d2f77ce43a37211aacf65ef7b358af48725a1 Mon Sep 17 00:00:00 2001 From: BennyKok Date: Wed, 24 Jan 2024 10:31:24 +0000 Subject: [PATCH 10/11] fix: comparison operator in CreateShareButton --- web/src/components/CreateShareButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/src/components/CreateShareButton.tsx b/web/src/components/CreateShareButton.tsx index 8447887..1596ec0 100644 --- a/web/src/components/CreateShareButton.tsx +++ b/web/src/components/CreateShareButton.tsx @@ -31,7 +31,7 @@ export function CreateShareButton({ const [isLoading, setIsLoading] = useState(false); const workflow_version_id = workflow?.versions.find( - (x) => x.version === version, + (x) => x.version == version, )?.id; return ( From 0f9e0c9c7670d7e8442b4fe79632207f37173a4b Mon Sep 17 00:00:00 2001 From: BennyKok Date: Thu, 25 Jan 2024 00:34:41 +0800 Subject: [PATCH 11/11] feat: pricing plan + usage page --- web/bun.lockb | Bin 498007 -> 499775 bytes web/drizzle/0035_fearless_golden_guardian.sql | 14 + web/drizzle/0036_flippant_meltdown.sql | 22 + web/drizzle/0037_eager_cyclops.sql | 3 + web/drizzle/0038_yummy_darkhawk.sql | 1 + web/drizzle/0039_nostalgic_lyja.sql | 2 + web/drizzle/0040_salty_archangel.sql | 1 + web/drizzle/0041_thick_norrin_radd.sql | 1 + web/drizzle/meta/0035_snapshot.json | 894 +++++++++++++++ web/drizzle/meta/0036_snapshot.json | 970 ++++++++++++++++ web/drizzle/meta/0037_snapshot.json | 984 ++++++++++++++++ web/drizzle/meta/0038_snapshot.json | 989 ++++++++++++++++ web/drizzle/meta/0039_snapshot.json | 1001 ++++++++++++++++ web/drizzle/meta/0040_snapshot.json | 1007 ++++++++++++++++ web/drizzle/meta/0041_snapshot.json | 1013 +++++++++++++++++ web/drizzle/meta/_journal.json | 51 +- web/package.json | 3 + .../app/(app)/api/stripe/callback/route.tsx | 175 +++ .../app/(app)/api/stripe/checkout/route.tsx | 46 + .../app/(app)/api/stripe/dashboard/route.tsx | 41 + web/src/app/(app)/api/update-run/route.ts | 94 +- .../pricing/components/gpuPricingTable.tsx | 81 -- .../pricing/components/pricePlanList.tsx | 157 --- web/src/app/(app)/pricing/const/Icon.tsx | 37 - web/src/app/(app)/pricing/page.tsx | 6 +- web/src/app/(app)/providers.tsx | 16 +- web/src/app/(app)/usage/loading.tsx | 9 + web/src/app/(app)/usage/page.tsx | 57 + web/src/components/Navbar.tsx | 23 +- web/src/components/PricingPlan.tsx | 381 +++++++ web/src/components/ui/progress.tsx | 28 + web/src/db/schema.ts | 31 + web/src/server/APIKeyBodyRequest.ts | 2 +- web/src/server/createRun.ts | 12 +- web/src/server/editWorkflowOnMachine.tsx | 7 +- web/src/server/getCurrentPlan.tsx | 32 + web/src/server/getUrlServerSide.tsx | 10 + web/src/server/linkToPricing.ts | 45 - web/src/server/stripe.ts | 3 + 39 files changed, 7847 insertions(+), 402 deletions(-) create mode 100644 web/drizzle/0035_fearless_golden_guardian.sql create mode 100644 web/drizzle/0036_flippant_meltdown.sql create mode 100644 web/drizzle/0037_eager_cyclops.sql create mode 100644 web/drizzle/0038_yummy_darkhawk.sql create mode 100644 web/drizzle/0039_nostalgic_lyja.sql create mode 100644 web/drizzle/0040_salty_archangel.sql create mode 100644 web/drizzle/0041_thick_norrin_radd.sql create mode 100644 web/drizzle/meta/0035_snapshot.json create mode 100644 web/drizzle/meta/0036_snapshot.json create mode 100644 web/drizzle/meta/0037_snapshot.json create mode 100644 web/drizzle/meta/0038_snapshot.json create mode 100644 web/drizzle/meta/0039_snapshot.json create mode 100644 web/drizzle/meta/0040_snapshot.json create mode 100644 web/drizzle/meta/0041_snapshot.json create mode 100644 web/src/app/(app)/api/stripe/callback/route.tsx create mode 100644 web/src/app/(app)/api/stripe/checkout/route.tsx create mode 100644 web/src/app/(app)/api/stripe/dashboard/route.tsx delete mode 100644 web/src/app/(app)/pricing/components/gpuPricingTable.tsx delete mode 100644 web/src/app/(app)/pricing/components/pricePlanList.tsx delete mode 100644 web/src/app/(app)/pricing/const/Icon.tsx create mode 100644 web/src/app/(app)/usage/loading.tsx create mode 100644 web/src/app/(app)/usage/page.tsx create mode 100644 web/src/components/PricingPlan.tsx create mode 100644 web/src/components/ui/progress.tsx create mode 100644 web/src/server/getCurrentPlan.tsx create mode 100644 web/src/server/getUrlServerSide.tsx delete mode 100644 web/src/server/linkToPricing.ts create mode 100644 web/src/server/stripe.ts diff --git a/web/bun.lockb b/web/bun.lockb index 650dd43bf9f70e00173efe1b412186dd13171118..ed42cf30664004b10056a212496a5649d148de8b 100755 GIT binary patch delta 94506 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 delta 92719 zcmeFaeSFvR;{X4Czw4d7BowJF$xsTVOIuc(BD%hy)RtANR$J|=U1%X&k_sU&dA1lr zM;$_lLWmQE5GPuUvqMfHgs9`h@BVl_pIiH!Z=Z8J-*Y>^+wYHG@0<2`KJL%!%h$!; z<>gmS`{=3D?&#Fvk|og{Q(BnIf4+P5dl^Gcn%C*+=ZEjTbLwNwp1ksnmfbTuzp?a~ zkUo`*N4F_kb$i3W*dND*Lgm+#6cuOWO%B}=4TW0Z3o|n&6%#$AQ7EMNRj8+Q`ICc8 zB_-KGU>NBe!{BVs6>xQ0)ZjT9tTB4iLCS?R(B%lOmkf14g0(ugvQdMA4 z$)v)JqRh}<%*ptI?81!V%%V{4HMY@jlUeDCvoiCtr_2gH6zU0=FUT({hJ}tl#inlvS9y6EdHI^0 zc6g2Gtc=_ob$ADnYVfIz>Aw=bOS4tc@vgv`Opthi#*@z^yoUZDkR;__qpG+DRk~m4 zt_qx3m@$c&2^Gd!z7AEoV;Kg;*H%0&yEt3rW|tLp45sBE2~^NleyD=?8rTfEnT1m` zyM{uw{EbuX+)c?SDxN_Bg_$KqYU6^|wub{wvukMyswsTVrJtO0wdxDK<{CUHD}Q?S zGK$Ss8^>g94tW0IlLMi&W`8 zh_~A24BLRBnT0{RC-CaXK6ZoBe|(nh&|9c{VcTHDyOx*QDG9ym5+t^>Q*jQe3Z8*W zOY$aXPh!xz`SA@~WPj1#_VdyXHnu0K3H$<8wI8D%+S%#yb8PcYIoEE!srdzy)y@cB z6T9bZyEH#UwNjot&+RdjqP`T<7!&RHaYKXB0C-p*!(RK>0*wiUP~KbhGK> zQFWGe7!1lOc(tx~cgw#**`(zc^su}*qp;(YqEP5*JmXy6?1G@2lgg(O&>%EImEm9y ze_-^qvRluz?IroQl64AyEF5chri%e&ijdWbY4bJ!sqw2=?d9H`s~Gv=Vs?+ z=VlibBLQDU`D$-o{^ZP#856UMGIOuaq}-gOpx!bzR89`*L+`l`J%OsA2T%>z5>y3n zqUIK47l(SEZyQpWkvlnqD!Sm+pS`_px`bq>3@BTwd^`;}1wA#zrfUOdE0(XtpAhn= zG-_7%J7caxrzEd1V&RL@!!cuJ!R$Z5Kw{=l)B3Yl8{YNzOlcpXzT#17rS^5y^#3m zpiqd_S^h5R<%iP>RZviv&lytmf1Jh{rP=vKbnuoTcJgjOz0lZDdAp%@mUFXnGdoV6 z7;1q(fr7q5wHh*tX5~$qo?To>h7<8cSs9(CQPK)_meM5-x2uR_IWs47Qt>@-t(vgE z?U)v2Pmi$fR+oB%TXTh(lS@izPBC0l()J3s77MeBaw+~=ylT%JX>}~BQU{_<(cYtM z?dRilkvIj_ls811p)<%&`hn$bM%y*e7(JPY(&9|6&Y{qcSK5lJQLT~pQLVMw%V~jY zNKXFD;A$1?uZd|%wpG#N6LGvh-N=)@|vTQ_vMpW&S! zKbBpglO=9~)#E1GVxo91e&s9uHC~&t2PfI>Fs&#*Z%TGf<`TTh+B@D3$zM@bJ~JzO zQWmwcaZ9N(^xI_H=xrFKFUTm)>Nq`f)}-u?T+{PI9P>HTN%z(iJ7-*nJ5I^TnEDD{ z<@r;Cd}ZZ-C7{vRMn#&;*XfLU{S2z+-;XMOiPI8PqeOf2bbwSfv<*#~cDN&)d7=4u zRWvbsYOq9$va+XVPslfei|D{J%5-84dvv_t8?-R zPtKfCl0l=MBcWRSCQRF74XSn3@@g%DQ2B2qRzF4=obs1ZuGQuDp=#g_&W}Vja?_pm zM#}_FClIs{Jsn@WZwAp5RnQsLzAC)d#*aj`z>kOPJdC26s*Fkbg#<%4GE&Fm_s_N? zbIr_bF8iU-t=HRz^`h5Zh;Q1E@z)TKCqg}(g`R{?M^!)#1t|VLR6T!wj;-jl8*GC- zv^jio=EM?~Q7D&@)aMZCRNkDqHht}WewT7|AY5^y?O2~1$5>E%Vln z8f}WUMfcroCtwTO9zT|R8mA9$v*}(%HC`)j4|rMm9{^ekx1*|{0M!~iX|Wx^TTx{w z%*@RwoE{22#ah<{JcQ~#YqT+1d!sfrGfx-)(0hNh`D)AAh*v#&_Q=R7DhsUuXr{^@vx|8mszrPmstTTR z8EVsAir4Y?zg;nE*XTc8IqEJPO`ou9u^r{dbD)&Br{!9l)9jO7$WVa>z7$o@)<0z% zQi*DFjD~Bsxm(e?JJD9p*pX_q)~*bm6Eku$CTAXmtAo4HlhH#@+vD(Sv{@OT3k5bu zKU-y&S|SY!?rT^98mc2czQcnn0vaXVap=JYRtG(Ar=l0C{OwUy9P7M?s>27@bD%5m z6#*rjHnT{3BQ$NMHf1RE;)`~BKZwQ=pOv4NFa8Y`sYl;$ust2|k}a?bek}Y&R22?< z*-m9IR3rKaxYo!$PT3=6#Z$TYOAXr|pSjU)CMpXO4t>@3XmZ9Z-8P15&yPvDlR14t zp@i3LLmnl+HsgUm*#!$}3`T}0^x|0snW3E5Z9~VRT0{FcG5%`Vy=2fx%ttj9 zEjHVR6yS9V?4@9}{0+1nI%bPKS@R>dr=Qaht&PWt*C}x~swq72ExT6A@oHcms$=L1 zREs;IjDRwpg2tm~Z?)U&JqkPt|2wJ%Ov))LRgdR3umzW*YETBM_53{}E5`@F zXDe=mSH}+FH8tPSaOEqjeZle6Hak=gq8f>vBv6K$_iamGa~U50!0w7JG)C!ad;HHM z@y{dmzl=y(`BDnh&}{g~PQ?mTL$}Cj?Ff|O)u4%}(qC6)8?Xb_kiLOxPHTtwe;d)& zbVT_p(37?QM}K06E*aI_Z9%o#=emUNR@?Y1@ru95@!G{!H8<=JT}Fb$v~IR@3@SV#dnP-gA+&pG9^ zvetVnZh&fFe%kGha8x7z50b0A+I#ntzqZ+nGYT>$=45j6*>)G9YWJ0>PI&wJhX*aZ zs_U`W_UAlQ&2ql1Jc$H4pUy?K=3-G*96>dryT7mvtNzX|{>`XHxcGZp;8S?@@9%gu z;CB3(XaU*=eTn=kujdc8VShy1_)_qpI*vPH#fB>mEeUKp!Q;N$3~* zZAG;sJ{GPK>hz1{*Q2WNH&p3=LUnLfqb<<0oNsrKkHaz2^Z&3N+)TVS5%2g4v-75gp2m05P~J~K1)a-UQvofV z9)l{wrr+&FEg|Gz)3Q_9m*H@*BzK~k+S&tnD_%2D`>w7-gK#j_>)@&;zM;)mgeu*u zPMb!zC32)nhxrlBs>Qk=xj|d~$wq$4R_P z&&v-abk%W|wg=Yr;0v4C26(8JR5hwK7?0}o`PrqbM&&O#IUF2o z&!S4V#Fcj*Uin`mT^X$}A3-2E#z>%Zuz3rcp#iFfy^Jc|u2aIn&l-gC*&;vgu1ujbw3APFeOudi^JWj*E*=wH4h-236RmwXNtF zR0aE_Rf9&K5e|+S)_z_|ZYXpKUPIp%Rs5_o!=ba#Q}L&uhvLJ*@$uwYcI{kuy6xb{ z@nyD!6Z2;V2k=WI)D+x@o{rvxs^Z$;-(=$B@uN}ous5oPwndfhWK=!-l?pU6gF4vq zJEI!eYWQjBjpu}ebM2WjKnH-2s^BbCyLS+(hMbG4At$4n!~Jb+Pd-9b(95VQei&5+ zvr*m=mQO;}uwKr$MsBVLnv!H!-f33L$_q%Kgnv)41$DryN3)n~ z71Xn*T?6l;Dri)a9ih`v4e|C1?Hpf>s$o6hTAUG7BlI;~Be$OXS_==j^v|Mgbjg@c zKm`@Jgkw-Opbe@PA4kTH=%kD6qRXdYx&-h*Tv$N(x4yPPdr&oC2dXvj!^JlJD|nUH z71c=o0aeFNM9{l1?*sE~;HQd5oReR(MsHO3~^kzf{eenv+?$AkFq`R(?tF zE;ezjZQmS}0WB-vOh5-4?^=s>r#Aj7yJT|pd+147neK5gG&8?&dS>C|P?K@C0sGQz z#qXn98f#H4l_luu=ss8RZl{wn3i1j%78iYr*G$ep8*7tHbzoM8jmSbZ@?+qd(#)cX zCD}QXLtQ7^hPFX9VvSL)?Sqpn--XJ*k1GBZ#~*Y2Zd7ak2Ir@vEwo8Sxrn}~GInwa zPDM2`G0y)m(H8I-s&sFn+6>R4s`vpHf2;FDf*$fXhqfdBNF6Erul0lq{)3K`{aZab zceZvoqV3{Z?XY$<55o&%P!zGqcnt8;fd14MlZ~ z_eIs3tc*O~-G@St%(C%IQ7x$2FCx@_-{4wWrL9x@J%ZYoO11ZslZofBD=Yu$T3hf% z*Vzo!c%6brn%MvTyz)Bmzr8|-(=)By2j|+6+%?xKx(s{O@v$`Y(hi{Ja7u{t0 z+XK}ZGZwC$IvCZ!PRhwH(SWa>Z;Lw-u6b;LYGMxDX!8}81}}0#eMqZ`x@4iv-xHtBsn_QKOoCKQC9Zr^iw`04TscSN3^(7UurIL)sbm=b=(j~$fa#Wk|O znr-IC4@wB9`W3LJU>8zDLq8)YA@WTlKW=bxxV@h`I3+yBuNa)-J#$Pblth9cQ{=!g ze%z2`uUkw=oh(0AxuV6m{(gE+lDC)87nXP7=syz zi7H|ESifp$O1Q+29hMTF=cn>B>{syfa=(h73;fvODc(nnT{1bsetd4CUoku-Jle0~ z=Mq15L`vkNCVtw8hctC z3$xsdm{8E}D4XVzx^x5liYrpQIk3cl)eKAU*5hnr)c;>_7y7M7B!#>96(dt3e`@OQ z9GM(G$B!MA;?3qfQBUdihy?Eq+@(P=%P&s|xAdz>aT8l=imi^qzQOhKtA{2r3l&$U zc)6@&H9Df9_8!M+NW(t)Bj2Cwr;Wbe8_!{_Bn^TjK2EI<<{b3biNve$}LW%FeW zP4Loj>TXyWv^Y{zypLf+VJrj&r-NSsOJ(h8akzqU%0&t$_Y<5-q+QJ5X?{f-gTxvR z$~84@!ih1s&PrjHA8+08AUBK8>&@!c0NRqT#i_}Gi@Y4`$6b}|HROg*l}G&L!xN&( zxbA-X&?N6VLaOALpc${@lr`$tJee57UQ!mK7^@-9Q9xQk_)fnnJtgv5D?e^rve)2L zTSg?9loXsA!-&!K*?!eH7SySJ-1ua#F;{*?Mg924Sasu5!uR-9<5RqM;1|G|hbt1o z4gJ&!DbZ1BcNbbxv~OgB z*YtGj7=z&n-T<7s6|~*E52rOmNsQg@!znWoywl@(i9sAYiJ2XW)5fH|gA$^*<1X=A zKi-SQ9yd8T+|^H=%q*Q@b1-wP$Q?NKkfpyT(T~kc@xDLHj$*J9ymPqgtlLcCGQWxx z8)2%Gz4%08xUHWyCE4rOu5N{Cv*UvHn~bZ%iQ#sB+|=aAZ)f{yQuV0ywc1~=5N9+wn-i_ma| zyjDEiXhMPw?obxH>2`VpMAZ^(~- zBQe~`Ps>e?F6zp6(ERk=r0_+4Rc=anz8{;H5_z|qpO(iscJr6zC3{22q?tJ;=-tma zjUDqiJR#i2Pt8y9%6inE9qRuEoHkCdio)@JY(Yx2gmz!zR}W9}))TU0&)$g~yujaC zknANTghF)M_AETrPo0tC-2<~rKO;XOvMs^iIpcb-F+J9Nhy0q1gzzxGqA>W$(T+55sM$8AK{x-sfid2- zSWOc{#M0V`Qw`M5*7_Z1i>Vox5b4p|kK=+&Vz!%|~wW}q96VJuAu5BFoQNr~PB8yKX0 zj}Ys^9+S}s`}_vK`r2L%2~1Fe=ofXNOBm}3s;aVx?EIR|rj0D14z`aa~Gu zE`x7lqU<*tnosEZAa#`HT@{2f2-(=r>q42A)u#KLPCs zo34Z{bVrb`)1Xi&F9_XB$g=YWyL!0+s47p1yfWC2o0IJQ9jpPf*PV;}ia9A>#SpuI zIE~qW)i}*Q>yE2iXFv6ZlyI(J!B5WR8&bRjtSK!wyLo#Jv)eV~FXyJH*sqwI64@}! z-#Itg`++D`6%$-Q*itv9c-L`EXm>~b-5FsusKmd1YUycDnh2s=qEp@M|)HGTzb z15D{SUe+eYU{tDY-bg?7rWEfsjvLKva69C^f=k7n;K%1BcnMe7?gSTx@IpUzev0=B zOkH3QSkgr!YdfT4^EsTYOzuaVJ*jZf!K0|#PhXG{9_LpUCPlx;rv;&bR|YF`M3Q$m zA?3H5r^o0}h$1vt6B4|IIGvNUlY^@Yr&b3Sig07U;^vg-q%oxTt8Ylsk$y{x_bpzN z!C^lyLANxwq=d)&Rs3A)$KJ|CkdCU1;6my(POCi%mvd=L!P%Xpo;-p}Cnd)uJEh@R zJBqaO^28X-WLpW@KE;uiDs{E&b5(5vbhWz{rw%mmYdAE1yvkp8Te8=gVlM=q=r6xA z!JCG&^HXy}g7+kj0nvQ3v|5a_qsd9dC3^jXdT&gAg9 ze#M?%(_0( zA&OpeNC9aJ{rQy!Ki4rYdaWFXjqUQNd#qNMp-78pb_4j(heQB+a&)C*s%4 zNbn}(IM3|;X!Hpjx3Fxn&k1QDm|kY)vT1b#xF9hGW9Pbt{q`rE+GqP3nQo_-wV06* zxnQ~1y6IBfZXNFMh@4ScKkf$H zm31k1{14Y@R{gjeaT*cZmM?LvD=iYnVCXfR&o&OX40pJlKjX#`XXon9Yi+)WiEqMV z7mkhQ;>KOam(1(jo45;cJUeLz&JG3l9x;A=R)Uv?)2^{)Hom@gj&+B&64%|Yyduf_ zgi!4$B*v75LN}9z<}OtWSah%9)L5IZ=MA>YcBl;Q@S@v;>l&n7o|@pbnrm-iIhJ{1zHF|a_E>V{X5I%q zmh8PmTmmWC4h+D4oQ7CkPHcE%aQBgu6x~8-aM1LQ^Xl)3`8eA=HT^T3Izsbk`k6Ob zXNO`ct`~9EJ%n?snUs5Rm)6B~n_t&0;uhoV3SOR>7=uZ(2^ozx3v7{gH15TzAC2`i z>V1Y&|2gR?r0K%CLTF|`+(pC%k1El5iVGg9*Awb&OJ{lQ!3_w?({}I5r1q(EMK~>I zyD*mB!Z+1zKI%ID*81C^6gSbvQOZsn``9h+!He7?4GxrNaO?{gciwHaYeKdEh&x=$ zsN3sS2=7Xs#_{y>Sg(czxZQmwC3<+Lt-hoFiPC9t-5%kc&;z*P!5gdZ3GrOSy;evtM04KG;6__t&!1M2KgtRllCZi#5 zEFSQ8ZcO%OJz!Udt@3f4HVI3AF!v$2V$}U zu(mUD`8Ycya7kTnwf7zyF?-yVX zn#n|vq~{8|z_^9rq{zjcM;x=7!5bFE`PJX_3a{{YzMdSt_75yLKb^6uBBYJQ7GRy6 z|A;-ZSTz$8A~!zb?|dWKTMyKs!+|s*A^J6rH=>i1yyBI0*DYQvyt2~Yxj8v<_9{Pa zOLC-am7j(jT;(s@lI(r=N82>+9Jw_=^HD$U&17%FqxG{t_Nc$?&E)8pz>ECKElJ*r z$LyYH?AN@S5d8ti9ow5pkxr}qWp5=%?p^Kgd@I>Iu-cx~+-VL;hzx(+PkTE#y7+M= zrisz5gm_CvW8A1c& zt}-EdKdzUbo{<#&Sln;DB`Ml^4S!qIuil&#y@3#Kwcbqfwi40+a_6`)A^JNmSzV0u zeoBKB{qs}w!LNQRDSF=1q0m@A{q3aad_t3h%x6DSdnMN?l7YJ*XsQ;xdB$J1E!jJD ztz9@A0HYJUYjCzVO7hfNKkfbG$o{qdviFmtmp#i-8H~&dLYD?3^R+@j>saj3F3+(Z zg2v1zbh)3-R8$dC3LbF^xjwD4x1C&PxCNhz8$%qAjjXemaee*t{3I{D-d+l66I*D| zdOvM@viC=zHX`p&ctLaJ^BM@=t$TM7QU$>kHo6nXyEyLW&UwLdCg!EY7)<{lk=FM* z=j`=8^kQuRy4k-J*NK!o%F(7`IluMzq{zE3`f)pwz0)?>JFMWmj9!E5;#a?#6nS)m zzjH@&q|r-$Tvc);<0U^0dEg~~8B+a{zq2YidgIHX&{V&=Dk=Ikp#chc-CwCaEO;)6 zUW-fdD`zG}CT#TMK2G+QZnOgtyu6G2b)&!R$QuAxr#jXx*zvxa^$Di{j^V$y`FE>USK#&qO)=RgLj9U2whG&l*;-) zeY0JRcIeV@SNfHyNzo?>CHvJAlDuyTO{;5D=@xrwwk`Y+r)jqC)Hm(PV_hL`cwOA9 zxS@5f%UkwV)TUgF8(0_jF-{|5<66I6_ez5inSr~qF76H7ggQ51tG)NI`5wjTJh1LN z+~7Kw^iJLV6J<`vX}vQathCo~2{_NM8JZCJ`#b)!FOtIp{i-igyocWng)R%Cn8wK0 z@A_%GlA{yf3-;8mq{uVx`8xqkw~@-P-j(EyA*61xPNr}{#Er&rV$MtOn!j)N4R;F# z3En7Nf8yAHEQv~-njTD0^dC6xeugJS2Y;Y@TirWsC3F=jIMBugzy8^s;^q9gcDQx< zeGwN-jHx-9OY`=+VdGjj1~)Cptt;cJxN&vv^bhN%iMTwR8(`c!I6F;j*J#U+a5^fz zw+QKS&QOyox}#nR(JSQq*86(J5O6adQ*dsTP~J+MZK!rw%*VAWK|?VOr{T2CdmLvwp|}G$yMA>76@5}W zOmd&&-1?=4Zq;_z1TFUF;SQJbHO{R{Qug_@HlJ!(j8jS`lS}H?pZd$bXKQ{|yQo#s zBHZEZpX2N{*J#H7r8XrUi{@7EV~3Ioco;~>jR~sLTdplQb&tyw?u5VA zHJU+6#SIOHMQwNlXFIE7sM+UrwbF$txE`eBri7F$aGGsqP6w599|!2w^{fukdwtG9pUFFTm*Z3k*OwhCSso&L35Ry={TI49#S3bHfJ z(T8ytn99N7UNM9;TJ|>mTM6MJI;3I8=T4uZiBs)y>^&vzH4zR z)4H`Tj`srm24f$Nn*e?vlkly5EQHhZa@=6@*yZ~+&aSxSCLwahcmB>p$qe{Q} zP*Sw>_jFAm?|MR-UJfR%yU*Y*^(%kx)o`C~lk_}uF`)@TriTb|&qMZK332Hlbmb3P zuL`|SXqw;pw_Xi@WDy3a$xn=b5K1S+wTWaa>Oy-7T^_KM{kp>;Hd49Y#6`l%k$wA3 z8XE2Rvzn346+4@d+G!VM(l7RG zoX{(#4(qbn^`HhtzsW8n)Hg`3ZT$>RyC>MzUgYm}yN;QhjkAY}4xXFKb}Znvnhc zhPF_s8i!Nk?9ITt|HHM4hJ$559Ovg~oT{~ZYZ1;ijpgrsj#Ev+J+0Tek##(r(WKG1 zi;1)Qe3^^0ZTfQ~6L%ur&p5`Uq2B9!fj@z??DYAG4Ke+6?Thq{F>y^vc6E$Nll~H8 zmZ9GHo=wiy{UsqX#WQiuh+XZOG->!)vkdi8jtvLDrw^IJo&vbwy@|UZ zxXB2e5DwmQQQ2dB;{vDq2TtqagvjC(%+3~!#YZQYxRzA)Hebut_2W+~FPF_oQ&`O)_zJ;p}x(*JK9G#l^pq7;|zsxUHka zgS?f&9WJC*^KkGEgud)x@Ngq+n@RZ`PJ4-bJU}--#q4ZF`^NGY4XzBRexYz4e=Wh5 zreAJdgX>q9zX~_1&UI=TwpT9`-z=OExw)lDYfZO*ZE2RF-q6^3RY&fRHF2jgOy5I$ zo7Sg=lOi4C%ra2ql{m8#_0DJ&4qkECUfqOCrmo;jiTt^hS=NR$$MAOwshPTbypT zZ3}vwX_pM=6eCfI%L?Lf(db!Wdn*(fahBP61}%FJGQs98Oo()DYtqi7Z)I)GGSvH` zZ8*4{VXN|fB(`1Hy{Xk3mm-|asl()hc4paGaPTTAMz7u@BhNN*ZRyB!P=>E9 z9r=l1-DE@uv}d$~i0Cqc7YD&eb$dG(xgEmp*PmKT+i-TmwFb{VCmj6N)OPw2+|;@u zIR4ylsHo1(!A+`l(JycVf-#MDJTDv?8;pN+0l|!5exrK`4zo0|V>mS41`WaVAQ<_n zqg@mIIo_h)A+hF7KHK|%D(Fp_{eV5>POFQwmEpmgPx0;~tT!O_C-HV%Q(~Rt* zpjJlo1%i`o@U5fohysHSN z)kb*F;tnTkbOB4rmOF%ClC5n4!E77cN6=NwlXdNwJx$PMYo1s;Dqapj-ALK?tix#+ zbIdN|F|Maw@PUhb($nnh%sRw@pTc$T~-%y6~V(1FW_8J z$MmmPls6HVUYp;08JAJ(qNfk2>rWm*?vB*PR|s|`4R-?^$G_pUvN@pEC3u4e+9Qek zI_?eb!Rd(Pj)~i~FL8Qe;zX;B_BvJKMn2G~#sv&URLB51+-^4bKCJcLINd zMUI;!4zyvozIA0T!|6(I?_&Rq(|I2}xOg#_*WOI%M&ojvZbF*qC2;g+9CrcSvwuiP zHQUlpzQVfTTN2UBal8R1)y;(Ly`#?bw_Gavi}Oa>(QD+_ypR}!v6nCnvBBA2u)Rg7 zv#o{~Z;eLTYS{8z6fPNMmR-UyUISGnTt;3^jB$pg!Q1CAaq1cGkTMgZaaS_oe(R5u zyevX>N29k=JSafz`q{-D6D+3-M%x3-_VXs3y(QC_zJ$}ohEwLr#PArCb{VZHA5(jU zr;X8VIKF1U3(}^kCayp6kMSM*o@8PIPvQolGR-U#ZZy^|aAss=LiA!>vPo~v4Z$sA zP1*nw>;&n!3-0(L?XEIAp^>7iOx!?X-@D2-Ecl&QBqrS~gGR=ro1JL%+;O@-R1f61 zxS8Ns8{9=O!v-%Muj@~c;30yOY_QP;-Mv+A>=mPct($xJYj7F_7COu9DV%1GZ+qds z#c5fv(7A^{kH5O3IA(^&i@DAPj}DQSGfdo2THauyy{y=NjhtwfL8F&U*1bvPP+Gi@ zAg8~A?-3kegRz-)3C0n0^bvwC?YD;$bemF_;5vdsYzbQq(`HkHi?XW7Am|c2PS6#$ zpP;KEIjgSXxda`3o1n`Un_ZV}0>MGHwnquNv_BDaY5Pp8qc;;w_S1RIyP1#<>fk(! zTsGb89Lb1WKb?(lsz=hsR|#HfgE2Y5B~5fVL6_jJ!}Jq^mzvh2!YN!5g4|Pb>#{sf zkc*gd|NSuSo2L^vpmz{-2|ghh6x6F>eq9062)be)KTLln=yLTfsB7v1f?Qlx+4}^! z5Gxorqb}_ff{s2;aDu5kmg{IC`!9Ixzk`t505|bHdYsO);C)r(v?8-?EQ=|xi0bU} zThFTjoE=DAG+GqfI|O_9PsizCv3C!T;BK|f{Z#zDsY|krpMbtNQW1@iYuH~YR?n8HH!DdIM)%5vXwZy|CaM4 z_yvw%r2UfQwVPGHgef>(TPcCt{WUn{32y$QdvUzQ;`d11uCX2FE!(EV7>ugnu7t6u z#OXT7(-mj#w=T{LT>EQn;r7~+hEqO%rC7{&Y*_pl?y=`2c%kcTn;M$s<9QYxj#ZiV zrerCO-w2IMiqu?Z;xgF|v9p7RmrRz>ID(g%)(Wm5$nCd+-yTlT?fN=;9YL4&HG(|; zC~ZtxU4jt=hgf>wVfr_M!z{g^ye`39g08SP3A&0;np0Qq7=n&2C+N!kmY~bl;|3iN zK^w{my0lvey0oXvt)-FibIs0aEQ?1$8bc0D4&xti+6Tc?dZhb}X4!PoOuy0I_VCqA z4&`+?Ef|hy)>`bmaPWntrgorj#P%VwdGPjh6Hd#T>EiKjKhEAlXakMD$vz?3EwdV@ zlb$;(E`?v??CUMvOZAvx-1!&OD2=OMraQ@8yEOo^Z~B+6}EMM-I+j zN0#4~;QbM&R&hzbEg|yN0<$xpPF}Il*21RcC3OYP-jKxe^`*by>}x9hisG}I!@)O$ zxlrR0Z>hU%;}+qDQMQfy1UIP8oqemlmfN^eoL*mAw+UC5FLLrCv#cG}mb!s?U)$0x#fC1OD)g8RRc^TH<&qs&v;lel4mGS{7uy9;1rO_;U(> zmhk5o{@lwSed?y9c(52qKPitj1tR1HgVzP<|ea{RE``i~G1{L43?G%_?MW2Va}Rd9;)QdP*^qyFY= zh})1Lp1X3Wu};xMT$l<_Z#|yMgOc@ZpLP0Imi>0*>RLU=GgUQ(sjf2V(H4 zuNsL(j!PB1&3UOBa;NjPnqC{IuS(eZ!~OLSBBdJL%h@#Q-P}e_qgJu z9{yqHr3$WaUaF(-G3TZ7Pdj}c)zW{}>6?ykbGk!IOf&d7fd4{YxQMTv{^0Z=s)E9_ zP8GyBJ;CWIPFp)Y3sw5_oOX9S$!TB52S(_>3LF8@;X4}DM@pTcF-}ua&EQooUMfG{ z#ZPcts(cyFA4wH8$)%fYs_qLnj)jCKgA_HzMNO44hh}j+sl;sAe^Rwr{|cO1Qt0BP z;-${lSD|Yh|5vKb5S-0cFATa=?lK-p)xbF}zP?7xhWlA#YR}CsTB_u?plbJRsG{z0 ze6izqIW>ypQ(u*DnM;3Og)LRhISoaaha#83bNwUgU>{ z>J?NC*^FvPx1#FFJI;TAs-h}X>1t5r+l8uP{Y$Iz-=oUEAJs?NK+hxxT*M)#5mGBd zBmHoy;IaHr&yPdZfF`Io|E6~E3Dl&o2)781_EQ{|DtQa%rP>^)J1rbx0H(bOPR1JF5`L~_lifSM~LiPDiR2A!gaG(x+(vYR4imF|K^;M{bABz90i?6RL zV3&*k(#1<^jF8FD(4@l^8N07D0q+s1mpcrs=N&~4^DMiXpYyRcPgs*(@_<8 zrc3v)RO#B0PD#&o>B|&QLFc1tVP{kc^$%*RCq0}`bpAqA>620Z3+ex#rF8uqAAl@?Hq6jT*uqxwkYbDWndID;Q* zV3FhXHMr9(Awm^gjcSPJqiXpg$8U4~E>t~VimIY}oWI}s2T@JUD(4?VRnAkWPKk}E z>UkAaIj>7~w7p3{1#U%^;REMCMAh;gs6J8^P=%_1YE--7Z_a=1;=e&P)IXuR6$n%4 z@#qPt>S>1R0@VsF(>=%8F5(=N|3aPl5r+;$)uR!p3QR>+z*VRkl8&n2>8N^m4XP9V zHkAKDckx5zKY+GCpF_1P-bB@~j~X%mDqxobKcK2$ztaP#K2q^t(U#~*v`SI2s79hS zs*!4=*8VT5_;}*g@H0@A*Y+5<|Jwmn&^a!_xu`z>j;f$eF5mes-@mPc$)J{XaT%p* zVOQtttI~CMT&i?EP>n>AxY@A4J$v?c$&REdCWUylyRSk_$BpAhQkB0{ zGpdjNFM@i4Sm`pZav7yc_(xO~uXbFjo~?0Ss&r4G>Z$$#GsUlS{&^Swg3}kBZYU$5 zf?q+kJKse0sjn*dEytxQ_+3;LZF5|zUAoipPf+EncKRu*PkmLrWi>9MzN+BQ;Y#o& zstUhyey>Y^Bvrb7#4G=gE?s>U-w#*Aenv@O7W%tOC{+&{umDtXBP|4{${2%}9_#ct zR0TD0>Hd{!Z8amEw1vyp5^WGVpM%X6AXR~<1`!+&sCslJ%73AA`4Kj=*MwX2Q9CZg zN_z>Ty`3gIei5qr`l0Gie-}SM@n*xV>^)^4iPZ><6-LuhC75*?c#mDtEr1RePg;GeGUX1=aZ9<@^$-ccXmeBJ{5F@1gogRp19s zKXmaQIlmKC$7)cG!b^eT1Jr z;P0Xup>3!-^dYLl6beGf1ziP?SE!efy-P$(y%$SHr&D-_iXsYRK?xr;-sqdey0yOUGCzg zihmH*x>@1;ADljd>JzA0^ektgl0E9MRMo9^UMl~D^HLT6r1Mhc*ZwJAxy6@oHSUJ&o2MZ$GWpn zKoJLAgj5aD|EpFXsn-7qIxha3s()YnzgpnGC{IJ*jCggVy-QbC8~Fc7%j#P4?=(PD z(t(z%C+DH^9bHeP@|~QQ%AfDFv*S|b?-uYB4o4RuRfZnUOSRZ8M71`0IWAQJDdMK% z5_dy!iHnvhTK_vDT{MQFDt5Swm#VnSQC$PBbbgGBudk{;9j^T2T)GJ^T|KpnSU?3& zbQvbOgi`TLR8xPg2xa8dSEF1gh|Um$1HS4Lsubf2tG_d_iX_sx>p6KdLy#YFQ}P zfjm^7BdOLv0e{q^|KM9XLB1n@Nr(Bb|Lq*g54paIs}Gc5wM$T6)u1Q&qxd6zJ4ac>m9FmFIf8uT)sbhN*8h@D_~^HE zj($sr#i8}l!|Bm)=^Xu*j=cdm`YoOM-`3IDJBc6KD@VVja~mU}5jpxT9R}g(w{)}= zj($t$=(lu^eoIGBIedHGS`Yj!MlW_D~I!C{ybM#v}!F!dX-_kkyEuEv^(i!8v&2aQvI!C{ybM#v}|G~F- zYQJFcU;p|~WBYoiez|(hbM#v}N57@xmd1bYOEv$0|CUbb|7+jUd9LckaB-d)bzWqU zS$b}yiCIl3e6cxrUSzcCe;y#cBcPvI)e&$&ph+jdWhS)~U}Z&}27Cc86WoxoOsVJ5ZKch-rWJIW?^^04uQP_V@=No>_G<;DA7r zO91mt>Lq}c7Xvm3EHqv}z?e$_x%~jQnDqiN{Q#{m1uQbzmjc!aY!$fO#9ju-x)d<` zGQeW9MWE$nfR6nEzM0h@uvws5V2SB408rW=uxJ3lm@0wx0|31T0xHbHfq)$Xdj;+> zJqH0636WA*7go(Wz zkTn7@`*Oe9pt^jNns1{gjI*bIAUIAD%67Za<5@8>yo|z%pX0}M)H}T_;56mpdpUpPOcGF=zm6VR7l11aG=8)J01TN3_{>yHr0l<#eUch8U=s3Ivt07IIVkzUjF^n< zGOHwCns6raH@2`Ovqhj~7NBD`;72nn8?afRT42BFFbz|mdph8tSvVcALtwAK zucl`XV8L`iWlm&J-6Dq|;jkHyN2aB@fYo_`2IinZ z|2#l?J|JpVQ*djnyAz*e9psCp+(6R{7u^4cYnNl0pDuMPTfZkUF zV$H&<0Xqct3bZmkX95;n4XB(6Xl?cgB+dj3DFw7K6{UdP0*3_R&45{erKNz?vjAtB zg980$0n)Dlv^A@)0UQu$axLI&lX@*+%5Q2WWB=V1P-z2{7g+zy^Uq z#+wg_nGeXF4;W(B3#=1py#O%GWG?_@EdXp47-3=;0$MHv%w7n%!fX-PEYR_0z$i28 zW+zn`dH(-~*EYrmRb_gsnfNM>Szybs4w-hkjEM5voTngAP zP-gm60Co$kr~u3{`vjI&07fkX%r(oG0s1ckMDGF2Gb8Q+91vJ5FyDml1+2UWka;g) zp;;p^=3YSaO2929qY@BP3D_jC$TYnVuuh=lKEUl}qd?YufVTGo7MmIO16tk>*e>9k z_y+)+1?D{fSYoybls*9Hu^eE`oaKP_%K^ItDomFL0XqbiJP5eQ)Ceqi5K#FLpwjGl z2$1*?V93LO`%T5efZYOz1eTitD*#I$2CQBIc*q}LS$1hxviYhu>| zvYr9VUJKY}wg|Lb3+VVP-~%)3S-@t2YJu&h!*hVrX90_z1AJtv1lm6b=)De5Wfraj z>=4*1@UiK+9{kH$%oc%`uK+r31pH`bZ3Juh?-u}OCzTt7s1i;Q}mOkuP9 zbuum81c<%?XkbRX0qFlaV68yZgf{~Y2xM*s9Anl9tb7B|d<(!c8Cw8jHUl;ZG&W7& z1jK9sl)MROVm1n_6KMMu-~=<{EkM?rfb9ZJP5j${mTv*(y$v|YY!lcl&|@p0xtX&S zQ2I7tmp}{C+X34Jx|sNn04+ZR%=-w?&1@6c zEYM>Ipof{W15o-AV3$CG=~4w~zXPzO3eeNk2<#B(w-bR4=xzFZ3`pDw zSn)9+#q1N*!S-cCd;0wTh zfppX7OF-f-z=|&cP!6W#+jAdtBS zFx9LPSh*X}{3}4V$@mH|W)EPKz;x5}Ye39bfRe8Pxn`rlI)S#|0P@X@Zva_e1GWpy zF!6fTVT`=fH`LQ4}hin0MQ=-bIph!0sVgftQDAN z!ao5H2xR^Qm~Ykyto#wsd_Q2J$=DAV^Ali`z%8cf&w!ZyfRdj9i_AuWbpmaF0o-n8 z`~t}O8L(Yov57wbX!#3Z-T{Dbwh3$&=y4FR#LPJeC_Mn!C16aKzXRGI1T6VGpu*G$ z>=5YpE8rfp_*cM!zXSFQRGL2j03`kjSn&_Q{brxQZh=vU0L#ttLx83K07QQSJY+`v z2IzkXuvTD&3I7f_AdvYx;1RP15MH^&YcM*zYDoq^|F~p5KOZ$s!^mSMTe8}0lss-? zBghkG24b?p4H$q(1Ko1OH-JB7W=Wnl+a%AJ4h@mDW{%`pQzd!MbcrJC%tFa}QzLoa z^lXH@U=~YWGM|9#{kv} zY%<|v0S5#!j|IG8)(EWh0L>c%wwR2@fHB7cHVM3CnjQy;X$&Yi4zSg16j&$Fwh7=} zGouM0>o~x6fo&%KctFc0fO*FQJ}}z^HVgDP0kGZ7IRQ|5JYbi=N2be(fc7T4DgxRC$L*!)JcFEv-~8$(q@3@$$-zz zh?4>RPXeqJ*k!`a0S5#!n*;u4)(EUT8PNO`z#fxv3Sdlgz$SsOP16>Dm{R~HEdYDX zMuBw#ZCe7qGc#HOvRVMP3+yxTv4EB>0rO%3KbmaH{vG&HLuQ4>BLX=G9*$Cx#US=ok?o5xd?XENdeV@?Nb5@>9io&ku7 z2b7!vXks=3!pED~Gm#U_49SURi=?TEKMQGQW=T#m+axEO4sDU)2BUhnyHYqG5aK^n*kk=c(Yt`hB+uX(~LL=Im@h) zv^C*#k#;6ka<*9`X>YvqkPaq8a*kOqIoCAph@5A#B^}L1NhcHA2|3@)kaRX%BwbAW z`AAnYOVZ73lXN#7IwL*I9LWWyN|Io@bU_l$LP<|kBe~G@?206r#gblTkEFNh(+x>B z6_OOQ4>7yDGTfuOGu(a5^6r48-2l-ZfQ!wD9)SMc0c!>NneYXG0|J>B04_6Y1XlI{ zG*18wFc}GeF&6+f2@En#69F*^fRaSO5VKKWoj}{3fMI4vPe4{8V7tHw6MrF~WlzAo z3jtS{Z33GGdL#ixnK?;-(hC8*1V)=Ky#Vc#084rSQcaD(4uO8X0b|YL-hc(Y0Q&{f zO`l{yVsF5TWWac{Phhves1!hkS)Kw|nhc0u1ejz-Tmc1Juz$bYrd=F-RR9sE!KEGvUGNs6ggmze|0Cnp5EjycFU@L;LZQk5@H`mJRKbo9ku3 zc|LTjLpR4RVO_emZ;i8hWB+bw-``*!;ejBrgS*++Flk}tHbWjGk{E7}J;NE#WEB-V*v~dM3Bz#)Vq#tUz-i(3 z2el+qMd(2?#y;<8FASPnhaO$K6v9gb9b->)wqIdy^c)yFsGI#p2XnHSIHim6F3|)< zzCQNJjmc(;Cw=Xo81pR>SNho(HUGT`rwB4nr8J#e_J__r@hki^@p+#%z&<%fCFtC7 z^4ta{^W~K|;F7*gcxk-6Qd}8e|JuBF9ko>j=I*gUJM$$vyis z48>j>WxvqO|BINJu2b)bR*_-h9qroO5=R@_XVP?u8wFiF?jXm^M64#5Dy+vZ-P?C* zYnS%3EbJu?8^i5QS`JgR=@S{&y+=g%Hdzd@#~Ru@>iLeGjtqDR)ax-VMN@3_@AfW6 z^ZBX~-eER{0R3q{E0~{g|JrQO~=BGbBQ+4jyYVQI}eAHR(O-=R&~)5zqSVHT)>^pB!1u+gjLq zk^lewf0R!Kr)To`-Xhb*lF6nLK77&U^B4V(c1Qf8ioZeT5i9(26ox6L^ifXInQ!6n zCQ9!JW*R8o%TSmf1Q(DkJoPY1~--O@-m#vdfzoOQP-ErH_F zkw;lmM;<~{TDql^ZhSqYoODYs-FU`QW$ESuH}<(yKpm9gD&=@K(;j)U5r1LFG%4j*^Z%r)GlYq@T!54S6={6zP@)a?Bl%8RbEF{L3c8@~aO*x@DJcJSTO!bju;# zFk0Jfk#0GqTa*QkajY!-sWZGY!@f(p<&lD(aN8~2^1_YEc!53AEx(lWhTC50<}2NN z;P#%41b+pjTNc=H=B@sYj-PbQN(r)P|jHr-C|YIX5mG=!-vfaCjcrounIoj>rhv%GEhURb+&0 z<;PIRY*75UBC8T}pxtTN7FtRtkW zCR$6k0N8n;9{(bwTOjOdrCS^6RuFFKq+46*#`%-S1#0ErPCBx0R)-`1cq%!SDGUs< z(R7e*Mc{Tu)^SJa#*-V*O1DnZtti~uNjIKq&iIM}2e|pb#EIrnnj`yva@0HPzbgb; z)FptEbmNid3|tbVkZ#?jTPe7ul5RZtoN}dsvvm7Kx|M+&?fmO0-O4imy`&>eCR`5m zk!~~@VR_I`y7iTA72wuiy3vneD}tr8;BSDGs|0&z={8WxRfZdnsmjap=NQ07Qw1zU zJ+c0$%D`3W23Y^oq+1B=lTm~$ULoD8!JbhTHIHMb($xXO@Nb563x%CwSQ;~7YRBQ# zz{MZ9C=2s z*q_Og;R*80NE5&eRA>FKgN2GU1uQxi(FQ4q&mU{WL^pNpd~?{>Lm6nV9X-zoTL69t zhswvwuq|Ql2{$UgNxFr>UYes8{x;K%_1_BQm5y7aU^v|F%RakRy0wNI6J{>ANw)~t zsWfx6UAnb_opnpM9n!5W?6Y8JCU;7=cCh=>k&(nn$M&$}yPw+ME+xnm@E5s4^jl-f z5!-N(fK@1-vDkviJRa!O5qf^0y{sua1z)S8E_Vy1N?>(zpwNdaXbM}!81G2Z@wv0 z+IO&j03X38@L4RHZz@;iA*}tu05A}6WZDEc^6*PgJRY7$2aW`zz;9qQ7z4%vzKYG& zPMFxf%9Pj90&8aADatG`<&5IFjg3HK&=l}o#|D6JvipMoULzHLW9~0B+QZ-o_#2!A zrvTSTXTVu-4y@%hG(8J)Lc3fbH{kcJ_JRFi6=YWPAk}5CaGf*@{0?FOfA2B_97P2D zE+9{@odza=iC_vC2Y765IA{niLH07Z3T}YEz&@}W>;$o36Ic)a02{zm&K%QWnE_^k z7*Gb0xr0o=8E_%Sg_jG+03JFbVGs^lg9y+Dv;*xy2hbF>1YDePEmi}JN3SgoGdpkx zp}2P9q0%WpGVlrxr2)_ME(Cal_D2-kXYd7ZLCrbfUY1CaOqk>q?&Ka808Hs4;ZehKCmBD1tFjsxQw{3fUEoj$Te8_CAE`)UsU9W z=jMX>U;$VN7J7Dj*0H0l}asXn{nsz|00*fGgm=LQeD_ez1ohb~%s6 zegW`)fve3_AH9;-#8Q4MI z0A9d;16%+X!9U(LlMsae${jZE~bHfzzdGmz%|&fgBu_mdVTT!y0jLLfitmj_|;0)F*300aU7aw2|yaJMbU&)*^PjPwV9-{as{Dm#Eq zpfl(Kx&q#@bOYT%55N!Ujt9SiF`y^t1Ngz*zMwzAm*?$<0)7>h>Fh)rBfwTDydR4G zg3^rYivR4uNf@WmeD{EwfICQkLDMD(cnpD#gMYvlupSIY4p+cjif~uJ4loS};0pI8 z7(C{H_sG;IBxZ!^1J1#I9{dgdN@nM&?UnFTP-fr&k^yd&I07e;dzHx}A|0%Uq0e5h z59|j6z+f;Blm)G!YbIpW190Qv9dvjPK7fzl6Zj0i06X{_fDzaO6EKUhtFY$tgj&oJ z;a0^$nEbgpKM*kr>i-Jr!)}Io1F}~Dw<`QVL#WvZ)BsgMY2Xh8)Z^~M2CxK70b{^8 zz|8^P_;&+1&bxqJ8|cy&v;*xy2hb680-Zq@&=o|2ZYe~o)utR#i=ZeKo(3g6z#K$8 z9n1hT0dMTrfYrbr@Kcm;kRb21`+@#oAQ%L?gC5`)z?=JCpf}(l?Ud(NX>8-h?R6=; z7(_}1q9MS~=$3&nPji1L6@!o_!@UZdurG!=8Ss3;0PqEVoN+#ZkKi463z%6hAh?()4Y;u2B4Zwy3$XBr z(pD2(Rm1>}vs?;I0nE@Oz!k<=z>;Apbpc#uaK*t7Q?>&fliL7xQLa4LDl38tpgbrE zN`Rt(_e#MqgFqn;M7d$f1=xSH!h8brF?a;{o#(6I3b+gog3TZn{0WeG?PJntns#e( zy#}lXs{mIbp`Z%jWKb4xV(0+bb|3t>+uyCUpFPms4 z?ag6lK-w9&5m13BkLP-tA7z>Wn##W;>hM*~YD^g>f^}j1Or)wDIA8{CmE`p#*1xT`oLTYkRhw<842zwDEQ!&ubN00dtUKB{u2IqPU>q0=CP=$& zVzz0p#1?|z!7LU<444X-&`g*Vo&lx<0j2@^DTNpTi4%yZLg`|a$;$td+aeQkdL_X~ij+y{(D zO9|#Za2MPGx4|uN6WjpT!8L#!i6wESR8jA6;fz@-3wR6rEASG$08c>=&xLiSckPg@Z6Zj07Pv9dM0zQE9Y$@+yv5ingk_Lh7fe{!0 zBVq&$`~^@^!pLbdoLSma!%PNJ04IMg!9{UU3@`!O zxx~RnmL^0Q{*{KC=(fj{S48hInWMOb(>=a?DFZu~eS47hc2ExX%AgWZ?U&uI6|NhC zaL^L80L?)&&=fQVjX(oX57Y%!fQq9I?6m;$(8jJNEL8!Opg;}XLtA_DIuzH{0dEDF zX|74>PJ3I1aR-5y{6JxztHU6U}xiq1YH5w+kB|b zhwZ#U;9yD^@fck91w+AaU=)Y~gTMgL8}tGFKu@u2AM#5l>d*_QqTw~8qbS{Zt^DZD zB$OMkZSDQP-J-erkAaL z%A5K5nPh)Oc$N2&u#b>1Y{Ixz@hi1P8|?ygU2Gy@z=VZFHwI?FetNy|lGQi?uo_kM zjfb7pr)3eQ(oID%5pJq@R9K}C!`YO5qD3#m2F16P!~&>{QbA2;n3KU^O?M}2d5azU zOqrr)z>7f=>c%EI9SC6CR2e1P9*c=Ovz!?{?}Is>Oalq?Z!@mM4=YlS`dURZW2zt$ z24>+|mDU@EQd$;>RuQTav^J;ZHM?z5u)LLsswZo)1lx)xm30+d^-?XnN%vG$>q<$M z;vAXL|I$i+qz-Zu6<;MuRY5{!5=NTXDD<;&4KP+p(A1F2#Hx{nyZ|I@Yb+V9sam_2 zZK0`hSIvzxl4=p05-ub760is?2FmXW?DSg-E`lZ)iBG~j4gLaL8XSV@4i16?U_T3U zH!QorKM>&BFAnyd;3^W^0dpPL4wiva@aOW43!E*|Z!OH_fC;YwOlURC6<`%u3DiQx z6@Hs>{RddDnOI+Mf+ZGg1RKDgfD_R+uoVtIbZ40JfbJJKDV+mn0gLGjpn$C){pm;dgbCS3M!8FXMNgPhnp|=5)|b`w z8Z?FdUzm|Fqh7*t2RsG$z+G?)aDQeNxC%S#l{aqM>3}mx1^9S@LVU#F z2%JC)kOsgl$}Tl5Y|m+7-h}LRz|Q4?>x{q^qz4&*3!p5adnVup+@-rkn)Iigig-#l zrC=Uh=LWezPJ48)9I$u;rDYb_eLz;g1#C8HW|t=2{9rEt_+W+Cd0{HI{5J0NqYR%} z(N1jrP250akuz}`)$kvm{qh-bSx^!b1c5+BP)1%Cl5VA87L#s8VHO6#AP6uFuW1&M zrizE|QM@Px3ll01R6;aM03~eePB&Y5CQ3IYQw7(RKt({e@}L~Bm8qcn;dz!#Kovn{ zc&fmO`Ll!)DoeRKaHk)Ys}59rp|CUeyk^Nz8D=hs_0NDcaG^YTT?^NYsHQY)OFRAO zUJo#bDj`)xb>T)C#Uxyh0Kb9>U8})`srrWIhV(U0TSs;db=?{EPBsy!_Rh$=+PJfs*(Q?E zU-_{G*_Kcg2U9vyK;@3ttOAuo`q`EU{n<8bbEe{87}{BC^jCdBl_vdc!bNGqw%Xa+ zZ3MM`5{1BwfE`Ntsgg?AZ`v@T?ZEfCkSbaxrWzd^Fxy5rNUSF% zR!YA?Hi{aK0;>2%!frd{a2O&gHylR3nRr+()iTYe z^T9kY7evj*e{%qZrh{1^1_&?{Oalx=Ke{P+&9JR5nRsgmW$}=3pGakkl z%kiHHFri>9F}K4k3Udd{o!~im3Z4M|YJj&#h2ZZCxJmsO?vKDja39tCoCGIW|Do_W4)Yio4*OA<2SFqPd*k|V*!P2dU=P?0c7eU%FK`4L z28RH{9RPIaHO+s(DR3IxMSK@wUI3Rs)Mfm41zZESzzuL6cp-N;Ve-C?_jBC=bN2wm z0p9n~kGXsXSQ=E8B}6+*fw@&VWya`F<@xd>UxW_hZ*E$`(gI`$%|TPp2vh)k$Bymc zB?9rLq8!}#21z!M74V@2e+1^8BWW^wtVDbU>+R=$JHcd_|SHk(v&nAt_{OQw*h+_2^XIRW2wD*;M@ z(x9ZYmx0M5EDx%J%Ag{s1gZeOPtNzt)jQ=O^17OI3x!EL-$rAxF%uCW9JB^)SXnEK zqSs|p)u;}zw+HP&TQCSjfoQ;fxdHI?rU|$n55@uRRE&i=6pRKQxc&|1DDW#74u*k| zU<6XUV#|*C!G4(VG-|HqBhtK%Jt%_ASncts2zW%-e&{M2JP!B#{ zb%lWQyEOw+-KmmQ6Y%rJgMwY+Is^gcwGa%;zxlN+y%LP~F^pbLTlCesBfj|xJHBq}t$vWq0Rn+T*6o7UY;FAG9OMms; zUZKjB67UJ|4e<5XcW@Zy--~wb9;d!M5I)GaufLz215T?#;vOOfhDQLZBR%9U1yx?X zd`184kPAlHqJ%1lV-yI303%vx28^0rYm1g(KrnP!EPa|epV;;(@MayQia!4_=VLqco^r9x2v?(lGZkau+`u~b zFSRiHfT3wKAxxleAZwP>3f|j_KG|VFg`h95>ua$U_RSdRuMHt=NrmPf%s%*Z>e@!b zO?we~+vIJ0XD=deo7_CiXo=W&ir#B?zs`%XZSzVc(VEfm*jk$f?Z}fkp$HyMA zKr};8oV3*Yt|`#C&m>mfHMtp&nZ*9PrfSCXCgF0=6kvRA60Kl*@OL}Zcy)wG{b}q; zAH;*E!H$(ithtA(<*&lhLZIE-c_VHigY+8QQ^ zsQaeAj-L=JGeT7th6g71^vf`BFdz4p{+8y<8HY$C4!y_^kF0#%4})BE!i+i_l#doe zCY-`E?13o&=V35Dar}WPlW|*e@hqR&&3G`mh^qwibaLVS5Lr#=uCA4tKwkXw(3H-R zzcFDG|3f@|XsT}9<0MKxG6h(YXksXyzn#RGN2Y2){6!42*2mKR`1O&^Uswx}FU7MF zKJ2_Vrs3UMhvCB!3BBf_lSus-EsZaDvQhljy~FlqRqyYIgdEjOqReAcphs%>vUdEs z9-A>Ssk7EXOC-xWJ8>iqL%Vw@_Xe!n{MMI7dwX&Pt#pkD{OhHYs zQHy`kjdngU&${wB7juJ{F+{C{GnH*n>!0e)UL3lv`DnxY&NL$QnW-8Mg^78F);Ix8 zkt6N9v=JRY7yNsMCWxWN&u#^dr!~74ftu;@n3sc5%PQe1vW%*C0WyJllTIphLAx3v z^K(Ss3}wkG8@e{)Sf1b-o24Gmu&t=|9NC#CVm_h$&3riql;@dTuI+ z1Ef%G?l}0VRH)hAc+N@Ge_?84JeE=Hc!9$Y7ubQSU#U^wa> zkUl%}#at*>&#kJaeE)#)|X zIt`ifXON~8GJqRA=`*Qm*PO531s^vW{5k)j0G5g05fmrX#lFEPx;?9S^af3Se^%k} z)>O@M2H`k~)V?#!`EuoyY_CQ1ByVOFUEZQV9%mJyGcYK<%__FNMLyGH(|c9u%u6m| zF*!>?NzPSJGOKv{7D^U}07t^b1GA=Uw#@UCEI9}?h7Y?<%&fuFr$1aj6+W^jw-+Ve zLCIf4gLi0~W5j4)#fU|`S|rZX*dS89N3rkDCUU)pT8FcVrtguFi`hi4_oh50ZXs^= z-EYTV<@l*Wd)d}9N75uC|HR0n8pCKimx4G!|&nT-; zBz({aqDM__T`4Hv;ks6zN$}yEGh{)Udu`sm>mz-{vJa-r9&6yqhFSj1o*B1xx~)MI zE~uCPCUN}(O6WjN@$myn=uA%G_Yoy@Kc}er(bNVfn63K=?_0UV5jcDJ<<{dV)%-=T z_vPlSwB|M#Cn=g-ytSTK5mFq_D)cQobL*}OsWd4pnXtd04IsvgxkczFq;e~_X!i*n zQg_B7Xo$nrga$ZI9K%54Va%&Ho70xKOLaEvU8qHbK@;P~-TWlqIUEwrYS(HtRy_WUhSfs&d_imT z5@AO4QhyPa2E%-pFBlh_iZpLwpZ^5|VhM3Q0~SY@jb<-H;i)Oi?j8wi*2L*0m{VHS zsin;Bg*q0{YyMrO`&s7wZftJ#9}OSYeC5_-&riNIqnOnva_U%wTqXVc%nE7PX50J9 zR{vx0!L4v~#(o)l?3ljV)#~Fo^&)gChl)Xij*eRwur(;vtiudu_n;*ZKm&@d z^5x>*&bcq1v0~ZXN;f#thXC*Z$GOk>0P(h>rgzhE2>kLx~#y$;(1C{kAYuRo2&SQ8usu(%Fc+P z&p(}edu%aq0OP#^voHMZG2xdGQTB*os@V0w?CJ^kxwtt=gAkTC!%sGK{MZj^a(Y2L z7}M>|ftKA6U@zI>RI6E*yahgKN)@8O@q)r)GPf~aD=3DU%mE$`Ajx6MlJ(`$h5q$9 zNBa3<5XAEUal&K{H0~}a9L(kb94s1a#^t+0qKnz=h9ewD;1Y)|Zl%#yJT*f@ZQj;8 zS&+!;U~UWV(GGAQBNjR6VJ|qC1B^S1h}6lD_DL+bIldjaX(?RSJ|r#DmOY`XXp#)! zmWiIp%+-yLgT-FRH8%$1P8gU18CJ6P&Ce zODR2zOVS-!8+xFa338YqIGV_b@P{>NTZQhz*U_xHpMy4F{3!-HqMBsCwH5xVzC{}+ zb0#IFHx7@4Jxj}j)@NIZV@}9}*8OEPDo1K)h!h>s@4pg}1Hun;B-`d_k;>(JF{qSe zo)(IE>Aolav zpmo9k-i>LUuz(q>5Ib4JvhZZ_|3pQ}V*Uxqj^adGWb!8@f3iwc4N7IdQ;14ZD*F?X zQrRC%dQ`ALrD#tFrKO#gOx(wu56&wUM@o_~M$Np(NJS zl=zPtwQ8A3=i$c%U@(hanf_C~{-|%O+L96fgbImt0e75%des9HeA0J`-K*>U!Xu0Q zoLX}W-bT$~%qxW5zab*O1z8#`Dp@cCWEA~*l|xL$mGMES_{)M3Tbo1NaS-jgmsq#> zWybht5Fwc%|A&amjD)vixzEL8VCcP74Rhox>1-%fTi;Vl^!5dJn^@P1zcXXF%`QAV zao^%wM~|VKsNo3(`iu6Sh~6ZA$CZa`U40pRAbQ2=>FX91(6raqS_Q-jidPj6Dc1yY zypIX(Kk`@ef}NZN^vGB}nj;q4!U339k-;)8`zk*0dt z)%Bme?#zXQyyxfsB~~=JEt}wjKBw&px%g;09fmYl9b-#vJ5u@g-S;7l#RLCvYj(xQ zoX7D3BzV_R9mh7~E*;w$`LaN52hoC;38lisDmd$H#6?`pVh%Q*Xdzs)nyXoEw9u#a znu9uRyR_~P-V5-?6YH19EySR#h|?_AWkujj;&4{;F+*(;lMO|Y*aiuj_#Ez&49kwj zr`ruF#l#wB7f#;(c7EbicC@CY!Y2pfn<|RY&;(pX#~kL&h31Fr%ZHC=s~RiRJv!1_ zNlE*p6x$IEHwDh+z=G#h%55Oc%KCS$P4d)4eKK!w!KD zCzRLwH`eIr^Oe_j5z%?DJL(45J*E>a9A z2gko6g`XeH8;Nyq%rfmM_GVS~_HXx;wP7NgL*_ZOW4U?#1T-s)BR_^OpFjsDMD_gB#+rArdg zi^T=a>6}ah_1d02P=uC5Mm7!N(hHGZ<`at1a27MRZ}9Ee46m(lBNJDb#V0 zKHx0L?a^%A=|;R)ltX7<_@qZWa(y?%#jAAc6!78001RXLLnY&wL84|6%w^hBmB9GE zUOY*bb@MQgI%n-b5RzNFN8B8K0M%fARwE{lzGHw|x zEKts^rYn z*8ce89_u+oR4b2MeA{#NW+_|X_tNMp;)v}D2SZs*VkVju**r6q8 z_3&-E+cp$2u9&%C!b%A0k40i?w2@Kwyfc+=`ifh?vW=7(ru}#=`p&p9t!I|)$B9Jx z)EOr7ab#B|uDX_Nk$Q7-H)a?vRzu8^$Wl`_Py{I51no~B01{i1O2Go6KnXMn*$_Rd zVo{nFN|y;(k@e4Q8Eh(~i5Lh$j|d1bSDAZ;josDt&30>zl@RM7faMP5jNg{ncUx+c zkzy8Fw59z>eR|js-uAMC=Px}Gy;L-Mq&UttKW3zOP!f$$7KsQdWezo-8YzA)Wv-?i zzbQY}k7NfCbxUK)QjV(k$mTA#!87R4Z`!X$qIWqA`7Nu+|+evZ$1r9_?4qBJCeet`rw+N0<1dz*D;_p-c4 zkP=Dv895^*>}+Z%QJwXNVz%>IP|{Op(o>~1MJ=kNMgiG_jjEqogMHOMlk}I>Vu>85 zuY*31{IYM{)?f68P}*2Kew;Xp5g=$WB)C#=a%i)v#{G|R*3#S!9~bx(7`b%Utc4|n z)#uDOVX1)TWHV$Y)j&1(MdQUI%B#j=6HXfn5^+bk{K>RcZ$eL1G_nPXES1a!E$Juf zOVbkhdhc8CY3oVoDx1EVOI3p%Gf{YVhAwJWP>;%$e}b+e8do-_^Xf54ALPD$Hl+Dz z_i82gKqv#sEAM2z+*(K037Zp`HXn4s147PkrQnkS64la%j9dDptIgQOTdm6GJjSY% zg;N!CfRlP@;FOQ3SOvSk3#W?JRnR-uP1SEm8s^LMcx&gEcmyTyYVCGR6*mylcyg+6 zt%^Ic%TjXr#*a1Dl+61H`{2Bd!0q^hsbUZ$jHjoGBUKUSO&s*ZQK`yti(}LNXYiDJ zkc{;Cv}qwIs?XCzrVw)-38}v2eY;|*9qxT$P3N?Etcs%}Mj%XZe zZi5(ig_`r4!{%Z9)Ekv*2;a6mH9WZAA>`f^0=nd=UrNys}R!O z!9Z0_#$RWOYc)_Pvk)bF{$T&pzqsU`+)&H9))^D649y3X;afAQ%FrYdtqjcvl`#Ne zEs0i!CQ%_qtc8T}>!P=0UaWVh4evZJOo*Pn2}NJnH-I5>Ef&>kA<80HvXyq zt*qQA(j*Gn)m$v1Az|#gSUjtP2Xm`ynSZtX0da1bEQxqLvHbb>jUbMjyHtaYN?3h_0?r!M`M_o7mG)=k+A=AeKfFZvt#e$3ElKNP;C^b zxLkPGK}qF8TFyx8VTb;|Iu;F@qpKE(-JS*r%X_kd1IA8&F<|`_t52Whq6@-W1SHsJ zE8XZ+AyygMaxCY`q(RBJnNT>ZIs>xY33@^+s==dg=FEjfRxrV?`Ax{ zTsYM=mp9&6E^5{_7fmvkQg=(zy60FaQrAQ7Dy`H<F;Xtv(t5Sfuw(+9#ecJ z)2&e2HDXGAb3jlcTR5z1^xH9*P1yd&&0AmZ)4*f(pds2661KzU&PRmB=1zeI*pIu> zR^Ns^(Qx_kDzD~Xvz22kT8o`*9%4WPb0*8T?|i8>t15r_1`<9bh*x*;ju1i_f4=r) znOlBeug~Sp&p-1Gotp`-3b3A;=gsTIEVfov!cx6&I*>C%XzK&pGM4tDjOpPY`ucmn zCH?2$@27E7^;*d86MXpE#={j6i)Npkv(f6~u|afdgavgcF}#tvy5-yP=-dW zJb|F)oxF~9+jr^s@z1vq6_Uh0`%953aPIcb)9}J&7hIhgtMXBpZajP z4HGRVg_sPn4>Aqk))7%)Kaz8f{(6)-7_Z%b-DkzK#`;c9O051Zfp~9^-7}k4ru3iw zaB@ck99PjinwO?wmJ;xjV(Si+Sb&B-q#ge7W}7l&!9O z2~WP=@ouwd-V{C4af_a@6{$uK8F9S<*U!9zDu{^?J`CH>{Z6SsM@wTZR&5tI*A`K; z6AGocl*m0}ZSDd^48>$vWGrNhxYiU?nEnL8GJl)CebB4aq<$se)x=VVJqU7k+qQ`T z&CnR+qXyj&2b-bjpKTYnnwbM45>9q5=zsb?X008%?o(!#p10u#gL&$lpDw=2F= zu3`@CD8K5T9VM~EfQu7yQxzu1n^@6tLNbA0fGFX}oQy2pwA z&CT9HTjKOuHn*+X@oI{^*If)HOR(?bcN_5Gn&r2ho1HISx;fnH^Ds_WTA&~s8T7DK z(%4O^nPXiyO6cW-DXu0Yg5DvH42UDTMbq)g797t`36>wSxl8w%|F(;t>0qYLF7dbA zS$B!q44V%UoZox4Uwx`lg^Dk%62b6ctL{}dpE>){;p416Rd$I-2y1MxOE|PNA2lMb zGcEN6rBfIl{)g_?S9y+Ii|>C>YbJJ(@#b4V5DI^VC=rI6*TSMf820pS_qefqo!bU+ z9^WJ4!eHLqBb?jA{DSNLW*0NMik+*N*V&xGi`K$>_3>-TpW&tVq&~XLy1K0+%Ctff zU4+kI?4L)rGMn(>yE3E985|gH+FmiC6{20eR~+vyqwOlj!&}sBi>>wpd&L#{Ki(^z zjD`7juP8kPQ+|$cvuoBA`}Bb#VWV?4D4$5NYY6VjN9+@qhM+)Z?Gw&J5zESbBF|8B z9<#O((^^yfvi;wE!nL)zyxD#~nx5tr{~9oE@mnJ&orGv@ZebJF_{l6jMwq=lG9J_i zFwYs6uJzfP;Xb+;yAJYML{yK!>d=~=3L{l>6GtP==@Rpo^-OI5WE*(MCmVpltJ-k%Scs1B+Lh%W8S|3L|v zcv5AcV%6HKUWWg-dM4}DS3@vdllB4=*$Jggu?m zU>slLE~ww>$r;4B{)CwD9K(MlF|?C8FI!|MvyXg%*m(VO&uiQFB8!VLl+~untfEs%Vfo+uKy_+J*VXpwoDP--JCC>BMLKWI989o z-M;lpG=M5cH2<*PTy}Q*FS;cjrC!R-|3gW(Ix9N$z?9hMtUj%!bc!fxY3KDuAN@I@ zCaCWCn$+_vwYQ8#crLoOy;=0G?}bLItV@nXXNC6&RQ2|=qW&-D|Dv00czP1KMdUEE zC1I({SOcc@O=O%*teRBQ`H3PLa9*tJrMj5A<-mD;gLzqv%qM0|I*BP5Q$sO_&*pF1#kOiuZJS~1gKb4GZcvps+GbL6Gst<4-p!Hvwp6Y|*Nx%Qn z@ZzIU-M^&pN4wWo2jBE}V}na#E@yq&;r~w)J9J5m>5pgf*BF!UeVzHD2Ti&yk1 z#lyMI+hOY$V0%s7NvJIRpl0OcP*^;UMkCQyk{QgrWzbfW-%J;(2K8c>tfJobn^e9aru9?LnbIj zRnKxkr8?;Ud1e)tlnX6g(qqa!Y@FkiN^|9Me!864#FdHIFUnpk0O^UBw3EIS~P4ic|t@2D`Q{6jvp#%>>e z9Aj59`9u08~-4T2>?w+Qb_UIyq$cyc1OEd)d$f?=c3teZGH}utl22sUP zw?#{Vw?d{uf}2;VPkwx{;oa1=kif55`1{s@GsS9w-vTB5q($EYH-5Y=K0?qk3Q_T` z$HAxeTO90tsV9HK3O$qE5q{J0XrS>OF=#pxJ%ue_s&yuHaF=u$LaJzL;U@upc9D0) zk?Dx**d4vXhkf~T_6N5N>f8eCt;F1%HUnDy%&xKeJ!9K@qTLKsY2SNd7R^`p#Bs!7 zvA?fxeGV)2k4M$x2Pe2ztN6UPn$71fkXxZ}3*UT~I!p0r9#LC|hZ{$-E83S|t zQ&D;rG+O^uztMk{XY1xRj+=bAghJ~K!dWm+#SThdekumchWX1gF%BV&@1Kd33>o}F zZzP)<2A`g?&F+IWq>6hvByvGRr=vj^>orfa(<-5~P;n~letjv{GA$Lu{FnL*r!lc9 z&W`tgfu~(cyS*=kGx8I35fa?XFTC(>t|hBKYx{z_{`b)FGQp?EhDj+Jxn;yz0xIl_ zm!dh#LZzCN7BUS>(lMzRl)gV-nkr<192;et##{f2&nyY`{--k0vZ~F|-TCTk{G$N< z%{9x_n|h-#mVLM8?{Y83SR2@!*W&0L^n^cN>)p>ao=92G&)TOYZUL`!~5*9$CH&!)3oh$ zYuL1J#B7Gm_C{AQI8$hc6KQi@wT3-r(tW(o7&cFTd3J==N4|Gq@kLk;KJylJ@3(bv zW@kvCs;QbjCI@`y-Cp_TmweMp%$IjC zjfk6%lK=ch9LL*^>fJH<-jsSL*(eLknB$#jy5Q@I)GAKS4=Obk{BnKqb^%h8mC^XU z{o#F)iREE@-lGkFYU)*eL)2V?%9hi1yyI*-$~SUlT^SaL$4kuB?e~4L6D5|KBaDUZ z#KNWKX!+}UQF56%UA7Q|LF*phZhk7C=?3Au0wuZFAjU02li!38obaZa4i)L?(HlRk z$8^qT@OFR0hYdQa+N~RoBeuc^Pl&ZAVHXVI62cnq7{u#k=H`}HkaU6Mx2e7|h{)w; zZ_Bsyx_r|FXU2+^%gxo~;Q&tRZ~&>M%T$LMwi_t zQEesSNNYA|^IF8t8l7i48ire&>Ec&ik63Q?U+uK-iXwF(iybp zzbX3me^LI}rlMK_Y8{|xIuZFNV$vl8jF;1ilH1Tcp8bh8aiyarpNp>iswSPo+SL-A zKeg8%3fU>8%e#ncvGEGv7uuTgcuU_!ILD%5WoF{d#KS4YRrmnoI#*HpGU7etDrz2p zdD~U2-4vgWo6$a_NPP>}88V8`n~)8ej%8;?gSHMkkbled9fSAJwQ8JD6Loz9zvww_ z&S3Trvimxb_()acM!ianiRU@MGAWaub^*_v!JXp#eofdGR83n}LXhL@?&b^E9Lc{q zv$a-~QjQ+tBkNJtiqznH^{E$xDtI@es^6X-V&w^&g7Zlya&1R}?e!2%x5FKIx`0c~ za5I*(h~pQ`m6B=mg3NBR%pxD#r>Y8Bh2P1=*Dcx2=#^P?I*PV+Z3o&`ZcpL26Va9N z6qf5Sn|O+nXJAHpia~TA>M3f%-7>+`VCREED)}imO}SYy$E~Hg&QlzLq~#w-;8&p0 zEB!;G4xGC?$lA5ucutE$RGGcR+=~z_jsqfjRK)AHxt;q}9GJ^0815xPDLK$fjDZs0 zsltU`ViqJVI}sQAbLd{jhYjxH6Fl+#`K*^X&ba>d5^;>{M?-_r#ak4=gaCQHMQV2D z5N{EQYfC$Cy?K<5*mtZ+*qMxa&UxQEz+24Sg-L!gBv>}D_tu=!tLfI})>gg&KDps@ zvPzRVsq+8!(CTy9TRcHnHFQ`$K$5S9c_2Q6; zIj{4VGg|L2Y*)fZMDB(j4IsfeI(wbB&fS)M>1maSfDbi%m44sNYs0Rpceect#}9kI z`iLvcwd(0=q*KjI4Q*<~NZ6><2%v_%**@YDhr%5`!tXrHi$216FU(IqVgg4BOBOMR z?g3dubGoGV3h?R72kVU+`h2i(@UhKFeJpihn+82ij9Yip7t((@~qTFTG zS=Qpi6W%D8)@^UDTC!-xORdQ8@C-+w%Aw9?K>9k*0r6eXMnt72i$fGVfLTLDr95Q^ zj2|s+!hfBFoA5knZWkY3mA%Sj0$~|ne3^>khp@I#fmF_w5^6;HzI*)KrADwIzuX4x z*PidkWq%OS-hG{HWLN}*z=x;L1ax1usrrX;|ET7N^KkV!RL+OhjKlJX)f`WiyBc5B zwK5aRDR(&(eqF8sqRro2)@u{J8lqW%1(lm@bHZ};Cn`n8qeg{<#rRb++JKGag;B4` z_(jBb24y`f))`aA_jAc4D2IfB@zYnbH5M=R3A+%0Js5faC|5)A^V!!Cs7{#J zti()yEghftBqkD+iQUA9pK*lS|##+bSpYH*3 z2r&M?siP2CGe3?Enc z^zzBDzw+Kq7H7jMxbXSXF__%6x;600@)t9TAG7*+;kf^7@UdI9cX8fXn-6hI48N-2 z+o0u&iqa1-VKjsYZ%@`2|IlqyP~MMH1QL-&r`?6X2ncZ5e>(ViT7?bfbd9D_=RY*eX%4n22N=Qr-BtWk_Q}Q>CqRQ~oNRgx5*QDR-5pq{1nG6~EF` z6>rk@8D3h9dw^|1?X0~(OTjV*?MczHtt}rc7}BPf3H!x?+Ff->8R7g8MbNU0IQkfc z6$ME?{;Xm0$lN)_?lAnuP2V%On^i_Mr{tzGBASwCAj#jgY}_?}eNejFi>#8b%7~Sa zv^ba57sM^=)^>YTcWbCsBA~3e28p2Bkl@zClaV7YC9l+Nh*hsP@L_}O|ESfoltY)z zxB3hyD|{az>?9d>@G)b~Izx>EtrCmj!>32qAGSE;r0rCofqQ;44+bv_Hq;Jj{Yzwur8aE^IJd3_2IR~RZ;HQ|@a0UK{Pn<-f2 zdjXZx;+q0a2vqO<^}Ol4Li%aNz>N>P>(xX{NEl~S7yVu!@Pg`MHLtf-7YBL0zqUZnw|j~q*#jUUi&Q_T%otZ&9D$(maBXqtC2A?Ij=n8lU`ffiJHuP?9SS}- zLWXM96``-N-~6GjIQ|MD@EHBUD`W(xA9><&x+N0j#|KV#SNEOR;6^vRgp8!Lwu0KL z{V#T?zxS}7kK_Z4ts9DeVB+*wocrx6GQTztXI(CQt=wc?Jr33%Zq-#szklQp5%HL$^c$pwBg=oG*}suk`o>(%V>CkW z9f%W^N-kVh)@uVFm}%X`PCJXXZP0B9aFTd?)G5!5(2ZxbqS5Nw(Ac1zt8l}4en`yn zJ$j*OzkSWwSgd@D!m8d_?0<^}j0aY}?@*@=5rU0vY1cDbPjpM=t*NKIs?rudY*B{1 z$tzEsllqwSL7T%Px&a7l#48!m?_qXpEY{-MWh6pS@oW3+23MaEJi%xf&{$l0hu@-J zX)N5{Ba8PMi)sjw$U`vodutWv^TuN4d;FU9ePeO$y?LauNE6ZF17aB5M9ltx7!Kkq zm3;D3c-QES)5={}+M#)9uYqWNqeWBkh_Z#6={afFWA&H!X;!qyZ_(J{k&{x*g!f0Y zThvrYaBHc=q3mbN&6yZ(GQ3A#I0XC&AI>pHZxm}WwEMoBR-cpb@q*8$6Pc=o5ANQ= z>hl~vtRK5_?Pp{vG&q;lCslKO9$Ht@SnFOD`?=D`9>T)&sX3!K@zI>w*e*;wgI31A zVFEu#3NVgoB}#rmUCnK!&oi}49?xsZoOTJvc|O+*w%Z6F&P{Ib-}~48D=5P1^H(b| z24O8%A;C`JS9WHLScf!5tHg^|B95^q50_i(c26qhxNj_Nm9W5vW!-*r@udYFI^#fL zm9B5NNc|aM%R+*&&tEpE!;|FMaiXx2s0Sa;jVmg)Z`Qq3&RJHUj^Uyy!diyNbn~Rk z6=)cJbDmXVTDX|N*jGx4R<0i%(|EbOwo1gohnn4;_REWTrCx8f`kV|GR~YuT3_H2l zqpTgq&Kzl#cqhZ|x;=4e`izy{Sbb8o7WuwFGq2Wqu9BxMnRk<6$`PwXKx@&G5=l=b zc{_?JU+`Yg7+Et1lhqUz?{(g-#Sx6z$u7~_)O5RekI`X+@pDg+(&XSK=G!}D zGCK7V*US!no&|$y;uE|aK7=Fn{j$yvDU%C&0|SlJ*N2&`{n(m=}W!?#HBaVh(8X}Kbb?IK|ktL z3`*vZFWc>Ydgd~Nb|YcO3Y^1L_3itk!UBzl_?Gvp-7=$Maz_kqclF8&EafiSN{#2o`lcV z+M~91wOM8(y44U?D{n94XB9rk&CXiy)T3E%$;P~pE?=VMrJ90 z0TNh-atW))9MC?|SBR;f-?s-WXTp<4N9i zIXj9fX&k%^9YuQ>Wt*ccSR5DY^PJ#p=f>wUp3>XhnL z^z5Id^f&FstoSlzcg2pC_LdTVrE%~y!hDd%p`>whX_3d-!86MgEV5ac#`l9ZW;*P= ze}P<;N4<8mAKv?H=P8Xu2gn)c4imq@%rqCxnx(e%&r{E<7O5KDGKHRtozr7?J3B-e zMEP_M7e(Rp4rgLLT^ug9iT$&`LqtPyJd;B*QK-K|RBWby98Au!EpIs#OC5Xvg@cD@ MY{Rt4?vDF^0ASQl)&Kwi diff --git a/web/drizzle/0035_fearless_golden_guardian.sql b/web/drizzle/0035_fearless_golden_guardian.sql new file mode 100644 index 0000000..47a9c77 --- /dev/null +++ b/web/drizzle/0035_fearless_golden_guardian.sql @@ -0,0 +1,14 @@ +CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "org_id" text, + "user_id" text NOT NULL, + "usage_time" real DEFAULT 0 NOT NULL, + "created_at" timestamp DEFAULT now() NOT NULL, + "ended_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/web/drizzle/0036_flippant_meltdown.sql b/web/drizzle/0036_flippant_meltdown.sql new file mode 100644 index 0000000..8f0d8bf --- /dev/null +++ b/web/drizzle/0036_flippant_meltdown.sql @@ -0,0 +1,22 @@ +DO $$ BEGIN + CREATE TYPE "subscription_plan" AS ENUM('basic', 'pro', 'enterprise'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + CREATE TYPE "subscription_plan_status" AS ENUM('active', 'deleted', 'paused'); +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +CREATE TABLE IF NOT EXISTS "comfyui_deploy"."subscription_status" ( + "stripe_customer_id" text PRIMARY KEY NOT NULL, + "user_id" text, + "org_id" text, + "plan" "subscription_plan" NOT NULL, + "status" "subscription_plan_status" NOT NULL, + "subscription_plan_id" text, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); diff --git a/web/drizzle/0037_eager_cyclops.sql b/web/drizzle/0037_eager_cyclops.sql new file mode 100644 index 0000000..5a3a572 --- /dev/null +++ b/web/drizzle/0037_eager_cyclops.sql @@ -0,0 +1,3 @@ +ALTER TABLE "comfyui_deploy"."subscription_status" RENAME COLUMN "subscription_plan_id" TO "subscription_id";--> statement-breakpoint +ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_plan_id" text;--> statement-breakpoint +ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_api_id" text; \ No newline at end of file diff --git a/web/drizzle/0038_yummy_darkhawk.sql b/web/drizzle/0038_yummy_darkhawk.sql new file mode 100644 index 0000000..e7e2c0a --- /dev/null +++ b/web/drizzle/0038_yummy_darkhawk.sql @@ -0,0 +1 @@ +ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "cancel_at_period_end" boolean DEFAULT false; \ No newline at end of file diff --git a/web/drizzle/0039_nostalgic_lyja.sql b/web/drizzle/0039_nostalgic_lyja.sql new file mode 100644 index 0000000..37cbdc2 --- /dev/null +++ b/web/drizzle/0039_nostalgic_lyja.sql @@ -0,0 +1,2 @@ +ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "user_id" text;--> statement-breakpoint +ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "org_id" text; \ No newline at end of file diff --git a/web/drizzle/0040_salty_archangel.sql b/web/drizzle/0040_salty_archangel.sql new file mode 100644 index 0000000..34acf4f --- /dev/null +++ b/web/drizzle/0040_salty_archangel.sql @@ -0,0 +1 @@ +ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "gpu" "machine_gpu"; \ No newline at end of file diff --git a/web/drizzle/0041_thick_norrin_radd.sql b/web/drizzle/0041_thick_norrin_radd.sql new file mode 100644 index 0000000..dafde7a --- /dev/null +++ b/web/drizzle/0041_thick_norrin_radd.sql @@ -0,0 +1 @@ +ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "machine_type" "machine_type"; \ No newline at end of file diff --git a/web/drizzle/meta/0035_snapshot.json b/web/drizzle/meta/0035_snapshot.json new file mode 100644 index 0000000..9d920ed --- /dev/null +++ b/web/drizzle/meta/0035_snapshot.json @@ -0,0 +1,894 @@ +{ + "id": "2b2a5d0a-2494-45ea-9d4a-58a70df97829", + "prevId": "8d654f92-7f7e-420f-bbd3-73b6b27adf35", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0036_snapshot.json b/web/drizzle/meta/0036_snapshot.json new file mode 100644 index 0000000..83c5d7b --- /dev/null +++ b/web/drizzle/meta/0036_snapshot.json @@ -0,0 +1,970 @@ +{ + "id": "4db08fc3-2444-42da-b742-f1832ad8caf1", + "prevId": "2b2a5d0a-2494-45ea-9d4a-58a70df97829", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_plan_id": { + "name": "subscription_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0037_snapshot.json b/web/drizzle/meta/0037_snapshot.json new file mode 100644 index 0000000..f2eb459 --- /dev/null +++ b/web/drizzle/meta/0037_snapshot.json @@ -0,0 +1,984 @@ +{ + "id": "cde8f758-0055-4326-981d-293ac84db54a", + "prevId": "4db08fc3-2444-42da-b742-f1832ad8caf1", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_plan_id": { + "name": "subscription_item_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_api_id": { + "name": "subscription_item_api_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": { + "\"comfyui_deploy\".\"subscription_status\".\"subscription_plan_id\"": "\"comfyui_deploy\".\"subscription_status\".\"subscription_id\"" + } + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0038_snapshot.json b/web/drizzle/meta/0038_snapshot.json new file mode 100644 index 0000000..510c5e5 --- /dev/null +++ b/web/drizzle/meta/0038_snapshot.json @@ -0,0 +1,989 @@ +{ + "id": "bd893271-b9ea-4832-a3e8-a6970b9f20d9", + "prevId": "cde8f758-0055-4326-981d-293ac84db54a", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_plan_id": { + "name": "subscription_item_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_api_id": { + "name": "subscription_item_api_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0039_snapshot.json b/web/drizzle/meta/0039_snapshot.json new file mode 100644 index 0000000..b53aec6 --- /dev/null +++ b/web/drizzle/meta/0039_snapshot.json @@ -0,0 +1,1001 @@ +{ + "id": "b9a3bdfb-4187-4647-860e-1006b38b7497", + "prevId": "bd893271-b9ea-4832-a3e8-a6970b9f20d9", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_plan_id": { + "name": "subscription_item_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_api_id": { + "name": "subscription_item_api_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0040_snapshot.json b/web/drizzle/meta/0040_snapshot.json new file mode 100644 index 0000000..2ad2884 --- /dev/null +++ b/web/drizzle/meta/0040_snapshot.json @@ -0,0 +1,1007 @@ +{ + "id": "f9f2dcab-1196-42db-bd79-872d2784c8b9", + "prevId": "b9a3bdfb-4187-4647-860e-1006b38b7497", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_plan_id": { + "name": "subscription_item_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_api_id": { + "name": "subscription_item_api_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/0041_snapshot.json b/web/drizzle/meta/0041_snapshot.json new file mode 100644 index 0000000..10b8023 --- /dev/null +++ b/web/drizzle/meta/0041_snapshot.json @@ -0,0 +1,1013 @@ +{ + "id": "ca1ab9de-49df-4d4a-81ae-d3db96bf55ad", + "prevId": "f9f2dcab-1196-42db-bd79-872d2784c8b9", + "version": "5", + "dialect": "pg", + "tables": { + "api_keys": { + "name": "api_keys", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "revoked": { + "name": "revoked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "api_keys_user_id_users_id_fk": { + "name": "api_keys_user_id_users_id_fk", + "tableFrom": "api_keys", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_keys_key_unique": { + "name": "api_keys_key_unique", + "nullsNotDistinct": false, + "columns": [ + "key" + ] + } + } + }, + "auth_requests": { + "name": "auth_requests", + "schema": "comfyui_deploy", + "columns": { + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "api_hash": { + "name": "api_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expired_date": { + "name": "expired_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "deployments": { + "name": "deployments", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "share_slug": { + "name": "share_slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showcase_media": { + "name": "showcase_media", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "environment": { + "name": "environment", + "type": "deployment_environment", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "deployments_user_id_users_id_fk": { + "name": "deployments_user_id_users_id_fk", + "tableFrom": "deployments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_workflow_version_id_workflow_versions_id_fk": { + "name": "deployments_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "deployments", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "deployments_workflow_id_workflows_id_fk": { + "name": "deployments_workflow_id_workflows_id_fk", + "tableFrom": "deployments", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "deployments_machine_id_machines_id_fk": { + "name": "deployments_machine_id_machines_id_fk", + "tableFrom": "deployments", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "deployments_share_slug_unique": { + "name": "deployments_share_slug_unique", + "nullsNotDistinct": false, + "columns": [ + "share_slug" + ] + } + } + }, + "machines": { + "name": "machines", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "auth_token": { + "name": "auth_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "machine_type", + "primaryKey": false, + "notNull": true, + "default": "'classic'" + }, + "status": { + "name": "status", + "type": "machine_status", + "primaryKey": false, + "notNull": true, + "default": "'ready'" + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "models": { + "name": "models", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "build_machine_instance_id": { + "name": "build_machine_instance_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_log": { + "name": "build_log", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "machines_user_id_users_id_fk": { + "name": "machines_user_id_users_id_fk", + "tableFrom": "machines", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "subscription_status": { + "name": "subscription_status", + "schema": "comfyui_deploy", + "columns": { + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan": { + "name": "plan", + "type": "subscription_plan", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "subscription_plan_status", + "primaryKey": false, + "notNull": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_plan_id": { + "name": "subscription_item_plan_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subscription_item_api_id": { + "name": "subscription_item_api_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_usage": { + "name": "user_usage", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_time": { + "name": "usage_time", + "type": "real", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_usage_user_id_users_id_fk": { + "name": "user_usage_user_id_users_id_fk", + "tableFrom": "user_usage", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_run_outputs": { + "name": "workflow_run_outputs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_run_outputs_run_id_workflow_runs_id_fk": { + "name": "workflow_run_outputs_run_id_workflow_runs_id_fk", + "tableFrom": "workflow_run_outputs", + "tableTo": "workflow_runs", + "columnsFrom": [ + "run_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_runs": { + "name": "workflow_runs", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow_version_id": { + "name": "workflow_version_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "workflow_inputs": { + "name": "workflow_inputs", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "machine_id": { + "name": "machine_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "workflow_run_origin", + "primaryKey": false, + "notNull": true, + "default": "'api'" + }, + "status": { + "name": "status", + "type": "workflow_run_status", + "primaryKey": false, + "notNull": true, + "default": "'not-started'" + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "gpu": { + "name": "gpu", + "type": "machine_gpu", + "primaryKey": false, + "notNull": false + }, + "machine_type": { + "name": "machine_type", + "type": "machine_type", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_runs_workflow_version_id_workflow_versions_id_fk": { + "name": "workflow_runs_workflow_version_id_workflow_versions_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflow_versions", + "columnsFrom": [ + "workflow_version_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_runs_workflow_id_workflows_id_fk": { + "name": "workflow_runs_workflow_id_workflows_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_runs_machine_id_machines_id_fk": { + "name": "workflow_runs_machine_id_machines_id_fk", + "tableFrom": "workflow_runs", + "tableTo": "machines", + "columnsFrom": [ + "machine_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflows": { + "name": "workflows", + "schema": "comfyui_deploy", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "org_id": { + "name": "org_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflows_user_id_users_id_fk": { + "name": "workflows_user_id_users_id_fk", + "tableFrom": "workflows", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "workflow_versions": { + "name": "workflow_versions", + "schema": "comfyui_deploy", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "workflow": { + "name": "workflow", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "workflow_api": { + "name": "workflow_api", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workflow_versions_workflow_id_workflows_id_fk": { + "name": "workflow_versions_workflow_id_workflows_id_fk", + "tableFrom": "workflow_versions", + "tableTo": "workflows", + "columnsFrom": [ + "workflow_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": { + "deployment_environment": { + "name": "deployment_environment", + "values": { + "staging": "staging", + "production": "production", + "public-share": "public-share" + } + }, + "machine_gpu": { + "name": "machine_gpu", + "values": { + "T4": "T4", + "A10G": "A10G", + "A100": "A100" + } + }, + "machine_status": { + "name": "machine_status", + "values": { + "ready": "ready", + "building": "building", + "error": "error" + } + }, + "machine_type": { + "name": "machine_type", + "values": { + "classic": "classic", + "runpod-serverless": "runpod-serverless", + "modal-serverless": "modal-serverless", + "comfy-deploy-serverless": "comfy-deploy-serverless" + } + }, + "subscription_plan": { + "name": "subscription_plan", + "values": { + "basic": "basic", + "pro": "pro", + "enterprise": "enterprise" + } + }, + "subscription_plan_status": { + "name": "subscription_plan_status", + "values": { + "active": "active", + "deleted": "deleted", + "paused": "paused" + } + }, + "workflow_run_origin": { + "name": "workflow_run_origin", + "values": { + "manual": "manual", + "api": "api", + "public-share": "public-share" + } + }, + "workflow_run_status": { + "name": "workflow_run_status", + "values": { + "not-started": "not-started", + "running": "running", + "uploading": "uploading", + "success": "success", + "failed": "failed" + } + } + }, + "schemas": { + "comfyui_deploy": "comfyui_deploy" + }, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + } +} \ No newline at end of file diff --git a/web/drizzle/meta/_journal.json b/web/drizzle/meta/_journal.json index 69f5c17..60056be 100644 --- a/web/drizzle/meta/_journal.json +++ b/web/drizzle/meta/_journal.json @@ -246,6 +246,55 @@ "when": 1705902960991, "tag": "0034_even_lady_ursula", "breakpoints": true + }, + { + "idx": 35, + "version": "5", + "when": 1705981452482, + "tag": "0035_fearless_golden_guardian", + "breakpoints": true + }, + { + "idx": 36, + "version": "5", + "when": 1706081335387, + "tag": "0036_flippant_meltdown", + "breakpoints": true + }, + { + "idx": 37, + "version": "5", + "when": 1706086271525, + "tag": "0037_eager_cyclops", + "breakpoints": true + }, + { + "idx": 38, + "version": "5", + "when": 1706095853896, + "tag": "0038_yummy_darkhawk", + "breakpoints": true + }, + { + "idx": 39, + "version": "5", + "when": 1706109812261, + "tag": "0039_nostalgic_lyja", + "breakpoints": true + }, + { + "idx": 40, + "version": "5", + "when": 1706110859352, + "tag": "0040_salty_archangel", + "breakpoints": true + }, + { + "idx": 41, + "version": "5", + "when": 1706111421524, + "tag": "0041_thick_norrin_radd", + "breakpoints": true } ] -} +} \ No newline at end of file diff --git a/web/package.json b/web/package.json index c5625d3..717b26d 100644 --- a/web/package.json +++ b/web/package.json @@ -37,6 +37,7 @@ "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-progress": "^1.0.3", "@radix-ui/react-radio-group": "^1.1.3", "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-select": "^2.0.0", @@ -47,6 +48,7 @@ "@radix-ui/react-toggle": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.7", "@sindresorhus/slugify": "^2.2.1", + "@stripe/stripe-js": "^2.4.0", "@tailwindcss/typography": "^0.5.10", "@tanstack/react-table": "^8.10.7", "@tanstack/react-virtual": "beta", @@ -95,6 +97,7 @@ "shikiji": "^0.9.3", "simple-functional-loader": "^1.2.1", "sonner": "^1.2.4", + "stripe": "^14.13.0", "swagger-ui-react": "^5.11.0", "swr": "^2.2.4", "tailwind-merge": "^2.1.0", diff --git a/web/src/app/(app)/api/stripe/callback/route.tsx b/web/src/app/(app)/api/stripe/callback/route.tsx new file mode 100644 index 0000000..7eec55e --- /dev/null +++ b/web/src/app/(app)/api/stripe/callback/route.tsx @@ -0,0 +1,175 @@ +import { auth, clerkClient } from "@clerk/nextjs"; +import { headers } from "next/headers"; +import { redirect } from "next/navigation"; +import { stripe } from "../../../../../server/stripe"; +import { NextResponse } from "next/server"; +import { db } from "@/db/db"; +import { subscriptionStatusTable } from "@/db/schema"; +import { eq } from "drizzle-orm"; + +const secret = process.env.STRIPE_WEBHOOK_SECRET || ""; + +export async function POST(req: Request) { + try { + const body = await req.text(); + + const signature = headers().get("stripe-signature"); + + if (!signature) + return new NextResponse("Signature not found.", { + status: 500, + }); + + const event = stripe.webhooks.constructEvent(body, signature, secret); + + console.log(event); + + if (event.type === "checkout.session.completed") { + if (!event.data.object.customer_details?.email) { + throw new Error(`missing user email, ${event.id}`); + } + + const userId = event.data.object.metadata?.userId; + const plan = event.data.object.metadata?.plan; + if (!userId) { + throw new Error(`missing itinerary_id on metadata, ${event.id}`); + } + if (!plan) { + throw new Error(`missing plan on metadata, ${event.id}`); + } + + const orgId = event.data.object.metadata?.orgId; + + const customerId = + typeof event.data.object.customer == "string" + ? event.data.object.customer + : event.data.object.customer?.id; + const subscriptionId = + typeof event.data.object.subscription == "string" + ? event.data.object.subscription + : event.data.object.subscription?.id; + + if (!customerId) { + throw new Error(`missing customerId, ${event.id}`); + } + if (!subscriptionId) { + throw new Error(`missing subscriptionId, ${event.id}`); + } + + const items = await stripe.subscriptionItems.list({ + subscription: subscriptionId, + limit: 5, + }); + + // getting the subscription item id for the api plan + const subscription_item_api_id = items.data.find( + (x) => x.price.id === process.env.STRIPE_PR_API, + )?.id; + + // the plan could be either pro or enterprise + const subscription_item_plan_id = + items.data.find((x) => x.price.id === process.env.STRIPE_PR_PRO)?.id ?? + items.data.find((x) => x.price.id === process.env.STRIPE_PR_ENTERPRISE) + ?.id; + + if (!subscription_item_api_id) { + throw new Error( + `missing plan on subscription_item_api_id, ${event.id}`, + ); + } + if (!subscription_item_plan_id) { + throw new Error( + `missing plan on subscription_item_plan_id, ${event.id}`, + ); + } + + console.log(items); + + await db + .insert(subscriptionStatusTable) + .values({ + stripe_customer_id: customerId, + org_id: orgId, + user_id: userId, + subscription_id: subscriptionId, + plan: plan as "pro" | "enterprise" | "basic", + status: "active", + subscription_item_api_id: subscription_item_api_id, + subscription_item_plan_id: subscription_item_plan_id, + }) + .onConflictDoNothing(); + + // updateDatabase(event.data.object.metadata.itinerary_id); + // sendEmail(event.data.object.customer_details.email); + } else if (event.type === "customer.subscription.paused") { + const customerId = + typeof event.data.object.customer == "string" + ? event.data.object.customer + : event.data.object.customer?.id; + + if (!customerId) { + throw new Error(`missing customerId, ${event.id}`); + } + + await db + .update(subscriptionStatusTable) + .set({ status: "paused" }) + .where(eq(subscriptionStatusTable.stripe_customer_id, customerId)); + } else if (event.type === "customer.subscription.resumed") { + const customerId = + typeof event.data.object.customer == "string" + ? event.data.object.customer + : event.data.object.customer?.id; + + if (!customerId) { + throw new Error(`missing customerId, ${event.id}`); + } + + await db + .update(subscriptionStatusTable) + .set({ status: "active" }) + .where(eq(subscriptionStatusTable.stripe_customer_id, customerId)); + } else if (event.type === "customer.subscription.deleted") { + const customerId = + typeof event.data.object.customer == "string" + ? event.data.object.customer + : event.data.object.customer?.id; + + if (!customerId) { + throw new Error(`missing customerId, ${event.id}`); + } + + await db + .update(subscriptionStatusTable) + .set({ status: "deleted" }) + .where(eq(subscriptionStatusTable.stripe_customer_id, customerId)); + } else if (event.type === "customer.subscription.updated") { + const customerId = + typeof event.data.object.customer == "string" + ? event.data.object.customer + : event.data.object.customer?.id; + + if (!customerId) { + throw new Error(`missing customerId, ${event.id}`); + } + + const cancel_at_period_end = event.data.object.cancel_at_period_end; + + await db + .update(subscriptionStatusTable) + .set({ cancel_at_period_end: cancel_at_period_end }) + .where(eq(subscriptionStatusTable.stripe_customer_id, customerId)); + } + + return NextResponse.json({ result: event, ok: true }); + } catch (error) { + console.error(error); + return NextResponse.json( + { + message: `Something went wrong: ${error}`, + ok: false, + }, + { status: 500 }, + ); + } +} diff --git a/web/src/app/(app)/api/stripe/checkout/route.tsx b/web/src/app/(app)/api/stripe/checkout/route.tsx new file mode 100644 index 0000000..9ccd287 --- /dev/null +++ b/web/src/app/(app)/api/stripe/checkout/route.tsx @@ -0,0 +1,46 @@ +import { stripe } from "@/server/stripe"; +import { createCheckout } from "@/server/linkToPricing"; +import { auth, clerkClient } from "@clerk/nextjs"; +import { redirect } from "next/navigation"; +import { getUrlServerSide } from "@/server/getUrlServerSide"; + +export async function GET(req: Request) { + const { userId, orgId } = auth(); + + const plan = new URL(req.url).searchParams.get("plan"); + + if (!userId) return redirect("/"); + if (!plan) return redirect("/pricing"); + + const user = await clerkClient.users.getUser(userId); + + const mapping = { + pro: process.env.STRIPE_PR_PRO, + enterprise: process.env.STRIPE_PR_ENTERPRISE, + }; + + const api = process.env.STRIPE_PR_API; + + const session = await stripe.checkout.sessions.create({ + success_url: getUrlServerSide(), + line_items: [ + { + price: mapping[plan as "pro" | "enterprise"], + quantity: 1, + }, + { + price: api, + }, + ], + metadata: { + userId: userId, + orgId: orgId ?? null, + plan: plan, + }, + client_reference_id: orgId ?? userId, + customer_email: user.emailAddresses[0].emailAddress, + mode: "subscription", + }); + + if (session.url) redirect(session.url); +} diff --git a/web/src/app/(app)/api/stripe/dashboard/route.tsx b/web/src/app/(app)/api/stripe/dashboard/route.tsx new file mode 100644 index 0000000..95fe442 --- /dev/null +++ b/web/src/app/(app)/api/stripe/dashboard/route.tsx @@ -0,0 +1,41 @@ +import { stripe } from "@/server/stripe"; +import { createCheckout } from "@/server/linkToPricing"; +import { auth, clerkClient } from "@clerk/nextjs"; +import { redirect } from "next/navigation"; +import { getUrlServerSide } from "@/server/getUrlServerSide"; +import { db } from "@/db/db"; +import { and, eq, isNull } from "drizzle-orm"; +import { subscriptionStatusTable } from "@/db/schema"; +import { getCurrentPlan } from "@/server/getCurrentPlan"; + +export async function GET(req: Request) { + const { userId, orgId } = auth(); + + if (!userId) return redirect("/"); + + const change = new URL(req.url).searchParams.get("change"); + + const sub = await getCurrentPlan({ + org_id: orgId, + user_id: userId, + }); + + if (!sub) return redirect("/pricing"); + + const session = await stripe.billingPortal.sessions.create({ + customer: sub.stripe_customer_id, + return_url: getUrlServerSide() + "/pricing", + // flow_data: + // change === "true" && sub.subscription_id + // ? { + // type: "subscription_update", + // subscription_update: { + // subscription: sub.subscription_id, + // }, + // } + // : undefined, + }); + + redirect(session.url); + // if (session.url) redirect(session.url); +} diff --git a/web/src/app/(app)/api/update-run/route.ts b/web/src/app/(app)/api/update-run/route.ts index e4b98db..00dc35d 100644 --- a/web/src/app/(app)/api/update-run/route.ts +++ b/web/src/app/(app)/api/update-run/route.ts @@ -6,8 +6,8 @@ import { workflowRunsTable, workflowTable, } from "@/db/schema"; -import { getDuration } from "@/lib/getRelativeTime"; -import { getSubscription, setUsage } from "@/server/linkToPricing"; +import { getCurrentPlan } from "@/server/getCurrentPlan"; +import { stripe } from "@/server/stripe"; import { eq } from "drizzle-orm"; import { NextResponse } from "next/server"; import { z } from "zod"; @@ -34,21 +34,51 @@ export async function POST(request: Request) { data: output_data, }); } else if (status) { - const workflow_run = await db + const [workflow_run] = await db .update(workflowRunsTable) .set({ status: status, ended_at: status === "success" || status === "failed" ? new Date() : null, }) - .where(eq(workflowRunsTable.id, run_id)); + .where(eq(workflowRunsTable.id, run_id)) + .returning(); - // get data from workflowRunsTable - const userUsageTime = await importUserUsageData(run_id); + // Need to filter out only comfy deploy serverless + // Also multiply with the gpu selection + if (workflow_run.machine_type == "comfy-deploy-serverless") { + if ( + (status === "success" || status === "failed") && + workflow_run.user_id + ) { + const sub = await getCurrentPlan({ + user_id: workflow_run.user_id, + org_id: workflow_run.org_id, + }); - if (userUsageTime) { - // get the usage_time from userUsage - await addSubscriptionUnit(userUsageTime); + if (sub && sub.subscription_item_api_id && workflow_run.ended_at) { + let durationInSec = Math.abs( + (workflow_run.ended_at.getTime() - + workflow_run.created_at.getTime()) / + 1000, + ); + durationInSec = Math.ceil(durationInSec); + switch (workflow_run.gpu) { + case "A100": + durationInSec *= 7; + break; + case "A10G": + durationInSec *= 4; + break; + } + await stripe.subscriptionItems.createUsageRecord( + sub.subscription_item_api_id, + { + quantity: durationInSec, + }, + ); + } + } } } @@ -64,50 +94,6 @@ export async function POST(request: Request) { }, { status: 200, - } + }, ); } - -async function addSubscriptionUnit(userUsageTime: number) { - const subscription = await getSubscription(); - - // round up userUsageTime to the nearest integer - const roundedUsageTime = Math.ceil(userUsageTime); - - if (subscription) { - const usage = await setUsage( - subscription.data[0].attributes.first_subscription_item.id, - roundedUsageTime - ); - } -} - -async function importUserUsageData(run_id: string) { - const workflowRuns = await db.query.workflowRunsTable.findFirst({ - where: eq(workflowRunsTable.id, run_id), - }); - - if (!workflowRuns?.workflow_id) return; - - // find if workflowTable id column contains workflowRunsTable workflow_id - const workflow = await db.query.workflowTable.findFirst({ - where: eq(workflowTable.id, workflowRuns.workflow_id), - }); - - if (workflowRuns?.ended_at === null || workflow == null) return; - - const usageTime = parseFloat( - getDuration((workflowRuns?.ended_at - workflowRuns?.started_at) / 1000) - ); - - // add data to userUsageTable - const user_usage = await db.insert(userUsageTable).values({ - user_id: workflow.user_id, - created_at: workflowRuns.ended_at, - org_id: workflow.org_id, - ended_at: workflowRuns.ended_at, - usage_time: usageTime, - }); - - return usageTime; -} diff --git a/web/src/app/(app)/pricing/components/gpuPricingTable.tsx b/web/src/app/(app)/pricing/components/gpuPricingTable.tsx deleted file mode 100644 index 912f099..0000000 --- a/web/src/app/(app)/pricing/components/gpuPricingTable.tsx +++ /dev/null @@ -1,81 +0,0 @@ -const people = [ - { - name: "Nvidia T4 GPU", - gpu: "1x", - ram: "16GB", - price: "$0.000225/sec", - }, - { - name: "Nvidia A40 GPU", - gpu: "1x", - ram: "48GB", - price: "$0.000575/sec", - }, -]; - -export function GpuPricingPlan() { - return ( -
    -
    -
    - - - - - - - - - - {people.map((person) => ( - - - - - - - ))} - -
    - GPU - - No. - - RAM - - Price -
    - {person.name} -
    -
    No.
    -
    - {person.gpu} -
    -
    RAM
    -
    - {person.ram} -
    -
    -
    - {person.gpu} - - {person.ram} - - {person.price} -
    -
    -
    - ); -} diff --git a/web/src/app/(app)/pricing/components/pricePlanList.tsx b/web/src/app/(app)/pricing/components/pricePlanList.tsx deleted file mode 100644 index 89f4358..0000000 --- a/web/src/app/(app)/pricing/components/pricePlanList.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { checkMarkIcon, crossMarkIcon } from "../const/Icon"; -import { cn } from "@/lib/utils"; -import { getPricing } from "@/server/linkToPricing"; -import { useEffect, useState } from "react"; - -type Tier = { - name: string; - id: string; - href: string; - priceMonthly: string; - description: string; - features: string[]; - featured: boolean; - priority?: TierPriority; -}; - -enum TierPriority { - Free = "free", - Pro = "pro", - Enterprise = "enterprise", -} - -export default function PricingList() { - const [productTiers, setProductTiers] = useState(); - - useEffect(() => { - (async () => { - const product = await getPricing(); - - if (!product) return; - - const newProductTiers: Tier[] = product.data.map((item) => { - // Create a new DOMParser instance - const parser = new DOMParser(); - // Parse the description HTML string to a new document - const doc = parser.parseFromString( - item.attributes.description, - "text/html" - ); - // Extract the description and features - const description = doc.querySelector("p")?.textContent || ""; - const features = Array.from(doc.querySelectorAll("ul > li")).map( - (li) => li.textContent || "" - ); - - return { - name: item.attributes.name, - id: item.id, - href: item.attributes.buy_now_url, - priceMonthly: - item.attributes.price_formatted.split("/")[0] == "Usage-based" - ? "$20.00" - : item.attributes.price_formatted.split("/")[0], - description: description, - features: features, - - // if name contains pro, it's featured - featured: item.attributes.name.toLowerCase().includes("pro"), - - // give priority if name contain in enum - priority: Object.values(TierPriority).find((priority) => - item.attributes.name.toLowerCase().includes(priority) - ), - }; - }); - - // sort newProductTiers by priority - newProductTiers.sort((a, b) => { - if (!a.priority) return 1; - if (!b.priority) return -1; - return ( - Object.values(TierPriority).indexOf(a.priority) - - Object.values(TierPriority).indexOf(b.priority) - ); - }); - - setProductTiers(newProductTiers); - })(); - }, []); - - return ( -
    -
    -

    - Pricing -

    -

    - The right price for you, whoever you are -

    -
    -

    - Qui iusto aut est earum eos quae. Eligendi est at nam aliquid ad quo - reprehenderit in aliquid fugiat dolorum voluptatibus. -

    -
    - {productTiers && - productTiers.map((tier, tierIdx) => ( -
    -

    - {tier.name} -

    -

    - - {tier.priceMonthly} - - /month -

    -

    - {tier.description} -

    -
      - {tier.features.map((feature) => ( -
    • -
      - {feature.includes("[x]") ? crossMarkIcon : checkMarkIcon} -
      - {feature.replace("[x]", "")} -
    • - ))} -
    - - Get started today - -
    - ))} -
    -
    - ); -} diff --git a/web/src/app/(app)/pricing/const/Icon.tsx b/web/src/app/(app)/pricing/const/Icon.tsx deleted file mode 100644 index 2257aee..0000000 --- a/web/src/app/(app)/pricing/const/Icon.tsx +++ /dev/null @@ -1,37 +0,0 @@ -export const checkMarkIcon = ( - -); - -export const crossMarkIcon = ( - - - - -); diff --git a/web/src/app/(app)/pricing/page.tsx b/web/src/app/(app)/pricing/page.tsx index fd94f22..c417b1a 100644 --- a/web/src/app/(app)/pricing/page.tsx +++ b/web/src/app/(app)/pricing/page.tsx @@ -1,13 +1,9 @@ -"use client"; - -import { GpuPricingPlan } from "@/app/(app)/pricing/components/gpuPricingTable"; -import PricingList from "@/app/(app)/pricing/components/pricePlanList"; +import PricingList from "@/components/PricingPlan"; export default function Home() { return (
    -
    ); } diff --git a/web/src/app/(app)/providers.tsx b/web/src/app/(app)/providers.tsx index 7ccd3ae..f50a828 100644 --- a/web/src/app/(app)/providers.tsx +++ b/web/src/app/(app)/providers.tsx @@ -1,19 +1,19 @@ // app/providers.tsx -'use client' -import posthog from 'posthog-js' -import { PostHogProvider } from 'posthog-js/react' +"use client"; +import posthog from "posthog-js"; +import { PostHogProvider } from "posthog-js/react"; -if (typeof window !== 'undefined') { +if (typeof window !== "undefined") { posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, { api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, - capture_pageview: false // Disable automatic pageview capture, as we capture manually - }) + capture_pageview: false, // Disable automatic pageview capture, as we capture manually + }); } export function PHProvider({ children, }: { - children: React.ReactNode + children: React.ReactNode; }) { - return {children} + return {children}; } diff --git a/web/src/app/(app)/usage/loading.tsx b/web/src/app/(app)/usage/loading.tsx new file mode 100644 index 0000000..9ff4783 --- /dev/null +++ b/web/src/app/(app)/usage/loading.tsx @@ -0,0 +1,9 @@ +"use client"; + +import { LoadingPageWrapper } from "@/components/LoadingWrapper"; +import { usePathname } from "next/navigation"; + +export default function Loading() { + const pathName = usePathname(); + return ; +} diff --git a/web/src/app/(app)/usage/page.tsx b/web/src/app/(app)/usage/page.tsx new file mode 100644 index 0000000..9886f56 --- /dev/null +++ b/web/src/app/(app)/usage/page.tsx @@ -0,0 +1,57 @@ +import PricingList from "@/components/PricingPlan"; +import { Badge } from "@/components/ui/badge"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Progress } from "@/components/ui/progress"; +import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan"; +import { stripe } from "@/server/stripe"; + +const freeTierSeconds = 30000; + +export default async function Home() { + const sub = await getCurrentPlanWithAuth(); + + const data = sub?.subscription_item_api_id + ? await stripe.subscriptionItems.listUsageRecordSummaries( + sub?.subscription_item_api_id, + ) + : null; + + return ( +
    + + + Account Usage + View you account usage + {sub?.plan} + + {data && ( + +
    + Current free gpu usage: + { +
    + + {data.data[0].total_usage}s /{Math.floor(freeTierSeconds)}s + + + {Math.floor(data.data[0].total_usage / 60 / 60)}hr / + {Math.floor(freeTierSeconds / 60 / 60)}hr + +
    + } +
    + +
    + )} +
    +
    + ); +} diff --git a/web/src/components/Navbar.tsx b/web/src/components/Navbar.tsx index d344683..07c4475 100644 --- a/web/src/components/Navbar.tsx +++ b/web/src/components/Navbar.tsx @@ -91,13 +91,22 @@ export function Navbar() {
    {isDesktop && } {pricingPlanFlagEnable && ( - + <> + + + )}