diff --git a/server/bun.lock b/server/bun.lock index 80cfccd..1f31dfc 100644 --- a/server/bun.lock +++ b/server/bun.lock @@ -5,25 +5,24 @@ "": { "name": "server", "dependencies": { - "@aws-sdk/client-s3": "latest", - "@aws-sdk/s3-request-presigner": "latest", - "@hono/zod-validator": "latest", - "@libsql/client": "latest", - "better-sse": "latest", - "dotenv": "latest", - "drizzle-orm": "latest", - "google-auth-library": "latest", - "hono": "latest", - "pdf-lib": "latest", - "razorpay": "latest", - "short-unique-id": "latest", - "zod": "latest", + "@aws-sdk/client-s3": "^3.1051.0", + "@hono/zod-validator": "^0.8.0", + "@libsql/client": "^0.17.3", + "better-sse": "^0.16.1", + "dotenv": "^17.4.2", + "drizzle-orm": "^0.45.2", + "google-auth-library": "^10.6.2", + "hono": "^4.12.21", + "pdf-lib": "^1.17.1", + "razorpay": "^2.9.6", + "short-unique-id": "^5.3.2", + "zod": "^4.4.3", }, "devDependencies": { - "@types/bun": "latest", - "drizzle-kit": "latest", - "typescript": "latest", - "wrangler": "latest", + "@types/bun": "^1.3.14", + "drizzle-kit": "^0.31.10", + "typescript": "^6.0.3", + "wrangler": "^4.93.1", }, }, }, @@ -78,8 +77,6 @@ "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.10", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.12", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/fetch-http-handler": "^5.4.2", "@smithy/node-http-handler": "^4.7.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-FtQ/Bt327peZJuyo4WZSOLVUTw9ujRxntepiC7L65FxA2P82Xlq0g14T22BuqBUeMjDoxa9nvwiMHjLIfP3eUg=="], - "@aws-sdk/s3-request-presigner": ["@aws-sdk/s3-request-presigner@3.1051.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.12", "@aws-sdk/signature-v4-multi-region": "^3.996.27", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-9ZULJHf5IAObmqtg2XhiufMmgEl+aM9jlRog2V9qbICeSOgDCHekmlRxF9FuqZKMqrpLzGtJPDbd8gGAHJZv/A=="], - "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.27", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0Phbz4t6HI3D3skxvG2uI+VWU034/nSIw1T8d+FPzzQG9EQTrw94o9mOKO2Gv3n3Oc8P7JD7RAUxkoneLWv5Eg=="], "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1049.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.12", "@aws-sdk/nested-clients": "^3.997.10", "@aws-sdk/types": "^3.973.8", "@smithy/core": "^3.24.2", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-r7+d0lQMTHKypkmaF5jRTBYLYHCUHzt3gaVoN9SidLhQeWhCmHk3AKrboDTpPF5b7Pt7vKu3+oeMjznM2Eu1ow=="], diff --git a/server/package.json b/server/package.json index cd9d2e3..113ebaf 100644 --- a/server/package.json +++ b/server/package.json @@ -6,7 +6,6 @@ }, "dependencies": { "@aws-sdk/client-s3": "^3.1051.0", - "@aws-sdk/s3-request-presigner": "^3.1051.0", "@hono/zod-validator": "^0.8.0", "@libsql/client": "^0.17.3", "better-sse": "^0.16.1", diff --git a/server/src/database/drizzle/0000_thankful_toad.sql b/server/src/database/drizzle/0000_youthful_zaran.sql similarity index 90% rename from server/src/database/drizzle/0000_thankful_toad.sql rename to server/src/database/drizzle/0000_youthful_zaran.sql index ea13109..c228fd3 100644 --- a/server/src/database/drizzle/0000_thankful_toad.sql +++ b/server/src/database/drizzle/0000_youthful_zaran.sql @@ -21,10 +21,10 @@ CREATE TABLE `metadata` ( --> statement-breakpoint CREATE TABLE `orders` ( `id` text PRIMARY KEY NOT NULL, - `name` text NOT NULL, `email` text NOT NULL, `amount` real NOT NULL, + `payment_request_id` text NOT NULL, `paid` integer DEFAULT false NOT NULL, - `status` text DEFAULT 'processing' NOT NULL, + `status` integer DEFAULT 0 NOT NULL, `created_at` integer NOT NULL ); diff --git a/server/src/database/drizzle/0001_common_steve_rogers.sql b/server/src/database/drizzle/0001_common_steve_rogers.sql deleted file mode 100644 index 6e37137..0000000 --- a/server/src/database/drizzle/0001_common_steve_rogers.sql +++ /dev/null @@ -1,15 +0,0 @@ -PRAGMA foreign_keys=OFF;--> statement-breakpoint -CREATE TABLE `__new_orders` ( - `id` text PRIMARY KEY NOT NULL, - `name` text NOT NULL, - `email` text NOT NULL, - `amount` real NOT NULL, - `paid` integer DEFAULT false NOT NULL, - `status` integer DEFAULT 0 NOT NULL, - `created_at` integer NOT NULL -); ---> statement-breakpoint -INSERT INTO `__new_orders`("id", "name", "email", "amount", "paid", "status", "created_at") SELECT "id", "name", "email", "amount", "paid", "status", "created_at" FROM `orders`;--> statement-breakpoint -DROP TABLE `orders`;--> statement-breakpoint -ALTER TABLE `__new_orders` RENAME TO `orders`;--> statement-breakpoint -PRAGMA foreign_keys=ON; \ No newline at end of file diff --git a/server/src/database/drizzle/meta/0000_snapshot.json b/server/src/database/drizzle/meta/0000_snapshot.json index 7e72082..b31d954 100644 --- a/server/src/database/drizzle/meta/0000_snapshot.json +++ b/server/src/database/drizzle/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "6", "dialect": "sqlite", - "id": "c7e23e83-068d-4b16-92d4-c837d2ba0100", + "id": "96645ee7-79de-4d70-9564-2e4d4faa5df5", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "files": { @@ -139,13 +139,6 @@ "notNull": true, "autoincrement": false }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, "email": { "name": "email", "type": "text", @@ -160,6 +153,13 @@ "notNull": true, "autoincrement": false }, + "payment_request_id": { + "name": "payment_request_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, "paid": { "name": "paid", "type": "integer", @@ -170,11 +170,11 @@ }, "status": { "name": "status", - "type": "text", + "type": "integer", "primaryKey": false, "notNull": true, "autoincrement": false, - "default": "'processing'" + "default": 0 }, "created_at": { "name": "created_at", diff --git a/server/src/database/drizzle/meta/0001_snapshot.json b/server/src/database/drizzle/meta/0001_snapshot.json deleted file mode 100644 index 88416e4..0000000 --- a/server/src/database/drizzle/meta/0001_snapshot.json +++ /dev/null @@ -1,204 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "id": "8ea45a78-e586-4b2a-9b30-11df74a1df96", - "prevId": "c7e23e83-068d-4b16-92d4-c837d2ba0100", - "tables": { - "files": { - "name": "files", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "order": { - "name": "order", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "orientation": { - "name": "orientation", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "color": { - "name": "color", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "copies": { - "name": "copies", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "paper_format": { - "name": "paper_format", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "page_ranges": { - "name": "page_ranges", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "number_up": { - "name": "number_up", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sides": { - "name": "sides", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "print_scaling": { - "name": "print_scaling", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "document_format": { - "name": "document_format", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "metadata": { - "name": "metadata", - "columns": { - "file_id": { - "name": "file_id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "type": { - "name": "type", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "pages": { - "name": "pages", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - }, - "orders": { - "name": "orders", - "columns": { - "id": { - "name": "id", - "type": "text", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "amount": { - "name": "amount", - "type": "real", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "paid": { - "name": "paid", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": false - }, - "status": { - "name": "status", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": 0 - }, - "created_at": { - "name": "created_at", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - } - }, - "indexes": {}, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {}, - "checkConstraints": {} - } - }, - "views": {}, - "enums": {}, - "_meta": { - "schemas": {}, - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - } -} \ No newline at end of file diff --git a/server/src/database/drizzle/meta/_journal.json b/server/src/database/drizzle/meta/_journal.json index 79ce7ef..d29f6d1 100644 --- a/server/src/database/drizzle/meta/_journal.json +++ b/server/src/database/drizzle/meta/_journal.json @@ -5,15 +5,8 @@ { "idx": 0, "version": "6", - "when": 1757149051180, - "tag": "0000_thankful_toad", - "breakpoints": true - }, - { - "idx": 1, - "version": "6", - "when": 1779301867292, - "tag": "0001_common_steve_rogers", + "when": 1779394160491, + "tag": "0000_youthful_zaran", "breakpoints": true } ] diff --git a/server/src/database/schema.ts b/server/src/database/schema.ts index 431755d..70a292e 100644 --- a/server/src/database/schema.ts +++ b/server/src/database/schema.ts @@ -5,9 +5,9 @@ export const orders = sqliteTable("orders", { id: text("id") .primaryKey() .$defaultFn(() => crypto.randomUUID()), - name: text("name").notNull(), email: text("email").notNull(), amount: real("amount").notNull(), + paymentRequestId: text("payment_request_id").notNull(), paid: integer("paid", { mode: "boolean" }).notNull().default(false), status: integer("status").notNull().default(0), createdAt: integer("created_at", { mode: "timestamp_ms" }) diff --git a/server/src/index.ts b/server/src/index.ts index 85a4c32..7ef78c8 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -2,15 +2,20 @@ import { Hono } from "hono"; import orderRouter from "./routes/order"; import uploadRouter from "./routes/file"; import eventRouter from "./routes/event"; +import webhookRouter from "./routes/webhook"; const app = new Hono(); app.route("/order", orderRouter); app.route("/file", uploadRouter); app.route("/event", eventRouter); +app.route("/webhook", webhookRouter); app.get("/", async (c) => { return c.text("server up"); }); -export default app; +export default { + fetch: app.fetch, + idleTimeout: 0, +}; diff --git a/server/src/routes/order.ts b/server/src/routes/order.ts index bc19dee..6e4257d 100644 --- a/server/src/routes/order.ts +++ b/server/src/routes/order.ts @@ -4,14 +4,10 @@ import { z } from "zod"; import database from "../database/index"; import { metadata, orders, files } from "../database/schema"; import { eq } from "drizzle-orm"; -// import { razorpay } from "../services/razorpay"; +import { razorpay } from "../services/razorpay"; import { OAuth2Client } from "google-auth-library"; -import { orderChannel } from "../channels/orderChannel"; import { authMiddleware } from "../middlewares/auth"; import { PrintConfig } from "../types/index"; -import { Session } from "better-sse"; -import { upgradeWebSocket } from "hono/cloudflare-workers"; -import { WSContext } from "hono/ws"; const app = new Hono(); const client = new OAuth2Client(); @@ -22,7 +18,6 @@ app.post( zValidator("json", z.array(PrintConfig)), async (c) => { const file = c.req.valid("json")[0]; - // const user = c.get("w"); const metadataResponse = await database.query.metadata.findFirst({ where: eq(metadata.fileId, file.fileId), @@ -32,37 +27,34 @@ app.post( if (!metadataResponse) return c.json({ message: "something went wrong" }, 400); - // // if (!metadataResponse || !user.email) - // // return c.json({ message: "something went wrong" }); - // + const amount = metadataResponse.pages * 2; - const orderId = await database.transaction(async (tx) => { + const rp = await razorpay.orders.create({ + amount: amount * 100, + currency: "INR", + method: "upi", + receipt: "print #1", + }); + + await database.transaction(async (tx) => { const [order] = await tx .insert(orders) .values({ - name: file.name, - amount: metadataResponse.pages * 2, + amount, email: "adityadav1809@gmail.com", + paymentRequestId: rp.id, }) - .returning({ id: orders.id }); + .returning({ id: orders.id, amount: orders.amount }); await tx.insert(files).values({ order: order.id, ...file, }); - return order.id; + return order; }); - orderChannel.broadcast(file); - - // const response = await razorpay.orders.create({ - // amount: "100", - // currency: "INR", - // receipt: "payment for print #1", - // }); - - return c.json({ orderId }); + return c.json(rp); }, ); diff --git a/server/src/routes/webhook.ts b/server/src/routes/webhook.ts new file mode 100644 index 0000000..eb4a9c7 --- /dev/null +++ b/server/src/routes/webhook.ts @@ -0,0 +1,36 @@ +import { Hono } from "hono"; +import { orderChannel } from "../channels/orderChannel.js"; +import database from "../database"; +import { eq } from "drizzle-orm"; +import { orders } from "../database/schema.js"; + +const app = new Hono(); + +app.post(`/${process.env.WEBHOOK_SECRET || "webhook"}`, async (c) => { + console.log("got webhook"); + let payload = await c.req.json(); + + if (payload.event != "order.paid") return c.text("ok: done with payment"); + + const id = payload.payload.order.entity.id; + + // if (body.type !== WEBHOOK_TYPE.SUCCESS) + // return c.text("error: payment failed"); + + // // todo: update database & check key + + const order = await database.query.orders.findFirst({ + where: eq(orders.paymentRequestId, id), + with: { + files: true, + }, + }); + + if (!order) return c.text("error: invalid order"); + + orderChannel.broadcast(order.files[0]); + + return c.text("ok: done with payment"); +}); + +export default app;