Bansari Akhani commited on
Commit
389ef0e
·
1 Parent(s): adca714

invoice list apis

Browse files
package.json CHANGED
@@ -8,6 +8,7 @@
8
  "aws-sdk": "^2.1659.0",
9
  "axios": "^1.7.2",
10
  "babel-register": "^6.26.0",
 
11
  "bcryptjs": "^2.4.3",
12
  "dotenv": "^16.4.5",
13
  "express": "^4.19.2",
@@ -20,6 +21,7 @@
20
  "sequelize-typescript": "^2.1.6"
21
  },
22
  "devDependencies": {
 
23
  "@types/bcryptjs": "^2",
24
  "@types/dotenv": "^8.2.0",
25
  "@types/express": "^4.17.21",
 
8
  "aws-sdk": "^2.1659.0",
9
  "axios": "^1.7.2",
10
  "babel-register": "^6.26.0",
11
+ "cors": "^2.8.5",
12
  "bcryptjs": "^2.4.3",
13
  "dotenv": "^16.4.5",
14
  "express": "^4.19.2",
 
21
  "sequelize-typescript": "^2.1.6"
22
  },
23
  "devDependencies": {
24
+ "@types/cors": "^2",
25
  "@types/bcryptjs": "^2",
26
  "@types/dotenv": "^8.2.0",
27
  "@types/express": "^4.17.21",
src/app.ts CHANGED
@@ -1,18 +1,25 @@
1
  import express from 'express';
 
2
 
3
- import router from './routes';
 
4
  import userRouter from './routes/users';
5
 
6
  const app = express();
 
7
  const port = 3000;
8
  app.use(express.json());
9
 
10
- app.get('/', (req, res) => {
 
 
11
  res.send('Service is healthy!');
12
  });
13
 
 
 
 
14
  app.use('/api/users/', userRouter)
15
- app.use("/api/", router);
16
 
17
  try {
18
  app.listen(port, () => {
 
1
  import express from 'express';
2
+ import cors from 'cors';
3
 
4
+ import invoiceRouter from './routes/invoice.routes';
5
+ import pwRouter from './routes/propertyware.routes';
6
  import userRouter from './routes/users';
7
 
8
  const app = express();
9
+
10
  const port = 3000;
11
  app.use(express.json());
12
 
13
+ app.use(cors());
14
+
15
+ app.get('/', (_, res) => {
16
  res.send('Service is healthy!');
17
  });
18
 
19
+
20
+ app.use("/api/pw", pwRouter);
21
+ app.use('/api/invoices', invoiceRouter);
22
  app.use('/api/users/', userRouter)
 
23
 
24
  try {
25
  app.listen(port, () => {
src/controllers/invoice/invoice.controller.ts CHANGED
@@ -1,58 +1,138 @@
1
- import { Request, Response } from 'express';
2
 
3
  // import Invoice from '../../models/invoice';
4
- import { uploadInvoice } from '../../shared/services/invoice.service';
5
- import { parseInvoice } from '../../shared/services/ai.service'
6
- import FormData from 'form-data';
7
- import Invoice from '../../models/invoice';
 
 
8
 
9
  export const createInvoice = async (req: Request, res: Response) => {
10
- const files = req.files as Express.Multer.File[];
11
- const uploadPromises = uploadInvoice(files);
12
- const uploadResults = await Promise.all(uploadPromises);
13
-
14
- console.log(uploadResults);
15
- if (files?.length) {
16
-
17
- files.forEach(async (file, index) => {
18
- const formData = new FormData();
19
- formData.append('file', files[0].buffer, files[0].originalname);
20
- // Send the file URLs to the AI service API for parsing
21
- const aiServiceResponse = await parseInvoice(formData);
22
- const aiServiceData = aiServiceResponse;
23
- console.log(aiServiceData);
24
-
25
- try {
26
- let invoiceRecord = {
27
- reference_number: aiServiceData.refNo,
28
- vendor_name: aiServiceData.vendor,
29
- invoice_date: aiServiceData.billDate,
30
- due_date: aiServiceData.dueDate,
31
- total: aiServiceData.total,
32
- description: aiServiceData.description,
33
- status: 'Pending',
34
- amount_paid:0,
35
- pdf_url:uploadResults[index].Location,
36
- uploaded_by:1 // TODO : replace with logged in user when user module is implemented
37
- };
38
-
39
- // const invoiceRecords = uploadResults.map(result => ({
40
- // fileName: result.Key,
41
- // // s3Key: result.Key,
42
- // }));
43
-
44
- await Invoice.create(invoiceRecord);
45
-
46
- res.status(200).json({
47
- message: 'Invoices uploaded successfully',
48
- invoices: invoiceRecord
49
- });
50
- } catch (error) {
51
- console.error(error);
52
- res.status(500).json({ message: 'Error uploading invoices', error });
53
- }
54
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  }
56
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- export { uploadInvoice };
 
 
 
 
 
 
1
+ import { Request, Response } from "express";
2
 
3
  // import Invoice from '../../models/invoice';
4
+ import { uploadInvoice } from "../../shared/services/invoice.service";
5
+ import { parseInvoice } from "../../shared/services/ai.service";
6
+ import FormData from "form-data";
7
+ import Invoice from "../../models/invoice";
8
+ import InvoiceDetail from "../../models/invoicedetail";
9
+ import User from "../../models/users";
10
 
11
  export const createInvoice = async (req: Request, res: Response) => {
12
+ const files = req.files as Express.Multer.File[];
13
+
14
+ if (files?.length) {
15
+ try {
16
+ const uploadPromises = uploadInvoice(files);
17
+ const uploadResults = await Promise.all(uploadPromises);
18
+
19
+ const createInvoicePromises = files.map(async (file, index) => {
20
+ const formData = new FormData();
21
+ formData.append("file", file.buffer, file.originalname);
22
+
23
+ // Send the file URLs to the AI service API for parsing
24
+ const aiServiceResponse = await parseInvoice(formData);
25
+ const aiServiceData = aiServiceResponse[0];
26
+
27
+ const totalAmount = aiServiceData.billSplits.reduce(
28
+ (total: number, split: { amount: number }) => total + split.amount,
29
+ 0
30
+ );
31
+ const invoiceDate = new Date(aiServiceData.billDate);
32
+ const dueDate = new Date(aiServiceData.dueDate);
33
+ let invoiceRecord = {
34
+ reference_number: aiServiceData.refNo,
35
+ vendor_name: aiServiceData.vendor,
36
+ pw_vendor_id: aiServiceData.vendor,
37
+ invoice_date: invoiceDate,
38
+ due_date: dueDate,
39
+ total: totalAmount,
40
+ description: aiServiceData.description,
41
+ status: "Pending",
42
+ amount_paid: 0,
43
+ filename: file.originalname,
44
+ pdf_url: uploadResults[index].Location,
45
+ uploaded_by: 1, // TODO : replace with logged in user when user module is implemented
46
+ };
47
+
48
+ const result = await Invoice.create(invoiceRecord);
49
+
50
+ // Create Invoice Details
51
+ const invoiceDetails = aiServiceData.billSplits.map(
52
+ (details: {
53
+ portfolio: any;
54
+ building: any;
55
+ unit: any;
56
+ glAccount: any;
57
+ amount: any;
58
+ description: any;
59
+ }) => ({
60
+ invoice_id: result.id,
61
+ pw_portfolio_id: details.portfolio,
62
+ pw_building_id: details.building,
63
+ pw_unit_id: details.unit,
64
+ pw_gl_account_id: details.glAccount,
65
+ amount: details.amount,
66
+ description: details.description,
67
+ })
68
+ );
69
+
70
+ await InvoiceDetail.bulkCreate(invoiceDetails);
71
+ });
72
+
73
+ await Promise.all(createInvoicePromises);
74
+
75
+ res.status(201).json({ message: "Invoices created successfully" });
76
+ } catch (error) {
77
+ console.error(error);
78
+ res.status(500).json({ message: "Error creating invoices", error });
79
  }
80
+ } else {
81
+ res.status(400).json({ message: "No files uploaded" });
82
+ }
83
+ };
84
+
85
+ // Get All Invoices
86
+ export const getAllInvoices = async (req: Request, res: Response): Promise<Response> => {
87
+ try {
88
+ const invoices = await Invoice.findAll({
89
+ include: [
90
+ { model: User, as: 'uploadedBy' }
91
+ ]
92
+ });
93
+
94
+ if (invoices.length === 0) {
95
+ return res.status(404).json({ error: "No invoices found" });
96
+ }
97
+
98
+ return res.status(200).json(invoices);
99
+ } catch (error) {
100
+ console.error("Error fetching invoices:", error);
101
+ return res.status(500).json({ error: "Error fetching invoices" });
102
+ }
103
+ };
104
+
105
+ export const getInvoiceById = async (req: Request, res: Response): Promise<Response> => {
106
+ try {
107
+ const { id } = req.params;
108
+ const invoice = await Invoice.findByPk(id);
109
+
110
+ if (!invoice) {
111
+ return res.status(404).json({ error: "Invoice not found" });
112
+ }
113
+
114
+ return res.status(200).json(invoice);
115
+ } catch (error) {
116
+ console.error("Error fetching invoice:", error);
117
+ return res.status(500).json({ error: "Error fetching invoice details" });
118
+ }
119
+ };
120
+
121
+ // Delete an invoice
122
+ export const deleteInvoice = async (req: Request, res: Response): Promise<Response> => {
123
+ try {
124
+ const { id } = req.params;
125
+ const invoice = await Invoice.findByPk(id);
126
+
127
+ if (!invoice) {
128
+ return res.status(404).json({ error: "Invoice not found" });
129
+ }
130
+
131
+ await invoice.destroy();
132
 
133
+ return res.status(204).send();
134
+ } catch (error) {
135
+ console.error("Error deleting invoice:", error);
136
+ return res.status(500).json({ error: "Internal server error" });
137
+ }
138
+ };
src/db/migrations/20240711110620-create-invoice-table.js CHANGED
@@ -10,20 +10,16 @@ module.exports = {
10
  type: Sequelize.INTEGER
11
  },
12
  reference_number: {
13
- allowNull: false,
14
  type: Sequelize.STRING(100),
15
  unique: true
16
  },
17
  vendor_name: {
18
- allowNull: false,
19
  type: Sequelize.STRING(255)
20
  },
21
  invoice_date: {
22
- allowNull: false,
23
  type: Sequelize.DATE
24
  },
25
  total: {
26
- allowNull: false,
27
  type: Sequelize.DECIMAL(10, 2)
28
  },
29
  amount_paid: {
@@ -45,10 +41,14 @@ module.exports = {
45
  defaultValue: 'pending'
46
  },
47
  pw_work_order_id: {
48
- type: Sequelize.INTEGER
49
  },
50
  pw_vendor_id: {
51
- type: Sequelize.INTEGER
 
 
 
 
52
  },
53
  pdf_url: {
54
  type: Sequelize.STRING(255)
@@ -73,4 +73,4 @@ module.exports = {
73
  async down(queryInterface, Sequelize) {
74
  await queryInterface.dropTable('invoices');
75
  }
76
- };
 
10
  type: Sequelize.INTEGER
11
  },
12
  reference_number: {
 
13
  type: Sequelize.STRING(100),
14
  unique: true
15
  },
16
  vendor_name: {
 
17
  type: Sequelize.STRING(255)
18
  },
19
  invoice_date: {
 
20
  type: Sequelize.DATE
21
  },
22
  total: {
 
23
  type: Sequelize.DECIMAL(10, 2)
24
  },
25
  amount_paid: {
 
41
  defaultValue: 'pending'
42
  },
43
  pw_work_order_id: {
44
+ type: Sequelize.BIGINT
45
  },
46
  pw_vendor_id: {
47
+ type: Sequelize.BIGINT
48
+ },
49
+ filename:{
50
+ type: Sequelize.STRING(255),
51
+ allowNull: false,
52
  },
53
  pdf_url: {
54
  type: Sequelize.STRING(255)
 
73
  async down(queryInterface, Sequelize) {
74
  await queryInterface.dropTable('invoices');
75
  }
76
+ };
src/db/migrations/20240715065820-create-invoice-detail.js CHANGED
@@ -28,7 +28,7 @@ module.exports = {
28
  type: Sequelize.BIGINT,
29
  },
30
  pw_gl_account_id: {
31
- type: Sequelize.INTEGER,
32
  defaultValue: null,
33
  },
34
  amount: {
@@ -49,4 +49,4 @@ module.exports = {
49
  async down(queryInterface, Sequelize) {
50
  await queryInterface.dropTable('invoice_details');
51
  }
52
- };
 
28
  type: Sequelize.BIGINT,
29
  },
30
  pw_gl_account_id: {
31
+ type: Sequelize.BIGINT,
32
  defaultValue: null,
33
  },
34
  amount: {
 
49
  async down(queryInterface, Sequelize) {
50
  await queryInterface.dropTable('invoice_details');
51
  }
52
+ };
src/models/invoice.ts CHANGED
@@ -7,8 +7,9 @@ import {
7
  } from 'sequelize';
8
  import { sequelize } from './index';
9
  import { InvoiceInterface } from '../shared/interfaces/invoice.interface';
 
10
 
11
- class Invoice extends Model<InferAttributes<Invoice>, InferCreationAttributes<Invoice>> implements InvoiceInterface {
12
  declare id?: CreationOptional<number>;
13
  declare reference_number: string;
14
  declare vendor_name: string;
@@ -21,6 +22,7 @@ class Invoice extends Model<InferAttributes<Invoice>, InferCreationAttributes<In
21
  declare payment_status?: string;
22
  declare pw_work_order_id?: number;
23
  declare pw_vendor_id?: number;
 
24
  declare pdf_url?: string;
25
  declare status: string;
26
  declare uploaded_by: number;
@@ -35,24 +37,19 @@ Invoice.init(
35
  },
36
  reference_number: {
37
  type: DataTypes.STRING(100),
38
- allowNull: false,
39
  unique: true,
40
  },
41
  vendor_name: {
42
  type: DataTypes.STRING(255),
43
- allowNull: false,
44
  },
45
  invoice_date: {
46
  type: DataTypes.DATE,
47
- allowNull: false,
48
  },
49
  total: {
50
  type: DataTypes.DECIMAL(10, 2),
51
- allowNull: false,
52
  },
53
  amount_paid: {
54
  type: DataTypes.DECIMAL(10, 2),
55
- allowNull: false,
56
  },
57
  due_date: {
58
  type: DataTypes.DATE,
@@ -78,6 +75,10 @@ Invoice.init(
78
  type: DataTypes.INTEGER,
79
  allowNull: true,
80
  },
 
 
 
 
81
  pdf_url: {
82
  type: DataTypes.STRING(255),
83
  allowNull: true,
@@ -102,5 +103,6 @@ Invoice.init(
102
  }
103
  );
104
 
 
105
 
106
- export default Invoice;
 
7
  } from 'sequelize';
8
  import { sequelize } from './index';
9
  import { InvoiceInterface } from '../shared/interfaces/invoice.interface';
10
+ import User from './users';
11
 
12
+ class Invoice extends Model<InvoiceInterface> implements InvoiceInterface {
13
  declare id?: CreationOptional<number>;
14
  declare reference_number: string;
15
  declare vendor_name: string;
 
22
  declare payment_status?: string;
23
  declare pw_work_order_id?: number;
24
  declare pw_vendor_id?: number;
25
+ declare filename?: string;
26
  declare pdf_url?: string;
27
  declare status: string;
28
  declare uploaded_by: number;
 
37
  },
38
  reference_number: {
39
  type: DataTypes.STRING(100),
 
40
  unique: true,
41
  },
42
  vendor_name: {
43
  type: DataTypes.STRING(255),
 
44
  },
45
  invoice_date: {
46
  type: DataTypes.DATE,
 
47
  },
48
  total: {
49
  type: DataTypes.DECIMAL(10, 2),
 
50
  },
51
  amount_paid: {
52
  type: DataTypes.DECIMAL(10, 2),
 
53
  },
54
  due_date: {
55
  type: DataTypes.DATE,
 
75
  type: DataTypes.INTEGER,
76
  allowNull: true,
77
  },
78
+ filename:{
79
+ type: DataTypes.STRING(255),
80
+ allowNull: false,
81
+ },
82
  pdf_url: {
83
  type: DataTypes.STRING(255),
84
  allowNull: true,
 
103
  }
104
  );
105
 
106
+ Invoice.belongsTo(User, { foreignKey: 'uploaded_by', as: 'uploadedBy' });
107
 
108
+ export default Invoice;
src/routes/invoice.routes.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import express from 'express';
2
+ import { multipleUpload } from '../middlewares/multer';
3
+
4
+ import {
5
+ createInvoice,
6
+ getAllInvoices,
7
+ getInvoiceById,
8
+ deleteInvoice,
9
+ } from '../controllers/invoice/invoice.controller';
10
+
11
+ const invoiceRouter = express.Router();
12
+
13
+ invoiceRouter.post("/", multipleUpload, createInvoice);
14
+ invoiceRouter.get('/', getAllInvoices);
15
+ invoiceRouter.get('/:id', getInvoiceById);
16
+ invoiceRouter.delete('/:id', deleteInvoice);
17
+
18
+ export default invoiceRouter;
src/routes/{index.ts → propertyware.routes.ts} RENAMED
@@ -1,22 +1,17 @@
1
  import express from "express";
2
- import { multipleUpload } from '../middlewares/multer';
3
 
4
- import { fetchVendorsData } from "../controllers/propertyware/vendors.controller";
5
  import { fetchGLAccountsData } from "../controllers/propertyware/glAccounts.controller";
6
  import { syncPortfolioData } from "../controllers/propertyware/portfolio.controller";
7
- import { syncBuildingsData } from "../controllers/propertyware/buildings.controller";
8
  import { syncUnitsData } from "../controllers/propertyware/units.controller";
9
- import { createInvoice } from "../controllers/invoice/invoice.controller";
10
-
11
- const router = express.Router();
12
-
13
- router.get("/pw/glAccounts", fetchGLAccountsData);
14
- router.get("/pw/vendors", fetchVendorsData);
15
- router.get("/pw/syncPortfolio", syncPortfolioData);
16
- router.get("/pw/syncBuildings", syncBuildingsData);
17
- router.get("/pw/syncUnits", syncUnitsData);
18
 
19
- router.post("/invoice", multipleUpload, createInvoice);
20
 
 
 
 
 
 
21
 
22
- export default router;
 
1
  import express from "express";
 
2
 
3
+ import { syncBuildingsData } from "../controllers/propertyware/buildings.controller";
4
  import { fetchGLAccountsData } from "../controllers/propertyware/glAccounts.controller";
5
  import { syncPortfolioData } from "../controllers/propertyware/portfolio.controller";
 
6
  import { syncUnitsData } from "../controllers/propertyware/units.controller";
7
+ import { fetchVendorsData } from "../controllers/propertyware/vendors.controller";
 
 
 
 
 
 
 
 
8
 
9
+ const pwRouter = express.Router();
10
 
11
+ pwRouter.get("/glAccounts", fetchGLAccountsData);
12
+ pwRouter.get("/vendors", fetchVendorsData);
13
+ pwRouter.get("/syncPortfolio", syncPortfolioData);
14
+ pwRouter.get("/syncBuildings", syncBuildingsData);
15
+ pwRouter.get("/syncUnits", syncUnitsData);
16
 
17
+ export default pwRouter;
src/shared/interfaces/invoice.interface.ts CHANGED
@@ -1,9 +1,9 @@
1
  export interface InvoiceInterface {
2
  id?: number;
3
- reference_number: string;
4
- vendor_name: string;
5
- invoice_date: Date;
6
- total: number;
7
  amount_paid: number;
8
  due_date?: Date;
9
  term?: string;
@@ -11,6 +11,7 @@ export interface InvoiceInterface {
11
  payment_status?: string;
12
  pw_work_order_id?: number;
13
  pw_vendor_id?: number;
 
14
  pdf_url?: string;
15
  status: string;
16
  uploaded_by: number;
 
1
  export interface InvoiceInterface {
2
  id?: number;
3
+ reference_number?: string;
4
+ vendor_name?: string;
5
+ invoice_date?: Date;
6
+ total?: number;
7
  amount_paid: number;
8
  due_date?: Date;
9
  term?: string;
 
11
  payment_status?: string;
12
  pw_work_order_id?: number;
13
  pw_vendor_id?: number;
14
+ filename?: string;
15
  pdf_url?: string;
16
  status: string;
17
  uploaded_by: number;
src/shared/services/invoice.service.ts CHANGED
@@ -1,8 +1,6 @@
1
  import { s3 } from '../../middlewares/multer';
2
 
3
  export const uploadInvoice = (files: Express.Multer.File[]) => {
4
- console.log(files);
5
-
6
  const uploadPromises = files.map(file => {
7
  const params = {
8
  Bucket: process.env.AWS_S3_BUCKET_NAME || '',
 
1
  import { s3 } from '../../middlewares/multer';
2
 
3
  export const uploadInvoice = (files: Express.Multer.File[]) => {
 
 
4
  const uploadPromises = files.map(file => {
5
  const params = {
6
  Bucket: process.env.AWS_S3_BUCKET_NAME || '',
yarn.lock CHANGED
@@ -1546,6 +1546,15 @@ __metadata:
1546
  languageName: node
1547
  linkType: hard
1548
 
 
 
 
 
 
 
 
 
 
1549
  "@types/debug@npm:^4.1.8":
1550
  version: 4.1.12
1551
  resolution: "@types/debug@npm:4.1.12"
@@ -2534,6 +2543,16 @@ __metadata:
2534
  languageName: node
2535
  linkType: hard
2536
 
 
 
 
 
 
 
 
 
 
 
2537
  "create-require@npm:^1.1.0":
2538
  version: 1.1.1
2539
  resolution: "create-require@npm:1.1.1"
@@ -3138,7 +3157,7 @@ __metadata:
3138
  resolution: "fb-api@workspace:."
3139
  dependencies:
3140
  "@aws-sdk/client-s3": "npm:^3.614.0"
3141
- "@types/bcryptjs": "npm:^2"
3142
  "@types/dotenv": "npm:^8.2.0"
3143
  "@types/express": "npm:^4.17.21"
3144
  "@types/multer": "npm:^1"
@@ -3149,7 +3168,7 @@ __metadata:
3149
  aws-sdk: "npm:^2.1659.0"
3150
  axios: "npm:^1.7.2"
3151
  babel-register: "npm:^6.26.0"
3152
- bcryptjs: "npm:^2.4.3"
3153
  dotenv: "npm:^16.4.5"
3154
  eslint: "npm:^9.7.0"
3155
  eslint-config-prettier: "npm:^9.1.0"
@@ -4473,7 +4492,7 @@ __metadata:
4473
  languageName: node
4474
  linkType: hard
4475
 
4476
- "object-assign@npm:^4.1.1":
4477
  version: 4.1.1
4478
  resolution: "object-assign@npm:4.1.1"
4479
  checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
@@ -5675,7 +5694,7 @@ __metadata:
5675
  languageName: node
5676
  linkType: hard
5677
 
5678
- "vary@npm:~1.1.2":
5679
  version: 1.1.2
5680
  resolution: "vary@npm:1.1.2"
5681
  checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f
 
1546
  languageName: node
1547
  linkType: hard
1548
 
1549
+ "@types/cors@npm:^2":
1550
+ version: 2.8.17
1551
+ resolution: "@types/cors@npm:2.8.17"
1552
+ dependencies:
1553
+ "@types/node": "npm:*"
1554
+ checksum: 10c0/457364c28c89f3d9ed34800e1de5c6eaaf344d1bb39af122f013322a50bc606eb2aa6f63de4e41a7a08ba7ef454473926c94a830636723da45bf786df032696d
1555
+ languageName: node
1556
+ linkType: hard
1557
+
1558
  "@types/debug@npm:^4.1.8":
1559
  version: 4.1.12
1560
  resolution: "@types/debug@npm:4.1.12"
 
2543
  languageName: node
2544
  linkType: hard
2545
 
2546
+ "cors@npm:^2.8.5":
2547
+ version: 2.8.5
2548
+ resolution: "cors@npm:2.8.5"
2549
+ dependencies:
2550
+ object-assign: "npm:^4"
2551
+ vary: "npm:^1"
2552
+ checksum: 10c0/373702b7999409922da80de4a61938aabba6929aea5b6fd9096fefb9e8342f626c0ebd7507b0e8b0b311380744cc985f27edebc0a26e0ddb784b54e1085de761
2553
+ languageName: node
2554
+ linkType: hard
2555
+
2556
  "create-require@npm:^1.1.0":
2557
  version: 1.1.1
2558
  resolution: "create-require@npm:1.1.1"
 
3157
  resolution: "fb-api@workspace:."
3158
  dependencies:
3159
  "@aws-sdk/client-s3": "npm:^3.614.0"
3160
+ "@types/cors": "npm:^2"
3161
  "@types/dotenv": "npm:^8.2.0"
3162
  "@types/express": "npm:^4.17.21"
3163
  "@types/multer": "npm:^1"
 
3168
  aws-sdk: "npm:^2.1659.0"
3169
  axios: "npm:^1.7.2"
3170
  babel-register: "npm:^6.26.0"
3171
+ cors: "npm:^2.8.5"
3172
  dotenv: "npm:^16.4.5"
3173
  eslint: "npm:^9.7.0"
3174
  eslint-config-prettier: "npm:^9.1.0"
 
4492
  languageName: node
4493
  linkType: hard
4494
 
4495
+ "object-assign@npm:^4, object-assign@npm:^4.1.1":
4496
  version: 4.1.1
4497
  resolution: "object-assign@npm:4.1.1"
4498
  checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
 
5694
  languageName: node
5695
  linkType: hard
5696
 
5697
+ "vary@npm:^1, vary@npm:~1.1.2":
5698
  version: 1.1.2
5699
  resolution: "vary@npm:1.1.2"
5700
  checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f