diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 1fd5d51..52e9e15 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -3,7 +3,7 @@ name: Build and deploy on: push: branches: - - master + - main pull_request: types: - opened @@ -12,7 +12,7 @@ on: jobs: build_and_deploy: - name: Build and deploy PeterPortal + name: Build and deploy ZotNFound runs-on: ubuntu-latest steps: diff --git a/README.md b/README.md index df9680a..7fe2d95 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -test again -testsets +# testing_sst +testest +yrdy diff --git a/package.json b/package.json index 2723bfe..979aa73 100644 --- a/package.json +++ b/package.json @@ -13,13 +13,16 @@ "preinstall": "npx only-allow pnpm" }, "devDependencies": { - "sst": "^2.41.5", + "@tsconfig/node18": "^18.2.4", "aws-cdk-lib": "2.132.1", "constructs": "10.3.0", - "typescript": "^5.4.5", - "@tsconfig/node18": "^18.2.4" + "sst": "^2.41.5", + "typescript": "^5.4.5" }, "workspaces": [ "packages/*" - ] + ], + "dependencies": { + "dotenv-flow": "^4.1.0" + } } \ No newline at end of file diff --git a/packages/functions/src/routes/items.js b/packages/functions/src/routes/items.js index 2e16b02..968231d 100644 --- a/packages/functions/src/routes/items.js +++ b/packages/functions/src/routes/items.js @@ -202,75 +202,75 @@ itemsRouter.get("/:id", async (req, res) => { } }); -// // Get email associated with an item id (only if user is logged in) -// itemsRouter.get("/:id/email", middleware.decodeToken, async (req, res) => { -// try { -// const { id } = req.params; - -// const item = await client.query( -// `SELECT email FROM ${itemsTable} WHERE id=$1`, -// [id] -// ); - -// res.json(item.rows[0]); -// } catch (error) { -// console.error(error); -// } -// }); +// Get email associated with an item id (only if user is logged in) +itemsRouter.get("/:id/email", async (req, res) => { + try { + const { id } = req.params; -// // Retrieve Items by Category -// itemsRouter.get("/category/:category", async (req, res) => { -// try { -// const { category } = req.params; + const item = await client.query( + `SELECT email FROM ${itemsTable} WHERE id=$1`, + [id] + ); -// const items = await client.query( -// `SELECT * FROM ${itemsTable} WHERE type=$1`, -// [category] -// ); + res.json(item.rows[0]); + } catch (error) { + console.error(error); + } +}); -// res.json(items.rows); -// } catch (error) { -// console.error(error); -// } -// }); +// Retrieve Items by Category +itemsRouter.get("/category/:category", async (req, res) => { + try { + const { category } = req.params; -// //Update a item resolve and helpfulness -// itemsRouter.put("/:id", middleware.decodeToken, async (req, res) => { -// try { -// const { id } = req.params; -// const { ishelped } = req.body; - -// const item = await client.query( -// `UPDATE ${itemsTable} SET isresolved=$1, ishelped=$2 WHERE id=$3 RETURNING *`, -// [true, ishelped, id] -// ); - -// res.json(item.rows[0]); -// } catch (error) { -// console.error(error); -// } -// }); + const items = await client.query( + `SELECT * FROM ${itemsTable} WHERE type=$1`, + [category] + ); -// // Mark an item as deleted instead of removing it from the database -// itemsRouter.delete("/:id", middleware.decodeToken, async (req, res) => { -// try { -// const { id } = req.params; - -// const markAsDeleted = await client.query( -// `UPDATE ${itemsTable} SET is_deleted = true WHERE id = $1 RETURNING *`, -// [id] -// ); - -// // If no rows are returned, it means that there was no item with the given ID. -// if (markAsDeleted.rowCount === 0) { -// return res.status(404).json({ message: "Item not found" }); -// } - -// res.json(markAsDeleted.rows[0]); -// } catch (error) { -// console.error(error.message); -// res.status(500).send("Server error"); -// } -// }); + res.json(items.rows); + } catch (error) { + console.error(error); + } +}); + +//Update a item resolve and helpfulness +itemsRouter.put("/:id", async (req, res) => { + try { + const { id } = req.params; + const { ishelped } = req.body; + + const item = await client.query( + `UPDATE ${itemsTable} SET isresolved=$1, ishelped=$2 WHERE id=$3 RETURNING *`, + [true, ishelped, id] + ); + + res.json(item.rows[0]); + } catch (error) { + console.error(error); + } +}); + +// Mark an item as deleted instead of removing it from the database +itemsRouter.delete("/:id", async (req, res) => { + try { + const { id } = req.params; + + const markAsDeleted = await client.query( + `UPDATE ${itemsTable} SET is_deleted = true WHERE id = $1 RETURNING *`, + [id] + ); + + // If no rows are returned, it means that there was no item with the given ID. + if (markAsDeleted.rowCount === 0) { + return res.status(404).json({ message: "Item not found" }); + } + + res.json(markAsDeleted.rows[0]); + } catch (error) { + console.error(error.message); + res.status(500).send("Server error"); + } +}); -// module.exports = itemsRouter; +module.exports = itemsRouter; diff --git a/packages/functions/src/routes/leaderboard.js b/packages/functions/src/routes/leaderboard.js index 28bb53c..f9a4f7c 100644 --- a/packages/functions/src/routes/leaderboard.js +++ b/packages/functions/src/routes/leaderboard.js @@ -1,12 +1,12 @@ const express = require("express"); const leaderboardRouter = express.Router(); -const middleware = require("../middleware/index.js"); +// const middleware = require("../middleware/index.js"); const { leaderboardTable } = require("../config/db-config.js"); const client = require("../server/db"); // add a user to leaderboard -leaderboardRouter.post("/", middleware.decodeToken, async (req, res) => { +leaderboardRouter.post("/", async (req, res) => { try { const { email, points } = req.body; // Get email and points from request body @@ -29,7 +29,6 @@ leaderboardRouter.post("/", middleware.decodeToken, async (req, res) => { // get all users on leaderboard (descending) leaderboardRouter.get("/", async (req, res) => { try { - const lbData = await client.query( `SELECT * FROM ${leaderboardTable} ORDER BY points DESC LIMIT 3` ); @@ -43,7 +42,6 @@ leaderboardRouter.get("/", async (req, res) => { // get count of users in leaderboard leaderboardRouter.get("/count", async (req, res) => { try { - const lbCount = await client.query( `SELECT COUNT(*) as count FROM ${leaderboardTable}` ); @@ -59,31 +57,27 @@ leaderboardRouter.get("/count", async (req, res) => { } }); -leaderboardRouter.patch( - "/changeSubscription", - middleware.decodeToken, - async (req, res) => { - try { - const { subscription, email } = req.body; - if (subscription === undefined) { - return res.status(400).send("Unsubscribe action is unknown"); - } - - await client.query( - `UPDATE ${leaderboardTable} SET subscription=$1 WHERE email=$2`, - [subscription, email] - ); - - res.send("Subscription updated successfully!"); - } catch (err) { - console.error(err); - res.status(500).send("Internal server error"); +leaderboardRouter.patch("/changeSubscription", async (req, res) => { + try { + const { subscription, email } = req.body; + if (subscription === undefined) { + return res.status(400).send("Unsubscribe action is unknown"); } + + await client.query( + `UPDATE ${leaderboardTable} SET subscription=$1 WHERE email=$2`, + [subscription, email] + ); + + res.send("Subscription updated successfully!"); + } catch (err) { + console.error(err); + res.status(500).send("Internal server error"); } -); +}); // update user's points -leaderboardRouter.put("/", middleware.decodeToken, async (req, res) => { +leaderboardRouter.put("/", async (req, res) => { const { email, pointsToAdd } = req.body; // Assume you're sending email and pointsToAdd in the request body if (!email || typeof pointsToAdd !== "number") { @@ -91,14 +85,12 @@ leaderboardRouter.put("/", middleware.decodeToken, async (req, res) => { } try { - // First, fetch the current points of the user const currentPointsResult = await client.query( `SELECT points FROM ${leaderboardTable} WHERE email=$1`, [email] ); - if (currentPointsResult.rows.length === 0) { return res.status(404).send("User not found"); } @@ -106,7 +98,6 @@ leaderboardRouter.put("/", middleware.decodeToken, async (req, res) => { const currentPoints = currentPointsResult.rows[0].points; const newPoints = currentPoints + pointsToAdd; - // Now, update the user's points in the leaderboard await client.query( `UPDATE ${leaderboardTable} SET points=$1 WHERE email=$2`, @@ -121,7 +112,7 @@ leaderboardRouter.put("/", middleware.decodeToken, async (req, res) => { }); // delete user from leaderboard -leaderboardRouter.delete("/:id", middleware.decodeToken, async (req, res) => { +leaderboardRouter.delete("/:id", async (req, res) => { try { const { id } = req.params; // Extract id from request body if (!id) { diff --git a/packages/functions/src/server.js b/packages/functions/src/server.js index e3bd2c2..33210e1 100644 --- a/packages/functions/src/server.js +++ b/packages/functions/src/server.js @@ -7,9 +7,9 @@ const app = express(); // const port = 8080; const serverless = require("serverless-http"); // ROUTES -// const items = require("./routes/items"); -// const nodemailer = require("./routes/nodeMailer"); -// const leaderboard = require("./routes/leaderboard"); +const items = require("./routes/items"); +const nodemailer = require("./routes/nodeMailer"); +const leaderboard = require("./routes/leaderboard"); app.use(cors()); app.use(express.json({ limit: "25mb" })); @@ -26,8 +26,8 @@ app.get("/", async (req, res) => { console.error(error); } }); -// app.use("/items", items); -// app.use("/leaderboard", leaderboard); -// app.use("/nodemailer", nodemailer); +app.use("/items", items); +app.use("/leaderboard", leaderboard); +app.use("/nodemailer", nodemailer); module.exports = serverless(app); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3749d78..9f9c70a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,6 +7,10 @@ settings: importers: .: + dependencies: + dotenv-flow: + specifier: ^4.1.0 + version: 4.1.0 devDependencies: '@tsconfig/node18': specifier: ^18.2.4 @@ -171,7 +175,7 @@ importers: version: 5.2.10 vite-tsconfig-paths: specifier: ^4.3.2 - version: 4.3.2(vite@5.2.10) + version: 4.3.2(typescript@5.4.5)(vite@5.2.10) web-vitals: specifier: ^2.1.4 version: 2.1.4 @@ -925,7 +929,7 @@ packages: - aws-crt dev: true - /@aws-sdk/client-sso-oidc@3.572.0: + /@aws-sdk/client-sso-oidc@3.572.0(@aws-sdk/client-sts@3.572.0): resolution: {integrity: sha512-S6C/S6xYesDakEuzYvlY1DMMKLtKQxdbbygq3hfeG2R0jUt9KpRLsQXK8qrBuVCKa3WcnjN/30hp4g/iUWFU/w==} engines: {node: '>=16.0.0'} dependencies: @@ -970,6 +974,7 @@ packages: '@smithy/util-utf8': 2.3.0 tslib: 2.6.2 transitivePeerDependencies: + - '@aws-sdk/client-sts' - aws-crt dev: true @@ -1074,7 +1079,7 @@ packages: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.572.0 + '@aws-sdk/client-sso-oidc': 3.572.0(@aws-sdk/client-sts@3.572.0) '@aws-sdk/core': 3.572.0 '@aws-sdk/credential-provider-node': 3.572.0(@aws-sdk/client-sso-oidc@3.572.0)(@aws-sdk/client-sts@3.572.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -1643,7 +1648,7 @@ packages: peerDependencies: '@aws-sdk/client-sso-oidc': 3.572.0 dependencies: - '@aws-sdk/client-sso-oidc': 3.572.0 + '@aws-sdk/client-sso-oidc': 3.572.0(@aws-sdk/client-sts@3.572.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 @@ -3174,6 +3179,7 @@ packages: /@emotion/memoize@0.7.4: resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} + requiresBuild: true dev: false optional: true @@ -4577,6 +4583,7 @@ packages: /@google-cloud/paginator@5.0.0: resolution: {integrity: sha512-87aeg6QQcEPxGCOthnpUjvw4xAZ57G7pL8FS0C4e/81fr3FjkpUpibf1s2v5XGyGhUVGF4Jfg7yEcxqn2iUw1w==} engines: {node: '>=14.0.0'} + requiresBuild: true dependencies: arrify: 2.0.1 extend: 3.0.2 @@ -4586,12 +4593,14 @@ packages: /@google-cloud/projectify@4.0.0: resolution: {integrity: sha512-MmaX6HeSvyPbWGwFq7mXdo0uQZLGBYCwziiLIGq5JVX+/bdI3SAq6bP98trV5eTWfLuvsMcIC1YJOF2vfteLFA==} engines: {node: '>=14.0.0'} + requiresBuild: true dev: false optional: true /@google-cloud/promisify@4.0.0: resolution: {integrity: sha512-Orxzlfb9c67A15cq2JQEyVc7wEsmFBmHjZWZYQMUyJ1qivXyMwdyNOs9odi79hze+2zqdTtu1E19IM/FtqZ10g==} engines: {node: '>=14'} + requiresBuild: true dev: false optional: true @@ -4699,6 +4708,7 @@ packages: /@grpc/grpc-js@1.10.7: resolution: {integrity: sha512-ZMBVjSeDAz3tFSehyO6Pd08xZT1HfIwq3opbeM4cDlBh52gmwp0wVIPcQur53NN0ac68HMZ/7SF2rGRD5KmVmg==} engines: {node: '>=12.10.0'} + requiresBuild: true dependencies: '@grpc/proto-loader': 0.7.13 '@js-sdsl/ordered-map': 4.4.2 @@ -4845,6 +4855,7 @@ packages: /@js-sdsl/ordered-map@4.4.2: resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + requiresBuild: true dev: false optional: true @@ -5789,6 +5800,7 @@ packages: /@tootallnate/once@2.0.0: resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} engines: {node: '>= 10'} + requiresBuild: true dev: false optional: true @@ -5848,6 +5860,7 @@ packages: /@types/caseless@0.12.5: resolution: {integrity: sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==} + requiresBuild: true dev: false optional: true @@ -5970,6 +5983,7 @@ packages: /@types/request@2.48.12: resolution: {integrity: sha512-G3sY+NpsA9jnwm0ixhAFQSJ3Q9JkpLZpJbI3GMv0mIAT0y3mRabYeINzal5WOChIiaTEGQYlHOKgkaM9EisWHw==} + requiresBuild: true dependencies: '@types/caseless': 0.12.5 '@types/node': 20.12.7 @@ -6005,6 +6019,7 @@ packages: /@types/tough-cookie@4.0.5: resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + requiresBuild: true dev: false optional: true @@ -6129,6 +6144,7 @@ packages: /abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} + requiresBuild: true dependencies: event-target-shim: 5.0.1 dev: false @@ -6160,6 +6176,7 @@ packages: /agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} + requiresBuild: true dependencies: debug: 4.3.4 transitivePeerDependencies: @@ -6317,6 +6334,7 @@ packages: /arrify@2.0.1: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} engines: {node: '>=8'} + requiresBuild: true dev: false optional: true @@ -6353,6 +6371,7 @@ packages: /async-retry@1.3.3: resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + requiresBuild: true dependencies: retry: 0.13.1 dev: false @@ -7132,6 +7151,13 @@ packages: is-obj: 2.0.0 dev: true + /dotenv-flow@4.1.0: + resolution: {integrity: sha512-0cwP9jpQBQfyHwvE0cRhraZMkdV45TQedA8AAUZMsFzvmLcQyc1HPv+oX0OOYwLFjIlvgVepQ+WuQHbqDaHJZg==} + engines: {node: '>= 12.0.0'} + dependencies: + dotenv: 16.4.5 + dev: false + /dotenv@16.1.4: resolution: {integrity: sha512-m55RtE8AsPeJBpOIFKihEmqUcoVncQIwo7x9U8ZwLEZw9ZpXboz2c+rvog+jUaJvVrZ5kBOeYQBX5+8Aa/OZQw==} engines: {node: '>=12'} @@ -7322,6 +7348,7 @@ packages: /event-target-shim@5.0.1: resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} engines: {node: '>=6'} + requiresBuild: true dev: false optional: true @@ -7451,6 +7478,7 @@ packages: /fast-xml-parser@4.3.6: resolution: {integrity: sha512-M2SovcRxD4+vC493Uc2GZVcZaj66CCJhWurC4viynVSTvrpErCShNcDz1lAho6n9REQKvL/ll4A4/fw6Y9z8nw==} hasBin: true + requiresBuild: true dependencies: strnum: 1.0.5 dev: false @@ -7632,6 +7660,7 @@ packages: /form-data@2.5.1: resolution: {integrity: sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==} engines: {node: '>= 0.12'} + requiresBuild: true dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 @@ -7716,6 +7745,7 @@ packages: /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + requiresBuild: true dev: false optional: true @@ -7856,6 +7886,7 @@ packages: /google-gax@4.3.3: resolution: {integrity: sha512-f4F2Y9X4+mqsrJuLZsuTljYuQpcBnQsCt9ScvZpdM8jGjqrcxyJi5JUiqtq0jtpdHVPzyit0N7f5t07e+kH5EA==} engines: {node: '>=14'} + requiresBuild: true dependencies: '@grpc/grpc-js': 1.10.7 '@grpc/proto-loader': 0.7.13 @@ -8001,6 +8032,7 @@ packages: /html-entities@2.5.2: resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + requiresBuild: true dev: false optional: true @@ -8021,6 +8053,7 @@ packages: /http-proxy-agent@5.0.0: resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} engines: {node: '>= 6'} + requiresBuild: true dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 @@ -8033,6 +8066,7 @@ packages: /https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} + requiresBuild: true dependencies: agent-base: 6.0.2 debug: 4.3.4 @@ -8877,6 +8911,7 @@ packages: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} hasBin: true + requiresBuild: true dev: false optional: true @@ -9137,6 +9172,7 @@ packages: /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} + requiresBuild: true dev: false optional: true @@ -9239,6 +9275,7 @@ packages: /p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + requiresBuild: true dependencies: yocto-queue: 0.1.0 dev: false @@ -9505,6 +9542,7 @@ packages: /proto3-json-serializer@2.0.1: resolution: {integrity: sha512-8awBvjO+FwkMd6gNoGFZyqkHZXCFd54CIYTb6De7dPaufGJ2XNW+QUNqbMr8MaAocMdb+KpsD4rxEOaTBDCffA==} engines: {node: '>=14.0.0'} + requiresBuild: true dependencies: protobufjs: 7.3.0 dev: false @@ -10000,6 +10038,7 @@ packages: /retry-request@7.0.2: resolution: {integrity: sha512-dUOvLMJ0/JJYEn8NrpOaGNE7X3vpI5XlZS/u0ANjqtcZVKnIxP7IgCFwrKTxENw29emmwug53awKtaMm4i9g5w==} engines: {node: '>=14'} + requiresBuild: true dependencies: '@types/request': 2.48.12 extend: 3.0.2 @@ -10013,6 +10052,7 @@ packages: /retry@0.13.1: resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} engines: {node: '>= 4'} + requiresBuild: true dev: false optional: true @@ -10366,6 +10406,7 @@ packages: /stream-events@1.0.5: resolution: {integrity: sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==} + requiresBuild: true dependencies: stubs: 3.0.0 dev: false @@ -10448,6 +10489,7 @@ packages: /stubs@3.0.0: resolution: {integrity: sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw==} + requiresBuild: true dev: false optional: true @@ -10510,6 +10552,7 @@ packages: /teeny-request@9.0.0: resolution: {integrity: sha512-resvxdc6Mgb7YEThw6G6bExlXKkv6+YbuzGg9xuXxSgxJF7Ozs+o8Y9+2R3sArdWdW8nOokoQb1yrpFB0pQK2g==} engines: {node: '>=14'} + requiresBuild: true dependencies: http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 @@ -10571,7 +10614,7 @@ packages: hasBin: true dev: true - /tsconfck@3.0.3: + /tsconfck@3.0.3(typescript@5.4.5): resolution: {integrity: sha512-4t0noZX9t6GcPTfBAbIbbIU4pfpCwh0ueq3S4O/5qXI1VwK1outmxhe9dOiEWqMz3MW2LKgDTpqWV+37IWuVbA==} engines: {node: ^18 || >=20} hasBin: true @@ -10580,6 +10623,8 @@ packages: peerDependenciesMeta: typescript: optional: true + dependencies: + typescript: 5.4.5 dev: false /tslib@1.14.1: @@ -10624,7 +10669,6 @@ packages: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} hasBin: true - dev: true /ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} @@ -10772,7 +10816,7 @@ packages: - terser dev: true - /vite-tsconfig-paths@4.3.2(vite@5.2.10): + /vite-tsconfig-paths@4.3.2(typescript@5.4.5)(vite@5.2.10): resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} peerDependencies: vite: '*' @@ -10782,7 +10826,7 @@ packages: dependencies: debug: 4.3.4 globrex: 0.1.2 - tsconfck: 3.0.3 + tsconfck: 3.0.3(typescript@5.4.5) vite: 5.2.10 transitivePeerDependencies: - supports-color @@ -11167,6 +11211,7 @@ packages: /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + requiresBuild: true dev: false optional: true diff --git a/sst.config.ts b/sst.config.ts index 2745623..310d9e1 100644 --- a/sst.config.ts +++ b/sst.config.ts @@ -1,5 +1,11 @@ import { SSTConfig } from "sst"; -import { API } from "./stacks/MyStack"; +import { FrontendStack } from "./stacks/frontend"; +import { BackendStack } from "./stacks/backend"; +import dotenv from "dotenv-flow"; + +import { App } from "sst/constructs"; + +dotenv.config(); export default { config(_input) { @@ -9,6 +15,7 @@ export default { }; }, stacks(app) { - app.stack(API); - } + app + .stack(BackendStack, { stackName: `${app.name}-${app.stage}-backend` }) + .stack(FrontendStack, { stackName: `${app.name}-${app.stage}-frontend` }); }, } satisfies SSTConfig; diff --git a/stacks/backend.ts b/stacks/backend.ts new file mode 100644 index 0000000..d8481c1 --- /dev/null +++ b/stacks/backend.ts @@ -0,0 +1,24 @@ +import { StackContext, Api, EventBus } from "sst/constructs"; + +export function BackendStack({ stack }: StackContext) { + const bus = new EventBus(stack, "bus", { + defaults: { + retries: 10, + }, + }); + + const api = new Api(stack, "api", { + defaults: { + function: { + bind: [bus], + }, + }, + routes: { $default: "packages/functions/src/server.default" }, + }); + + stack.addOutputs({ + ApiEndpoint: api.url, + }); + + process.env.API_URL = api.url; // Set the API URL to be used by the frontend stack +} diff --git a/stacks/frontend.ts b/stacks/frontend.ts new file mode 100644 index 0000000..e15ae4c --- /dev/null +++ b/stacks/frontend.ts @@ -0,0 +1,27 @@ +import { StackContext, StaticSite } from "sst/constructs"; + +export function FrontendStack({ stack }: StackContext) { + const apiUrl = process.env.API_URL as string; // Ensure API_URL is treated as a string + + const web = new StaticSite(stack, "web", { + path: "packages/web", + buildOutput: "dist", + buildCommand: "pnpm run build", + customDomain: "zotnfound.com", + environment: { + VITE_REACT_APP_AWS_BACKEND_URL: apiUrl, + VITE_REACT_APP_API_KEY: process.env.VITE_REACT_APP_API_KEY!, + VITE_REACT_APP_AUTH_DOMAIN: process.env.VITE_REACT_APP_AUTH_DOMAIN!, + VITE_REACT_APP_PROJECT_ID: process.env.VITE_REACT_APP_PROJECT_ID!, + VITE_REACT_APP_STORAGE_BUCKET: process.env.VITE_REACT_APP_STORAGE_BUCKET!, + VITE_REACT_APP_MESSAGING_SENDER_ID: + process.env.VITE_REACT_APP_MESSAGING_SENDER_ID!, + VITE_REACT_APP_APP_ID: process.env.VITE_REACT_APP_APP_ID!, + VITE_REACT_APP_MEASUREMENT_ID: process.env.VITE_REACT_APP_MEASUREMENT_ID!, + }, + }); + + stack.addOutputs({ + WebEndpoint: web.customDomainUrl, + }); +}